/* ============================================================
   Gadebusch Extranet – App Styles
   Custom Design System, kein Build-Tool erforderlich.
   ============================================================ */

/* CSS Reset */
*, *::before, *::after { box-sizing: border-box; }
html { font-size: 16px; -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, h4, h5, h6, p, ul, ol, li, figure, blockquote {
  margin: 0; padding: 0;
}
ul, ol { list-style: none; }
img, svg { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; }
a { color: inherit; }

/* ---- Textfarb-Utilities auf <a> wiederherstellen --------------------------
   `a { color: inherit }` steht unlayered im Reset und schlägt damit ALLE
   Farb-Utilities aus Tailwinds `@layer utilities` — unlayered CSS gewinnt
   gegen jeden Layer, unabhängig von der Spezifität (gleiche Falle wie bei
   `mb-*` auf <p>, siehe CLAUDE-UI §2.2). Folge: `<a class="bg-primary
   text-white">` bekam geerbtes Dunkelbraun statt Weiß (Leerzustand-Buttons
   „Erstes Formular anlegen", „Ersten Test anlegen"), `<a class="text-primary">`
   blieb grau („5 weitere im Kalender" auf dem Dashboard).
   Element + Klasse (0,1,1) schlägt `a` (0,0,1) — ohne !important, und die
   Utilities bleiben für alle anderen Elemente unangetastet. */
a.text-white            { color: #fff; }
/* Gleiche Falle für die Knopf-Bausteine: .extr-btn--primary/--danger liegen
   in @layer components und verlieren deshalb gegen das ungeschichtete
   `a { color: inherit }`. Betraf u. a. „Erste Lernstrecke anlegen". */
a.extr-btn--primary,
a.extr-btn--danger,
a.extr-btn--success     { color: #fff; }
a.extr-btn--outline     { color: hsl(var(--foreground)); }
a.extr-btn--ghost       { color: hsl(var(--muted-foreground)); }
a.extr-icon-btn         { color: hsl(var(--muted-foreground)); }
a.extr-icon-btn:hover   { color: hsl(var(--foreground)); }
a.extr-icon-btn--danger,
a.extr-icon-btn--danger:hover,
a.extr-icon-btn--danger-hover:hover { color: hsl(var(--destructive)); }
a.text-primary          { color: hsl(var(--primary)); }
a.text-foreground       { color: hsl(var(--foreground)); }
a.text-muted-foreground { color: hsl(var(--muted-foreground)); }
a.hover\:text-foreground:hover       { color: hsl(var(--foreground)); }
a.hover\:text-primary:hover          { color: hsl(var(--primary)); }
a.hover\:text-muted-foreground:hover { color: hsl(var(--muted-foreground)); }

/* ---- `hidden` schlägt die später ausgegebenen Display-Utilities ------------
   Tailwind gibt .inline-*, .table-* und .list-item im Stylesheet NACH .hidden
   aus. Bei gleichem Gewicht gewinnt die spätere Regel — `class="hidden
   inline-flex …"` bleibt also sichtbar, obwohl `hidden` gesetzt ist (traf
   u. a. den Button „Alle gelesen" im Benachrichtigungs-Modal, der nach dem
   Markieren stehen blieb). Zwei Klassen im Selektor geben das nötige Gewicht —
   ohne !important und ohne die responsiven Muster (`hidden lg:inline-flex`)
   zu stören, denn dort heißt die Klasse `lg:inline-flex`. */
.hidden.inline, .hidden.inline-block, .hidden.inline-flex, .hidden.inline-grid,
.hidden.inline-table, .hidden.list-item, .hidden.table, .hidden.table-caption,
.hidden.table-cell, .hidden.table-column, .hidden.table-column-group,
.hidden.table-footer-group, .hidden.table-header-group, .hidden.table-row,
.hidden.table-row-group { display: none; }

/* ---- Nachgereichte Utility: .pl-3 ----------------------------------------
   tailwind.css ist ein vorgebautes Artefakt (im Repo liegt kein Build-Tool).
   Der letzte Build hat `pl-3` nicht erfasst — die Klasse fehlt im Stylesheet,
   während .pl-2/.pl-4 vorhanden sind. Folge: Buttons mit `pl-3 pr-2.5`
   (Mehrfachauswahl in der Mitarbeiter-Detailansicht, Filter in „Termine")
   hatten links gar keinen Innenabstand, das Symbol klebte am Rahmen.
   Beim nächsten Tailwind-Build kann dieser Block entfallen. */
.pl-3 { padding-left: calc(var(--spacing) * 3); }

/* ---- Nachgereichte Utilities (fehlen im vorgebauten tailwind.css) ---------
   tailwind.css ist ein andernorts gebautes Artefakt; im Repo liegt kein
   Build-Tool. Der letzte Build ist gegenüber den PHP-Quellen veraltet: die
   folgenden im Markup verwendeten Klassen sind NICHT einkompiliert und tun
   optisch nichts. Sichtbare Folgen u. a.:
     · `top-16 bottom-16` fehlt → das Statistik-Modal in news-detail.php hatte
       keine Höhenbegrenzung, wuchs über den Bildschirm hinaus und ließ sich
       nicht mehr schließen.
     · `pb-28` fehlt → die Inventur-Liste lief unter die fixierte Abschlussleiste.
     · `max-w-xl`, `max-w-[…]`, `max-h-…` fehlen → Panels und Spalten liefen
       auf volle Breite/Höhe.
   Ermittelt durch Abgleich aller class="…"-Tokens der Partials gegen
   tailwind.css + app.css. Beim nächsten Tailwind-Build kann der Block entfallen.
   Spacing-Skala wie Tailwind v4: calc(var(--spacing) * n), --spacing = .25rem. */

/* Abstände */
.mt-2\.5  { margin-top: calc(var(--spacing) * 2.5); }
.mb-2\.5  { margin-bottom: calc(var(--spacing) * 2.5); }
.mr-3    { margin-right: calc(var(--spacing) * 3); }
.pl-1    { padding-left: calc(var(--spacing) * 1); }
.pl-2\.5  { padding-left: calc(var(--spacing) * 2.5); }
.pl-6    { padding-left: calc(var(--spacing) * 6); }
.pb-1\.5  { padding-bottom: calc(var(--spacing) * 1.5); }
.pb-5    { padding-bottom: calc(var(--spacing) * 5); }
.pb-28   { padding-bottom: calc(var(--spacing) * 28); }
.py-3\.5  { padding-block: calc(var(--spacing) * 3.5); }
.gap-x-3   { column-gap: calc(var(--spacing) * 3); }
.gap-x-6   { column-gap: calc(var(--spacing) * 6); }
.gap-y-1\.5 { row-gap: calc(var(--spacing) * 1.5); }
.gap-y-2\.5 { row-gap: calc(var(--spacing) * 2.5); }

/* Größen */
.w-44     { width: calc(var(--spacing) * 44); }
.w-48     { width: calc(var(--spacing) * 48); }
.h-52     { height: calc(var(--spacing) * 52); }
.max-h-12 { max-height: calc(var(--spacing) * 12); }
.max-h-36 { max-height: calc(var(--spacing) * 36); }
.max-h-44 { max-height: calc(var(--spacing) * 44); }
.max-h-52 { max-height: calc(var(--spacing) * 52); }
.max-w-12 { max-width: calc(var(--spacing) * 12); }
.max-w-xl { max-width: 36rem; }
.max-w-\[8rem\]  { max-width: 8rem; }
.max-w-\[10rem\] { max-width: 10rem; }
.max-w-\[12rem\] { max-width: 12rem; }
.max-w-\[220px\] { max-width: 220px; }
.min-w-\[720px\] { min-width: 720px; }
.min-w-\[44rem\] { min-width: 44rem; }
.min-h-\[7rem\]  { min-height: 7rem; }

/* Position & Sonstiges */
.top-10    { top: calc(var(--spacing) * 10); }
.top-16    { top: calc(var(--spacing) * 16); }
.bottom-10 { bottom: calc(var(--spacing) * 10); }
.bottom-16 { bottom: calc(var(--spacing) * 16); }
.bottom-36 { bottom: calc(var(--spacing) * 36); }
.left-0\.5  { left: calc(var(--spacing) * 0.5); }
.right-0\.5 { right: calc(var(--spacing) * 0.5); }
.z-\[55\]   { z-index: 55; }
.opacity-30 { opacity: .3; }
.border-t-2 { border-top-width: 2px; }
.border-l-2 { border-left-width: 2px; }
.border-primary\/50 { border-color: hsl(var(--primary) / 0.5); }

@media (min-width: 640px) {
  .sm\:w-56 { width: calc(var(--spacing) * 56); }
}
@media (min-width: 1024px) {
  .lg\:top-12    { top: calc(var(--spacing) * 12); }
  .lg\:bottom-12 { bottom: calc(var(--spacing) * 12); }
  .lg\:bottom-24 { bottom: calc(var(--spacing) * 24); }
}


/* ============================================================
   Design Tokens (aus React-UI-Demo übernommen)
   ============================================================ */
:root {
  /* ── Mobile Navigationsleiste ──────────────────────────────────────────────
     --extr-bottomnav-pb: unterer Innenabstand der Leiste. Von der Safe Area
       (Home-Indikator) wird der größere Teil des 0.75rem-Innenabstands der
       Einträge abgezogen, damit die Symbolzeile nicht zu hoch schwebt.
       Ohne Safe Area (Browser/Desktop) ist env() = 0. */
  --extr-bottomnav-pb: max(env(safe-area-inset-bottom, 0px) - 1.25rem, 0.25rem);

  /* ── Originalfarben aus src/styles/theme.css (HSL-Channels für hsl(var(--x)) Syntax) ── */
  /* #eb6809 */ --primary:            27 93% 47%;
  /* #eb6809 */ --primary-hsl:        hsl(27, 93%, 47%);
                --primary-foreground: 0 0% 100%;
  /* #faf9f7 */ --background:         40 33% 97%;
  /* #faf9f7 */ --background-hsl:     hsl(40, 33%, 97%);
  /* #2e2117 */ --foreground:         27 33% 13%;
  /* #ffffff */ --card:               0 0% 100%;
  /* #2e2117 */ --card-foreground:    27 33% 13%;
  /* #2e2117 */ --secondary:          27 33% 13%;
  /* #2e2117 */ --secondary-hsl:      hsl(27, 33%, 13%);
                --secondary-foreground: 0 0% 100%;
  /* #f5f4f2 */ --muted:              40 17% 95%;
  /* #6b6158 */ --muted-foreground:   27 10% 38%;
  /* warm   */ --border:             27 20% 88%;
  /* #eb6809 */ --accent:             27 93% 47%;
  /* #d4183d */ --destructive:        350 73% 46%;

  /* Status-Töne für Hinweise, Pillen und Chips (UI-Audit CODE-08): Fläche und
     Schrift, im Dunkel-Scope umgesetzt — statt fester Hex-Werte im Partial.
     Nutzung ohne eigenen Alpha-Zusatz: background: hsl(var(--tone-warn-bg)). */
  /* #fffbeb */ --tone-warn-bg:       48 100% 96%;
  /* #92400e */ --tone-warn-fg:       23 83% 31%;
  /* #fcd34d */ --tone-warn-border:   46 97% 65%;
  /* #dcfce7 */ --tone-ok-bg:         141 84% 93%;
  /* #15803d */ --tone-ok-fg:         142 72% 29%;
  /* #fee2e2 */ --tone-bad-bg:        0 93% 94%;
  /* #b91c1c */ --tone-bad-fg:        0 74% 42%;

  /* #faf9f7 */ --sidebar-bg:         40 33% 97%;
                --sidebar-border:     27 20% 88%;

  --radius:   1rem;
  /* Elevations-System (warm getönt; im Dark-Scope gedämpft überschrieben) */
  --extr-shadow-sm: 0 1px 2px hsl(27 20% 14% / 0.05), 0 1px 3px hsl(27 20% 14% / 0.07);
  --extr-shadow-md: 0 2px 6px hsl(27 35% 18% / 0.08), 0 8px 20px hsl(27 35% 18% / 0.10);
  --extr-shadow-lg: 0 12px 32px hsl(27 35% 18% / 0.16);
  --font-sans: 'Inter', 'SF Pro Display', system-ui, -apple-system, sans-serif;
}

/* ============================================================
   Base
   ============================================================ */
body.extr-body {
  font-family: var(--font-sans);
  background-color: hsl(var(--background));   /* #faf9f7 warm off-white */
  color: hsl(var(--foreground));               /* #2e2117 dark brown */
  margin: 0;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

/* ============================================================
   Shell Layout
   ============================================================ */
.extr-shell {
  display: flex;
  min-height: 100vh;
}

/* ---- Sidebar ---- */
.extr-sidebar {
  display: none; /* Mobile: hidden */
  width: 256px;
  flex-shrink: 0;
  background: hsl(var(--sidebar-bg));
  border-right: 1px solid hsl(var(--sidebar-border));
  flex-direction: column;
  position: fixed;
  top: 0;
  left: 0;
  height: 100vh;
  z-index: 40;
  overflow-y: auto;
}

@media (min-width: 1024px) {
  .extr-sidebar { display: flex; }
  .extr-main { padding-left: 256px; padding-bottom: 0; }
}

.extr-sidebar-logo {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1.5rem;
  border-bottom: 1px solid hsl(var(--sidebar-border));
}

.extr-logo-icon {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 9999px;
  background: hsl(var(--primary) / 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--primary-hsl);
  flex-shrink: 0;
}

.extr-logo-icon svg { width: 1.25rem; height: 1.25rem; }

.extr-logo-name {
  font-weight: 600;
  font-size: 0.9375rem;
  color: hsl(var(--foreground));
}
.extr-logo-sub {
  font-size: 0.75rem;
  color: hsl(var(--muted-foreground));
}

/* Sidebar User */
.extr-sidebar-user {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem 1.5rem;
  border-bottom: 1px solid hsl(var(--sidebar-border));
}

.extr-sidebar-user-info { flex: 1; min-width: 0; }
.extr-sidebar-user-name {
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.extr-sidebar-user-role {
  font-size: 0.75rem;
  color: hsl(var(--muted-foreground));
}

/* Sidebar Nav */
.extr-sidebar-nav {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}
/* Dezente Zwischenüberschriften in der Seitenleisten-Navigation */
.extr-nav-heading {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: hsl(var(--muted-foreground));
  opacity: 0.65;
  padding: 0.75rem 0.75rem 0.2rem;
}

.extr-nav-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.65rem 1rem;
  border-radius: var(--radius);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  color: hsl(var(--muted-foreground));
  transition: background 0.15s, color 0.15s;
}

.extr-nav-item:hover {
  background: hsl(var(--muted));
  color: hsl(var(--foreground));
}

.extr-nav-item--active {
  background: hsl(var(--primary) / 0.1);
  color: var(--primary-hsl);
}

.extr-nav-item--logout {
  color: hsl(var(--muted-foreground));
}
.extr-nav-item--logout:hover {
  background: hsl(0 84% 60% / 0.1);
  color: hsl(0, 84%, 60%);
}

.extr-nav-icon { width: 1.25rem; height: 1.25rem; flex-shrink: 0; }
/* Menütext kürzt mit „…", damit Icon und Badge ihre Breite behalten. */
.extr-nav-label { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Indikator-Badge (Sidebar) */
.extr-nav-badge {
  margin-left: auto;
  flex-shrink: 0;
  white-space: nowrap;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: hsl(0 84% 60%);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px hsl(var(--sidebar-background, var(--background)));
}
.extr-nav-badge.hidden { display: none; }

/* Sidebar Footer */
.extr-sidebar-footer {
  padding: 1rem;
  border-top: 1px solid hsl(var(--sidebar-border));
}
/* Profil-Block sitzt jetzt im Footer (über Abmelden): kompakt, ohne eigene Trennlinie */
.extr-sidebar-footer .extr-sidebar-user {
  padding: 0.5rem;
  border-bottom: none;
  margin-bottom: 0.5rem;
}
.extr-sidebar-version {
  font-size: 0.7rem;
  color: hsl(var(--muted-foreground));
  text-align: center;
  margin-top: 0.5rem;
}

/* ---- Main ---- */
.extr-main {
  flex: 1;
  min-height: 100vh;
  /* Platz für die fixierte Bottom-Nav. Die feste Reserve von 5rem war zu knapp:
     die Leiste ist im Browser bereits ~87px hoch und in der PWA mit Safe Area
     ~97px – bei zweizeiligen Beschriftungen noch mehr. Dadurch lag das letzte
     Element einer Seite (z. B. die Kachel „Weitere") unter der Navigation.
     app.js misst die Leiste und schreibt --extr-bottomnav-h (Höhe + 1rem Luft);
     der Fallback greift, solange das Skript noch nicht gelaufen ist. */
  padding-bottom: var(--extr-bottomnav-h, calc(6.5rem + env(safe-area-inset-bottom, 0px)));
  overflow-x: clip; /* clip statt hidden: bricht position:sticky der Header nicht */
  width: 100%;
  min-width: 0;
}

/* Desktop: keine Bottom-Nav → keine Reserve. Muss hier stehen (nach der
   Basisregel) und die Variable setzen, weil die frühere Media-Query weiter
   oben im Stylesheet bei gleicher Spezifität von der Basisregel überstimmt
   wurde und deshalb wirkungslos blieb. */
@media (min-width: 1024px) {
  .extr-main { --extr-bottomnav-h: 0px; padding-bottom: 0; }
}

/* Inhalts-Container (max. 1845px, linksbündig) */
.extr-content,
.extr-container {
  width: 100%;
  max-width: 1845px;
  margin-left: 0;
  margin-right: auto;
  padding-left: 1rem;
  padding-right: 1rem;
}

@media (min-width: 1024px) {
  .extr-content,
  .extr-container {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
}

/* ---- PWA: Statusleiste (Uhrzeit, Batterie) nicht aussparen ----
   Mit viewport-fit=cover und status-bar-style „black-translucent" reicht das
   App-Fenster bis unter die Statusleiste. Ohne Ausgleich läge der Inhalt unter
   der Uhr. Die obersten Elemente ziehen den Hintergrund deshalb bis an den
   Bildschirmrand und rücken ihren Inhalt um die Safe-Area ein. Im Browser und
   auf dem Desktop ist env(safe-area-inset-top) = 0 — dort ändert sich nichts. */
.extr-body { padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px); }


/* Vollbreiter Header-Hintergrund; Inhalt in .extr-content */
.extr-header-bar {
  position: sticky;
  top: 0;
  z-index: 40;
  padding-top: env(safe-area-inset-top, 0px);
  background-color: rgba(255, 255, 255, 0.8);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid hsl(var(--border));
  width: 100%;
}

/* Fallback: ohne Blur-Unterstützung deckend weiß, damit es lesbar bleibt */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .extr-header-bar {
    background-color: #fff;
  }
}

/* Dashboard-Willkommensbereich */
.extr-dashboard-hero {
  --extr-hero-grad: linear-gradient(90deg, rgba(46, 33, 23, 1) 0%, rgba(92, 66, 44, 1) 100%);
  position: relative;
  background: var(--extr-hero-grad);
  /* Hero füllt in der PWA auch den Bereich hinter der Statusleiste (s. o.);
     der Inhalt rückt entsprechend nach unten (Basis: Tailwind pt-6 = 1.5rem). */
  padding-top: calc(1.5rem + env(safe-area-inset-top, 0px));
}
@media (min-width: 1024px) {
  /* Desktop: Hero liegt mit Abstand im Layout, kein Safe-Area-Ausgleich nötig. */
  .extr-dashboard-hero { padding-top: 1.5rem; }
}
/* Standort-Hintergrundbild als echtes <img class="extr-hero-photo"> (erstes Kind), NICHT
   als CSS-Hintergrund: ein dynamisch gesetztes Hintergrundbild (CSS-Variable ODER direkt,
   per JS-setProperty / innerHTML-Injektion) malt Chromium teils erst nach einem Reload.
   Ein echtes <img> malt zuverlässig. Darüber die 15%-Gradient-Maske via ::after. */
.extr-hero-photo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit; z-index: 0;
}
.extr-dashboard-hero.has-photo::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: var(--extr-hero-grad);
  opacity: 0.85;
  border-radius: inherit;
}
.extr-dashboard-hero.has-photo > *:not(.extr-hero-photo) { position: relative; z-index: 2; }

/* Der Inhaltsbereich wird mobil per negativem Rand (-mt-4) unter den Hero
   gezogen. Ohne eigene Ebene malt der positionierte Hero (bzw. seine
   Foto-Maske ::after) über die erste Karte („Nächste Schicht"). Der Hero
   bekommt darum eine eigene Stacking-Ebene, der Inhalt liegt darüber. */
.extr-dashboard-hero { z-index: 0; }
.extr-dashboard-body { position: relative; z-index: 1; }

/* ============================================================
   News-Artikel Detailansicht – Fließtext-Typografie
   ============================================================ */
.nd-article-body h1,
.nd-article-body h2,
.nd-article-body h3,
.nd-article-body h4 {
  color: hsl(var(--foreground));
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.nd-article-body h1 { font-size: 2rem;    margin-top: 2.5rem; margin-bottom: 0.875rem; }
.nd-article-body h2 { font-size: 1.5rem;  margin-top: 2.25rem; margin-bottom: 0.75rem;
                      padding-bottom: 0.4rem;
                      border-bottom: 2px solid hsl(var(--border)); }
.nd-article-body h3 { font-size: 1.125rem; margin-top: 1.75rem; margin-bottom: 0.5rem; font-weight: 600; }
.nd-article-body h4 { font-size: 1rem;    margin-top: 1.5rem;  margin-bottom: 0.375rem; font-weight: 600; }

/* Erstes Element braucht keinen Abstand nach oben */
.nd-article-body > *:first-child { margin-top: 0; }

/* Eingebettete Bildergalerie im Beitrag (Summernote-Button „Bildergalerie einfügen").
   Der HTML-Sanitizer lässt nur eine Property-Allowlist im style-Attribut durch —
   das Layout darf deshalb nicht an Inline-Styles hängen, sondern kommt über die Klasse.
   Gilt in News-/Wissen-Detail UND im Editor (Summernote rendert im selben Dokument). */
.news-embed-gallery {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding: 6px 0;
  margin: 16px 0;
}
.news-embed-gallery img,
.nd-article-body .news-embed-gallery img,
.wd-prose .news-embed-gallery img {
  flex: 0 0 auto;
  width: min(85%, 520px);
  max-height: 360px;
  object-fit: cover;
  scroll-snap-align: center;
  border-radius: 12px;
  margin: 0;
}

.extr-page {
  max-width: 1845px;
  margin-left: 0;
  margin-right: auto;
  padding: 1.5rem 1rem;
}

@media (min-width: 1024px) {
  .extr-page { padding: 2rem 2rem; }
}

/* ---- Bottom Nav (Mobile) ---- */
/* Schwebende Navigation im Glas-Look.
   Die Leiste klebt nicht mehr am Rand, sondern schwebt als freistehende Pille
   über dem Inhalt: Weichzeichner plus kräftigere Farben lassen den Inhalt
   durchscheinen, eine helle Innenkante wirkt als Lichtreflex, zwei weiche
   Schattenlagen heben die Pille ab. Farben kommen aus den Design-Tokens des
   Projekts, der Dunkelmodus wird weiter unten nachgezogen. */
.extr-bottom-nav {
  display: flex;
  justify-content: center;
  position: fixed;
  left: 0;
  right: 0;
  /* Abstand zum unteren Rand; auf Geräten mit Home-Indikator entsprechend mehr. */
  bottom: max(env(safe-area-inset-bottom, 0px) - 0.75rem, 1rem);
  /* Unter den Overlays (z-index ab 50): sonst deckt die Leiste die Fußzeile
     eines Modals ab, weil sie im DOM nach dem Seiteninhalt steht. */
  z-index: 45;
  /* Seitlicher Rand inkl. Sicherheitsbereich (Notch im Querformat). */
  padding: 0 max(0.875rem, env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  pointer-events: none;   /* nur die Pille selbst nimmt Eingaben an */
}

.extr-bottom-nav-pill {
  position: relative;   /* Bezugsrahmen der gleitenden Kapsel */
  pointer-events: auto;
  display: flex;
  align-items: stretch;
  gap: 0.125rem;
  width: 100%;
  max-width: 27rem;
  padding: 0.375rem;
  border-radius: 1.625rem;
  background: hsl(var(--background) / 0.62);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid hsl(0 0% 100% / 0.55);
  box-shadow:
    0 1px 0 hsl(0 0% 100% / 0.7) inset,
    0 -1px 0 hsl(0 0% 0% / 0.03) inset,
    0 10px 30px hsl(0 0% 0% / 0.16),
    0 2px 8px hsl(0 0% 0% / 0.10);
}

/* Ohne Weichzeichner (ältere Browser) und bei „Transparenz reduzieren“ wird die
   Fläche deckend – sonst wäre die Leiste über hellem Inhalt schlecht lesbar. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .extr-bottom-nav-pill { background: hsl(var(--background) / 0.97); }
}
@media (prefers-reduced-transparency: reduce) {
  .extr-bottom-nav-pill {
    background: hsl(var(--background) / 0.97);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

@media (min-width: 1024px) {
  .extr-bottom-nav { display: none; }
}

.extr-bottom-nav-item {
  flex: 1;
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 0.25rem 0.4375rem;
  border-radius: 1.3125rem;
  text-decoration: none;
  color: hsl(var(--muted-foreground));
  font-size: 0.6875rem;
  gap: 0.25rem;
  transition: color 0.15s, background 0.25s ease;
}

/* Der aktive Eintrag trägt nur noch die Farbe – die Kapsel darunter ist ein
   eigenes Element (siehe .extr-bottom-nav-slider), damit sie beim Wechsel von
   einem Eintrag zum nächsten gleiten kann. */
.extr-bottom-nav-item--active { color: var(--primary-hsl); }
.extr-bottom-nav-item:active { transform: scale(0.97); }

/* Gleitende Kapsel: Position und Breite setzt app.js an den echten Maßen des
   aktiven Eintrags – so passt sie auch bei unterschiedlich breiten Texten. */
.extr-bottom-nav-slider {
  position: absolute;
  top: 0.375rem;
  bottom: 0.375rem;
  left: 0;
  width: 0;
  border-radius: 1.3125rem;
  background: hsl(0 0% 100% / 0.82);
  box-shadow: 0 1px 0 hsl(0 0% 100% / 0.9) inset, 0 2px 6px hsl(0 0% 0% / 0.10);
  transform: translateX(0);
  opacity: 0;
  pointer-events: none;
  transition: transform 0.42s cubic-bezier(0.34, 1.28, 0.42, 1),
              width 0.42s cubic-bezier(0.34, 1.28, 0.42, 1),
              opacity 0.2s ease;
}
.extr-bottom-nav-slider.is-on { opacity: 1; }
/* Beim ersten Zeichnen ohne Bewegung an die richtige Stelle setzen. */
.extr-bottom-nav-slider.is-instant { transition: none; }
/* Symbol und Text liegen über der Kapsel. */
.extr-bottom-nav-item { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) {
  .extr-bottom-nav-slider { transition: opacity 0.2s ease; }
}

.extr-bottom-nav-icon { width: 1.25rem; height: 1.25rem; }

/* Indikator-Badge (Mobile-Nav, über dem Icon) */
.extr-bottom-nav-icon-wrap {
  position: relative;
  display: inline-flex;
}
.extr-bottom-nav-badge {
  white-space: nowrap;
  position: absolute;
  top: -0.4rem;
  left: 60%;
  min-width: 1.05rem;
  height: 1.05rem;
  padding: 0 0.3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: hsl(0 84% 60%);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px #fff;
}
.extr-bottom-nav-badge.hidden { display: none; }

/* Indikator-Badge (Dashboard-Schnellaktionen) */
.extr-quick-badge {
  white-space: nowrap;
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: hsl(0 84% 60%);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  box-shadow: 0 0 0 2px #fff;
}
.extr-quick-badge.hidden { display: none; }

/* ── Mobiles „Weitere"-Overlay (Schnellaktionen-Überlauf) ── */
/* In @layer components: das Blatt trägt im Markup `hidden lg:hidden` — beide
   Utilities müssen den Baustein schlagen können. Ungeschichtet gewänne
   `display:flex`, und ein am Handy geöffnetes Blatt bliebe beim Drehen aufs
   Querformat über der Schreibtisch-Ansicht liegen (samt Scroll-Sperre). */
@layer components {
  .extr-more-overlay {
    position: fixed; inset: 0; z-index: 70;
    display: flex; align-items: flex-end;
    background: rgb(0 0 0 / 0.5);
    backdrop-filter: blur(2px);
  }
}
.extr-more-overlay.hidden { display: none; }
.extr-more-sheet {
  width: 100%;
  max-height: 75vh;
  background: #fff;
  border-radius: 1.25rem 1.25rem 0 0;
  box-shadow: 0 -8px 30px -8px rgb(0 0 0 / 0.25);
  display: flex; flex-direction: column;
  overflow: hidden;
  animation: extr-more-up 0.18s ease-out;
}
@keyframes extr-more-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
.extr-more-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid hsl(var(--border));
  flex-shrink: 0;
}
.extr-more-list { overflow-y: auto; padding: 0.5rem; padding-bottom: calc(0.5rem + env(safe-area-inset-bottom)); }
.extr-more-item {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.75rem 0.75rem;
  border-radius: 0.75rem;
  color: hsl(var(--foreground));
  transition: background 0.15s;
}
.extr-more-item:hover, .extr-more-item:active { background: hsl(var(--muted)); }
.extr-more-ic {
  width: 2.25rem; height: 2.25rem; flex-shrink: 0;
  border-radius: 0.625rem;
  background: hsl(var(--primary) / 0.1);
  display: inline-flex; align-items: center; justify-content: center;
}
.extr-more-badge {
  flex-shrink: 0; white-space: nowrap;
  min-width: 1.25rem; height: 1.25rem; padding: 0 0.375rem;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 9999px;
  background: hsl(0 84% 60%); color: #fff;
  font-size: 0.6875rem; font-weight: 700; line-height: 1;
}
.extr-more-badge.hidden { display: none; }
body.extr-more-open { overflow: hidden; }

/* Das Sheet steht im Markup innerhalb von .extr-dashboard-body — und die spannt
   mit position:relative + z-index:1 einen eigenen Stapelkontext auf. Darin ist
   das z-index:70 des Overlays gegenüber der Bottom-Nav (z-index:45) wirkungslos,
   weil verglichen wird, was der Kontext insgesamt wiegt (1 gegen 45): die Leiste
   lag über dem geöffneten Sheet und schnitt die untersten Einträge ab. Solange
   das Sheet offen ist, hebt sich der Kontext deshalb über die Leiste. */
body.extr-more-open .extr-dashboard-body { z-index: 60; }

/* ============================================================
   Avatar
   ============================================================ */
.extr-avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 9999px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 600;
  font-size: 0.875rem;
  flex-shrink: 0;
  text-transform: uppercase;
}

.extr-avatar--lg {
  width: 4rem;
  height: 4rem;
  font-size: 1.25rem;
}

.extr-avatar--xl {
  width: 5rem;
  height: 5rem;
  font-size: 1.5rem;
}

/* Tailwind bg-* Klassen für Avatar-Farben */
.bg-blue-500   { background-color: #3b82f6; }
.bg-violet-500 { background-color: #8b5cf6; }
.bg-emerald-500{ background-color: #10b981; }
.bg-rose-500   { background-color: #f43f5e; }
.bg-amber-500  { background-color: #f59e0b; }
.bg-teal-500   { background-color: #14b8a6; }
.bg-indigo-500 { background-color: #6366f1; }
.bg-pink-500   { background-color: #ec4899; }

/* ============================================================
   Page Header
   ============================================================ */
.extr-page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.extr-page-header-left { display: flex; align-items: center; gap: 0.75rem; }
.extr-page-title { font-size: 1.375rem; font-weight: 700; color: hsl(var(--foreground)); margin: 0; }
.extr-breadcrumb {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  color: hsl(var(--muted-foreground));
}
.extr-breadcrumb a { color: hsl(var(--muted-foreground)); text-decoration: none; }
.extr-breadcrumb a:hover { color: hsl(var(--foreground)); }

/* ============================================================
   Cards
   ============================================================ */
.extr-card {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: calc(var(--radius) * 1.5);
  overflow: hidden;
}

.extr-card-header {
  padding: 1rem 1.25rem 0.75rem;
  border-bottom: 1px solid hsl(var(--border));
}

.extr-card-title {
  font-size: 0.9375rem;
  font-weight: 600;
  color: hsl(var(--foreground));
}

.extr-card-body { padding: 1.25rem; }

/* ============================================================
   Buttons
   ============================================================ */
/* In @layer components: Utility-Klassen im selben class-Attribut
   (bg-muted/40, font-mono, pr-20 …) sollen die Vorgaben überschreiben
   können. tailwind.css meldet die Layer-Reihenfolge an. */
@layer components {
  .extr-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
    /* rounded-lg dieses Builds (0.75rem) — die Radiusvariable (1rem) ist für
       Karten gedacht. */
    border-radius: var(--radius-lg, 0.75rem);
    /* Achtung: auf <button> bleiben font-size/-weight WIRKUNGSLOS —
       `button, input, select, textarea { font: inherit }` steht oben
       ungeschichtet und schlägt jede Regel aus einem @layer. Auf <a> greifen
       sie. Das war mit der alten Kette `text-sm font-medium` genauso; wer es
       ändern will, muss den Reset in einen Layer ziehen. */
    font-size: 0.875rem;
    font-weight: 500;
    /* Kein Rahmen in der Grundform — die Primärkette im Bestand hatte keinen.
       Nur .extr-btn--outline setzt einen, sonst wären alle Knöpfe 2 px höher. */
    border: 0;
    line-height: calc(1.25 / 0.875);
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s, color 0.15s, border-color 0.15s, opacity 0.15s, transform 0.12s, box-shadow 0.15s;
    white-space: nowrap;
  }
  .extr-btn svg, .extr-btn i { width: 1rem; height: 1rem; }
  .extr-btn:active { transform: scale(0.97); }
  .extr-btn--primary:hover, .extr-btn--danger:hover, .extr-btn--success:hover { box-shadow: var(--extr-shadow-md); }

  .extr-btn--primary {
    background: var(--color-primary, var(--primary-hsl));
    color: #fff;
  }
  .extr-btn--primary:hover { opacity: 0.9; }

  .extr-btn--outline {
    background: transparent;
    border: 1px solid hsl(var(--border));
    color: hsl(var(--foreground));
  }
  .extr-btn--outline:hover { background: hsl(var(--muted)); }
  /* Deckend weiß statt durchsichtig — für Leisten auf gemustertem Grund
     (im Bestand die Kette mit zusätzlichem bg-white). */
  .extr-btn--solid { background: hsl(var(--card)); }

  .extr-btn--ghost {
    background: transparent;
    color: hsl(var(--muted-foreground));
  }
  .extr-btn--ghost:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }

  .extr-btn--danger {
    /* red-600 wie im Bestand (bg-red-600), nicht red-500. */
    background: var(--color-red-600, hsl(0 72% 51%));
    color: #fff;
  }
  .extr-btn--danger:hover { opacity: 0.9; }

  /* Bestätigende Aktion — Einbuchen, Freigeben, Abschließen (UI-Audit BTN-05).
     green-700: Weiß darauf ≈ 5:1. Das green-600 der ersetzten Ketten kam nur auf ≈ 3,3:1 (WCAG AA verlangt 4,5:1). */
  .extr-btn--success {
    background: var(--color-green-700, hsl(142 72% 29%));
    color: #fff;
  }
  .extr-btn--success:hover { opacity: 0.9; }

  .extr-btn--sm { padding: 0.375rem 0.75rem; font-size: 0.8125rem; gap: 0.375rem; }
  .extr-btn--icon { padding: 0.5rem; }
  /* Deckt die Kette „disabled:opacity-60 disabled:cursor-not-allowed" mit ab. */
  .extr-btn:disabled,
  .extr-btn[disabled],
  .extr-btn.is-disabled { opacity: 0.6; cursor: not-allowed; }
  .extr-btn:disabled:active { transform: none; }
  /* Breite Knöpfe (Modal-Fuß, mobile Formulare). */
  .extr-btn--block { width: 100%; }
}

/* ============================================================
   Form Elements
   ============================================================ */
/* In @layer components: Utility-Klassen im selben class-Attribut
   (bg-muted/40, font-mono, pr-20 …) sollen die Vorgaben überschreiben
   können. tailwind.css meldet die Layer-Reihenfolge an. */
@layer components {
  .extr-form-group { margin-bottom: 1rem; }
  .extr-label {
    display: block;
    font-size: var(--text-sm, 0.875rem);
    line-height: calc(1.25 / 0.875);
    font-weight: 500;
    margin-bottom: 0.25rem;   /* mb-1 wie im Bestand */
    color: hsl(var(--foreground));
  }
  /* Zweizeiliger Abstand, wo das Feld Luft braucht (mb-2 im Bestand). */
  .extr-label--roomy { margin-bottom: 0.5rem; }
  .extr-label--required::after { content: ' *'; color: hsl(0 84% 60%); }

  .extr-input,
  .extr-select,
  .extr-textarea {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid hsl(var(--border));
    /* Exakt die Kette, die der Bestand hundertfach kopiert hatte (BTN-04):
       rounded-lg (0.75rem in diesem Build), durchsichtiger Grund, Fokusring. */
    border-radius: var(--radius-lg, 0.75rem);
    font-size: 0.875rem;
    color: hsl(var(--foreground));
    background: transparent;
    transition: border-color 0.15s, box-shadow 0.15s;
    font-family: inherit;
  }

  .extr-input:focus,
  .extr-select:focus,
  .extr-textarea:focus {
    outline: none;
    box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
  }

  .extr-input:disabled,
  .extr-select:disabled,
  .extr-textarea:disabled {
    background: hsl(var(--muted) / 0.4);
    color: hsl(var(--muted-foreground));
    cursor: not-allowed;
  }

  .extr-input::placeholder,
  .extr-textarea::placeholder { color: hsl(var(--muted-foreground)); }

  .extr-input--error { border-color: hsl(0 84% 60%); }
  .extr-error-text { color: hsl(0 84% 60%); font-size: 0.8rem; margin-top: 0.25rem; }

  .extr-textarea { resize: vertical; }
  /* Auswahlfelder trugen im Bestand fast durchweg bg-white. */
  .extr-select { background-color: hsl(var(--card)); appearance: none; 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='%236b7280' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.75rem center; padding-right: 2rem; }
}

/* ============================================================
   Badges
   ============================================================ */
.extr-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.2rem 0.6rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 500;
}
.extr-badge--green  { background: hsl(142 71% 45% / 0.15); color: hsl(142 71% 35%); }
.extr-badge--red    { background: hsl(0 84% 60% / 0.15);   color: hsl(0 84% 45%);   }
.extr-badge--yellow { background: hsl(38 92% 50% / 0.15);  color: hsl(38 92% 35%);  }
.extr-badge--blue   { background: hsl(221 83% 53% / 0.15); color: hsl(221 83% 43%); }
.extr-badge--gray   { background: hsl(var(--muted));        color: hsl(var(--muted-foreground)); }

/* ============================================================
   Tabs
   ============================================================ */
.extr-tabs {
  border-bottom: 1px solid hsl(var(--border));
  display: flex;
  gap: 0;
  margin-bottom: 1.5rem;
  overflow-x: auto;
}

.extr-tab {
  padding: 0.75rem 1.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
  border-bottom: 2px solid transparent;
  cursor: pointer;
  background: none;
  border-top: none;
  border-left: none;
  border-right: none;
  white-space: nowrap;
  transition: color 0.15s, border-color 0.15s;
  text-decoration: none;
  display: block;
}

.extr-tab:hover { color: hsl(var(--foreground)); }
.extr-tab--active { color: var(--primary-hsl); border-bottom-color: var(--primary-hsl); }

.extr-tab-panel { display: none; }
.extr-tab-panel--active { display: block; }

/* ============================================================
   Grid Utilities
   ============================================================ */
.extr-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.extr-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.extr-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }

@media (max-width: 767px) {
  .extr-grid-2, .extr-grid-3, .extr-grid-4 { grid-template-columns: 1fr; }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .extr-grid-3, .extr-grid-4 { grid-template-columns: 1fr 1fr; }
}

/* ============================================================
   Employee Cards
   ============================================================ */
.extr-employee-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1rem;
}

.extr-employee-card {
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: calc(var(--radius) * 1.5);
  padding: 1.25rem;
  text-decoration: none;
  color: hsl(var(--foreground));
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  transition: box-shadow 0.15s, border-color 0.15s, transform 0.15s cubic-bezier(.22,.61,.36,1);
  cursor: pointer;
}

.extr-employee-card:hover {
  border-color: var(--primary-hsl);
  box-shadow: var(--extr-shadow-md);
  transform: translateY(-2px);
}
.extr-employee-card:active { transform: translateY(0) scale(0.995); }

.extr-employee-card-body { flex: 1; min-width: 0; }
.extr-employee-card-name { font-weight: 600; font-size: 0.9375rem; margin-bottom: 0.125rem; }
.extr-employee-card-role { font-size: 0.8125rem; color: hsl(var(--muted-foreground)); margin-bottom: 0.5rem; }
.extr-employee-card-meta { display: flex; align-items: center; gap: 0.5rem; font-size: 0.75rem; color: hsl(var(--muted-foreground)); flex-wrap: wrap; }
.extr-employee-card-meta i { width: 0.875rem; height: 0.875rem; }

/* ============================================================
   Search & Filters
   ============================================================ */
.extr-search-bar {
  display: flex;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

.extr-search-wrap {
  position: relative;
  flex: 1;
  min-width: 200px;
}

.extr-search-wrap i {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1rem;
  height: 1rem;
  color: hsl(var(--muted-foreground));
}

.extr-search-input {
  width: 100%;
  padding: 0.5rem 0.75rem 0.5rem 2.25rem;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius);
  font-size: 0.875rem;
  background: hsl(var(--muted) / 0.5);
  color: hsl(var(--foreground));
  transition: border-color 0.15s;
}
.extr-search-input:focus { outline: none; border-color: var(--primary-hsl); background: hsl(var(--background)); }

/* ============================================================
   Detail: Profile Header
   ============================================================ */
.extr-profile-header {
  background: linear-gradient(135deg, hsl(var(--primary) / 0.08), hsl(var(--background)));
  border: 1px solid hsl(var(--border));
  border-radius: calc(var(--radius) * 1.5);
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}

.extr-profile-header-inner {
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.extr-profile-info { flex: 1; min-width: 0; }
.extr-profile-name { font-size: 1.375rem; font-weight: 700; margin: 0 0 0.25rem; }
.extr-profile-role { font-size: 0.9375rem; color: hsl(var(--muted-foreground)); margin: 0 0 0.5rem; }
.extr-profile-meta {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  font-size: 0.8125rem;
  color: hsl(var(--muted-foreground));
}
.extr-profile-meta-item { display: flex; align-items: center; gap: 0.25rem; }
.extr-profile-meta-item i { width: 0.875rem; height: 0.875rem; }

.extr-profile-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ============================================================
   Detail Info Grid
   ============================================================ */
.extr-detail-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

@media (max-width: 600px) {
  .extr-detail-grid { grid-template-columns: 1fr; }
}

.extr-detail-field { }
.extr-detail-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.25rem;
}
.extr-detail-value { font-size: 0.9375rem; color: hsl(var(--foreground)); }
.extr-detail-value--empty { color: hsl(var(--muted-foreground)); font-style: italic; }

/* ============================================================
   Modal
   ============================================================ */
.extr-modal-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.5);
  z-index: 100;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  /* Safe-Area (PWA): Die Abdunklung bleibt vollflächig, das Modal selbst rückt
     um Dynamic Island bzw. Home-Indikator ein (s. Block „Safe-Area" unten). */
  padding-top: calc(1rem + env(safe-area-inset-top, 0px));
  padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
}
.extr-modal-backdrop--open { display: flex; }

.extr-modal {
  background: hsl(var(--background));
  border-radius: calc(var(--radius) * 2);
  padding: 1.5rem;
  width: 100%;
  max-width: 540px;
  /* 100% = Höhe abzüglich der Safe-Area-Abstände des Backdrops */
  max-height: min(90vh, 100%);
  overflow-y: auto;
  box-shadow: 0 20px 60px rgba(0,0,0,0.2);
}

.extr-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 1.25rem;
}

.extr-modal-title { font-size: 1.125rem; font-weight: 700; }
.extr-modal-close { background: none; border: none; cursor: pointer; color: hsl(var(--muted-foreground)); padding: 0.25rem; border-radius: var(--radius); }
.extr-modal-close:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-modal-close svg, .extr-modal-close i { width: 1.25rem; height: 1.25rem; }

.extr-modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid hsl(var(--border));
}

/* ---- Safe-Area: Modale nicht unter Insel / Home-Indikator ------------------
   Mit viewport-fit=cover reicht das App-Fenster bis an die Bildschirmkanten.
   Overlays liegen als `fixed inset-0` über dem gesamten Bildschirm — Kopf- und
   Fußzeile eines Modals lägen damit unter der Kamera-Insel bzw. der Leiste am
   unteren Rand. Die Overlay-Wurzel wird deshalb oben und unten um die
   Safe-Area eingerückt: absolut positionierte Kinder (das Panel) beziehen sich
   auf deren Padding-Box und rücken automatisch mit. Nur die Abdunklung wird
   wieder auf volle Höhe gezogen, damit kein heller Streifen entsteht.
   Ausgenommen ist .extr-modal-backdrop – dort ist die Wurzel selbst die
   Abdunklung und rückt per Innenabstand ein (s. o.).
   Ohne Safe-Area (Browser, Desktop) ist env() = 0 → alles unverändert. */
[class~="fixed"][class~="inset-0"]:not(.extr-modal-backdrop),
.extr-dlg:not(.extr-modal-backdrop) {
  top: env(safe-area-inset-top, 0px);
  bottom: env(safe-area-inset-bottom, 0px);
}
[class~="fixed"][class~="inset-0"]:not(.extr-modal-backdrop) > [class*="bg-black/"],
.extr-dlg:not(.extr-modal-backdrop) > .extr-dlg-backdrop {
  top: calc(-1 * env(safe-area-inset-top, 0px));
  bottom: calc(-1 * env(safe-area-inset-bottom, 0px));
}
/* Panels, die ihre Höhe inline an der Viewport-Höhe festmachen
   (style="max-height: calc(100vh - 2rem)"), kennen die Safe-Area nicht:
   ohne Korrektur ragen sie über den eingerückten Bereich hinaus. */
[class~="fixed"][class~="inset-0"] [style*="100vh"],
.extr-dlg [style*="100vh"] {
  max-height: calc(100vh - 2rem
                   - env(safe-area-inset-top, 0px)
                   - env(safe-area-inset-bottom, 0px)) !important;
}


/* ---- Modal-Panels: Höhe hart begrenzen, Scroll-Bereiche dürfen schrumpfen ---
   Zwei wiederkehrende Fehlerbilder in Overlays (`fixed inset-0` + absolut
   positioniertes Panel):
   1) Ein Flex-Kind mit `flex-1 overflow-y-auto` hat implizit `min-height:auto`
      und schrumpft deshalb NICHT unter seine Inhaltshöhe. Vor allem WebKit
      (iOS/PWA) zieht das Panel dadurch über den Bildschirmrand hinaus – der
      Inhalt scrollt nicht, Kopf-/Fußzeile samt Schließen-Knopf werden
      unerreichbar. `min-height: 0` ist der Standard-Gegengriff.
   2) Panels ohne top/bottom (oder mit einer Klasse, die im vorgebauten
      tailwind.css fehlt) wachsen mit ihrem Inhalt. `max-height: 100%` bezieht
      sich auf die bereits um die Safe-Area eingerückte Overlay-Wurzel und
      deckelt sie zuverlässig.
   Beides schränkt nur ein, was ohnehin passen sollte – Panels, die bereits
   korrekt begrenzt sind, ändern sich nicht. */
[class~="fixed"][class~="inset-0"] [class~="flex-col"] > [class~="flex-1"],
.extr-dlg [class~="flex-col"] > [class~="flex-1"],
.extr-dlg-panel > .extr-dlg-body { min-height: 0; }
[class~="fixed"][class~="inset-0"]:not(.extr-modal-backdrop) > [class~="absolute"]:not([class*="bg-black/"]) {
  max-height: 100%;
}

/* ============================================================
   Toast Notifications
   ============================================================ */
.extr-toasts {
  position: fixed;
  bottom: 5rem;
  right: 1rem;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  pointer-events: none;
}

@media (min-width: 1024px) {
  .extr-toasts { bottom: 1.5rem; }
}

.extr-toast {
  position: relative;
  overflow: hidden;
  background: hsl(var(--foreground));
  color: hsl(var(--background));
  padding: 0.7rem 1rem 0.7rem 0.85rem;
  border-left: 3px solid hsl(var(--primary));
  border-radius: var(--radius);
  font-size: 0.875rem;
  max-width: 340px;
  pointer-events: all;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  box-shadow: var(--extr-shadow-lg);
  animation: extrToastIn 0.26s cubic-bezier(.22,.61,.36,1);
}
.extr-toast-icon { width: 1.05rem; height: 1.05rem; flex-shrink: 0; }
.extr-toast-msg  { flex: 1; min-width: 0; }
.extr-toast-bar  {
  position: absolute; left: 0; bottom: 0; height: 2px; width: 100%;
  background: rgba(255,255,255,0.5); transform-origin: left;
  animation: extrToastBar 3.5s linear forwards;
}
.extr-toast--success { background: hsl(152 56% 30%); border-left-color: hsl(142 71% 58%); }
.extr-toast--error   { background: hsl(0 55% 38%);  border-left-color: hsl(0 84% 66%); }
.extr-toast--info    { background: hsl(var(--foreground)); border-left-color: hsl(var(--primary)); }
.extr-toast--out     { animation: extrToastOut 0.26s ease forwards; }

@keyframes extrToastIn  { from { opacity: 0; transform: translateX(18px); } to { opacity: 1; transform: none; } }
@keyframes extrToastOut { to { opacity: 0; transform: translateX(18px); } }
@keyframes extrToastBar { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* ============================================================
   Loading Overlay
   ============================================================ */
.extr-loading {
  position: fixed;
  inset: 0;
  background: rgba(255,255,255,0.6);
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
}

.extr-loading-spinner {
  width: 2.5rem;
  height: 2.5rem;
  border: 3px solid hsl(var(--border));
  border-top-color: var(--primary-hsl);
  border-radius: 9999px;
  animation: spin 0.6s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ============================================================
   Utilities
   ============================================================ */
.extr-divider { border: none; border-top: 1px solid hsl(var(--border)); margin: 1.25rem 0; }
.extr-text-muted { color: hsl(var(--muted-foreground)); }
.extr-text-sm { font-size: 0.875rem; }
.extr-flex { display: flex; align-items: center; }
.extr-flex-between { display: flex; align-items: center; justify-content: space-between; }
.extr-gap-2 { gap: 0.5rem; }
.extr-gap-3 { gap: 0.75rem; }
.extr-mt-1 { margin-top: 0.25rem; }
.extr-mt-2 { margin-top: 0.5rem; }
.extr-mt-4 { margin-top: 1rem; }
.extr-mb-4 { margin-bottom: 1rem; }
.extr-mb-6 { margin-bottom: 1.5rem; }
.extr-p-4 { padding: 1rem; }
.extr-w-full { width: 100%; }
.extr-hidden { display: none; }

/* Back Button */
.extr-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: hsl(var(--muted-foreground));
  font-size: 0.875rem;
  text-decoration: none;
  padding: 0.375rem 0;
  background: none;
  border: none;
  cursor: pointer;
  transition: color 0.15s;
}
.extr-back-btn:hover { color: hsl(var(--foreground)); }
.extr-back-btn i { width: 1rem; height: 1rem; }

/* Permissions Table */
.extr-perm-table { width: 100%; border-collapse: collapse; }
.extr-perm-table th, .extr-perm-table td { padding: 0.625rem 0.75rem; text-align: left; border-bottom: 1px solid hsl(var(--border)); font-size: 0.875rem; }
.extr-perm-table th { font-weight: 500; color: hsl(var(--muted-foreground)); }
.extr-toggle { position: relative; display: inline-block; width: 2.5rem; height: 1.375rem; }
.extr-toggle input { opacity: 0; width: 0; height: 0; }
.extr-toggle-slider {
  position: absolute; cursor: pointer; inset: 0;
  background: hsl(var(--border)); border-radius: 9999px; transition: background 0.2s;
}
.extr-toggle-slider::before {
  content: ''; position: absolute;
  width: 1rem; height: 1rem;
  left: 0.1875rem; top: 0.1875rem;
  background: #fff; border-radius: 9999px; transition: transform 0.2s;
}
.extr-toggle input:checked + .extr-toggle-slider { background: var(--primary-hsl); }
.extr-toggle input:checked + .extr-toggle-slider::before { transform: translateX(1.125rem); }

/* Custom Checkbox */
.extr-check {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  vertical-align: middle;
}

.extr-check input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  margin: 0;
}

.extr-check-box {
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid hsl(var(--border));
  border-radius: 0.375rem;
  background: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.extr-check-box svg {
  width: 0.875rem;
  height: 0.875rem;
  color: #fff;
  opacity: 0;
  transform: scale(0.75);
  transition: opacity 0.15s, transform 0.15s;
}

.extr-check input:checked + .extr-check-box {
  background: var(--primary-hsl);
  border-color: var(--primary-hsl);
}

.extr-check input:checked + .extr-check-box svg {
  opacity: 1;
  transform: scale(1);
}

.extr-check input:focus-visible + .extr-check-box {
  box-shadow: 0 0 0 3px hsl(var(--primary) / 0.25);
}

.extr-check input:disabled + .extr-check-box {
  opacity: 0.45;
  cursor: not-allowed;
}

.extr-check:has(input:disabled) {
  cursor: not-allowed;
}

/* Team-Chats Zugriffstabelle */
.chat-access-grid {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.chat-access-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 4.5rem 4.5rem;
  gap: 0.75rem;
  align-items: center;
}

.chat-access-row--head {
  padding: 0 0.5rem 0.625rem;
  border-bottom: 1px solid hsl(var(--border));
  font-size: 0.75rem;
  font-weight: 500;
  color: hsl(var(--muted-foreground));
}

.chat-access-row--data {
  padding: 0.5rem;
  border: 1px solid hsl(var(--border));
  border-radius: 0.75rem;
}

.chat-access-col-check {
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

/* ============================================================
   Summernote – Design-Anpassungen (Lite-Version)
   ============================================================ */
.note-editor.note-frame {
  border: 1px solid hsl(var(--border)) !important;
  border-radius: 0.5rem !important;
  overflow: hidden;
  box-shadow: none !important;
}
.note-editor.note-frame .note-toolbar {
  background: hsl(var(--muted)) !important;
  border-bottom: 1px solid hsl(var(--border)) !important;
  padding: 4px 6px !important;
}
.note-editor.note-frame .note-editable {
  background: #fff !important;
  color: hsl(var(--foreground)) !important;
  font-family: var(--font-sans) !important;
  font-size: 0.9rem !important;
  line-height: 1.7 !important;
  padding: 1rem !important;
}
.note-editor.note-frame .note-statusbar {
  background: hsl(var(--muted)) !important;
  border-top: 1px solid hsl(var(--border)) !important;
}
/* Toolbar-Buttons */
.note-btn {
  border-radius: 0.375rem !important;
  border: 1px solid transparent !important;
  padding: 2px 6px !important;
  font-size: 0.8125rem !important;
  background: transparent !important;
  color: hsl(var(--foreground)) !important;
  transition: background 0.15s, color 0.15s !important;
}
.note-btn:hover, .note-btn:focus {
  background: hsl(var(--border)) !important;
  border-color: transparent !important;
}
.note-btn.active, .note-btn.active:hover {
  background: var(--primary-hsl) !important;
  color: #fff !important;
}
.note-dropdown-menu {
  border: 1px solid hsl(var(--border)) !important;
  border-radius: 0.5rem !important;
  box-shadow: 0 4px 16px -4px rgb(0 0 0 / 0.12) !important;
  padding: 4px !important;
}
.note-dropdown-item {
  border-radius: 0.375rem !important;
  padding: 4px 10px !important;
  font-size: 0.875rem !important;
}
.note-dropdown-item:hover {
  background: hsl(var(--muted)) !important;
}
/* Toolbar-Gruppen */
.note-btn-group { gap: 2px !important; }
/* Fullscreen / Codeview z-Index */
.note-editor.note-fullscreen { z-index: 9999 !important; }
/* Überschriften-Dropdown sauber */
.note-style .dropdown-style blockquote,
.note-style .dropdown-style h1,
.note-style .dropdown-style h2,
.note-style .dropdown-style h3,
.note-style .dropdown-style h4,
.note-style .dropdown-style p {
  font-size: 0.875rem !important;
  margin: 0 !important;
}

/* ============================================================
   Chat – Vollhöhen-Layout
   ============================================================ */

/* Wenn Chat-Detail aktiv ist, kein Padding unten im Main */
.extr-main--chat {
  /* Chat auf Viewport-Höhe fixieren: sonst wächst der Wrapper mit dem Inhalt,
     die ganze Seite scrollt und Mitglieder-Leiste + Eingabezeile scrollen weg. */
  height: 100vh;
  height: 100dvh;
  padding-bottom: 0 !important;
  overflow: hidden !important;
}
.extr-main--chat #extr-main {
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Desktop-Chat-Raster: Zeilenhöhe an den Container binden (minmax(0,1fr)), sonst
   sprengt die Nachrichtenspalte das Raster, der Feed scrollt nicht intern und
   die Mitglieder-Leiste rechts scrollt mit der Seite weg. */
.extr-chat-grid { grid-template-rows: minmax(0, 1fr); }

/* Chat-Wrapper füllt verfügbare Höhe */
#extr-chat-page {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

/* Nachrichten-Feed */
#chat-messages-feed {
  flex: 1;
  overflow-y: auto;
  scroll-behavior: smooth;
  /* Überziehen am Verlaufsanfang nicht an die Seite weiterreichen — sonst löst ein
     Browser-Tab (Android-Chrome) sein eigenes Neuladen aus (vgl. ptrBlocked in app.js). */
  overscroll-behavior-y: contain;
}

/* Eingabeleiste: auf Mobile über der fixierten Bottom-Nav halten,
   damit Textfeld + Senden-Button sichtbar bleiben (PWA / iOS). */
@media (max-width: 1023px) {
  .extr-chat-composer {
    padding-bottom: calc(5.5rem + env(safe-area-inset-bottom, 0px));
  }
}

/* Eigene Nachrichten-Blase */
.chat-bubble-own {
  background: hsl(var(--primary));
  color: #fff;
  border-radius: 1rem 1rem 0.25rem 1rem;
  padding: 0.625rem 1rem;
  min-width: 0;
  max-width: 100%;
  width: fit-content;
  overflow-wrap: anywhere;
  line-height: 1.5;
  font-size: 0.875rem;
}

/* Fremde Nachrichten-Blase */
.chat-bubble-other {
  background: #fff;
  border: 1px solid hsl(var(--border));
  border-radius: 1rem 1rem 1rem 0.25rem;
  padding: 0.625rem 1rem;
  min-width: 0;
  max-width: 100%;
  width: fit-content;
  overflow-wrap: anywhere;
  line-height: 1.5;
  font-size: 0.875rem;
}

/* Spalte einer Nachricht (Zitat, Blase, Zeit, Reaktionen). Die Breitengrenze sitzt
   hier, nicht an der Blase: mit width:fit-content bezog sich max-width:75 % der Blase
   auf die eigene Inhaltsbreite, deshalb brachen kurze Wörter wie „Hallo“ mitten im
   Wort um (Feedback CHAT-04). */
.chat-msg-col { max-width: min(75%, 32rem); min-width: 0; }

/* Avatar Initialen */
.chat-avatar {
  width: 2rem;
  height: 2rem;
  border-radius: 9999px;
  background: hsl(var(--primary) / 0.12);
  color: hsl(var(--primary));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 600;
  flex-shrink: 0;
}

/* Datum-Trennlinie */
.chat-date-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0;
  font-size: 0.75rem;
  color: hsl(var(--muted-foreground));
}
.chat-date-divider::before,
.chat-date-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: hsl(var(--border));
}

/* Chat-Aktions-Icons & Reaktion-Hinzufügen: am Desktop nur bei Hover,
   auf Touch-Geräten (kein Hover → sonst unsichtbar) dauerhaft sichtbar. */
.chat-msg-actions {
  opacity: 0;
  transition: opacity 0.15s ease;
}
.group:hover .chat-msg-actions,
.chat-msg-actions:focus-within {
  opacity: 1;
}
@media (hover: none), (pointer: coarse) {
  .chat-msg-actions { opacity: 1; }
}

/* Like-Icon in News-Übersicht: filled-Zustand über currentColor (Lucide-path-Override) */
.news-like-icon.filled path {
  fill: currentColor;
  stroke: currentColor;
}

/* ---------------------------------------------------------------------------
   PWA: Installations-Overlay & Willkommens-Modal
   --------------------------------------------------------------------------- */
.extr-pwa-locked { overflow: hidden; }

.extr-pwa-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  /* Safe-Area (PWA): Karte nicht unter Insel / Home-Indikator schieben */
  padding-top: calc(1.5rem + env(safe-area-inset-top, 0px));
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(160deg, hsl(27 93% 47% / 0.96), hsl(27 93% 38% / 0.97));
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.extr-pwa-overlay.hidden { display: none; }

.extr-pwa-card {
  width: 100%;
  max-width: 420px;
  background: #fff;
  border-radius: 1.25rem;
  padding: 1.75rem;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.3);
  /* 100% = Höhe abzüglich der Safe-Area-Abstände des Overlays */
  max-height: min(calc(100vh - 3rem), 100%);
  overflow-y: auto;
}
.extr-pwa-card--welcome { text-align: center; }

.extr-pwa-logo {
  width: 4rem;
  height: 4rem;
  margin: 0 auto 1rem;
  border-radius: 1rem;
  background: hsl(var(--primary) / 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
}
.extr-pwa-logo img { width: 2.75rem; height: 2.75rem; object-fit: contain; }

.extr-pwa-title {
  font-size: 1.35rem;
  font-weight: 700;
  color: hsl(222 47% 11%);
  margin: 0 0 0.5rem;
  text-align: center;
}
.extr-pwa-sub {
  color: hsl(215 16% 47%);
  font-size: 0.925rem;
  line-height: 1.5;
  margin: 0 0 1.25rem;
  text-align: center;
}

.extr-pwa-list {
  list-style: none;
  counter-reset: pwa;
  margin: 0;
  padding: 0;
}
.extr-pwa-list li {
  position: relative;
  counter-increment: pwa;
  padding: 0.7rem 0 0.7rem 2.5rem;
  border-bottom: 1px solid hsl(214 32% 91%);
  font-size: 0.9rem;
  line-height: 1.45;
  color: hsl(222 47% 20%);
}
.extr-pwa-list li:last-child { border-bottom: none; }
.extr-pwa-list li::before {
  content: counter(pwa);
  position: absolute;
  left: 0;
  top: 0.6rem;
  width: 1.65rem;
  height: 1.65rem;
  border-radius: 50%;
  background: var(--primary-hsl);
  color: #fff;
  font-weight: 700;
  font-size: 0.8rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.extr-pwa-ic {
  width: 1rem;
  height: 1rem;
  display: inline-block;
  vertical-align: -0.18rem;
  color: var(--primary-hsl);
}
.extr-pwa-note {
  margin: 1rem 0 0;
  font-size: 0.8rem;
  color: hsl(215 16% 47%);
  background: hsl(var(--primary) / 0.08);
  border-radius: 0.5rem;
  padding: 0.6rem 0.75rem;
}
.extr-pwa-dismiss {
  display: block;
  width: 100%;
  margin-top: 1.25rem;
  background: none;
  border: none;
  color: hsl(215 16% 47%);
  font-size: 0.85rem;
  cursor: pointer;
  padding: 0.5rem;
}
.extr-pwa-dismiss:hover { color: hsl(222 47% 20%); text-decoration: underline; }

.extr-pwa-welcome-icon {
  width: 4.5rem;
  height: 4.5rem;
  margin: 0 auto 1.25rem;
  border-radius: 50%;
  background: hsl(var(--primary) / 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
}
.extr-pwa-welcome-icon i { width: 2.25rem; height: 2.25rem; color: var(--primary-hsl); }

/* ── Trennlinien: nur noch .extr-divided (UI-Audit CODE-05, 2026-09-22) ──────
   Hier stand der Ausgleich für Tailwinds divide-y: dessen Linie hängt als
   border-bottom an „> :not(:last-child)" und stand ohne passende Farbregel auf
   currentColor. Seit CODE-05 trägt keine Liste mehr divide-y — alle nutzen
   .extr-divided (weiter unten), und der Wächter bausteine-semantik.php hält das
   so. divide-y wieder einzusetzen hieße: schwarze Linien. */

/* ============================================================
   UX-Überarbeitung 2026 — Dark Mode, Navigations-Feedback,
   Interaktions-Politur, A11y. Additiv, ohne Bestehendes zu ändern.
   ============================================================ */

/* ---- Dark Mode (über data-theme am <html>; warmes Dunkel passend zur Marke) - */
:root { color-scheme: light; }
html[data-theme="dark"] {
  color-scheme: dark;
  /* Status-Töne (siehe :root): durchscheinende Fläche, helle Schrift */
  --tone-warn-bg:         43 96% 56% / .14;
  --tone-warn-fg:         43 96% 56%;
  --tone-warn-border:     43 96% 56% / .4;
  --tone-ok-bg:           142 69% 58% / .16;
  --tone-ok-fg:           142 77% 73%;
  --tone-bad-bg:          0 91% 71% / .18;
  --tone-bad-fg:          0 94% 82%;
  --primary:              27 90% 55%;
  --primary-hsl:          hsl(27, 90%, 55%);
  --primary-foreground:   0 0% 100%;
  --background:           20 14% 9%;
  --background-hsl:       hsl(20, 14%, 9%);
  --foreground:           30 12% 92%;
  --card:                 24 12% 13%;
  --card-foreground:      30 12% 92%;
  --secondary:            27 24% 24%;
  --secondary-hsl:        hsl(27, 24%, 24%);
  --secondary-foreground: 0 0% 100%;
  --muted:                24 10% 18%;
  --muted-foreground:     30 8% 64%;
  --border:               24 10% 24%;
  --accent:               27 90% 55%;
  --destructive:          350 75% 58%;
  --sidebar-bg:           22 13% 11%;
  --sidebar-border:       24 10% 24%;
  --extr-shadow-sm: 0 1px 2px rgba(0,0,0,0.40);
  --extr-shadow-md: 0 4px 16px rgba(0,0,0,0.48);
  --extr-shadow-lg: 0 14px 36px rgba(0,0,0,0.58);
}

/* Literale Tailwind-Flächen-Utilities im Dark-Scope auf Tokens umlenken */
html[data-theme="dark"] .bg-white { background-color: hsl(var(--card)); }
html[data-theme="dark"] .bg-gray-50,
html[data-theme="dark"] .bg-gray-100,
html[data-theme="dark"] .bg-slate-50,
html[data-theme="dark"] .bg-neutral-50 { background-color: hsl(var(--muted)); }
html[data-theme="dark"] .text-gray-900,
html[data-theme="dark"] .text-slate-900,
html[data-theme="dark"] .text-black { color: hsl(var(--foreground)); }
html[data-theme="dark"] .text-gray-500,
html[data-theme="dark"] .text-gray-600,
html[data-theme="dark"] .text-gray-700 { color: hsl(var(--muted-foreground)); }
html[data-theme="dark"] .border-gray-100,
html[data-theme="dark"] .border-gray-200,
html[data-theme="dark"] .border-slate-200 { border-color: hsl(var(--border)); }
html[data-theme="dark"] .bg-red-50     { background-color: rgba(248,113,113,0.14); }
html[data-theme="dark"] .bg-amber-50   { background-color: rgba(251,191,36,0.14); }
html[data-theme="dark"] .bg-yellow-50  { background-color: rgba(250,204,21,0.14); }
html[data-theme="dark"] .bg-green-50,
html[data-theme="dark"] .bg-emerald-50 { background-color: rgba(52,211,153,0.14); }
html[data-theme="dark"] .bg-blue-50,
html[data-theme="dark"] .bg-sky-50     { background-color: rgba(96,165,250,0.14); }
html[data-theme="dark"] .bg-violet-50,
html[data-theme="dark"] .bg-purple-50  { background-color: rgba(167,139,250,0.14); }
html[data-theme="dark"] .shadow-lg,
html[data-theme="dark"] .shadow-xl,
html[data-theme="dark"] .shadow-2xl { box-shadow: 0 10px 30px rgba(0,0,0,0.45); }

/* ---- Dark-Mode-Vervollständigung 2026 -------------------------------------
   App nutzt vielerorts slate-/zinc-/Pastell-Utilities statt semantischer
   Klassen. Im Dark-Scope auf Tokens bzw. Transluzenz umlenken, sonst bleiben
   Flächen hell und Texte dunkel-auf-dunkel. */
/* Flächen (helle Grautöne) → Muted */
html[data-theme="dark"] .bg-slate-100,
html[data-theme="dark"] .bg-zinc-100 { background-color: hsl(var(--muted)); }
html[data-theme="dark"] .hover\:bg-white:hover,
html[data-theme="dark"] .hover\:bg-slate-100:hover,
html[data-theme="dark"] .hover\:bg-slate-50:hover,
html[data-theme="dark"] .hover\:bg-gray-100:hover { background-color: hsl(var(--muted)); }
/* Sekundärtext (mittlere Grautöne) → Muted-Foreground */
html[data-theme="dark"] .text-slate-400,
html[data-theme="dark"] .text-slate-500,
html[data-theme="dark"] .text-slate-600,
html[data-theme="dark"] .text-gray-400,
html[data-theme="dark"] .text-zinc-500,
html[data-theme="dark"] .text-zinc-600 { color: hsl(var(--muted-foreground)); }
/* Primärtext (dunkle Grautöne) → Foreground */
html[data-theme="dark"] .text-slate-700,
html[data-theme="dark"] .text-slate-800,
html[data-theme="dark"] .text-zinc-700,
html[data-theme="dark"] .text-zinc-800,
html[data-theme="dark"] .text-gray-800 { color: hsl(var(--foreground)); }
/* Rahmen */
html[data-theme="dark"] .border-slate-100,
html[data-theme="dark"] .border-slate-300,
html[data-theme="dark"] .border-gray-300,
html[data-theme="dark"] .border-zinc-200 { border-color: hsl(var(--border)); }
/* Pastell-Tints vollständig (-50 + -100, alle Familien) → dezente Transluzenz */
html[data-theme="dark"] .bg-red-50,     html[data-theme="dark"] .bg-red-100     { background-color: rgba(248,113,113,0.13); }
html[data-theme="dark"] .bg-orange-50,  html[data-theme="dark"] .bg-orange-100,
html[data-theme="dark"] .bg-amber-50,   html[data-theme="dark"] .bg-amber-100,
html[data-theme="dark"] .bg-yellow-50,  html[data-theme="dark"] .bg-yellow-100  { background-color: rgba(251,191,36,0.14); }
html[data-theme="dark"] .bg-lime-50,    html[data-theme="dark"] .bg-lime-100,
html[data-theme="dark"] .bg-green-50,   html[data-theme="dark"] .bg-green-100,
html[data-theme="dark"] .bg-emerald-50, html[data-theme="dark"] .bg-emerald-100,
html[data-theme="dark"] .bg-teal-50,    html[data-theme="dark"] .bg-teal-100    { background-color: rgba(52,211,153,0.13); }
html[data-theme="dark"] .bg-cyan-50,    html[data-theme="dark"] .bg-cyan-100,
html[data-theme="dark"] .bg-sky-50,     html[data-theme="dark"] .bg-sky-100,
html[data-theme="dark"] .bg-blue-50,    html[data-theme="dark"] .bg-blue-100    { background-color: rgba(96,165,250,0.14); }
html[data-theme="dark"] .bg-indigo-50,  html[data-theme="dark"] .bg-indigo-100,
html[data-theme="dark"] .bg-violet-50,  html[data-theme="dark"] .bg-violet-100,
html[data-theme="dark"] .bg-purple-50,  html[data-theme="dark"] .bg-purple-100  { background-color: rgba(167,139,250,0.14); }
html[data-theme="dark"] .bg-pink-50,    html[data-theme="dark"] .bg-pink-100,
html[data-theme="dark"] .bg-rose-50,    html[data-theme="dark"] .bg-rose-100,
html[data-theme="dark"] .bg-fuchsia-50, html[data-theme="dark"] .bg-fuchsia-100 { background-color: rgba(244,114,182,0.14); }
/* Custom-Komponenten mit hartkodiertem Weiß → im Dark-Scope auf Tokens */
html[data-theme="dark"] .extr-header-bar { background-color: hsl(var(--card) / 0.85); }
html[data-theme="dark"] .chat-bubble-other { background: hsl(var(--card)); color: hsl(var(--foreground)); }
html[data-theme="dark"] .extr-more-sheet,
html[data-theme="dark"] .extr-pwa-card,
html[data-theme="dark"] .extr-check-box { background: hsl(var(--card)); }
/* PWA-Install/Welcome-Texte im Dark Mode lesbar (Basisfarben sind hart auf Hell-Mode kodiert) */
html[data-theme="dark"] .extr-pwa-title { color: hsl(var(--foreground)); }
html[data-theme="dark"] .extr-pwa-sub,
html[data-theme="dark"] .extr-pwa-note,
html[data-theme="dark"] .extr-pwa-dismiss { color: hsl(var(--muted-foreground)); }
html[data-theme="dark"] .extr-pwa-note { background: hsl(var(--primary) / 0.12); }
html[data-theme="dark"] .extr-pwa-list li { color: hsl(var(--foreground)); border-bottom-color: hsl(var(--border)); }
html[data-theme="dark"] .extr-pwa-dismiss:hover { color: hsl(var(--foreground)); }
html[data-theme="dark"] .note-editor.note-frame .note-editable { background: hsl(var(--card)) !important; }
html[data-theme="dark"] .note-dropdown-menu { background: hsl(var(--card)) !important; }
/* Farbiger Text (Badges/Labels/Icons): dunkle -600/-700/-800-Töne auf Dunkel
   unlesbar → auf helle -400-Töne derselben Farbe umlenken (inkl. Hover). */
html[data-theme="dark"] .text-red-500,html[data-theme="dark"] .text-red-600,html[data-theme="dark"] .text-red-700,html[data-theme="dark"] .text-red-800,html[data-theme="dark"] .text-red-900,html[data-theme="dark"] .hover\:text-red-600:hover,html[data-theme="dark"] .hover\:text-red-700:hover{color:#f87171}
html[data-theme="dark"] .text-orange-500,html[data-theme="dark"] .text-orange-600,html[data-theme="dark"] .text-orange-700,html[data-theme="dark"] .text-orange-800,html[data-theme="dark"] .hover\:text-orange-600:hover{color:#fb923c}
html[data-theme="dark"] .text-amber-500,html[data-theme="dark"] .text-amber-600,html[data-theme="dark"] .text-amber-700,html[data-theme="dark"] .text-amber-800,html[data-theme="dark"] .text-amber-900,html[data-theme="dark"] .hover\:text-amber-600:hover{color:#fbbf24}
html[data-theme="dark"] .text-yellow-500,html[data-theme="dark"] .text-yellow-600,html[data-theme="dark"] .text-yellow-700,html[data-theme="dark"] .text-yellow-800{color:#facc15}
html[data-theme="dark"] .text-lime-500,html[data-theme="dark"] .text-lime-600,html[data-theme="dark"] .text-lime-700{color:#a3e635}
html[data-theme="dark"] .text-green-500,html[data-theme="dark"] .text-green-600,html[data-theme="dark"] .text-green-700,html[data-theme="dark"] .text-green-800,html[data-theme="dark"] .text-green-900,html[data-theme="dark"] .hover\:text-green-600:hover,html[data-theme="dark"] .hover\:text-green-700:hover{color:#4ade80}
html[data-theme="dark"] .text-emerald-500,html[data-theme="dark"] .text-emerald-600,html[data-theme="dark"] .text-emerald-700,html[data-theme="dark"] .text-emerald-800{color:#34d399}
html[data-theme="dark"] .text-teal-500,html[data-theme="dark"] .text-teal-600,html[data-theme="dark"] .text-teal-700{color:#2dd4bf}
html[data-theme="dark"] .text-cyan-500,html[data-theme="dark"] .text-cyan-600,html[data-theme="dark"] .text-cyan-700{color:#22d3ee}
html[data-theme="dark"] .text-sky-500,html[data-theme="dark"] .text-sky-600,html[data-theme="dark"] .text-sky-700{color:#38bdf8}
html[data-theme="dark"] .text-blue-500,html[data-theme="dark"] .text-blue-600,html[data-theme="dark"] .text-blue-700,html[data-theme="dark"] .text-blue-800,html[data-theme="dark"] .hover\:text-blue-600:hover,html[data-theme="dark"] .hover\:text-blue-700:hover{color:#60a5fa}
html[data-theme="dark"] .text-indigo-500,html[data-theme="dark"] .text-indigo-600,html[data-theme="dark"] .text-indigo-700{color:#818cf8}
html[data-theme="dark"] .text-violet-500,html[data-theme="dark"] .text-violet-600,html[data-theme="dark"] .text-violet-700,html[data-theme="dark"] .text-violet-800{color:#a78bfa}
html[data-theme="dark"] .text-purple-500,html[data-theme="dark"] .text-purple-600,html[data-theme="dark"] .text-purple-700,html[data-theme="dark"] .text-purple-800{color:#c084fc}
html[data-theme="dark"] .text-fuchsia-500,html[data-theme="dark"] .text-fuchsia-600,html[data-theme="dark"] .text-fuchsia-700{color:#e879f9}
html[data-theme="dark"] .text-pink-500,html[data-theme="dark"] .text-pink-600,html[data-theme="dark"] .text-pink-700,html[data-theme="dark"] .hover\:text-pink-600:hover{color:#f472b6}
html[data-theme="dark"] .text-rose-500,html[data-theme="dark"] .text-rose-600,html[data-theme="dark"] .text-rose-700{color:#fb7185}
/* ── KERNFIX: semantische Tailwind-Utilities sind im precompiled CSS mit
   HELL-Werten gebacken (reagieren NICHT auf data-theme). Im Dark-Scope auf die
   im Dark überschriebenen CSS-Variablen zurückführen — sonst hell-auf-dunkel
   (Flächen) bzw. dunkel-auf-dunkel (Text) in allen Modulen. */
html[data-theme="dark"] .bg-card,
html[data-theme="dark"] .bg-popover { background-color: hsl(var(--card)); }
html[data-theme="dark"] .bg-background { background-color: hsl(var(--background)); }
html[data-theme="dark"] .bg-muted { background-color: hsl(var(--muted)); }
html[data-theme="dark"] .bg-muted\/10 { background-color: hsl(var(--muted) / 0.1); }
html[data-theme="dark"] .bg-muted\/20 { background-color: hsl(var(--muted) / 0.2); }
html[data-theme="dark"] .bg-muted\/30 { background-color: hsl(var(--muted) / 0.3); }
html[data-theme="dark"] .bg-muted\/40 { background-color: hsl(var(--muted) / 0.4); }
html[data-theme="dark"] .bg-muted\/50 { background-color: hsl(var(--muted) / 0.5); }
html[data-theme="dark"] .bg-muted\/60 { background-color: hsl(var(--muted) / 0.6); }
html[data-theme="dark"] .bg-muted\/70 { background-color: hsl(var(--muted) / 0.7); }
html[data-theme="dark"] .hover\:bg-muted:hover { background-color: hsl(var(--muted)); }
html[data-theme="dark"] .hover\:bg-muted\/40:hover { background-color: hsl(var(--muted) / 0.4); }
html[data-theme="dark"] .hover\:bg-muted\/50:hover { background-color: hsl(var(--muted) / 0.5); }
html[data-theme="dark"] .hover\:bg-muted\/60:hover { background-color: hsl(var(--muted) / 0.6); }
html[data-theme="dark"] .text-foreground,
html[data-theme="dark"] .text-card-foreground,
html[data-theme="dark"] .text-popover-foreground { color: hsl(var(--foreground)); }
html[data-theme="dark"] .text-muted-foreground { color: hsl(var(--muted-foreground)); }
html[data-theme="dark"] .hover\:text-foreground:hover { color: hsl(var(--foreground)); }
html[data-theme="dark"] .placeholder\:text-muted-foreground::placeholder { color: hsl(var(--muted-foreground)); }
html[data-theme="dark"] .border-border,
html[data-theme="dark"] .border-input { border-color: hsl(var(--border)); }

/* ---- Navigations-Feedback: Top-Progressbar ------------------------------- */
.extr-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0;
  background: hsl(var(--primary)); z-index: 300; opacity: 0;
  transition: width .2s ease, opacity .3s ease;
  box-shadow: 0 0 8px hsl(var(--primary) / 0.6);
}
.extr-progress--active { opacity: 1; }
@keyframes extrFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.extr-fade-in { animation: extrFadeIn .22s ease both; }

/* ---- Skeleton-Loader ------------------------------------------------------ */
.extr-skel { position: relative; overflow: hidden; background: hsl(var(--muted)); border-radius: .5rem; }
.extr-skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, hsl(var(--card) / 0.6), transparent);
  transform: translateX(-100%); animation: extrShimmer 1.3s infinite;
}
@keyframes extrShimmer { 100% { transform: translateX(100%); } }
.extr-skel-line { height: .8rem; border-radius: .375rem; margin: .5rem 0; }
.extr-skel-card { height: 5rem; border-radius: 1rem; margin: .75rem 0; }
.extr-skel-avatar { height: 2.5rem; width: 2.5rem; border-radius: 9999px; flex: 0 0 auto; }
.extr-skel-row { display: flex; gap: .75rem; align-items: center; padding: .5rem 0; }
.extr-skel-tile { height: 6.5rem; border-radius: 1rem; }

/* ---- Empty-State (Helfer extr_empty_state) -------------------------------- */
.extr-empty { text-align: center; padding: 2.5rem 1rem; }
.extr-empty-icon {
  height: 3rem; width: 3rem; margin: 0 auto .75rem; border-radius: 9999px;
  display: flex; align-items: center; justify-content: center;
  background: hsl(var(--muted)); color: hsl(var(--muted-foreground));
}
.extr-empty-title { font-weight: 600; margin-bottom: .25rem; }
.extr-empty-text { font-size: .875rem; color: hsl(var(--muted-foreground)); max-width: 24rem; margin: 0 auto; }
.extr-empty-cta { margin-top: 1rem; }

/* ---- Command-Palette: aktiver (tastaturgewählter) Eintrag ----------------- */
.extr-cmd-item--active { background: hsl(var(--muted)); }

/* ---- Button-Spinner (extrBtnBusy) ----------------------------------------- */
.extr-btn-spin {
  display: inline-block; height: 1em; width: 1em; vertical-align: -0.15em;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 9999px; animation: spin .6s linear infinite;
}

/* ---- Auswahlkästchen und Radios: Markenfarbe (UI-Audit BTN-03) -------------
   Vorher trugen 337 Stellen `accent-primary` im Markup und 132 nicht — die
   erschienen im Browser-Standardblau neben den grünen. Eine Regel löst das
   für alle; `accent-primary` im Markup ist damit überflüssig (schadet aber
   nicht, es setzt denselben Wert). */
input[type="checkbox"],
input[type="radio"] { accent-color: hsl(var(--primary)); }

/* ---- A11y: sichtbarer Fokusring für Tastaturnutzer ------------------------ */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible, [role="button"]:focus-visible {
  outline: 2px solid hsl(var(--primary)); outline-offset: 2px; border-radius: 4px;
}

/* ---- Pull-to-Refresh Indikator -------------------------------------------- */
.extr-ptr {
  position: fixed; top: 0; left: 50%; transform: translate(-50%, -120%);
  z-index: 250; height: 2.25rem; width: 2.25rem; border-radius: 9999px;
  background: hsl(var(--card)); color: hsl(var(--primary));
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 14px rgba(0,0,0,0.18); transition: transform .15s ease;
}

/* ---- Reduced Motion respektieren ------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .extr-fade-in, .extr-skel::after, .extr-progress { animation: none !important; transition: none !important; }
}

/* ============================================================
   Motion & Delight 2026 — Mikro-Interaktionen (additiv)
   Richtungs-Übergänge, Stagger, Hover-Lift, Erfolgs-Häkchen,
   Konfetti, Skeleton-Dissolve. Dark- + reduced-motion-fest.
   ============================================================ */

/* ---- Richtungsabhängiger View-Übergang (vor/zurück) ---------------------- */
@keyframes extrSlideFwd  { from { opacity: 0; transform: translateX(16px); }  to { opacity: 1; transform: none; } }
@keyframes extrSlideBack { from { opacity: 0; transform: translateX(-16px); } to { opacity: 1; transform: none; } }
.extr-view-fwd  { animation: extrSlideFwd  .26s cubic-bezier(.22,.61,.36,1) both; }
.extr-view-back { animation: extrSlideBack .26s cubic-bezier(.22,.61,.36,1) both; }

/* ---- Skeleton → Content Dissolve ----------------------------------------- */
.extr-fading-out { opacity: 0 !important; transition: opacity .13s ease; }

/* ---- Stagger-Reveal für Listen/Grids (Opt-in-Klasse .extr-stagger) ------- */
@keyframes extrRise { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }
.extr-stagger > * { animation: extrRise .34s cubic-bezier(.22,.61,.36,1) both; animation-delay: calc(var(--extr-i, 0) * 28ms); }

/* ---- Hover-Lift für klickbare Kacheln (Opt-in-Klasse .extr-lift) --------- */
.extr-lift { transition: transform .15s cubic-bezier(.22,.61,.36,1), box-shadow .15s; }
.extr-lift:hover  { transform: translateY(-2px); box-shadow: var(--extr-shadow-md); }
.extr-lift:active { transform: translateY(0) scale(.995); }

/* ---- Erfolgs-Häkchen-Morph (extrBtnSuccess) ------------------------------ */
.extr-btn-success { background: hsl(142 64% 38%) !important; color: #fff !important; border-color: transparent !important; opacity: 1 !important; }
.extr-btn-check { display: inline-block; width: 1.15em; height: 1.15em; position: relative; vertical-align: -0.2em; }
.extr-btn-check::after {
  content: ""; position: absolute; left: 0.42em; top: 0.1em;
  width: 0.3em; height: 0.62em; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(45deg) scale(0); transform-origin: center;
  animation: extrCheckPop .42s cubic-bezier(.2,1.25,.4,1) .05s forwards;
}
@keyframes extrCheckPop { to { transform: rotate(45deg) scale(1); } }

/* ---- Konfetti-Burst (extrBurst) ------------------------------------------ */
.extr-burst { position: fixed; inset: 0; pointer-events: none; z-index: 400; }
.extr-burst > span {
  position: absolute; width: 8px; height: 8px; border-radius: 2px; opacity: 0;
  animation: extrBurstFly .9s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes extrBurstFly {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(.4) rotate(0); }
  70%  { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1) rotate(200deg); }
}

/* ---- Reduced Motion: alle neuen Bewegungen aus --------------------------- */
@media (prefers-reduced-motion: reduce) {
  .extr-view-fwd, .extr-view-back, .extr-stagger > *,
  .extr-lift, .extr-lift:hover, .extr-lift:active,
  .extr-btn:active, .extr-employee-card:hover, .extr-employee-card:active,
  .extr-btn-check::after, .extr-toast, .extr-toast-bar, .extr-burst > span {
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
  .extr-fading-out { transition: none !important; }
}

/* ---- Wissen: Dokumentansicht — Reihenfolge auf schmalen Bildschirmen --------
   Auf dem Desktop stehen Zusammenfassung, Inhaltsverzeichnis, Aktionen und
   verwandte Inhalte gesammelt in der rechten Spalte. In der PWA (eine Spalte)
   sollen Zusammenfassung und Inhaltsverzeichnis ÜBER dem Artikeltext stehen,
   Aktionen und verwandte Inhalte darunter — deshalb drei eigene Rasterbereiche
   statt eines Sidebar-Blocks. Eigene Klassen, weil das vorgebaute tailwind.css
   weder grid-template-areas noch `order-*` in den nötigen Stufen kennt. */
.wd-doc-grid{display:grid;gap:1.5rem;grid-template-columns:minmax(0,1fr);
  grid-template-areas:"sidetop" "main" "sidebottom"}
.wd-doc-main      {grid-area:main;min-width:0}
.wd-doc-side-top  {grid-area:sidetop;min-width:0}
.wd-doc-side-bot  {grid-area:sidebottom;min-width:0}
@media(min-width:1024px){
  .wd-doc-grid{grid-template-columns:minmax(0,3fr) minmax(0,1fr);
    grid-template-areas:"main sidetop" "main sidebottom"}
  /* Die Nebenspalte klebt oben — sie darf dabei NICHT höher als das Fenster
     werden. Bei langen Dokumenten wuchs das Inhaltsverzeichnis auf mehrere
     tausend Pixel: der untere Teil war nie erreichbar (sticky schiebt ihn immer
     mit nach unten), und die überhohe Sticky-Ebene hinterließ beim Scrollen
     Geisterbilder über dem Artikeltext. Deshalb auf Fensterhöhe begrenzen und
     bei Bedarf INNEN scrollen. */
  .wd-doc-side-top{
    position:sticky;
    top:6rem;
    align-self:start;
    max-height:calc(100vh - 7.5rem);
    overflow-y:auto;
    overscroll-behavior:contain;
    /* eigene Compositing-Ebene: verhindert Restbilder beim Scrollen */
    transform:translateZ(0);
  }
  /* Der Scroll-Schatten darf die abgerundeten Karten nicht abschneiden. */
  .wd-doc-side-top{padding-right:.25rem;margin-right:-.25rem}
}

/* ---- Dashboard: Schichtkarte überlappt die Hero-Kante ---------------------
   Nur die Schichtkarte schiebt sich unter die abgerundete Unterkante des
   Hero-Headers — das sieht dort gewollt aus. Früher trug der ganze
   .extr-dashboard-body diesen negativen Abstand; ohne Planzuweisung entfällt
   die Karte, und der nächste Block (Schnellaktionen) rutschte unter den Header.
   Der Nachbar-Selektor greift nur, solange der Favoriten-Block ausgeblendet ist:
   wird er sichtbar, steht er ganz oben und die Karte darf nicht mehr ziehen. */
@media (max-width: 1023px) {
  /* ~ statt +: zwischen beiden liegt das (mobil ausgeblendete) Desktop-Raster. */
  #dash-personal.hidden ~ .dash-shift-lead { margin-top: -2rem; }
}

/* ---- Schichtplanung: Status-Farben (Arbeitsplan-Farbkonvention) ----------
   Eigene Klassen statt Tailwind-Utilities: das vorkompilierte tailwind.css
   enthält nicht alle benötigten Farbstufen. Verwendung über den Statuskatalog
   extr_shift_statuses() (bg-Feld trägt die komplette Klasse). */
.shift-st-frueh        { background:#dbeafe; color:#1e40af; border-color:#93c5fd; } /* Frühschicht: blau */
.shift-st-spaet        { background:#ffffff; color:#334155; border-color:#94a3b8; } /* Spätschicht: weiß */
.shift-st-arbeitstag   { background:#e0f2fe; color:#0369a1; border-color:#7dd3fc; } /* Arbeitstag: hellblau */
.shift-st-frei         { background:#fef9c3; color:#854d0e; border-color:#fde047; } /* Freier Rolltag: gelb */
.shift-st-urlaub       { background:#dcfce7; color:#166534; border-color:#86efac; } /* Urlaub: grün */
.shift-st-blumenstrauss{ background:#ccfbf1; color:#115e59; border-color:#5eead4; } /* Blumenstraußtag: türkis */
.shift-st-krank        { background:#fee2e2; color:#b91c1c; border-color:#fca5a5; } /* Krank: rot */
.shift-st-schule       { background:#ede9fe; color:#6d28d9; border-color:#c4b5fd; } /* Schule/Studium: violett */
.shift-st-dienstreise  { background:#e0e7ff; color:#4338ca; border-color:#a5b4fc; } /* Dienstreise: indigo */
.shift-st-sonntag      { background:#e2e8f0; color:#64748b; border-color:#cbd5e1; } /* Sonntag (frei): grau, ≠ gelber Rolltag */

/* Zellmarker: Einsatz (TUDOR/GADORO), Schlüsseldienst, Bereitschaft */
.shift-badge { position:absolute; bottom:1px; left:50%; transform:translateX(-50%);
  font-size:8px; line-height:1; font-weight:700; letter-spacing:.02em; padding:1px 3px;
  border-radius:4px; background:rgba(15,23,42,.78); color:#fff; white-space:nowrap; }
/* Split-Kürzel (logische Unterteilung des Plans) — unten rechts in der Zelle */
.shift-split { position:absolute; bottom:1px; right:2px;
  font-size:8px; line-height:1; font-weight:700; letter-spacing:.02em;
  color:currentColor; opacity:.75; white-space:nowrap; }
.shift-flag  { position:absolute; top:2px; left:2px; display:flex; gap:1px; }
.shift-flag i, .shift-flag svg { width:9px; height:9px; }
/* Eingereichter, noch nicht genehmigter Urlaub im Raster: gleiche Farbe wie genehmigt, gestrichelt (Feedback PLAN-07) */
.shift-abs-pending { border-style: dashed; opacity: .8; }
/* Summenzeile „Anwesend“ (Feedback PLAN-10) — klebt im scrollenden Gesamtplan am unteren Rand */
.shift-sum-row td { background: #f1f5f9; border-top: 2px solid hsl(var(--border)); }
.shift-gesamt-scroll tfoot td { position: sticky; bottom: 0; z-index: 20; }
.shift-gesamt-scroll tfoot td:first-child { z-index: 30; }
.shift-cell-time { position:absolute; bottom:1px; left:50%; transform:translateX(-50%);
  font-size:8px; line-height:1; white-space:nowrap; opacity:.75; }

/* ---- Umschalter-Streifen (Reiter) ------------------------------------------
   Reiter wie „Dokumente / Lernstrecken / Assistent" passen auf schmalen
   Bildschirmen nicht nebeneinander. Ohne Scrollmöglichkeit ragen sie aus dem
   Bildschirm und die hinteren Reiter sind nicht erreichbar. Der Streifen
   scrollt deshalb seitlich; die Bildlaufleiste bleibt verborgen, die Reiter
   selbst schrumpfen nicht und brechen nicht um.
   min-width:0 ist nötig, weil Flex-Elemente sonst nicht unter ihre
   Inhaltsbreite schrumpfen und der Streifen die Seite breiter machen würde. */
.extr-tab-strip {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  flex-wrap: nowrap;          /* sonst brechen Streifen mit flex-wrap um, statt zu scrollen */
}
.extr-tab-strip::-webkit-scrollbar { display: none; }
.extr-tab-strip > * { flex: 0 0 auto; white-space: nowrap; }

/* ── Dashboard-Konfiguration ────────────────────────────────────────────────
   Platzhalter-Widgets: „Widget wechseln"-Knopf erscheint erst beim Überfahren
   der Karte. Der Raster-Editor (Einstellungen → Dashboard-Ansicht) nutzt
   HTML5-Drag&Drop; die Klassen markieren Zieh-Quellen und Einfüge-Position. */
.dash-ph-swap {
  position: absolute;
  top: -0.5rem;
  right: -0.5rem;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.75rem;
  width: 1.75rem;
  border-radius: 9999px;
  background: #fff;
  border: 1px solid hsl(var(--border));
  color: hsl(var(--muted-foreground));
  box-shadow: 0 4px 12px -4px rgba(0, 0, 0, 0.25);
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.dash-ph-card:hover .dash-ph-swap { opacity: 1; }
.dash-ph-swap:hover { color: hsl(var(--primary)); }

.dashcfg-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.5rem;
  align-content: start;
  min-height: 14rem;
  padding: 0.75rem;
  border-radius: 1rem;
  border: 1px solid hsl(var(--border));
  background-color: hsl(var(--muted) / 0.3);
  /* Spalten-Hilfslinien: 1px-Linie je 25%-Kachel (kein repeating-gradient —
     das kippt bei %-Stops in WebKit in endlose Mini-Wiederholungen) */
  background-image: linear-gradient(to left, hsl(var(--border) / 0.35) 1px, transparent 1px);
  background-size: 25% 100%;
  background-repeat: repeat-x;
}
.dashcfg-item {
  position: relative;
  border-radius: 0.75rem;
  border: 1px solid hsl(var(--border));
  background: #fff;
  padding: 0.6rem 0.6rem;
  min-height: 4.5rem;
  cursor: grab;
  user-select: none;
}
.dashcfg-item.is-ph { border-style: dashed; background: hsl(var(--muted) / 0.4); }
.dashcfg-item.drag-src { opacity: 0.35; }
.dashcfg-item .dashcfg-actions { display: flex; gap: 0.25rem; }
.dashcfg-drop-before::before,
.dashcfg-drop-after::after {
  content: '';
  position: absolute;
  top: 0.2rem;
  bottom: 0.2rem;
  width: 3px;
  border-radius: 2px;
  background: hsl(var(--primary));
}
.dashcfg-drop-before::before { left: -0.35rem; }
.dashcfg-drop-after::after { right: -0.35rem; }
.dashcfg-grid.drag-over-empty { outline: 2px dashed hsl(var(--primary) / 0.5); outline-offset: -6px; }
.dashcfg-src { cursor: grab; user-select: none; }
.dashcfg-src.is-used { opacity: 0.45; cursor: not-allowed; }

/* Abstände der Beschreibungstexte im Dashboard-Editor: der globale Reset oben
   (p{margin:0}, ungelayert) sticht Tailwinds mb-*-Utilities auf <p> aus —
   deshalb eigene, ebenfalls ungelayerte Klassen. */
.dashcfg-h { margin-bottom: 0.4rem; }
.dashcfg-desc { margin-bottom: 1rem; }
.dashcfg-desc-lg { margin-bottom: 1.5rem; }
.dashcfg-item > p { margin-top: 0.4rem; }
.dash-ph-chooser h3 { margin-bottom: 0.3rem; }
.dash-ph-chooser > p { margin-bottom: 0.85rem; }

/* Safe-Area (Notch) additiv zum py-Utility der Seite: ohne diese Regeln ersetzt
   das padding-top oben ein gesetztes py-* (Header wäre oben bündig, unten gepolstert). */
.extr-header-bar.py-3 { padding-top: calc(0.75rem + env(safe-area-inset-top, 0px)); }
.extr-header-bar.py-4 { padding-top: calc(1rem    + env(safe-area-inset-top, 0px)); }
.extr-header-bar.py-5 { padding-top: calc(1.25rem + env(safe-area-inset-top, 0px)); }
.extr-header-bar.py-6 { padding-top: calc(1.5rem  + env(safe-area-inset-top, 0px)); }

/* ── Editor-Typografie (Summernote) ─────────────────────────────────────────
   Der globale Reset (app.css) und Tailwinds Preflight setzen h1–h6 auf
   font-size:inherit und entfernen Abstände/Listenpunkte. Im Editor sah damit
   eine Überschrift wie Fließtext aus (kein WYSIWYG). Diese Regeln stellen die
   Formatierung nur innerhalb der Editorfläche wieder her. */
.note-editor.note-frame .note-editable h1,
.note-editor.note-frame .note-editable h2,
.note-editor.note-frame .note-editable h3,
.note-editor.note-frame .note-editable h4,
.note-editor.note-frame .note-editable h5,
.note-editor.note-frame .note-editable h6 {
  font-weight: 700;
  line-height: 1.3;
  color: hsl(var(--foreground));
  margin: 1.2em 0 0.5em;
}
.note-editor.note-frame .note-editable h1 { font-size: 1.75rem; }
.note-editor.note-frame .note-editable h2 { font-size: 1.4rem; }
.note-editor.note-frame .note-editable h3 { font-size: 1.2rem; }
.note-editor.note-frame .note-editable h4 { font-size: 1.05rem; }
.note-editor.note-frame .note-editable h5,
.note-editor.note-frame .note-editable h6 { font-size: 0.95rem; }
.note-editor.note-frame .note-editable > :first-child { margin-top: 0; }
.note-editor.note-frame .note-editable p { margin: 0 0 0.85em; }
.note-editor.note-frame .note-editable ul,
.note-editor.note-frame .note-editable ol { margin: 0 0 0.85em; padding-left: 1.5rem; }
.note-editor.note-frame .note-editable ul { list-style: disc outside; }
.note-editor.note-frame .note-editable ol { list-style: decimal outside; }
.note-editor.note-frame .note-editable li { margin: 0.2em 0; display: list-item; }
.note-editor.note-frame .note-editable blockquote {
  margin: 0 0 0.85em; padding: 0.35em 0 0.35em 0.9rem;
  border-left: 3px solid hsl(var(--primary)); color: hsl(var(--muted-foreground));
}
.note-editor.note-frame .note-editable a { color: hsl(var(--primary)); text-decoration: underline; }
.note-editor.note-frame .note-editable strong, .note-editor.note-frame .note-editable b { font-weight: 700; }
.note-editor.note-frame .note-editable em, .note-editor.note-frame .note-editable i { font-style: italic; }
.note-editor.note-frame .note-editable u { text-decoration: underline; }
.note-editor.note-frame .note-editable hr { margin: 1.2em 0; border: 0; border-top: 1px solid hsl(var(--border)); }
.note-editor.note-frame .note-editable img { display: inline-block; max-width: 100%; height: auto; border-radius: 8px; }
.note-editor.note-frame .note-editable table { border-collapse: collapse; margin: 0 0 0.85em; width: 100%; }
.note-editor.note-frame .note-editable th,
.note-editor.note-frame .note-editable td { border: 1px solid hsl(var(--border)); padding: 0.4em 0.6em; }
.note-editor.note-frame .note-editable th { background: hsl(var(--muted)); font-weight: 600; }
.note-editor.note-frame .note-editable code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.875em;
  background: hsl(var(--muted)); padding: 0.1em 0.35em; border-radius: 4px;
}
/* Der Code-View (</>) zeigt Roh-HTML — dort Monospace und Umbruch erzwingen */
.note-editor.note-frame .note-codable { font-family: ui-monospace, SFMono-Regular, Menlo, monospace !important; font-size: 0.8125rem !important; }

/* ============================================================
   Gesamtplan (Zeitkonto/Schichten): Datumszeile beim Scrollen
   anheften. Das Raster scrollt vertikal selbst (begrenzte Höhe) –
   nur so kann der Tabellenkopf im horizontal scrollbaren
   Container kleben bleiben; die Namensspalte bleibt sticky links.
   ============================================================ */
.shift-gesamt-scroll { max-height: max(420px, calc(100vh - 240px)); overflow: auto; }
.shift-gesamt-scroll thead th {
  position: sticky;
  top: 0;
  z-index: 20;
  /* Opak: durchscheinende Utility-Hintergründe ließen sonst die
     darunter scrollenden Zeilen durchschimmern */
  background: linear-gradient(hsl(var(--muted) / 0.4), hsl(var(--muted) / 0.4)) #fff;
  /* border-collapse-Rahmen wandern beim Kleben nicht mit → Linie als Schatten */
  box-shadow: inset 0 -1px 0 hsl(var(--border));
}
.shift-gesamt-scroll thead th:first-child { z-index: 30; }
.shift-gesamt-scroll thead th.bg-slate-100 { background: linear-gradient(#f1f5f9, #f1f5f9) #fff; }
.shift-gesamt-scroll thead th.bg-primary\/10 { background: linear-gradient(hsl(var(--primary) / 0.1), hsl(var(--primary) / 0.1)) #fff; }

/* ============================================================
   Chat: Nachrichten-Spalte auf volle Zeilenbreite ziehen.
   Ohne feste Breite ist die Spalte shrink-to-fit — die 75%-
   max-width der Bubbles bezog sich dann auf die eigene Inhalts-
   breite, wodurch schon kurze Nachrichten grundlos umbrachen
   („Hallo wie geht's" brach nach „wie" um). Volle Breite lässt
   die Prozent-Angabe auf die Zeile wirken; die Ausrichtung
   übernehmen items-end (eigene) bzw. items-start (fremde).
   ============================================================ */
#chat-messages-feed [data-msg-id] > .flex-col { flex: 1 1 auto; min-width: 0; }

/* Schwebende Navigation im Dunkelmodus: dieselbe Glasoptik, aber mit dunkler
   Fläche und zurückgenommenen Lichtkanten. */
html[data-theme="dark"] .extr-bottom-nav-pill {
  background: hsl(var(--card) / 0.60);
  border-color: hsl(0 0% 100% / 0.10);
  box-shadow:
    0 1px 0 hsl(0 0% 100% / 0.10) inset,
    0 -1px 0 hsl(0 0% 0% / 0.30) inset,
    0 12px 34px hsl(0 0% 0% / 0.55),
    0 2px 10px hsl(0 0% 0% / 0.40);
}
html[data-theme="dark"] .extr-bottom-nav-slider {
  background: hsl(0 0% 100% / 0.10);
  box-shadow: 0 1px 0 hsl(0 0% 100% / 0.12) inset, 0 2px 6px hsl(0 0% 0% / 0.35);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  html[data-theme="dark"] .extr-bottom-nav-pill { background: hsl(var(--card) / 0.97); }
}
@media (prefers-reduced-transparency: reduce) {
  html[data-theme="dark"] .extr-bottom-nav-pill { background: hsl(var(--card) / 0.97); }
}

/* ============================================================
   Header-Aktionen — EINHEITLICH FÜR ALLE MODULE (CLAUDE-UI §3.2)
   ------------------------------------------------------------
   Genau zwei Bedienelemente, immer oben rechts im Modul-Header:
     „+"  legt neuen Inhalt an (nur wenn der Nutzer das darf)
     „⋮"  öffnet das Kontextmenü mit allen weiteren Optionen
   Das Menü klappt auf Höhe des Buttons nach unten auf, wiederholt
   die Neu-Anlegen-Aktion und animiert die drei Punkte zu einem X.
   Markup ausschließlich über extr_page_actions() (page-header.php),
   Verhalten in app.js — NICHT je Modul nachbauen.
   ============================================================ */

.extr-page-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-shrink: 0;
  margin-left: auto;
}

/* Tap-Ziel 44 px — auf dem Handy waren die alten Icon-Buttons zu klein. */
.extr-action-primary,
.extr-action-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.75rem;
  width: 2.75rem;
  flex-shrink: 0;
  border-radius: .75rem;
  /* Kein Rahmen in der Grundform: die Primärkette im Bestand hatte keinen,
     nur die Outline-Variante setzt einen (sonst wären alle Knöpfe 2 px höher). */
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}

.extr-action-primary {
  background: hsl(var(--primary));
  color: hsl(var(--primary-foreground));
}
.extr-action-primary:hover { background: hsl(var(--primary) / .9); }
.extr-action-primary svg   { height: 1.375rem; width: 1.375rem; }

.extr-action-more {
  background: hsl(var(--card));
  color: hsl(var(--muted-foreground));
  border-color: hsl(var(--border));
}
.extr-action-more:hover,
.extr-action-more[aria-expanded="true"] {
  background: hsl(var(--muted));
  color: hsl(var(--foreground));
}

.extr-action-primary:focus-visible,
.extr-action-more:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px hsl(var(--primary) / .25);
}

/* Drei Punkte → X. Die Punkte werden zu zwei gekreuzten Balken, der
   mittlere blendet aus; alles über transform/width/height animierbar. */
.extr-action-dots {
  position: relative;
  display: block;
  height: 1.25rem;
  width: 1.25rem;
}
.extr-action-dots span {
  position: absolute;
  left: 50%;
  top: 50%;
  height: .25rem;
  width: .25rem;
  border-radius: 999px;
  background: currentColor;
  transition: transform .22s cubic-bezier(.4, 0, .2, 1),
              width .22s cubic-bezier(.4, 0, .2, 1),
              height .22s cubic-bezier(.4, 0, .2, 1),
              border-radius .22s cubic-bezier(.4, 0, .2, 1),
              opacity .14s linear;
}
.extr-action-dots span:nth-child(1) { transform: translate(-50%, -50%) translateY(-.4375rem); }
.extr-action-dots span:nth-child(2) { transform: translate(-50%, -50%); }
.extr-action-dots span:nth-child(3) { transform: translate(-50%, -50%) translateY(.4375rem); }

.extr-action-more[aria-expanded="true"] .extr-action-dots span:nth-child(1) {
  height: .125rem;
  width: 1.0625rem;
  border-radius: 1px;
  transform: translate(-50%, -50%) rotate(45deg);
}
.extr-action-more[aria-expanded="true"] .extr-action-dots span:nth-child(2) {
  opacity: 0;
  transform: translate(-50%, -50%) scale(.3);
}
.extr-action-more[aria-expanded="true"] .extr-action-dots span:nth-child(3) {
  height: .125rem;
  width: 1.0625rem;
  border-radius: 1px;
  transform: translate(-50%, -50%) rotate(-45deg);
}

/* Kontextmenü — klappt auf Höhe des Buttons nach unten auf, rechtsbündig. */
.extr-action-menu-wrap { position: relative; }

.extr-action-menu {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + .5rem);
  min-width: 15rem;
  max-width: min(22rem, calc(100vw - 2rem));
  padding: .375rem;
  z-index: 60;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: .875rem;
  box-shadow: var(--extr-shadow-lg);
}
.extr-action-menu-wrap.is-open .extr-action-menu {
  display: block;
  animation: extr-action-menu-in .16s cubic-bezier(.2, .7, .3, 1);
}
@keyframes extr-action-menu-in {
  from { opacity: 0; transform: translateY(-.375rem) scale(.98); }
  to   { opacity: 1; transform: none; }
}

.extr-action-item {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  padding: .5rem .625rem;
  border: 0;
  border-radius: .5rem;
  background: none;
  color: hsl(var(--foreground));
  font-size: .875rem;
  font-weight: 500;
  line-height: 1.35;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
}
.extr-action-item:hover  { background: hsl(var(--muted)); }
.extr-action-item svg    { height: 1rem; width: 1rem; flex-shrink: 0; opacity: .7; }
.extr-action-item-label  { flex: 1 1 auto; min-width: 0; }

.extr-action-item--primary     { color: hsl(var(--primary)); font-weight: 600; }
.extr-action-item--primary svg { opacity: 1; }

.extr-action-item--danger        { color: hsl(var(--destructive)); }
.extr-action-item--danger:hover  { background: hsl(var(--destructive) / .1); }
.extr-action-item--danger svg    { opacity: 1; }

.extr-action-sep {
  height: 1px;
  margin: .375rem .25rem;
  background: hsl(var(--border));
}

/* Live-Zaehler am „+"-Button (z. B. Warenkorb) */
.extr-action-primary { position: relative; }
.extr-action-count {
  white-space: nowrap;
  position: absolute;
  top: -.25rem;
  right: -.25rem;
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 .25rem;
  border-radius: 999px;
  border: 2px solid hsl(var(--background));
  background: hsl(var(--card));
  color: hsl(var(--primary));
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.extr-action-count.hidden { display: none; }

.extr-action-badge {
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 1.25rem;
  padding: 0 .3125rem;
  border-radius: 999px;
  background: hsl(var(--primary) / .12);
  color: hsl(var(--primary));
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.25rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.extr-action-badge.hidden { display: none; }

@media (prefers-reduced-motion: reduce) {
  .extr-action-dots span,
  .extr-action-primary,
  .extr-action-more { transition: none; }
  .extr-action-menu-wrap.is-open .extr-action-menu { animation: none; }
}

/* ── Desktop ab 1024 px: dieselben Elemente als Button-Reihe ────────────────
   In der PWA/auf dem Handy bleibt es bei „+" und „⋮" mit Kontextmenü; am
   Desktop stehen die Aktionen wieder als beschriftete Buttons nebeneinander.
   Bewusst dasselbe DOM, nur anders layoutet — zwei getrennte Markup-Varianten
   würden IDs doppeln (Zähler-Badges, Modul-JS per getElementById). */
.extr-action-primary-label { display: none; }

@media (min-width: 1024px) {
  /* Sekundäre Aktionen links, Neu-Anlegen rechts — wie vor der Vereinheitlichung. */
  .extr-page-actions > .extr-action-menu-wrap { order: 1; min-width: 0; }
  .extr-page-actions > .extr-action-primary   { order: 2; }

  /* „⋮", Trenner und der wiederholte Neu-Eintrag sind hier überflüssig. */
  .extr-action-more,
  .extr-action-sep,
  .extr-action-item--primary { display: none; }

  /* Aus dem Popover wird eine Inline-Reihe. */
  .extr-action-menu-wrap { position: static; }
  .extr-page-actions .extr-action-menu-wrap .extr-action-menu {
    display: flex;
    position: static;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: .5rem;
    min-width: 0;
    max-width: none;
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    animation: none;
  }

  /* Aus jedem Menüeintrag wird ein Umriss-Button. */
  .extr-action-item {
    width: auto;
    height: 2.5rem;
    padding: 0 .875rem;
    gap: .5rem;
    border: 1px solid hsl(var(--border));
    border-radius: .5rem;
    background: hsl(var(--card));
    color: hsl(var(--muted-foreground));
    white-space: nowrap;
  }
  .extr-action-item:hover {
    background: hsl(var(--muted));
    color: hsl(var(--foreground));
  }
  .extr-action-item:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px hsl(var(--primary) / .25);
  }
  .extr-action-item svg { opacity: 1; }
  .extr-action-item-label { flex: 0 0 auto; }
  .extr-action-item--danger {
    border-color: hsl(var(--destructive) / .35);
    color: hsl(var(--destructive));
  }

  /* Primärbutton mit Label statt reinem Icon. */
  .extr-action-primary {
    width: auto;
    height: 2.5rem;
    padding: 0 1rem;
    gap: .5rem;
    border-radius: .5rem;
  }
  .extr-action-primary svg { height: 1rem; width: 1rem; }
  .extr-action-primary-label {
    display: inline;
    font-size: .875rem;
    font-weight: 500;
    white-space: nowrap;
  }
}

/* ---------------------------------------------------------------------------
   Listen: Tabellenkopf bleibt beim Scrollen stehen (2026-08-28)

   Es scrollt die SEITE — die Tabelle bekommt bewusst KEINEN eigenen
   Scrollbereich: Das nutzte die Fensterhöhe nicht aus und erzeugte bei
   niedrigen Fenstern zwei Scrollleisten übereinander.

   Damit `position: sticky` gegenüber dem Fenster wirkt, darf zwischen Zelle
   und Fenster kein Scroll-Container liegen. Die Listen stecken aber in
   overflow-Containern (runde Kartenecken bzw. waagerechtes Scrollen). Lösung:
   `overflow: clip` statt `hidden`/`auto` — das schneidet genauso ab, ist aber
   KEIN Scroll-Container, `sticky` bezieht sich dadurch aufs Fenster.

   Der Kopf hält unterhalb der App-Kopfleiste (selbst sticky, variable Höhe);
   deren Höhe liefert syncStickyTop() in app.js als --extr-sticky-top.

   Der Kopf braucht eine DECKENDE Fläche — die übliche Tönung bg-muted/50 ist
   halbtransparent, darunter würden die Zeilen durchscheinen. Die Trennlinie
   kommt als inset-Schatten, weil echte Rahmen an sticky-Zellen bei
   border-collapse nicht mitgezeichnet werden.
--------------------------------------------------------------------------- */
/* Karte, die nur ihre runden Ecken beschneiden soll. `clip` statt `hidden`:
   clippt identisch, ist aber KEIN Scroll-Container — sonst rechnet ein
   position:sticky im Inneren gegen die Karte statt gegen das Fenster und der
   Tabellenkopf bleibt nicht stehen. */
.extr-clip {
    overflow: clip;
}

.extr-table-sticky {
    overflow: clip;
}
.extr-table-sticky thead th {
    position: sticky;
    top: var(--extr-sticky-top, 0px);
    z-index: 3;
    background-color: hsl(var(--muted));
    box-shadow: inset 0 -1px 0 hsl(var(--border));
}

/* Schmale Schirme: Tabellen müssen waagerecht schiebbar bleiben. Dort ist der
   Container wieder ein Scroll-Container, der Kopf haftet folglich nicht —
   auf Mobilgeräten ist das verschmerzbar (viele Listen sind dort ohnehin
   durch Karten ersetzt). */
@media (max-width: 1023px) {
    /* Als Scroll-Container ist der Kasten selbst der Bezugsrahmen des Kopfes:
       der Fenster-Versatz (Höhe der Kopfleiste) schob den Kopf sonst mitten in
       die Tabelle (sichtbar seit den echten 390-px-Aufnahmen, 2026-09-16). */
    .extr-table-sticky { overflow-x: auto; --extr-sticky-top: 0px; }
}

/* ---- Fixierter Kopf im EIGENEN Scrollbereich (UI-Audit LST-03) -------------
   Für Raster, die selbst scrollen (Wochendetails, Monatsraster, Statistik-
   Tabellen). Sie setzen den Fenster-Versatz auf 0 zurück und begrenzen ihre
   Höhe — sonst hat `position: sticky` nichts, woran es kleben könnte.
   Anwenden zusammen mit .extr-table-sticky:
     <div class="extr-table-sticky extr-table-sticky--local"> … </div> */
/* Nur der Bezugsrahmen: der Kopf klebt am nächsten scrollenden Vorfahren
   (z. B. am Modalkörper) statt am Fenster. Kein eigener Scrollbereich. */
.extr-table-sticky--local { --extr-sticky-top: 0px; }

/* Eigener Scrollbereich in BEIDE Richtungen, mit begrenzter Höhe — sonst
   hat `position: sticky` nichts, woran es kleben könnte. Zusammen mit
   --local verwenden. Nicht mit .extr-table-scroll kombinieren: dessen
   `overflow: clip` steht ungeschichtet und würde hier gewinnen. */
.extr-table-sticky--scroll {
  overflow: auto;
  max-height: var(--extr-table-max, calc(100vh - 16rem));
  overscroll-behavior: contain;
}
/* Erste Spalte trägt die Bezeichnung der Zeile und bleibt stehen. */
.extr-table-sticky--scroll .extr-table th:first-child,
.extr-table-sticky--scroll .extr-table td:first-child {
  position: sticky; left: 0; z-index: 2;
  background: hsl(var(--card));
  box-shadow: 1px 0 0 hsl(var(--border));
}
.extr-table-sticky--scroll .extr-table thead th:first-child { z-index: 4; }
/* ---- Team: Rechtematrix ---------------------------------------------------
   Namensspalte klebt links, Kopfzeile oben (extr-table-sticky). Nur Desktop:
   das Markup ist hidden lg:block, die installierte App blendet zusätzlich per
   JS aus (display-mode: standalone). */
/* Das Raster scrollt in BEIDE Richtungen selbst (Höhe setzt das Partial-JS
   auf den sichtbaren Rest des Fensters, hier nur der Rückfall). Ein Container
   mit overflow wird zum Sticky-Bezugsrahmen — deshalb kleben Kopfzeile und
   Namensspalte hier bewusst am Container (top/left: 0) und NICHT über
   .extr-table-sticky am Fenster: der dort gesetzte App-Header-Versatz
   (--extr-sticky-top) würde den Kopf mitten ins Raster schieben. */
.emp-matrix-wrap { overflow: auto; max-height: calc(100vh - 16rem); overscroll-behavior: contain; }
.emp-matrix { border-collapse: separate; border-spacing: 0; }
.emp-matrix th, .emp-matrix td { white-space: nowrap; }
.emp-matrix thead th {
  position: sticky; top: 0; z-index: 3;
  background: hsl(var(--muted));
  box-shadow: inset 0 -1px 0 hsl(var(--border));
}
.emp-matrix .emp-matrix-name {
  position: sticky; left: 0; z-index: 2;
  background: hsl(var(--card));
  box-shadow: inset -1px 0 0 hsl(var(--border));
  min-width: 15rem;
}
.emp-matrix thead .emp-matrix-name { z-index: 4; background: hsl(var(--muted)); }
.emp-matrix th.emp-matrix-mod { min-width: 4.75rem; font-weight: 500; text-transform: none; letter-spacing: 0; }
.emp-matrix th.emp-matrix-mod > span { display: flex; flex-direction: column; align-items: center; gap: .25rem; font-size: .6875rem; line-height: 1.15; max-width: 5.5rem; white-space: normal; text-align: center; }
.emp-matrix td.emp-matrix-cell { text-align: center; }
.emp-matrix-mark { display: inline-flex; align-items: center; justify-content: center; height: 1.5rem; width: 1.5rem; border-radius: .5rem; }
.emp-matrix-mark--manage { background: hsl(var(--primary) / .12); color: hsl(var(--primary)); }
.emp-matrix-mark--access { color: hsl(var(--muted-foreground)); }
.emp-matrix-mark--none   { color: hsl(var(--border)); }
.emp-matrix-mark svg { height: .95rem; width: .95rem; }
/* Die Namensspalte klebt links; die Modulzellen scrollen UNTER ihr durch. Ihr Hintergrund
   muss deshalb deckend sein — eine Tönung allein (6 % Primärfarbe) ließe die Symbole
   durchscheinen. Daher: Tönung als Verlaufsschicht ÜBER dem deckenden Kartenweiß. */
.emp-matrix tr.is-admin .emp-matrix-name {
  background: linear-gradient(hsl(var(--primary) / .06), hsl(var(--primary) / .06)), hsl(var(--card));
}
.emp-matrix tbody tr:hover .emp-matrix-name {
  background: linear-gradient(hsl(var(--muted) / .4), hsl(var(--muted) / .4)), hsl(var(--card));
}
.emp-matrix tbody tr.is-admin:hover .emp-matrix-name {
  background: linear-gradient(hsl(var(--muted) / .4), hsl(var(--muted) / .4)), linear-gradient(hsl(var(--primary) / .06), hsl(var(--primary) / .06)), hsl(var(--card));
}

/* ============================================================
   Aufklappende Suche (extr_search_field, CLAUDE-UI.md §3.4)
   Ein Icon-Knopf, der sich per Animation zu einem Suchfeld öffnet und die
   Inhalte rechts daneben (Filter-Pills, Selects) überlagert, statt sie zu
   verschieben. Klick daneben oder Esc schließt das Feld; ein gesetzter
   Begriff bleibt aktiv und als Chip am Knopf sichtbar. Höhe 38px = Höhe
   der Filter-Selects (py-2), damit die Zeile bündig bleibt.
   ============================================================ */
.extr-sf { position: relative; flex: 0 0 auto; height: 2.375rem; }
.extr-sf-toggle {
  display: inline-flex; align-items: center; gap: .45rem;
  height: 2.375rem; min-width: 2.375rem; max-width: 16rem; padding: 0 .625rem;
  border: 1px solid hsl(var(--border)); border-radius: .5rem; background: #fff;
  color: hsl(var(--muted-foreground)); font-size: .875rem; font-weight: 500; white-space: nowrap;
  cursor: pointer; transition: background-color .15s, color .15s, border-color .15s;
}
.extr-sf-toggle:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-sf-toggle:focus-visible { outline: 2px solid hsl(var(--primary) / .5); outline-offset: 2px; }
.extr-sf-toggle svg { height: 1rem; width: 1rem; flex: 0 0 auto; }
.extr-sf.has-value .extr-sf-toggle { background: hsl(var(--primary)); border-color: hsl(var(--primary)); color: #fff; }
.extr-sf.has-value .extr-sf-toggle:hover { background: hsl(var(--primary) / .9); }
.extr-sf-chip { display: none; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.extr-sf.has-value .extr-sf-chip { display: block; }
.extr-sf-panel {
  position: absolute; top: 0; left: 0; z-index: 30;
  display: flex; align-items: center;
  height: 2.375rem; width: 2.375rem; opacity: 0; pointer-events: none; overflow: hidden;
  border: 1px solid hsl(var(--border)); border-radius: .5rem; background: #fff;
  box-shadow: 0 10px 30px -12px rgba(15, 23, 42, .25);
  transition: width .28s cubic-bezier(.22, .61, .36, 1), opacity .16s ease;
}
.extr-sf.is-open .extr-sf-panel { width: var(--extr-sf-open, 28rem); opacity: 1; pointer-events: auto; }
.extr-sf--right .extr-sf-panel { left: auto; right: 0; }   /* öffnet nach links (Feld am rechten Rand) */
.extr-sf-panel:focus-within {
  border-color: hsl(var(--primary));
  box-shadow: 0 0 0 3px hsl(var(--primary) / .15), 0 10px 30px -12px rgba(15, 23, 42, .25);
}
.extr-sf-icon { position: absolute; left: .75rem; height: 1rem; width: 1rem; color: hsl(var(--muted-foreground)); pointer-events: none; }
.extr-sf-input {
  flex: 1 1 auto; min-width: 0; height: 100%; border: 0; outline: 0; background: transparent;
  padding: 0 2.25rem 0 2.5rem; font-size: .875rem; color: hsl(var(--foreground));
}
.extr-sf-input::-webkit-search-cancel-button,
.extr-sf-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.extr-sf-clear {
  position: absolute; right: .3rem; display: none; align-items: center; justify-content: center;
  height: 1.75rem; width: 1.75rem; border-radius: .375rem; color: hsl(var(--muted-foreground)); cursor: pointer;
}
.extr-sf-clear svg { height: 1rem; width: 1rem; }
.extr-sf-clear:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-sf.has-value .extr-sf-clear { display: inline-flex; }
/* Inline-Suche: das Leeren-„x" folgt dem Feldinhalt selbst — auch wenn ein Modul
   den Wert per Skript zurücksetzt, ohne ein input-Ereignis auszulösen (UI-Audit CODE-03). */
.extr-sf--inline .extr-sf-input:not(:placeholder-shown) ~ .extr-sf-clear { display: inline-flex; }
.extr-sf--inline.has-value .extr-sf-input:placeholder-shown ~ .extr-sf-clear { display: none; }
.extr-sf-spinner {
  position: absolute; left: .8rem; display: none; height: .9rem; width: .9rem; border-radius: 9999px;
  border: 2px solid hsl(var(--border)); border-top-color: hsl(var(--primary)); animation: extrSfSpin .7s linear infinite;
}
.extr-sf.is-loading .extr-sf-spinner { display: block; }
.extr-sf.is-loading .extr-sf-icon { visibility: hidden; }
@keyframes extrSfSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .extr-sf-panel { transition: none; } }

/* Suche im „⋮“-Menü (Detailköpfe am Handy, Feedback CHAT-05): unter 1024 px ist der
   Suchknopf ausgeblendet, ein Menüeintrag (extr-action-item--mobile) öffnet das Feld;
   ein gesetzter Begriff bleibt als Chip sichtbar. Der Menüeintrag verschwindet auf dem
   Desktop, dort steht der Knopf wie gewohnt im Kopf. */
@media (max-width: 1023px) {
  .extr-sf--menu:not(.is-open):not(.has-value) { width: 0; min-width: 0; margin-right: -.5rem; }
  .extr-sf--menu:not(.is-open):not(.has-value) .extr-sf-toggle { display: none; }
}
@media (min-width: 1024px) { .extr-action-item--mobile { display: none; } }

/* Filter-Pills mit Zähler (extr_filter_pill): Badge folgt dem Aktivzustand des Knopfs. */
.extr-pill-count {
  display: inline-flex; align-items: center; padding: .1rem .4rem; border-radius: 9999px;
  font-size: .75rem; font-weight: 500; line-height: 1.1;
  background: hsl(var(--muted)); color: hsl(var(--muted-foreground));
}
.bg-primary .extr-pill-count, .extr-pill.is-active .extr-pill-count { background: rgba(255, 255, 255, .22); color: #fff; }

/* Leerzustand in Inhalts-Containern mit eigenen p-Regeln (z. B. .ut-output p { margin:0 })
   bleibt zentriert: die Automargins hier binden stärker als eine Element-Regel. */
.extr-empty .extr-empty-text { margin-left: auto; margin-right: auto; }
.extr-empty .extr-empty-icon { margin-left: auto; margin-right: auto; }

/* ============================================================
   Filterzeile & Wechsler — vereinheitlicht (UI-Audit 2026-09)
   FLT-01: eine Höhe für Suche, Selects und Sortierknopf (38 px).
   SW-02:  ein Markup für alle Segment-Wechsler (extr_tab_strip).
   FLT-04: immer offenes Suchfeld für Auswahl-Fenster (Picker).
   Alles hier, nicht in Tailwind: der Build ist gepurged.
   ============================================================ */

/* Selects der Filterzeile — bündig zur aufklappenden Suche (2.375rem = 38 px).
   Vorher standen 34-px-Selects (py-1.5) neben 38-px-Suchfeldern.
   Eigener Name: .extr-select gehört dem Formular-Baustein weiter oben (width:100%,
   gefüllter Hintergrund) — der würde die Filterzeile über die volle Breite ziehen. */
/* Mehrfachauswahl-Listen (multiple) behalten ihre Höhe — dort ist size="n" gewollt. */
select.extr-filter-select:not([multiple]) {
  height: 2.375rem;
  line-height: 1.25;
}
/* Form und Farbe des Filter-Selects stehen hier, nicht als Kette im Markup:
   die Kette stand 76-mal in vier Fassungen (px-2 / px-2.5 / px-3, teils ohne
   Fokusring), der Innenabstand driftete um 4 px. In @layer components, damit
   ein w-full oder eine Modulklasse daneben weiter greift. */
@layer components {
  .extr-filter-select {
    border: 1px solid hsl(var(--border));
    border-radius: var(--radius-lg, .75rem);
    padding: .5rem .75rem;
    font-size: .875rem;
    background: hsl(var(--card));
    color: hsl(var(--foreground));
    flex-shrink: 0;
  }
  .extr-filter-select:focus {
    outline: none;
    box-shadow: 0 0 0 2px hsl(var(--primary) / 0.2);
  }
}

/* Richtungsknopf der Sortierung — quadratisch, gleiche Höhe wie Select+Suche. */
.extr-sort-dir {
  height: 2.375rem;
  width: 2.375rem;
}
.extr-sort-dir svg { height: 1rem; width: 1rem; }

/* „Filter zurücksetzen" erscheint nur bei aktivem Filter (extr_filter_reset). */
.extr-filter-reset svg { height: 1rem; width: 1rem; }

/* ---- Reiter im Streifen (extr_tab_strip) ---------------------------------
   Der Streifen selbst (.extr-tab-strip) scrollt bereits seitlich. Unter
   640 px zeigen die Reiter nur ihr Symbol — die Beschriftung steckt in
   title/aria-label. Streifen mit mehrdeutigen Symbolen setzen
   'labels' => 'always' und behalten den Text. */
/* Eigener Name: .extr-tab gehört dem Design-System-Tabsystem (§3.7, Unterstrich-
   Reiter mit display:block) — dessen Regeln würden den Streifen zerlegen. */
.extr-tab-strip-btn { cursor: pointer; }
.extr-tab-strip-btn svg { height: 1rem; width: 1rem; flex: 0 0 auto; }
.extr-tab-strip-label { min-width: 0; }

@media (max-width: 639px) {
  .extr-tab-strip:not(.extr-tab-strip--labels) .extr-tab-strip-label {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }
  /* Ohne Text braucht der Reiter kein waagerechtes Polster mehr. */
  .extr-tab-strip:not(.extr-tab-strip--labels) .extr-tab-strip-btn {
    padding-left: .625rem;
    padding-right: .625rem;
  }
}

/* ---- Immer offenes Suchfeld für Auswahl-Fenster (Picker) -----------------
   Gleiche Bausteine wie die aufklappende Suche, nur ohne Knopf: das Feld
   steht offen in der Zeile und wächst mit. Damit verschwinden die letzten
   rohen <input type="search"> aus den Modalen. */
.extr-sf--inline { flex: 1 1 auto; min-width: 0; width: 100%; }
.extr-sf--inline .extr-sf-toggle { display: none; }
.extr-sf--inline .extr-sf-panel {
  position: static;
  width: 100%;
  opacity: 1;
  pointer-events: auto;
  box-shadow: none;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.extr-sf--inline.is-open .extr-sf-panel { width: 100%; }
.extr-sf--inline .extr-sf-panel:focus-within {
  box-shadow: 0 0 0 3px hsl(var(--primary) / .15);
}

/* Ungespeicherte Änderungen am Speichern-Knopf einer Detailseite (UI-Audit HDR-03). */
.extr-action-primary.is-dirty::after {
  content: '';
  position: absolute;
  top: .45rem;
  right: .45rem;
  height: .5rem;
  width: .5rem;
  border-radius: 9999px;
  background: hsl(var(--primary-foreground));
}

/* Die Zwischenlösung .extr-modal-wide / .extr-modal-xwide (Ersatz für die
   im gepurgten Build fehlenden lg:max-w-3xl/4xl) ist entfallen: die Breiten
   stecken jetzt in .extr-dlg-panel--wide / --xwide (siehe MOD-02 unten). */

/* ============================================================
   UI-Audit Charge 2 (2026-09-09) — Tabellen, Kacheln, Zeilen-
   Aktionen, Modal-Ebenen. Alles handgeschrieben, also purge-fest.
   Namen bewusst neu: .extr-btn, .extr-input, .extr-modal*,
   .extr-empty*, .extr-table-sticky und .extr-card gibt es bereits
   weiter oben — die werden hier NICHT umdefiniert.
   ============================================================ */

/* ---- LST-01: Tabellen ------------------------------------------------------
   Der Bestand zählte 14 verschiedene th-Klassenketten. Eine Tabelle sieht
   jetzt überall gleich aus; die Dichtevariante --dense ist für Datenraster
   (Zeitkonto, Schichtplan), in denen p-4 die Zeilen zu hoch macht. */
.extr-table { width: 100%; border-collapse: collapse; }
.extr-table thead { background: hsl(var(--muted) / .5); border-bottom: 1px solid hsl(var(--border)); }
.extr-table th {
  text-align: left;
  padding: 1rem;
  font-weight: 500;
  font-size: .875rem;
  color: hsl(var(--foreground));
  white-space: nowrap;
}
.extr-table td { padding: 1rem; font-size: .875rem; vertical-align: middle; }
.extr-table tbody tr { border-bottom: 1px solid hsl(var(--border)); }
.extr-table tbody tr:last-child { border-bottom: 0; }
.extr-table tbody tr:hover { background: hsl(var(--muted) / .5); }
.extr-table th.is-right, .extr-table td.is-right { text-align: right; }
.extr-table th.is-center, .extr-table td.is-center { text-align: center; }

/* Dichter: halbe Polsterung, für Raster mit vielen Spalten. */
.extr-table--dense th,
.extr-table--dense td { padding: .5rem .625rem; }
.extr-table--dense th { font-size: .8125rem; }

/* ---- LST-04: Leerzustand INNERHALB einer Liste -----------------------------
   Nicht zu verwechseln mit .extr-empty (ganze Ansicht leer, extr_empty_state).
   Hier: „Filter/Suche liefert nichts" — eine Zeile, immer gleich formuliert. */
.extr-empty-inline {
  padding: 2rem 1rem;
  text-align: center;
  font-size: .875rem;
  color: hsl(var(--muted-foreground));
}
/* Dichter: in Auswahl-Aufklappern (Personensuche, Ticketsuche) ist die Liste
   nur ein paar Zeilen hoch — gleicher Wortlaut, weniger Polsterung. */
.extr-empty-inline--sm { padding: .5rem .75rem; font-size: .75rem; text-align: left; }

/* ---- Dashboard-Widget (UI-Audit CON-03) ------------------------------------
   Das Dashboard folgt bewusst NICHT dem Listenmuster der Module: es ist ein
   Raster aus Kacheln. Damit die Ausnahme trotzdem eine feste Form hat, sind
   Hülle, Kopf und Leerzustand hier benannt — vorher stand die Kette 39-mal
   im Partial. Der leichte Schatten ist gewollt: die Kacheln schweben über
   dem Raster, anders als die Karten in den Listen (§3.3).
     <div class="extr-dash-widget">
       <div class="extr-dash-widget-head"><h3>…</h3><a …>Alle</a></div>
       <div class="extr-dash-empty">…</div>  ODER  <div class="extr-divided">…</div>
     </div> */
/* In @layer components: Utility-Klassen im selben class-Attribut — die
   Mobil-Kachel trägt lg:hidden und muss den Baustein schlagen können. */
@layer components {
  .extr-dash-widget {
    display: flex; flex-direction: column; height: 100%;
    background: hsl(var(--card));
    border: 1px solid hsl(var(--border));
    border-radius: 1rem;
    /* Tailwinds shadow-md — dieselbe Zahl wie in der abgelösten Kette. */
    box-shadow: var(--shadow-md, 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a);
    padding: 1.25rem;
  }
  .extr-dash-widget-head {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 1rem;
  }
  .extr-dash-widget-head h3 {
    display: flex; align-items: center; gap: .5rem;
    font-size: .875rem; font-weight: 600;
  }
  .extr-dash-widget-head h3 svg,
  .extr-dash-widget-head h3 i { height: 1rem; width: 1rem; color: hsl(var(--primary)); }
  .extr-dash-empty {
    flex: 1 1 auto;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center; padding: 1.5rem 0;
  }
  .extr-dash-empty svg, .extr-dash-empty i { height: 2rem; width: 2rem; margin-bottom: .5rem; }
  .extr-dash-empty p { font-size: .875rem; color: hsl(var(--muted-foreground)); }
}
/* ---- Getrennte Liste (UI-Audit CODE-01) ------------------------------------
   Eine feine Linie zwischen aufeinanderfolgenden Einträgen. Stand vorher
   53-mal als eigener <style>-Block in den Partials — jedes Dashboard-Widget,
   jede Auswahlliste brachte ihre eigene Kopie mit.
   Anwenden am Container, nicht an den Kindern:
     <div class="extr-divided"> <a …>…</a> <a …>…</a> </div> */
.extr-divided > * + * { border-top: 1px solid hsl(var(--border) / 0.45); }
/* Kräftigere Linie, wo die Einträge Karten sind. */
.extr-divided--strong > * + * { border-top-color: hsl(var(--border)); }
/* ---- LST-06: Nachladen ----------------------------------------------------
   Vier Arten standen nebeneinander: Seitenzahlen, „Mehr laden“, Endlos-Scroll
   und alles auf einmal. Regel jetzt: Tabellen blättern (.extr-pager),
   Kartenraster laden nach (.extr-more, Endlos-Scroll hängt zentral in app.js). */
.extr-pager {
  display: flex; justify-content: center; align-items: center;
  gap: .5rem; flex-wrap: wrap; padding-top: .5rem;
}
.extr-pager-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.25rem; height: 2.25rem; padding: 0 .625rem;
  border: 1px solid hsl(var(--border));
  border-radius: var(--radius-lg, .75rem);
  background: hsl(var(--card));
  color: hsl(var(--muted-foreground));
  font-size: .875rem; font-weight: 500;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.extr-pager-btn:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-pager-btn.is-active {
  background: var(--color-primary, var(--primary-hsl));
  border-color: var(--color-primary, var(--primary-hsl));
  color: #fff;
}
.extr-pager-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px hsl(var(--primary) / .25); }
.extr-pager-gap { color: hsl(var(--muted-foreground)); padding: 0 .125rem; }

.extr-more { display: flex; justify-content: center; margin-top: 1.5rem; }
/* `.hidden` kommt aus @layer utilities und verliert gegen diese ungeschichteten
   Regeln — deshalb ausdrücklich (Muster wie .extr-nav-badge weiter oben). */
.extr-row-btn.hidden,
.extr-more.hidden,
.extr-pager.hidden { display: none; }
/* ---- BTN-02: Symbolknöpfe --------------------------------------------------
   Der Bestand mischte h-9 w-9 rounded-md mit h-8 w-8 rounded-lg — zwei Größen
   und zwei Rundungen nebeneinander. Jetzt: eine Größe je Ort.
     .extr-icon-btn      36 px, ohne Rahmen — Kopfzeilen und Werkzeugleisten
     .extr-icon-btn--sm  32 px, ohne Rahmen — innerhalb von Karten
     .extr-icon-btn--outline  mit Rahmen, wo der Knopf allein steht
   In Listenzeilen gilt weiter .extr-row-btn (32 px mit Rahmen, LST-05) — die
   Rolle ist eine andere, deshalb bleibt es eine eigene Klasse. */
@layer components {
  .extr-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    height: 2.25rem; width: 2.25rem; flex: 0 0 auto;
    border: 0;
    /* rounded-lg wie bei .extr-btn — der Bestand mischte rounded-md (6 px)
       und rounded-lg (12 px); 12 px ist die Mehrheit und passt zu den
       übrigen Knöpfen (Befund aus der Prüfung von Charge 3). */
    border-radius: var(--radius-lg, .75rem);
    background: transparent;
    color: hsl(var(--muted-foreground));
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease, border-color .15s ease;
  }
  .extr-icon-btn svg, .extr-icon-btn i { height: 1.25rem; width: 1.25rem; }
  .extr-icon-btn:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
  .extr-icon-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px hsl(var(--primary) / .25); }
  .extr-icon-btn:disabled { opacity: .5; cursor: not-allowed; }
  .extr-icon-btn--sm { height: 2rem; width: 2rem; }
  .extr-icon-btn--sm svg, .extr-icon-btn--sm i { height: 1rem; width: 1rem; }
  .extr-icon-btn--outline {
    border: 1px solid hsl(var(--border));
  }
  /* Deckend weiß nur, wo der Knopf auf gemustertem Grund steht. */
  .extr-icon-btn--solid { background: hsl(var(--card)); }
  .extr-icon-btn--danger { color: hsl(var(--destructive)); }
  .extr-icon-btn--danger:hover { background: hsl(var(--destructive) / .1); color: hsl(var(--destructive)); }
  /* Leise Gefahr: gedämpft, erst beim Überfahren rot — für das „x"/Papierkorb
     in Karten und Auswahllisten, wo ein dauerhaft rotes Symbol zu laut wäre
     (Gegenstück zu .extr-row-btn--danger, UI-Audit CODE-03). */
  .extr-icon-btn--danger-hover:hover { background: hsl(var(--destructive) / .1); color: hsl(var(--destructive)); }
  /* Kompakt (24 px) für gestapelte Reihenfolge-Pfeile und dichte Zeilen, in denen
     32 px die Zeile aufblähen würden — WCAG 2.5.8 verlangt 24 px (UI-Audit CODE-03). */
  .extr-icon-btn--xs { height: 1.5rem; width: 1.5rem; border-radius: var(--radius-md, .375rem); }
  .extr-icon-btn--xs svg, .extr-icon-btn--xs i { height: .875rem; width: .875rem; }
  /* „x" in einem Chip (Personen, Filter): erbt die Chipfarbe, rund, 18 px. */
  .extr-chip-x {
    display: inline-flex; align-items: center; justify-content: center;
    height: 1.125rem; width: 1.125rem; flex: 0 0 auto;
    border: 0; border-radius: 9999px; background: transparent; color: inherit; cursor: pointer;
  }
  .extr-chip-x svg, .extr-chip-x i { height: .75rem; width: .75rem; }
  .extr-chip-x:hover { background: color-mix(in srgb, currentColor 18%, transparent); }
  .extr-chip-x:focus-visible { outline: none; box-shadow: 0 0 0 2px hsl(var(--primary) / .35); }
}
/* ---- UX-05: Tipp-Ziele bei Fingerbedienung ----------------------------------
   Symbolknöpfe messen 32–36 px; mit dem Finger sind 44 px das Maß (Apple/Material,
   WCAG 2.5.8 verlangt mindestens 24 px). Bei grobem Zeiger wachsen deshalb alle
   Symbol-Bausteine auf 2.75rem — ungeschichtet, damit auch h-8/w-8 im Markup
   sie nicht kleiner halten. Mit Maus und Trackpad bleibt alles wie gehabt. */
@media (pointer: coarse) {
  .extr-icon-btn:not(.extr-icon-btn--xs),
  .extr-row-btn,
  .extr-dlg-x { min-width: 2.75rem; min-height: 2.75rem; }
}
/* ---- LST-05: Aktionen in einer Listenzeile ---------------------------------
   Zwei Stile, mehr nicht: Symbolknopf (bis drei Aktionen) und „⋮"-Menü. */
.extr-row-actions { display: inline-flex; align-items: center; gap: .25rem; }
.extr-row-btn {
  display: inline-flex; align-items: center; justify-content: center;
  height: 2rem; width: 2rem; flex: 0 0 auto;
  border: 1px solid hsl(var(--border));
  /* Dieselbe Rundung wie .extr-btn, .extr-icon-btn, .extr-input und
     .extr-pager-btn — BTN-02 wollte genau eine, nicht zwei. */
  border-radius: var(--radius-lg, .75rem);
  background: hsl(var(--card));
  color: hsl(var(--muted-foreground));
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.extr-row-btn svg, .extr-row-btn i { height: 1rem; width: 1rem; }
.extr-row-btn:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-row-btn:focus-visible { outline: none; box-shadow: 0 0 0 3px hsl(var(--primary) / .25); }
.extr-row-btn--danger:hover {
  background: hsl(var(--destructive) / .1);
  border-color: hsl(var(--destructive) / .35);
  color: hsl(var(--destructive));
}
/* Die eine Hauptaktion einer Zeile darf beschriftet sein („Abruf", „Buchen"). */
.extr-row-btn--text { width: auto; padding: 0 .75rem; gap: .375rem; font-size: .8125rem; font-weight: 500; }

/* ---- MOD-01: Ebenen-Skala --------------------------------------------------
   Vorher: z-40, z-50, z-[55], z-[60], z-[70], z-[80], z-[200] querbeet — ein
   verschachtelter Dialog lag mal über, mal unter seinem Auslöser.
   Kopfzeile 40, Menüs 30 bleiben, wie in CLAUDE-UI.md §3.4 beschrieben. */
.extr-z-modal   { z-index: 60; }   /* Modal über der Ansicht          */
.extr-z-modal-2 { z-index: 70; }   /* Modal, das über einem Modal liegt */
.extr-z-preview { z-index: 80; }   /* Vollbild-Vorschau über den Modalen */
.extr-z-confirm { z-index: 250; }  /* Bestätigen/Verwerfen — MUSS über  */
                                   /* Ladeschleier (90), Lightbox (100)  */
                                   /* und Fotoeditor liegen: die Rück-   */
                                   /* frage kommt aus diesen heraus.     */
.extr-z-toast   { z-index: 400; }  /* Kurzmeldungen über allem        */

/* ---- MOD-02: Modal-Skelett (extr_modal_open/-close) ------------------------
   Eigene Namen: .extr-modal* gehört dem älteren, zentrierten Dialog des
   Design-Systems (max-width 540px, display:flex am Backdrop). Das hier ist
   das Skelett aus §3.4, das die Partials tatsächlich verwenden. */
.extr-dlg { position: fixed; inset: 0; }
.extr-dlg-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.5); backdrop-filter: blur(4px); }
.extr-dlg-panel {
  position: absolute;
  left: 1rem; right: 1rem; top: 2rem; bottom: 2rem;
  /* Deckel wie im Altbestand: bezieht sich auf die bereits um die Safe-Area
     eingerückte Wurzel .extr-dlg. */
  max-height: 100%;
  display: flex; flex-direction: column;
  background: hsl(var(--card));
  border-radius: 1rem;
  overflow: hidden;
  box-shadow: 0 25px 50px -12px rgba(0,0,0,.25);
}
/* Kompaktes Dialogfenster: Höhe nach Inhalt statt fester Rahmen — für
   Rückfragen und kurze Formulare. `--auto` sitzt mittig, `--top` oben.
   Beide begrenzen die Höhe und scrollen selbst; enthält das Panel den
   Baustein .extr-dlg-body, übernimmt der das Scrollen und die eigene
   Scrollleiste erscheint gar nicht erst. */
.extr-dlg-panel--auto,
.extr-dlg-panel--top {
  bottom: auto;
  /* 100 % der Wurzel .extr-dlg — die ist bereits um die Safe-Area eingerückt.
     100vh wüsste davon nichts und ließe das Panel unter die Insel ragen. */
  max-height: 100%;
  overflow-y: auto;
}
.extr-dlg-panel--auto {
  top: 50%;
  transform: translateY(-50%);
}
/* Dialoge, die auch UNTER 1024 px schmal bleiben. Im Altbestand stand dort
   `max-w-*` ohne lg:-Präfix — ohne diesen Zusatz füllt der Dialog auf dem
   Tablet fast die ganze Breite. */
.extr-dlg-panel--compact { margin-left: auto; margin-right: auto; }
/* Dialog mit Luft nach oben und unten: das mittige --auto-Panel darf sonst die ganze
   Höhe füllen und klebt an den Rändern (Zuweisungsdialog der Schichtplanung). */
.extr-dlg-panel--inset { max-height: calc(100% - 2rem); }
/* Zuweisungsdialog: zwei Ansichten als Flex-Spalten, damit ihr Körper (.extr-dlg-body)
   scrollt; umgeschaltet wird per style.display — nicht .hidden, das verlöre display:flex. */
.sm-view { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.sm-grip { cursor: grab; touch-action: none; }
.sm-row.is-dragging { opacity: .45; }
@media (max-width: 1023px) {
  .extr-dlg-panel--compact                        { max-width: 32rem; }
  .extr-dlg-panel--compact.extr-dlg-panel--narrow { max-width: 24rem; }
  .extr-dlg-panel--compact.extr-dlg-panel--md     { max-width: 28rem; }
  .extr-dlg-panel--compact.extr-dlg-panel--xl     { max-width: 36rem; }
  .extr-dlg-panel--compact.extr-dlg-panel--2xl    { max-width: 42rem; }
}

/* Unten angeschlagenes Blatt (Legende, mobile Auswahl). */
.extr-dlg-panel--sheet {
  top: auto;
  bottom: 1rem;
  max-height: calc(100% - 4.5rem);
  overflow-y: auto;
}
@media (min-width: 1024px) {
  .extr-dlg-panel { left: 50%; right: auto; transform: translateX(-50%); width: 100%; max-width: 32rem; }
  .extr-dlg-panel--narrow { max-width: 24rem; }   /* sm  */
  .extr-dlg-panel--md     { max-width: 28rem; }   /* md  */
  .extr-dlg-panel--xl     { max-width: 36rem; }   /* xl  */
  .extr-dlg-panel--2xl    { max-width: 42rem; }   /* 2xl */
  .extr-dlg-panel--wide   { max-width: 48rem; }   /* 3xl */
  .extr-dlg-panel--xwide  { max-width: 56rem; }   /* 4xl */
  .extr-dlg-panel--full   { max-width: 72rem; }   /* Verwaltungsraster */
  .extr-dlg-panel--auto   { transform: translate(-50%, -50%); }
}
.extr-dlg-head {
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid hsl(var(--border));
  flex: 0 0 auto;
}
.extr-dlg-head-title { display: flex; align-items: center; gap: .625rem; min-width: 0; }
.extr-dlg-head-title h2 { font-size: 1.125rem; font-weight: 600; }
.extr-dlg-head-title svg, .extr-dlg-head-title i { height: 1.25rem; width: 1.25rem; color: hsl(var(--primary)); flex: 0 0 auto; }
.extr-dlg-sub { font-size: .75rem; color: hsl(var(--muted-foreground)); }
.extr-dlg-x {
  display: inline-flex; align-items: center; justify-content: center;
  height: 2.25rem; width: 2.25rem; flex: 0 0 auto;
  border-radius: .5rem; color: hsl(var(--muted-foreground)); cursor: pointer;
}
.extr-dlg-x:hover { background: hsl(var(--muted)); color: hsl(var(--foreground)); }
.extr-dlg-body { flex: 1 1 auto; overflow-y: auto; padding: 1.25rem; }
.extr-dlg-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: .75rem;
  padding: 1rem 1.25rem;
  border-top: 1px solid hsl(var(--border));
  flex: 0 0 auto;
}

/* ---- KPI-01: Kennzahl-Kachel ----------------------------------------------
   Muster Aufgaben/Inventar: Symbolkreis links, Wert, Beschriftung darunter.
   --compact für Reihen mit sechs bis acht Kacheln (Zeitkonto, Google Ads). */
.extr-stat {
  display: flex; align-items: center; gap: .75rem;
  background: hsl(var(--card));
  border: 1px solid hsl(var(--border));
  border-radius: 1rem;
  padding: 1rem;
}
.extr-stat-icon {
  display: flex; align-items: center; justify-content: center;
  height: 2.5rem; width: 2.5rem; flex: 0 0 auto;
  border-radius: 9999px;
  background: hsl(var(--primary) / .1);
  color: hsl(var(--primary));
}
.extr-stat-icon svg, .extr-stat-icon i { height: 1.25rem; width: 1.25rem; }
.extr-stat-body { min-width: 0; }
.extr-stat-value { font-size: 1.125rem; font-weight: 600; line-height: 1.1; }
.extr-stat-label { font-size: .75rem; color: hsl(var(--muted-foreground)); margin-top: .125rem; }
.extr-stat-hint  { font-size: .6875rem; color: hsl(var(--muted-foreground)); margin-top: .125rem; }

.extr-stat--compact { padding: .75rem; gap: .5rem; }
.extr-stat--compact .extr-stat-icon { height: 2rem; width: 2rem; }
.extr-stat--compact .extr-stat-icon svg, .extr-stat--compact .extr-stat-icon i { height: 1rem; width: 1rem; }
.extr-stat--compact .extr-stat-value { font-size: 1rem; }

/* Farbtöne — bewusst wenige, alle über Tokens (dataviz: eine Serie, eine Farbe). */
.extr-stat--muted   .extr-stat-icon { background: hsl(var(--muted)); color: hsl(var(--muted-foreground)); }
.extr-stat--good    .extr-stat-icon { background: hsl(142 71% 45% / .14); color: hsl(142 71% 32%); }
.extr-stat--warn    .extr-stat-icon { background: hsl(38 92% 50% / .16);  color: hsl(30 90% 38%); }
.extr-stat--danger  .extr-stat-icon { background: hsl(var(--destructive) / .12); color: hsl(var(--destructive)); }
.extr-stat--good   .extr-stat-value { color: hsl(142 71% 32%); }
.extr-stat--warn   .extr-stat-value { color: hsl(30 90% 38%); }
.extr-stat--danger .extr-stat-value { color: hsl(var(--destructive)); }

/* Kachelreihe: 2 Spalten mobil, 4 am Desktop (wie Aufgaben/Inventar). */
.extr-stat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
@media (min-width: 1024px) { .extr-stat-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.extr-stat-grid.hidden { display: none; }
.extr-stat-grid--6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 640px)  { .extr-stat-grid--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .extr-stat-grid--6 { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

/* ---- LST-02: breite Tabellen am Handy -------------------------------------
   Erste Wahl ist die Kartenliste (lg:hidden Karten + hidden lg:block Tabelle,
   Muster Inventar/Kundeninfo). Wo ein Raster keine Karte hergibt (Zeitkonto,
   Gesamtplan, Auswertungen), sorgt dieser Container dafür, dass die Tabelle
   seitlich scrollt, die erste Spalte stehen bleibt und ein Schatten am Rand
   zeigt, dass rechts noch etwas kommt. */
/* Waagerechter Rückfall für Raster, die als Karte keinen Sinn ergeben.
   Wichtig: `overflow: clip` erzeugt KEINEN Scroll-Container — der klebende
   Tabellenkopf aus .extr-table-sticky bezieht sich also weiter auf das
   Fenster. Erst unter 1024 px wird hier waagerecht gescrollt; dort haftet der
   Kopf ohnehin nicht (siehe .extr-table-sticky). */
.extr-table-scroll {
  overflow: clip;
}
@media (max-width: 1023px) {
  .extr-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Schatten nur, solange nicht ganz nach rechts gescrollt ist. */
    background:
      linear-gradient(to right, hsl(var(--card)) 30%, hsl(var(--card) / 0)) left / 2rem 100% no-repeat,
      linear-gradient(to left,  hsl(var(--card)) 30%, hsl(var(--card) / 0)) right / 2rem 100% no-repeat,
      radial-gradient(farthest-side at 0 50%, rgba(15,23,42,.14), rgba(15,23,42,0)) left / .75rem 100% no-repeat,
      radial-gradient(farthest-side at 100% 50%, rgba(15,23,42,.14), rgba(15,23,42,0)) right / .75rem 100% no-repeat;
    background-attachment: local, local, scroll, scroll;
  }
}
/* Erste Spalte bleibt stehen — sie trägt die Bezeichnung der Zeile. */
@media (max-width: 1023px) {
  .extr-table-scroll--sticky1 .extr-table th:first-child,
  .extr-table-scroll--sticky1 .extr-table td:first-child {
    position: sticky;
    left: 0;
    z-index: 2;
    background: hsl(var(--card));
    box-shadow: 1px 0 0 hsl(var(--border));
  }
  .extr-table-scroll--sticky1 .extr-table thead th:first-child { z-index: 4; }
}

/* ============================================================================
   Build-Nachtrag (UI-Audit CODE-06, 2026-09-16)
   Tailwind ist vorkompiliert und gepurged (CLAUDE-UI.md §2.1): Klassen, die beim
   letzten Build nicht im Quelltext standen, hatten keine Regel — Hover-Töne,
   Fokusringe und Dateiknopf-Stile passierten im Browser still nicht. Hier stehen
   genau diese Utilities, so wie Tailwind v4 sie erzeugen würde, in derselben
   Ebene (@layer utilities), damit Varianten und Reihenfolge stimmen.
   Neue Utility, die im Build fehlt? HIER ergänzen (in allen drei Installationen
   gleich) — der Wächter „Utilities ohne Regel im Build" steht auf 0.
   Farben der Schema-Tokens über hsl(var(--…)), damit der Dunkelmodus folgt (§2.5).
   ============================================================================ */
@layer utilities {
  /* Maße und Abstände */
  .h-0\.5 { height: calc(var(--spacing) * .5); }
  .w-28 { width: calc(var(--spacing) * 28); }
  .w-56 { width: calc(var(--spacing) * 56); }
  .max-h-60 { max-height: calc(var(--spacing) * 60); }
  .left-6 { left: calc(var(--spacing) * 6); }
  .right-6 { right: calc(var(--spacing) * 6); }
  .mt-px { margin-top: 1px; }
  .pb-2\.5 { padding-bottom: calc(var(--spacing) * 2.5); }
  .bottom-4 { bottom: calc(var(--spacing) * 4); }
  .mr-auto { margin-right: auto; }
  .pl-1\.5 { padding-left: calc(var(--spacing) * 1.5); }
  .pr-0\.5 { padding-right: calc(var(--spacing) * .5); }
  .py-7 { padding-block: calc(var(--spacing) * 7); }
  .gap-x-5 { column-gap: calc(var(--spacing) * 5); }
  .gap-y-3 { row-gap: calc(var(--spacing) * 3); }
  .rounded-l-lg { border-top-left-radius: var(--radius-lg); border-bottom-left-radius: var(--radius-lg); }
  .rounded-r-lg { border-top-right-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }
  .first\:mt-0:first-child { margin-top: 0; }
  .focus-visible\:underline:focus-visible { text-decoration-line: underline; }
  .last\:mb-0:last-child { margin-bottom: 0; }
  .font-sans { font-family: var(--font-sans); }
  .cursor-grab { cursor: grab; }
  .active\:cursor-grabbing:active { cursor: grabbing; }

  /* Flächen- und Schrifttöne */
  .bg-amber-50\/50 { background-color: color-mix(in oklab, var(--color-amber-50) 50%, transparent); }
  .bg-amber-50\/60 { background-color: color-mix(in oklab, var(--color-amber-50) 60%, transparent); }
  .bg-amber-50\/70 { background-color: color-mix(in oklab, var(--color-amber-50) 70%, transparent); }
  .bg-green-50\/50 { background-color: color-mix(in oklab, var(--color-green-50) 50%, transparent); }
  .bg-green-50\/60 { background-color: color-mix(in oklab, var(--color-green-50) 60%, transparent); }
  .bg-blue-400\/60 { background-color: color-mix(in oklab, var(--color-blue-400) 60%, transparent); }
  .bg-primary\/70 { background-color: color-mix(in oklab, var(--color-primary) 70%, transparent); }
  .bg-white\/95 { background-color: color-mix(in oklab, var(--color-white) 95%, transparent); }
  .bg-white\/70 { background-color: color-mix(in oklab, var(--color-white) 70%, transparent); }
  .bg-amber-50\/40 { background-color: color-mix(in oklab, var(--color-amber-50) 40%, transparent); }
  .border-cyan-200 { border-color: var(--color-cyan-200); }
  .text-muted-foreground\/30 { color: hsl(var(--muted-foreground) / .3); }
  .disabled\:opacity-30:disabled { opacity: .3; }
  .text-muted-foreground\/40 { color: hsl(var(--muted-foreground) / .4); }
  .text-muted-foreground\/50 { color: hsl(var(--muted-foreground) / .5); }
  .text-muted-foreground\/60 { color: hsl(var(--muted-foreground) / .6); }
  .text-muted-foreground\/70 { color: hsl(var(--muted-foreground) / .7); }
  .text-red-600\/90 { color: color-mix(in oklab, var(--color-red-600) 90%, transparent); }
  .active\:bg-primary\/10:active { background-color: color-mix(in oklab, var(--color-primary) 10%, transparent); }


  /* Ringe */
  .ring-amber-200 { --tw-ring-color: var(--color-amber-200); }
  .ring-primary\/15 { --tw-ring-color: color-mix(in oklab, var(--color-primary) 15%, transparent); }
  .ring-primary\/20 { --tw-ring-color: color-mix(in oklab, var(--color-primary) 20%, transparent); }
  .focus\:ring-amber-400\/40:focus { --tw-ring-color: color-mix(in oklab, var(--color-amber-400) 40%, transparent); }
  .focus\:ring-primary\/30:focus { --tw-ring-color: color-mix(in oklab, var(--color-primary) 30%, transparent); }

  /* Dateiauswahl-Knopf (input type=file) */
  .file\:mr-3::file-selector-button { margin-right: calc(var(--spacing) * 3); }
  .file\:px-3::file-selector-button { padding-inline: calc(var(--spacing) * 3); }
  .file\:py-1\.5::file-selector-button { padding-block: calc(var(--spacing) * 1.5); }
  .file\:rounded-lg::file-selector-button { border-radius: var(--radius-lg); }
  .file\:border-border::file-selector-button { border-color: hsl(var(--border)); }
  .file\:bg-white::file-selector-button { background-color: var(--color-white); }
  .file\:bg-muted::file-selector-button { background-color: hsl(var(--muted)); }

  /* Hover-Rückmeldungen (nur bei Zeigegeräten, wie Tailwind v4) */
  @media (hover: hover) {
    .hover\:bg-primary\/5:hover { background-color: color-mix(in oklab, var(--color-primary) 5%, transparent); }
    .hover\:bg-primary\/20:hover { background-color: color-mix(in oklab, var(--color-primary) 20%, transparent); }
    .hover\:bg-amber-700:hover { background-color: var(--color-amber-700); }
    .hover\:bg-violet-100:hover { background-color: var(--color-violet-100); }
    .hover\:bg-violet-700:hover { background-color: var(--color-violet-700); }
    .hover\:border-primary\/40:hover { border-color: color-mix(in oklab, var(--color-primary) 40%, transparent); }
    .hover\:border-primary\/60:hover { border-color: color-mix(in oklab, var(--color-primary) 60%, transparent); }
    .hover\:border-red-200:hover { border-color: var(--color-red-200); }
    .disabled\:hover\:bg-white:disabled:hover { background-color: var(--color-white); }
    .hover\:file\:bg-muted:hover::file-selector-button { background-color: hsl(var(--muted)); }
    .hover\:file\:bg-muted\/70:hover::file-selector-button { background-color: hsl(var(--muted) / .7); }
    .group-hover\:text-primary:is(:where(.group):hover *) { color: var(--color-primary); }
  }

  /* Bruchstellen: sm = 40rem, lg = 64rem (wie im Build) */
  @media (min-width: 40rem) {
    .sm\:w-8 { width: calc(var(--spacing) * 8); }
    .sm\:col-span-3 { grid-column: span 3 / span 3; }
  }
  @media (min-width: 64rem) {
    .lg\:p-5 { padding: calc(var(--spacing) * 5); }
    .lg\:w-56 { width: calc(var(--spacing) * 56); }
    .lg\:table-cell { display: table-cell; }
    .lg\:max-w-4xl { max-width: var(--container-4xl); }
  }
}


/* ---- Mein Profil → Benachrichtigungen: Raster Modul × Kanal ------------------
   Eine Zeile je Modul, drei Schalter (Mitteilung, Badge, Push). Auf dem Handy
   bleiben die Schalter als Symbole mit 44-px-Trefferfläche neben dem Modulnamen,
   statt wie früher in umbrechenden Pillen. Die Spaltenköpfe schalten die ganze
   Spalte um. Bewusst ohne .extr-Präfix (Klassenmenge der Bausteine bleibt gleich). */
.notif-grid { display:flex; flex-direction:column; }
.notif-head, .notif-row { display:grid; grid-template-columns:minmax(0,1fr) repeat(3, 3.25rem); align-items:center; column-gap:.25rem; }
.notif-head { padding-bottom:.375rem; border-bottom:1px solid hsl(var(--border)); color:hsl(var(--muted-foreground)); }
.notif-head-mod { font-size:.6875rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase; }
.notif-col { display:flex; flex-direction:column; align-items:center; gap:.125rem; padding:.25rem 0; border:0; border-radius:.5rem; background:none; color:inherit; font:inherit; font-size:.625rem; line-height:1.15; cursor:pointer; }
.notif-col:hover, .notif-col:focus-visible { background:hsl(var(--muted) / .6); color:hsl(var(--foreground)); }
.notif-col svg, .notif-col i { width:1rem; height:1rem; }
.notif-row { padding:.25rem 0; }
.notif-row + .notif-row { border-top:1px solid hsl(var(--border)); }
.notif-mod { display:flex; align-items:center; gap:.5rem; min-width:0; font-size:.875rem; font-weight:500; }
.notif-mod > svg, .notif-mod > i { width:1rem; height:1rem; flex-shrink:0; color:hsl(var(--primary)); }
.notif-mod > span { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.notif-tog { position:relative; display:flex; align-items:center; justify-content:center; height:2.75rem; cursor:pointer; }
.notif-tog input { position:absolute; inset:0; width:100%; height:100%; margin:0; opacity:0; cursor:pointer; }
.notif-tog > span { display:flex; align-items:center; justify-content:center; width:2.5rem; height:2.25rem; border-radius:.625rem; border:1px solid hsl(var(--border)); color:hsl(var(--muted-foreground)); opacity:.55; transition:background-color .15s, border-color .15s, color .15s, opacity .15s; }
.notif-tog > span svg, .notif-tog > span i { width:1rem; height:1rem; }
.notif-tog:hover > span { opacity:.85; }
.notif-tog input:checked + span { background:hsl(var(--primary) / .1); border-color:hsl(var(--primary) / .4); color:hsl(var(--primary)); opacity:1; }
.notif-tog input:focus-visible + span { outline:2px solid hsl(var(--primary) / .5); outline-offset:2px; }
.notif-legend { list-style:none; margin:.875rem 0 0; padding:0; display:flex; flex-wrap:wrap; gap:.25rem 1.25rem; font-size:.75rem; color:hsl(var(--muted-foreground)); }
.notif-legend li { display:flex; align-items:center; gap:.375rem; margin:0; }
.notif-legend svg, .notif-legend i { width:.875rem; height:.875rem; flex-shrink:0; }
.notif-actions { display:flex; justify-content:flex-end; margin-top:1rem; }
@media (max-width:639px) {
  .notif-actions > .extr-btn { width:100%; justify-content:center; }
}
@media (min-width:640px) {
  .notif-head, .notif-row { grid-template-columns:minmax(0,1fr) repeat(3, 5.5rem); }
  .notif-col { font-size:.6875rem; }
}

/* ---- Helpdesk-Ausbau 2026-09 (Feedback AZS) ---------------------------------
   In allen Installationen gleich (azs, rp, aurum, vbm).
   .hd-rich: Ticket-Text und Kommentare aus dem Editor (HD-01) — bereinigtes HTML
   mit Bildern; .hd-rich--plain: Altbestand als Text mit Zeilenumbrüchen. */
.hd-rich { font-size:.875rem; line-height:1.6; overflow-wrap:anywhere; }
.hd-rich > :first-child { margin-top:0; }
.hd-rich > :last-child { margin-bottom:0; }
.hd-rich p { margin:0 0 .5rem; }
.hd-rich h2 { font-size:1.05rem; font-weight:650; margin:1rem 0 .4rem; }
.hd-rich h3, .hd-rich h4 { font-size:.95rem; font-weight:600; margin:.85rem 0 .35rem; }
.hd-rich ul { list-style:disc; padding-left:1.25rem; margin:.25rem 0 .6rem; }
.hd-rich ol { list-style:decimal; padding-left:1.25rem; margin:.25rem 0 .6rem; }
.hd-rich li { margin:.125rem 0; }
.hd-rich a { color:hsl(var(--primary)); text-decoration:underline; text-underline-offset:2px; }
.hd-rich strong, .hd-rich b { font-weight:600; }
.hd-rich blockquote { border-left:3px solid hsl(var(--border)); padding-left:.75rem; color:hsl(var(--muted-foreground)); margin:.5rem 0; }
.hd-rich pre, .hd-rich code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.8125rem; background:hsl(var(--muted)); border-radius:.375rem; }
.hd-rich pre { padding:.5rem .75rem; overflow-x:auto; white-space:pre-wrap; }
.hd-rich code { padding:0 .25rem; }
.hd-rich table { border-collapse:collapse; margin:.5rem 0; font-size:.8125rem; }
.hd-rich th, .hd-rich td { border:1px solid hsl(var(--border)); padding:.3rem .5rem; text-align:left; vertical-align:top; }
.hd-rich img { display:inline-block; max-width:100%; height:auto !important; border-radius:.625rem; border:1px solid hsl(var(--border)); margin:.25rem 0; cursor:zoom-in; }
.hd-rich a:has(> img) { text-decoration:none; }
.hd-rich--plain { white-space:normal; }
/* HD-03: Unterkategorie in der Kategorieverwaltung eingerückt */
.hd-cat-row--sub { margin-left:1.5rem; }
/* HD-07: Auswahlliste zum Tippen (window.extrSelectSearch in app.js) — das Eingabefeld
   trägt die Klassen des versteckten Selects (.extr-select bzw. .extr-filter-select). */
.extr-combo { position:relative; }
.extr-combo--inline { display:inline-block; flex-shrink:0; }
.extr-combo--inline .extr-combo-input { width:13rem; }
.extr-combo-input.extr-filter-select { height:2.375rem; padding-right:2rem; 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='%236b7280' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right .75rem center; }
.extr-combo-input { text-overflow:ellipsis; }
.extr-combo-list { position:absolute; left:0; right:0; top:calc(100% + 4px); z-index:70; min-width:14rem; max-height:16rem; overflow-y:auto; padding:.25rem; background:hsl(var(--card)); border:1px solid hsl(var(--border)); border-radius:.75rem; box-shadow:0 12px 32px -12px rgb(0 0 0 / .25); }
.extr-combo-group { padding:.45rem .6rem .2rem; font-size:.6875rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:hsl(var(--muted-foreground)); }
.extr-combo-opt { padding:.45rem .6rem; border-radius:.5rem; font-size:.875rem; cursor:pointer; color:hsl(var(--foreground)); }
.extr-combo-opt--in-group { padding-left:1.1rem; }
.extr-combo-opt.is-current { font-weight:600; }
.extr-combo-opt.is-active, .extr-combo-opt:hover { background:hsl(var(--primary) / .08); color:hsl(var(--primary)); }
.extr-combo-empty { padding:.5rem .6rem; font-size:.8125rem; color:hsl(var(--muted-foreground)); }
/* HD-05: Ticket-Suche (Verwaltung) — Treffer und KI-Antwort */
.hd-ks-hit { border:1px solid hsl(var(--border)); border-radius:.75rem; padding:.625rem .75rem; background:hsl(var(--card)); }
.hd-ks-hit-head { display:flex; align-items:baseline; gap:.5rem; min-width:0; }
.hd-ks-ref { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.75rem; color:hsl(var(--primary)); text-decoration:none; white-space:nowrap; }
.hd-ks-ref:hover { text-decoration:underline; }
.hd-ks-hit-title { font-size:.875rem; font-weight:600; color:hsl(var(--foreground)); text-decoration:none; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; }
.hd-ks-hit-title:hover { text-decoration:underline; }
.hd-ks-hit-meta { font-size:.75rem; color:hsl(var(--muted-foreground)); margin-top:.125rem; }
.hd-ks-sol { display:inline-block; padding:0 .4rem; border-radius:999px; background:hsl(var(--tone-ok-bg, 141 84% 93%)); color:hsl(var(--tone-ok-fg, 142 72% 29%)); font-weight:600; }
.hd-ks-snip { font-size:.8125rem; color:hsl(var(--muted-foreground)); margin:.35rem 0 0; overflow-wrap:anywhere; }
.hd-ks-ai { border:1px solid hsl(var(--primary) / .25); background:hsl(var(--primary) / .05); border-radius:.75rem; padding:.75rem .875rem; font-size:.875rem; }
.hd-ks-ai-head { font-size:.6875rem; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:hsl(var(--primary)); margin:0 0 .35rem; }
.hd-ks-ai-text { margin:0; line-height:1.6; white-space:pre-line; }
.hd-ks-ai-note { margin:.5rem 0 0; font-size:.75rem; color:hsl(var(--muted-foreground)); }
/* HD-10: Tabellenansicht des Helpdesks */
.hd-list-row.is-done .hd-list-title a { color:hsl(var(--muted-foreground)); }
.hd-list-title { min-width:14rem; }
.hd-sla { display:inline-block; padding:.05rem .45rem; border-radius:999px; font-size:.75rem; font-weight:500; border:1px solid transparent; }
.hd-sla--ok { background:hsl(var(--tone-ok-bg, 141 84% 93%)); color:hsl(var(--tone-ok-fg, 142 72% 29%)); }
.hd-sla--warning { background:hsl(var(--tone-warn-bg, 48 100% 96%)); color:hsl(var(--tone-warn-fg, 23 83% 31%)); border-color:hsl(var(--tone-warn-border, 46 97% 65%)); }
.hd-sla--breached { background:hsl(var(--tone-bad-bg, 0 93% 94%)); color:hsl(var(--tone-bad-fg, 0 74% 42%)); }
/* HD-11: Helpdesk-Statistik — Säulen und Balken nach CLAUDE-UI §3.15 (wie KI-Verbrauch) */
.hd-st-plot { position:relative; height:220px; margin:1rem 0 0 2.5rem; }
.hd-st-grid { position:absolute; left:0; right:0; border-top:1px solid hsl(var(--border)); }
.hd-st-grid span { position:absolute; right:100%; margin-right:.5rem; transform:translateY(-50%); font-size:11px; color:hsl(var(--muted-foreground)); white-space:nowrap; }
.hd-st-cols { position:absolute; inset:0; display:flex; align-items:flex-end; gap:2px; }
.hd-st-col { flex:1 1 0; min-width:0; height:100%; display:flex; align-items:flex-end; justify-content:center; position:relative; cursor:default; }
.hd-st-colbar { width:100%; max-width:24px; border-radius:4px 4px 0 0; background:hsl(var(--primary)); transition:opacity .12s; }
.hd-st-col:hover .hd-st-colbar, .hd-st-col:focus .hd-st-colbar { opacity:.75; }
.hd-st-peak { position:absolute; bottom:100%; left:50%; transform:translateX(-50%); font-size:11px; color:hsl(var(--foreground)); white-space:nowrap; margin-bottom:2px; }
.hd-st-xaxis { display:flex; gap:2px; margin:.4rem 0 0 2.5rem; }
.hd-st-xaxis span { flex:1 1 0; min-width:0; font-size:11px; color:hsl(var(--muted-foreground)); text-align:center; white-space:nowrap; overflow:visible; }
.hd-st-bar { height:18px; border-radius:0 4px 4px 0; background:hsl(var(--primary)); transition:opacity .12s; }
.hd-st-brow:hover .hd-st-bar, .hd-st-brow:focus .hd-st-bar { opacity:.75; }
.hd-st-blabel { width:11rem; }
.hd-st-bval { width:3.5rem; }
#hd-st-tip { position:absolute; z-index:50; pointer-events:none; transform:translate(-50%, calc(-100% - 8px)); background:hsl(var(--foreground)); color:hsl(var(--background)); font-size:12px; line-height:1.3; padding:.35rem .6rem; border-radius:.4rem; white-space:nowrap; box-shadow:0 6px 20px -8px rgba(0,0,0,.4); }
@media (max-width:639px) { .hd-st-blabel { width:7.5rem; } }
/* HD-12: Antwortvorlagen im Kommentarfeld */
.hd-tpl-pop { position:absolute; left:0; bottom:calc(100% + 6px); z-index:60; width:min(22rem, 80vw); padding:.5rem; background:hsl(var(--card)); border:1px solid hsl(var(--border)); border-radius:.75rem; box-shadow:0 12px 32px -12px rgb(0 0 0 / .25); }
.hd-tpl-list { max-height:16rem; overflow-y:auto; margin-top:.4rem; display:flex; flex-direction:column; gap:2px; }
.hd-tpl-item { display:flex; flex-direction:column; align-items:flex-start; text-align:left; padding:.45rem .55rem; border-radius:.5rem; border:0; background:none; cursor:pointer; color:hsl(var(--foreground)); }
.hd-tpl-item:hover, .hd-tpl-item:focus-visible { background:hsl(var(--primary) / .08); }
.hd-tpl-item-title { font-size:.875rem; font-weight:600; }
.hd-tpl-item-text { font-size:.75rem; color:hsl(var(--muted-foreground)); }
/* HD-02: Personensuche „Ticket für dritte Person anlegen" */
.hd-proxy-opt { display:flex; flex-direction:column; width:100%; text-align:left; padding:.5rem .75rem; font-size:.875rem; border:0; background:none; cursor:pointer; color:hsl(var(--foreground)); }
.hd-proxy-opt:hover, .hd-proxy-opt:focus-visible { background:hsl(var(--muted)); }
.hd-proxy-opt-name { font-weight:500; }
.hd-proxy-opt-meta { font-size:.75rem; color:hsl(var(--muted-foreground)); }
.hd-proxy-empty { padding:.5rem .75rem; font-size:.875rem; color:hsl(var(--muted-foreground)); }

/* ---- SCHUL-01: Bilder in Tests (Feedback AZS 2026-09) ----------------------
   In azs, rp und aurum gleich. Editor: Bild zur Frage + Bild je Antwortoption;
   Ablauf/Ergebnis/Vorschau: Bild unter der Frage, Antwortbilder als Kachel. */
.sch-img-add { display:inline-flex; align-items:center; gap:.4rem; margin:-.25rem 0 .75rem; padding:.3rem .6rem; border:1px dashed hsl(var(--border)); border-radius:.6rem; font-size:.8125rem; color:hsl(var(--muted-foreground)); background:none; cursor:pointer; }
.sch-img-add:hover { color:hsl(var(--primary)); border-color:hsl(var(--primary) / .5); }
.sch-q-img { display:flex; align-items:flex-end; gap:.75rem; margin:-.25rem 0 .75rem; flex-wrap:wrap; }
.sch-q-img img, .sch-view-img { max-width:100%; max-height:16rem; border-radius:.75rem; border:1px solid hsl(var(--border)); background:hsl(var(--muted) / .4); }
.sch-view-img { display:block; margin:.5rem 0 .75rem; cursor:zoom-in; }
.sch-img-remove { display:inline-flex; align-items:center; gap:.3rem; font-size:.75rem; color:hsl(var(--muted-foreground)); background:none; border:0; cursor:pointer; }
.sch-img-remove:hover { color:hsl(0 74% 42%); }
.sch-ans-img { position:relative; display:inline-flex; flex-shrink:0; }
.sch-ans-img img { height:2.5rem; width:2.5rem; object-fit:cover; border-radius:.5rem; border:1px solid hsl(var(--border)); }
.sch-img-x { position:absolute; top:-.4rem; right:-.4rem; height:1.25rem; width:1.25rem; display:flex; align-items:center; justify-content:center; border-radius:999px; border:1px solid hsl(var(--border)); background:hsl(var(--card)); color:hsl(var(--muted-foreground)); cursor:pointer; }
.sch-img-x:hover { color:hsl(0 74% 42%); }
.sch-opt-img { display:block; max-height:9rem; max-width:100%; border-radius:.5rem; border:1px solid hsl(var(--border)); margin-top:.35rem; }
.sch-opt-thumb { height:2rem; width:2rem; object-fit:cover; border-radius:.35rem; border:1px solid hsl(var(--border)); flex-shrink:0; }
