/* Lumen - Oberflaechen-Stile.
 *
 * Bis v0.2.2 stand dieses gesamte Regelwerk als <style>-Block in
 * templates/base.html - rund 900 Zeilen, die bei JEDEM Seitenaufruf neu
 * mit ausgeliefert wurden und sich nie zwischenspeichern liessen. Vor
 * allem aber war "Formatierung systemweit vereinheitlichen" (Feedback
 * v0.2.2 §9) so praktisch nicht durchfuehrbar: eine Stelle zu aendern hiess,
 * in einer Template-Datei zwischen HTML zu suchen.
 *
 * In base.html verbleibt jetzt nur noch der winzige Teil, der wirklich vom
 * angemeldeten Benutzer abhaengt (die im Profil gewaehlte Systemfarbe, siehe
 * common.context_processors.theme). Alles andere steht hier und wird ueber
 * static_v mit Versionskennung ausgeliefert, sodass ein Browser die Datei
 * zwischenspeichern darf und nach einem Update trotzdem die neue Fassung
 * bekommt.
 */
/* ------------------------------------------------------------------
       Farbsystem. Die Systemfarbe selbst (--lumen-primary/--lumen-accent)
       steht NICHT hier, sondern kommt je Seitenaufruf aus
       common.context_processors.theme in den <style>-Block von
       templates/base.html - Auslieferungszustand ist Waldgruen #3F6B4B
       mit Sandgold #C9A66B aus der .env, darueber die Instanzeinstellung
       und die persoenliche Wahl im Profil.

       Grundidee der Oberflaeche: eine ruhige Shell (Sidebar/Topbar), eine
       leicht abgesetzte Arbeitsflaeche in der Mitte, die Systemfarbe
       ausschliesslich als Akzent fuer das jeweils Wichtigste (aktiver
       Menuepunkt, primaere Aktion). Die Shell gibt es in zwei Fassungen,
       hell und dunkel - siehe die beiden Bloecke unten.

       Text auf gefuellten Flaechen ist immer --lumen-on-primary, nie
       pauschal Weiss: die Palette enthaelt mit Limette (#B6FF2E) einen
       Ton, auf dem Weiss unlesbar waere (siehe accounts.models.
       kontrastfarbe).
       ------------------------------------------------------------------ */
    :root {
      --lumen-ink: #1F2329;
      --lumen-lime: #B6FF2E;
      /* Im Profil gewaehlte Systemfarbe + dazu berechnete lesbare Textfarbe */
      /* Auf hellem Grund lesbare Variante der Primaerfarbe (Links,
         Kartenueberschriften): Richtung Tinte abgedunkelt, damit auch die
         helle Limette als Textfarbe die WCAG-AA-Schwelle erreicht.
         36 % gemessen gegen beide hellen Untergruende - auf der
         Arbeitsflaeche (--lumen-canvas) ~4,9:1, auf weissen Karten
         ~5,4:1. Bei hoeheren Anteilen faellt der Wert auf der
         Arbeitsflaeche unter die geforderten 4,5:1. */
      --lumen-primary-text: color-mix(in srgb, var(--lumen-primary) 36%, var(--lumen-ink));
      --lumen-ink-800: #282D34;
      --lumen-ink-700: #333942;
      --lumen-ink-600: #454C56;
      --lumen-canvas: #F3F5F0;
      --lumen-surface: #FFFFFF;
      --lumen-line: rgba(31, 35, 41, .10);
      --lumen-muted: #6B7280;
      /* --- Shell-Palette, helle Fassung (Auslieferungszustand) --------
         Seitenleiste und Kopfzeile tragen seit dem 27.08. zwei
         austauschbare Fassungen. Welche gilt, entscheidet SHELL_VARIANTE
         in der .env; das Attribut data-shell am <html> traegt das
         Ergebnis hierher (siehe common.context_processors.shell_variante
         und templates/base.html).

         WARUM ALLE SHELL-WERTE UEBER VARIABLEN LAUFEN und nicht mehr als
         #fff / rgba(255,255,255,...) in den einzelnen Regeln stehen: mit
         hartcodierten Werten haette jede Regel zweimal geschrieben werden
         muessen, einmal je Fassung. Zwei Kopien derselben Aussage laufen
         auseinander - hier besonders schnell, weil Sidebar und Topbar
         dieselben Toene teilen, aber in verschiedenen Bloecken stehen. */
      --lumen-shell: #FFFFFF;
      --lumen-shell-line: rgba(31, 35, 41, .10);
      --lumen-shell-text: #4A525C;
      /* Hervorgehobener Text der Shell (Markenname, Bereichsanzeige,
         Benutzername). Auf heller Flaeche der abgedunkelte Primaerton -
         damit traegt die Marke die Instanzfarbe, statt neutral schwarz
         zu sein. */
      --lumen-shell-strong: var(--lumen-primary-text);
      --lumen-shell-muted: #7A828C;
      --lumen-shell-hover: rgba(31, 35, 41, .05);
      /* Textfarbe beim Ueberfahren. Auf heller Shell die Primaerfarbe
         selbst; die dunkle Fassung nimmt dafuer Limette, weil ein
         dunkler Primaerton auf der Tinte verschwinden wuerde. */
      --lumen-shell-akzent: var(--lumen-primary);
      /* Eingabefeld in der Kopfzeile (die Suche). Bootstrap-Standard
         passt hier nur in der hellen Fassung. */
      --lumen-shell-feld: #FFFFFF;
      --lumen-shell-feld-linie: rgba(31, 35, 41, .18);
      --lumen-shell-feld-text: var(--lumen-ink);
      --lumen-shell-feld-platzhalter: #8B939E;
      /* Die KOPFZEILE hat eigene Werte, weil sie in der Fassung "marke"
         die Systemfarbe traegt, waehrend die Seitenleiste hell bleibt
         (siehe [data-shell="marke"] unten). In "hell" und "dunkel" sind
         sie mit der Shell identisch - dann ist die Unterscheidung
         wirkungslos und kostet nichts. */
      /* Markenfeld und Kopfzeile stehen NEBENEINANDER und muessen
         deshalb exakt gleich hoch sein. Sie waren es nicht: 59px gegen
         60px, weil beide ihre Hoehe aus Innenabstand plus Inhalt
         bezogen - und unter dem kuerzeren Markenfeld schaute genau ein
         Pixel helle Seitenleiste hervor. Das war der gemeldete weisse
         Strich. Eine gemeinsame Mindesthoehe nagelt beide auf denselben
         Wert; wer den Innenabstand aendert, kann sie nicht mehr
         auseinanderlaufen lassen. */
      --lumen-bar-hoehe: 3.75rem;
      --lumen-bar: var(--lumen-shell);
      --lumen-bar-text: var(--lumen-shell-text);
      --lumen-bar-strong: var(--lumen-shell-strong);
      --lumen-bar-line: var(--lumen-shell-line);
      --lumen-bar-hover: var(--lumen-shell-hover);
      --lumen-bar-akzent: var(--lumen-shell-akzent);
      --lumen-bar-feld: var(--lumen-shell-feld);
      --lumen-bar-feld-linie: var(--lumen-shell-feld-linie);
      --lumen-bar-feld-text: var(--lumen-shell-feld-text);
      --lumen-bar-feld-platzhalter: var(--lumen-shell-feld-platzhalter);

      /* --- Baukasten: Mischgrund, Abstufungen, Geometrie, Status ------
         Der Auftrag vom 27.08. nach dem Farbschema: "Es soll einheitlich,
         mit den setzbaren Farben immer passen und leicht und
         uebersichtlich sein."

         WAS DAS FUER DEN QUELLTEXT HEISST: kein Ton wird zweimal
         geschrieben. Jede Flaeche, Linie und Textfarbe, die zur
         Systemfarbe gehoert, wird HIER aus --lumen-primary bzw.
         --lumen-accent gemischt. Stellt jemand die Instanzfarbe um,
         wandert alles mit - Reiter, Abzeichen, Tabellenkoepfe,
         Fortschrittsbalken. Vorher standen an rund zwei Dutzend Stellen
         eigene Hexwerte, die bei jeder Farbaenderung stehenblieben.

         DER MISCHGRUND ist der Grund, auf dem gemischt wird: im
         Hellmodus Weiss, im Dunkelmodus die Kartenflaeche. Ohne ihn
         ergaebe "12 % Primaerfarbe auf Weiss" im Dunkelmodus einen
         hellen Fleck auf dunklem Grund. */
      --lumen-mischgrund: #FFFFFF;
      --lumen-primary-weich: color-mix(in srgb, var(--lumen-primary) 8%, var(--lumen-mischgrund));
      --lumen-primary-hell: color-mix(in srgb, var(--lumen-primary) 16%, var(--lumen-mischgrund));
      --lumen-primary-linie: color-mix(in srgb, var(--lumen-primary) 32%, var(--lumen-mischgrund));
      --lumen-accent-weich: color-mix(in srgb, var(--lumen-accent) 16%, var(--lumen-mischgrund));
      --lumen-accent-linie: color-mix(in srgb, var(--lumen-accent) 45%, var(--lumen-mischgrund));
      /* Auf hellem Grund lesbare Fassung der Akzentfarbe - Sandgold als
         Text waere sonst zu blass (Kontrast unter 3:1). */
      --lumen-accent-text: color-mix(in srgb, var(--lumen-accent) 45%, var(--lumen-ink));

      /* Geometrie. Ein Radius, eine Linienstaerke, ein Rhythmus - die
         Vorlage lebt von ruhigen, kleinen Radien und 1px-Linien statt
         von Schatten. */
      --lumen-radius-klein: .25rem;
      --lumen-radius: .375rem;
      --lumen-radius-gross: .625rem;
      --lumen-schatten: 0 1px 2px rgba(31, 35, 41, .04);

      /* --- Schriftgroessen, alle an EINEM Regler ---------------------
         --lumen-basis ist die Grundgroesse der Anwendung. Sie steht als
         Standard auf 1rem (16px) und wird je Seitenaufruf aus dem
         Benutzerprofil ueberschrieben (Profil -> Allgemein ->
         Schriftgroesse, siehe common.context_processors.theme und den
         <style>-Block in templates/base.html).

         DER ERSTE WURF DIESES DURCHGANGS HATTE FESTE WERTE - und war
         schlicht zu klein: Grundschrift 15px, Knoepfe 13px, Abzeichen
         11px. Gemeldet wurde es als "die Zahlen sind riesig, aber der
         Text klein"; tatsaechlich war nicht die Zahl gross, sondern
         alles daneben zu klein geraten. Wer eine Oberflaeche
         verdichtet, verkleinert Abstaende - nicht die Schrift, mit der
         gearbeitet wird.

         Die beiden Nebengroessen rechnen sich seither AUS der Basis.
         Damit wandert die ganze Anwendung mit, wenn jemand am Regler
         dreht: ein fester Wert an einer dieser Stellen waere genau die
         Zeile, die dann nicht mitwaechst. */
      --lumen-basis: 1rem;
      --lumen-text-klein: calc(var(--lumen-basis) * .875);
      --lumen-text-label: calc(var(--lumen-basis) * .8125);

      /* --- Statusfarben ------------------------------------------------
         BEWUSST NICHT AUS DER SYSTEMFARBE ABGELEITET, und das ist die
         einzige Ausnahme von der Regel darueber. Ein Status ist eine
         Aussage ueber die Sache, keine Frage der Marke: "Fehler" muss
         rot bleiben, auch wenn die Instanz auf Rot eingestellt wird, und
         "erledigt" gruen, auch wenn die Marke gruen ist. Wuerden sie
         mitwandern, saehen bei gruener Marke Erfolg, Hinweis und
         Primaeraktion gleich aus.

         Gedeckte Toene, damit sie neben Waldgruen nicht schreien - je
         drei Werte: sehr helle Flaeche, Linie, kraeftiger Text. */
      --lumen-neutral-flaeche: #F1F3F5;
      --lumen-neutral-linie: #DEE2E6;
      --lumen-neutral-text: #5A6470;
      --lumen-info-flaeche: #EAF2F6;
      --lumen-info-linie: #C3DAE6;
      --lumen-info-text: #2C6E8F;
      --lumen-erfolg-flaeche: #E9F4EE;
      --lumen-erfolg-linie: #BFE0CC;
      --lumen-erfolg-text: #2E7D4F;
      --lumen-warnung-flaeche: #FBF3E3;
      --lumen-warnung-linie: #EDD9AE;
      --lumen-warnung-text: #96660F;
      --lumen-gefahr-flaeche: #FBECEB;
      --lumen-gefahr-linie: #F0CBC9;
      --lumen-gefahr-text: #B4342E;
    }
    /* --- Shell-Palette, Fassung "marke" (Auslieferungszustand) ------
       Helle Seitenleiste, Kopfzeile in der Systemfarbe. Das ist der
       Aufbau aus der Designvorlage vom 27.08.: die Marke steht als
       durchgehendes Band oben, die Navigation darunter bleibt hell und
       ruhig. Gegenueber "hell" aendert sich AUSSCHLIESSLICH die
       Kopfzeile - deshalb stehen hier nur die --lumen-bar-*-Werte und
       nicht die ganze Palette noch einmal.

       Die Textfarbe wird nicht geraten: --lumen-on-primary rechnet
       common.context_processors.theme je Systemfarbe aus (siehe
       accounts.models.kontrastfarbe). Auf Waldgruen ergibt das Weiss,
       auf einer hellen Farbe dunklen Text - eine fest eingetragene
       weisse Schrift waere dort unlesbar.

       Vor dem dunklen Block, damit der Dunkelmodus gewinnt. Praktisch
       tritt der Fall nicht ein, weil common.context_processors.
       shell_variante im Dunkelmodus ohnehin "dunkel" liefert; die
       Reihenfolge stimmt trotzdem, statt sich darauf zu verlassen. */
    [data-shell="marke"] {
      --lumen-bar: var(--lumen-primary);
      --lumen-bar-text: color-mix(in srgb, var(--lumen-on-primary) 82%, transparent);
      --lumen-bar-strong: var(--lumen-on-primary);
      --lumen-bar-line: color-mix(in srgb, var(--lumen-on-primary) 18%, transparent);
      --lumen-bar-hover: color-mix(in srgb, var(--lumen-on-primary) 12%, transparent);
      --lumen-bar-akzent: var(--lumen-on-primary);
      --lumen-bar-feld: color-mix(in srgb, var(--lumen-on-primary) 12%, transparent);
      --lumen-bar-feld-linie: color-mix(in srgb, var(--lumen-on-primary) 26%, transparent);
      --lumen-bar-feld-text: var(--lumen-on-primary);
      --lumen-bar-feld-platzhalter: color-mix(in srgb, var(--lumen-on-primary) 62%, transparent);
    }
    /* --- Shell-Palette, dunkle Fassung ------------------------------
       Der Stand bis v0.5: dunkle Shell als ruhiger Rahmen um die helle
       Arbeitsflaeche. Sie gilt bei SHELL_VARIANTE=dunkel - und IMMER im
       Dunkelmodus, wo eine helle Seitenleiste neben dunkler
       Arbeitsflaeche ein Bruch mitten im Bild waere.

       Beide Selektoren in EINER Regel und nicht zweimal derselbe Block:
       sonst waere die naechste Aenderung schon wieder eine Doppelpflege.
       Die Regel steht hinter der hellen Fassung, also gewinnt sie bei
       gleicher Spezifitaet ueber die Reihenfolge - auch gegen ein
       gleichzeitig gesetztes data-shell="hell" im Dunkelmodus. */
    [data-shell="dunkel"],
    [data-bs-theme="dark"] {
      --lumen-shell: var(--lumen-ink);
      --lumen-shell-line: rgba(255, 255, 255, .09);
      --lumen-shell-text: #C7CDD4;
      --lumen-shell-strong: #FFFFFF;
      --lumen-shell-muted: #7C8592;
      --lumen-shell-hover: rgba(255, 255, 255, .06);
      --lumen-shell-akzent: var(--lumen-lime);
      --lumen-shell-feld: rgba(255, 255, 255, .07);
      --lumen-shell-feld-linie: rgba(255, 255, 255, .14);
      --lumen-shell-feld-text: #FFFFFF;
      --lumen-shell-feld-platzhalter: #8B939E;
    }
    html, body { height: 100%; }
    body {
      background-color: var(--lumen-canvas);
      color: var(--lumen-ink);
      -webkit-font-smoothing: antialiased;
    }
    /* Textfarbe wird je Verwendung passend zur Hintergrundfarbe gesetzt
       (siehe partials/sidebar.html) - ein pauschales Weiss waere auf
       hellen Kalenderfarben wie Limette unlesbar. */
    .avatar-badge {
      width: 2rem; height: 2rem; border-radius: 50%; display: inline-flex;
      align-items: center; justify-content: center; color: #fff; font-weight: 700;
      font-size: .8rem; flex-shrink: 0;
    }

    /* App-Shell: Sidebar links (fix, eigenes Scrolling) + Inhaltsspalte
       (Topbar + Main + Footer) rechts - abgeloest von der vorherigen
       vollbreiten Navbar (siehe Feedback: "Navbar zu einer Sidebar
       umfunktionieren... soll aussehen wie sevdesk"). */
    .app-shell { display: flex; align-items: stretch; min-height: 100vh; }
    /* Die Shell trug bis v0.5 dauerhaft die dunkle Fassung ("die dunkle
       Shell rahmt die helle Arbeitsflaeche und laesst den Limetten-Akzent
       ueberhaupt erst wirken"). Mit Waldgruen als Primaerfarbe gilt die
       Begruendung nicht mehr: ein satter, dunkler Gruenton traegt sich
       auf hellem Grund, Limette tat das nicht. Die dunkle Fassung ist
       deshalb nicht entfallen, sondern eine .env-Einstellung geworden
       (SHELL_VARIANTE) - wer sie will, bekommt sie unveraendert. */
    .app-sidebar {
      width: 250px; flex-shrink: 0; background-color: var(--lumen-shell);
      border-right: 1px solid var(--lumen-shell-line); display: flex; flex-direction: column;
      position: sticky; top: 0; height: 100vh; overflow-y: auto; z-index: 1040;
      transition: width .16s ease;
    }
    .app-sidebar-brand {
      display: flex; align-items: center; justify-content: space-between;
      min-height: var(--lumen-bar-hoehe); box-sizing: border-box;
      padding: .6rem 1.1rem; border-bottom: 1px solid var(--lumen-shell-line);
    }
    .app-sidebar-brand-name { font-weight: 700; letter-spacing: .01em; color: var(--lumen-shell-strong); white-space: nowrap; }
    .app-sidebar-close { padding: .25rem; }
    /* Ein-/Ausklapp-Umschalter (Desktop) - Standard ist eingeklappt (siehe
       static/js/sidebar.js), damit die Sidebar nicht permanent so viel
       Platz belegt (Feedback: "das ist an sich zugeklappt immer wird,
       dass das ein bisschen leicht ist"). */
    .app-sidebar-collapse-toggle {
      border: none; background: none; color: var(--lumen-shell-muted); padding: .4rem 0;
      display: flex; align-items: center; justify-content: center; width: 100%;
      border-top: 1px solid var(--lumen-shell-line);
    }
    .app-sidebar-collapse-toggle:hover { color: var(--lumen-shell-akzent); background-color: var(--lumen-shell-hover); }
    .app-sidebar-nav { flex: 1 1 auto; padding: .75rem .75rem; overflow-y: auto; overflow-x: hidden; }
    .app-sidebar-link {
      display: flex; align-items: center; gap: .65rem; padding: .55rem .75rem;
      border-radius: .5rem; color: var(--lumen-shell-text); text-decoration: none; font-size: .92rem;
      margin-bottom: .1rem; transition: background-color .12s ease, color .12s ease;
      white-space: nowrap;
    }
    .app-sidebar-link i { font-size: 1.05rem; width: 1.2rem; text-align: center; flex-shrink: 0; }
    .app-sidebar-link:hover { background-color: var(--lumen-shell-hover); color: var(--lumen-shell-strong); }
    /* Aktiver Menuepunkt ist der einzige vollflaechig in der Systemfarbe
       gefuellte Bereich der Navigation - dadurch ist auf einen Blick klar,
       wo man steht. */
    .app-sidebar-link.active {
      background-color: var(--lumen-primary); color: var(--lumen-on-primary) !important;
      font-weight: 600;
    }
    .app-sidebar-link.active i { color: var(--lumen-on-primary); }
    .app-sidebar-section-label {
      font-size: .68rem; text-transform: uppercase; letter-spacing: .06em; color: var(--lumen-shell-muted);
      padding: 1rem .75rem .3rem; white-space: nowrap; overflow: hidden;
    }
    /* Bleibt (anders als .app-sidebar-section-label) auch im eingeklappten
       Zustand sichtbar, damit die "Verwalten"-Gruppe optisch von den
       Hauptlinks getrennt bleibt, statt als eine durchgehende Icon-Liste
       zu wirken (siehe Feedback: "wenn ich das zuklappe... macht wenig
       Sinn... da müsste eigentlich einmal so'n Strich hin zum Trennen"). */
    .app-sidebar-divider { border: none; border-top: 1px solid var(--lumen-shell-line); margin: .6rem .5rem .3rem; }
    .dokument-tag-chip.active { background-color: var(--lumen-primary); color: var(--lumen-on-primary); border-color: var(--lumen-primary); }
    /* Die Regeln fuer .app-sidebar-user* sind mit dem Benutzerblock selbst
       entfallen (Feedback Block J §2, siehe partials/topbar.html). Eine
       Regel fuer ein nicht mehr vorhandenes Element sieht beim naechsten
       Lesen aus wie eine Zusicherung, die es nicht gibt - dieselbe
       Ueberlegung wie beim schon frueher entfernten #nav-primary-links
       weiter unten. */
    .app-sidebar-backdrop { display: none; }

    /* Eingeklappter Zustand: nur Icons, Texte/Sektionslabels ausgeblendet
       (siehe Tooltip-Titel, per JS aus dem Linktext befuellt) - bewusst
       nur ab Desktop-Breite: auf Mobile ist die Sidebar ein Off-Canvas-
       Menue (siehe @media max-width weiter unten), das immer voll
       ausgeklappt bleiben soll, unabhaengig vom gespeicherten
       Collapse-Zustand. */
    @media (min-width: 992px) {
      /* html.lumen-sidebar-collapsed greift sofort beim ersten Malen (siehe
         Inline-Script ganz oben in <body>), .app-sidebar.collapsed erst
         nachdem static/js/sidebar.js auf DOMContentLoaded gelaufen ist -
         beide Selektoren zusammen verhindern das kurze Aufblitzen der
         ausgeklappten Sidebar bei jeder Seitennavigation (siehe Feedback:
         "wenn ich auf Kalender druecke, dann geht die einem auf und zu.
         Das sieht man kurz"). */
      html.lumen-sidebar-collapsed .app-sidebar,
      .app-sidebar.collapsed { width: 68px; }
      /* Nur die Ausrichtung aendert sich, NICHT die Hoehe: ein eigener
         senkrechter Innenabstand hier hiesse, dass das Markenband beim
         Ein- und Ausklappen um ein paar Pixel springt - gemeldet als
         "wenn die eingeklappt ist, so wie ausgeklappt, Hoehenunterschied
         drin". */
      html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-brand,
      .app-sidebar.collapsed .app-sidebar-brand { justify-content: center; padding-left: .5rem; padding-right: .5rem; }
      html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-brand-name,
      html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-section-label,
      html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-link span,
      .app-sidebar.collapsed .app-sidebar-brand-name,
      .app-sidebar.collapsed .app-sidebar-section-label,
      .app-sidebar.collapsed .app-sidebar-link span { display: none; }
      html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-link,
      .app-sidebar.collapsed .app-sidebar-link { justify-content: center; }
    }
    html.lumen-sidebar-collapsed .app-sidebar .app-sidebar-collapse-toggle i,
    .app-sidebar.collapsed .app-sidebar-collapse-toggle i { transform: rotate(180deg); }

    .app-content { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; min-height: 100vh; }
    .app-content > main { flex: 1 0 auto; }
    /* Die Fussleiste ist mit v0.6.3 entfallen (siehe templates/base.html).
       Die beiden Regeln dafuer bleiben trotzdem stehen: die Anmelde- und
       Fehlerseiten haengen NICHT an .app-content, und die Auszeichnung
       <footer> ist damit weiterhin gueltiges Markup, das eine Seite
       benutzen kann. Eine Regel zu loeschen, die nur gerade niemand
       braucht, spart nichts und kostet beim naechsten Mal die Suche nach
       dem Grund, warum ein Fussbereich mitwaechst. */
    .app-content > footer { flex-shrink: 0; }
    body > main, body > footer { flex-shrink: 0; }

    .app-topbar {
      display: flex; align-items: center; gap: .5rem; padding: .6rem 1.25rem;
      min-height: var(--lumen-bar-hoehe); box-sizing: border-box;
      background-color: var(--lumen-bar); border-bottom: 1px solid var(--lumen-bar-line);
      position: sticky; top: 0; z-index: 1030;
    }
    .app-topbar-burger { color: var(--lumen-bar-text) !important; padding: .25rem .4rem; }
    .app-topbar-spacer { flex: 1 1 auto; }
    /* Bereichsanzeige der Topbar (v0.4.6, Auftrag §6): unterhalb von lg ist
       die Seitenleiste aus dem Bild geschoben und mit ihr die aktive
       Markierung - ohne diese Zeile stand auf schmalen Fenstern nirgends
       mehr, in welchem Bereich man sich befindet. Den Text setzt
       static/js/sidebar.js aus dem aktiven Punkt der Seitenleiste; ohne
       aktiven Punkt bleibt das Element leer und belegt dank :empty auch
       keinen Platz. */
    .app-topbar-bereich {
      color: var(--lumen-bar-strong); font-weight: 600; font-size: .95rem; white-space: nowrap;
      overflow: hidden; text-overflow: ellipsis; max-width: 45vw; padding-right: .25rem;
    }
    .app-topbar-bereich:empty { display: none; }
    /* Das Suchfeld hatte seine Breite als style-Attribut im Template und
       konnte deshalb nicht schrumpfen: zwischen 992px und etwa 1100px
       drueckte es Glocke und Vorschau-Symbol aus der Zeile. */
    .app-topbar #global-search-input { flex: 0 1 22rem; width: 22rem; max-width: 100%; min-width: 0; }
    .app-topbar-bell { color: var(--lumen-bar-text) !important; }
    .app-topbar-burger:hover, .app-topbar-bell:hover { color: var(--lumen-bar-akzent) !important; }
    /* Benutzerblock ganz rechts (Feedback Block J §3). Er hat den
       Kuerzelkreis aus der Seitenleiste uebernommen (.avatar-badge, dort
       unveraendert), braucht in der Kopfzeile aber eigene Textfarben -
       die Bootstrap-Standardfarbe eines Dropdown-Togglers waere auf der
       dunklen Fassung praktisch unsichtbar. */
    .app-topbar-user-toggle {
      display: flex; align-items: center; gap: .55rem; text-decoration: none;
      color: var(--lumen-bar-text); padding: .25rem .5rem; border-radius: .5rem;
      max-width: 16rem;
    }
    .app-topbar-user-toggle:hover { background-color: var(--lumen-bar-hover); color: var(--lumen-bar-akzent); }
    .app-topbar-user-toggle::after { color: var(--lumen-bar-text); flex-shrink: 0; }
    .app-topbar-user-name {
      font-size: .88rem; font-weight: 600; color: var(--lumen-bar-strong);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    /* Unterhalb von lg teilen sich Burger, Bereichsanzeige, Suche, Glocke
       und Benutzerblock eine schmale Zeile. Der Name ist dort der einzige
       Teil, der ohne Verlust weichen kann: der Kuerzelkreis bleibt stehen
       und bedient dasselbe Menue. */
    @media (max-width: 991.98px) {
      .app-topbar-user-name { display: none; }
      .app-topbar-user-toggle::after { display: none; }
    }
    #search-toggle-btn, #search-close-btn { color: var(--lumen-bar-text) !important; }
    #search-toggle-btn:hover, #search-close-btn:hover { color: var(--lumen-bar-akzent) !important; }
    /* Das Suchfeld sitzt in der Kopfzeile und traegt deren Fassung, nicht
       die hellen Bootstrap-Standardfarben - auf der dunklen Shell waere
       ein weisses Feld ein Loch in der Leiste. */
    .app-topbar .form-control {
      background-color: var(--lumen-bar-feld); border-color: var(--lumen-bar-feld-linie);
      color: var(--lumen-bar-feld-text);
    }
    .app-topbar .form-control::placeholder { color: var(--lumen-bar-feld-platzhalter); }
    .app-topbar .form-control:focus {
      background-color: var(--lumen-bar-feld); border-color: var(--lumen-bar-akzent);
      color: var(--lumen-bar-feld-text);
      box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--lumen-bar-akzent) 25%, transparent);
    }
    /* Die Suche liegt auf JEDER Breite hinter der Lupe (Auftrag vom
       27.08.: "die Suchleiste soll erst nach nem Klick auf die Lupe
       aufgehen wie in der Vorgaengerversion"). Zwischen v0.4.4 und hier
       stand das Feld ab lg dauerhaft offen; der Grund dafuer war ein
       echter Befund und keine Geschmacksfrage:

         "Beim Fokussieren des Suchfelds wird die Kopfzeile ausgeblendet
          und die Eingabe geht verloren - Suchfeld muss erhalten bleiben,
          damit mehrere Aktionen schnell hintereinander ausgefuehrt
          werden koennen."

       Der Befund ist nicht zurueckgeholt worden, nur seine Ursache ist
       eine andere Stelle: ein Klick daneben klappte das Feld MIT INHALT
       zu, und getippter Text war dann nicht mehr von "weg" zu
       unterscheiden. Zu klappt jetzt nur ein LEERES Feld (siehe
       static/js/live-search.js) - offen bleibt es, solange etwas
       drinsteht. */
    #search-expand {
      display: flex;
      max-width: 0; opacity: 0; overflow: hidden;
      transition: max-width .18s cubic-bezier(.25,.8,.25,1), opacity .14s ease;
    }
    #search-expand.active { max-width: 500px; opacity: 1; }
    #search-toggle-btn {
      display: inline-flex;
      transition: opacity .12s ease, max-width .12s ease; max-width: 3rem; overflow: hidden;
    }

    /* Mobile: Sidebar wird zum Off-Canvas-Menue (siehe static/js/sidebar.js) */
    @media (max-width: 991.98px) {
      .app-sidebar {
        position: fixed; left: 0; top: 0; height: 100vh; transform: translateX(-100%);
        transition: transform .2s ease; box-shadow: none;
      }
      .app-sidebar.show { transform: translateX(0); box-shadow: .5rem 0 1.5rem rgba(0,0,0,.15); }
      .app-sidebar-backdrop {
        display: none; position: fixed; inset: 0; background-color: rgba(0,0,0,.35); z-index: 1039;
      }
      .app-sidebar-backdrop.show { display: block; }
      /* Solange das Off-Canvas-Menue offen ist, scrollt der Inhalt
         DAHINTER nicht mehr mit: ein Wisch neben dem Menue verschob sonst
         die Seite, die man gar nicht sieht - man kam zurueck und stand an
         einer anderen Stelle als vorher. Die Klasse setzt
         static/js/sidebar.js. */
      body.lumen-menue-offen { overflow: hidden; }
      /* Das Auf- und Zuklappen selbst steht seit dem 27.08. weiter oben
         und gilt auf jeder Breite. Hier bleibt nur, was wirklich
         breitenabhaengig ist: die feste Feldbreite von 22rem passt auf
         schmalen Schirmen nicht neben Burger, Bereichsanzeige und
         Glocke. */
      #search-expand .form-control { width: 100% !important; min-width: 0; }
    }
    @media (min-width: 992px) {
      .app-sidebar-close { display: none !important; }
    }
    /* Primaere Aktion: gefuellt mit der Systemfarbe, Textfarbe berechnet
       (siehe accounts.models.kontrastfarbe) - auf Limette also dunkel.
       Zuvor stand hier ein pauschales "color: #fff", das mit der neuen
       hellen Standardfarbe unlesbar waere. */
    .btn-primary, .btn-lumen {
      background-color: var(--lumen-primary) !important;
      border-color: var(--lumen-primary) !important;
      color: var(--lumen-on-primary) !important;
      font-weight: 600;
      box-shadow: 0 .2rem .5rem rgba(31,35,41,.14);
      transition: transform .12s ease, box-shadow .12s ease, filter .12s ease;
    }
    .btn-primary:hover, .btn-primary:focus, .btn-lumen:hover, .btn-lumen:focus {
      filter: brightness(1.06); color: var(--lumen-on-primary) !important;
      transform: translateY(-1px); box-shadow: 0 .4rem .9rem color-mix(in srgb, var(--lumen-primary) 40%, transparent);
    }
    .btn-primary:active, .btn-lumen:active { transform: translateY(0); }
    .btn-primary:focus-visible, .btn-lumen:focus-visible {
      outline: 2px solid var(--lumen-ink); outline-offset: 2px;
    }
    .btn-outline-primary { color: var(--lumen-primary-text) !important; border-color: var(--lumen-primary) !important; }
    .btn-outline-primary:hover { background-color: var(--lumen-primary) !important; color: var(--lumen-on-primary) !important; }
    .btn { transition: transform .12s ease, box-shadow .12s ease, filter .12s ease, background-color .12s ease; }
    .btn-outline-secondary:hover, .btn-outline-danger:hover { transform: translateY(-1px); }

    /* Design-Polish: etwas mehr Abrundung/Tiefe statt des vorherigen sehr
       flachen Bootstrap-Standardlooks (siehe Feedback: "das sieht mir
       noch alles sehr... schlicht aus... ein bisschen uebertreiben mit
       dem Design, damit wir das gleich wieder zurueckrollen koennen"). */
    :root { --bs-border-radius: .6rem; --bs-border-radius-sm: .45rem; --bs-border-radius-lg: .8rem; }
    .card {
      border-radius: .75rem !important; transition: box-shadow .15s ease, transform .15s ease;
    }
    .card:hover { box-shadow: 0 .5rem 1.4rem rgba(0,0,0,.07); }
    .form-control, .form-select { border-radius: .55rem; transition: box-shadow .12s ease, border-color .12s ease; }
    .form-control:focus, .form-select:focus { box-shadow: 0 0 0 .2rem rgba(0,0,0,.12); }
    .form-control:focus, .form-select:focus { box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--lumen-primary) 20%, transparent); }
    .dropdown-menu { border-radius: .65rem; box-shadow: 0 .6rem 1.6rem rgba(0,0,0,.14); border-color: rgba(0,0,0,.06); }
    .modal-content { border-radius: .85rem; overflow: hidden; }
    .list-row { transition: background-color .12s ease; }
    .avatar-badge { box-shadow: 0 .1rem .3rem rgba(0,0,0,.15); }
    /* Auf hellem Grund immer die abgedunkelte Variante verwenden - die
       reine Limette erreicht als Textfarbe auf Weiss nur ~1,3:1 Kontrast. */
    .text-lumen { color: var(--lumen-primary-text) !important; }
    a { color: var(--lumen-primary-text); text-underline-offset: .15em; }
    a:hover { color: var(--lumen-ink); }
    .nav-pills .nav-link.active {
      background-color: var(--lumen-primary) !important; color: var(--lumen-on-primary) !important;
    }
    .page-link { color: var(--lumen-primary-text); }
    .page-item.active .page-link {
      background-color: var(--lumen-primary); border-color: var(--lumen-primary);
      color: var(--lumen-on-primary);
    }
    .badge-lumen { background-color: var(--lumen-accent); color: var(--lumen-on-accent); }
    .stat-tile {
      text-decoration: none; color: inherit; display: block;
      transition: transform .15s ease, box-shadow .15s ease;
      border-left: 3px solid var(--lumen-primary) !important;
    }
    .stat-tile:hover { transform: translateY(-2px); box-shadow: 0 .6rem 1.2rem rgba(31,35,41,.10); color: inherit; }
    .card { border: 1px solid var(--lumen-line); background-color: var(--lumen-surface); }
    /* Kartenkoepfe (h5/h6 als erstes Kind einer Card-Body) mit dezentem
       Farbakzent statt reinem Schwarz-auf-Weiss - siehe Feedback: "das
       ist jetzt alles ein bisschen sehr weiss, vielleicht ein bisschen
       farblich was aendern". */
    .card-body > h5:first-child, .card-body > h6:first-child,
    .card > .card-header { color: var(--lumen-primary-text); }
    /* button + Ausklapp-Feld muessen als Flex-Reihe nebeneinander liegen,
       sonst rutscht #search-expand (auch im max-width:0-Zustand noch mit
       eigener Hoehe im Blockfluss) darunter und zieht den Button aus der
       vertikalen Mitte der Navbar. */
    #search-box-wrapper { position: relative; display: flex; align-items: center; }
    #search-results-dropdown {
      position: absolute; top: 100%; left: 0; right: 0; z-index: 1080;
      max-height: 70vh; overflow-y: auto; display: none;
    }
    .search-result-group-label { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--lumen-muted); }
    .list-row:hover { background-color: rgba(0,0,0,.02); }
    .theme-swatch { width: 1.5rem; height: 1.5rem; border-radius: 50%; display: inline-block; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.15); cursor: pointer; }
    .theme-swatch.active { box-shadow: 0 0 0 2px var(--lumen-primary); }
    .nav-tabs .nav-link { transition: color .15s ease, border-color .15s ease; color: var(--lumen-muted); }
    .nav-tabs .nav-link:hover { color: var(--lumen-ink); }
    .nav-tabs .nav-link.active {
      border-bottom: 2px solid var(--lumen-primary); font-weight: 600;
      color: var(--lumen-primary-text);
    }
    /* Reiterleiste der Sterbefall-Detailseite (Feedback v0.4.0 §12: "Die
       Reiter sehen sehr unscheinbar aus"). Bisher unterschied nur eine
       2px-Unterkante den aktiven Reiter von den anderen - auf einer Seite
       mit sieben Reitern war der aktive kaum zu finden.

       Bewusst KEIN .nav-pills: der Bootstrap-Pill-Stil laesst die
       Reiterleiste in der Luft haengen, weil ihm die Verbindung zum
       Inhaltsbereich darunter fehlt. Stattdessen eine eigene Klasse, die
       nur auf dieser Leiste liegt - alle uebrigen nav-tabs im Projekt
       (Stammdatenreiter, Vorlagen-Editor) bleiben unveraendert. */
    .lumen-falltabs {
      border-bottom: 1px solid var(--lumen-line);
      gap: .25rem;
      flex-wrap: wrap;
    }
    .lumen-falltabs .nav-link {
      border: 1px solid transparent;
      border-bottom: none;
      border-radius: .5rem .5rem 0 0;
      padding: .5rem .9rem;
      display: inline-flex; align-items: center; gap: .45rem;
      transition: background-color .15s ease, color .15s ease, border-color .15s ease;
    }
    .lumen-falltabs .nav-link:hover { background-color: rgba(0,0,0,.035); }
    .lumen-falltabs .nav-link.active {
      background-color: var(--lumen-surface);
      border-color: var(--lumen-line);
      /* Deckt die 1px-Linie der Leiste genau unter dem aktiven Reiter ab,
         damit Reiter und Inhalt als eine Flaeche zusammenhaengen. */
      border-bottom: 1px solid var(--lumen-surface);
      margin-bottom: -1px;
      box-shadow: inset 0 3px 0 var(--lumen-primary);
    }
    /* Zaehler am Reiter. Nicht .badge-lumen (Akzentfarbe), weil sieben
       kraeftige Badges nebeneinander mehr Aufmerksamkeit zoegen als der
       aktive Reiter selbst - der Zaehler ist eine Nebenangabe. */
    /* Suchzeile + Chips fuer <select multiple> (static/js/mehrfachauswahl.js,
       Feedback v0.4.0 §2). Die Trefferliste liegt ueber dem Formular statt
       im Fluss - sonst schoebe jede Eingabe die Felder darunter weg, und
       die Auswahl waere ein bewegliches Ziel. */
    /* Schreibflaeche der formatierten Texteingabe (static/js/rich-text.js,
       Feedback v0.4.0 §6). Hoehe wie eine Textarea mit 14 Zeilen, damit
       das Umschalten zwischen Text und Quelltext den Dialog nicht
       springen laesst. */
    .lumen-richtext-flaeche {
      min-height: 20rem; height: auto; overflow-y: auto;
      white-space: normal;
    }
    .lumen-richtext-flaeche:focus {
      border-color: var(--lumen-primary);
      box-shadow: 0 0 0 .2rem rgba(182,255,46,.25);
      outline: none;
    }
    /* Ueberschriften in der Flaeche und in der Anzeige duerfen den Rahmen
       nicht sprengen - im Fliesstext eines Textbausteins ist eine
       Ueberschrift eine Betonung, kein Seitentitel. */
    .lumen-richtext-flaeche h2, .lumen-richtext-anzeige h2 { font-size: 1.15rem; }
    .lumen-richtext-flaeche h3, .lumen-richtext-anzeige h3 { font-size: 1rem; }
    .lumen-richtext-flaeche > *:last-child, .lumen-richtext-anzeige > *:last-child { margin-bottom: 0; }
    .lumen-richtext-anzeige blockquote, .lumen-richtext-flaeche blockquote {
      border-left: 3px solid var(--lumen-line); padding-left: .75rem; color: var(--lumen-muted);
    }
    /* Aufgabenliste (Feedback v0.4.0 §9). Der abgehakte Eintrag bleibt
       lesbar, tritt aber zurueck - durchgestrichen und blass, nicht weg:
       er ist der Beweis, dass etwas getan wurde. */
    .lumen-todo-zeile .lumen-todo-titel { color: var(--lumen-ink); }
    .lumen-todo-zeile .lumen-todo-titel:hover { color: var(--lumen-primary-text); }
    .lumen-todo-erledigt .lumen-todo-titel {
      text-decoration: line-through; color: var(--lumen-muted);
    }
    .lumen-todo-haken, .lumen-todo-stern { line-height: 1; font-size: 1.15rem; }
    .lumen-todo-haken:disabled, .lumen-todo-stern:disabled { opacity: .5; }
    /* Die wandernde Zeile (Auftrag v0.4.3 §10, "sofort und sichtbar an
       ihren neuen Platz"): sie blendet an Ort und Stelle aus, erst danach
       haengt static/js/todo-liste.js sie um. Ohne diesen Moment spraenge
       sie unter dem Finger weg und die nachrueckende Aufgabe stuende
       genau dort, wo man gerade klickt. */
    .lumen-todo-zeile { transition: opacity .3s ease, transform .3s ease; }
    .lumen-todo-wandert { opacity: .15; transform: translateX(1.25rem); pointer-events: none; }
    /* Status und Prioritaet als Abzeichen - auf der Karte, in der Zeile
       und auf der Detailseite dieselben Farben, damit "Wartet" ueberall
       gleich aussieht. Bewusst gedeckte Toene aus der Bootstrap-Palette
       statt eigener Farben: das einzige kraeftige Rot der Oberflaeche
       gehoert der Ueberfaelligkeit. */
    .todo-status, .todo-prio { font-weight: 600; }
    .todo-status-offen { background-color: rgba(108, 117, 125, .18); color: var(--lumen-ink-600); }
    /* Seit dem Baukasten (27.08.) aus denselben fuenf Statuspaaren wie
       jedes andere Abzeichen der Anwendung. Vorher standen hier
       Bootstrap-Werte - ein blaues "in Arbeit" mitten in einer gruenen
       Oberflaeche, und in einer Liste neben Abzeichen, die schon anders
       aussahen. */
    .todo-status-in_arbeit { background-color: var(--lumen-info-flaeche); color: var(--lumen-info-text); }
    .todo-status-wartet { background-color: var(--lumen-warnung-flaeche); color: var(--lumen-warnung-text); }
    .todo-status-erledigt { background-color: var(--lumen-erfolg-flaeche); color: var(--lumen-erfolg-text); }
    .todo-prio-niedrig { background-color: rgba(108, 117, 125, .18); color: var(--lumen-ink-600); }
    .todo-prio-mittel { background-color: var(--lumen-warnung-flaeche); color: var(--lumen-warnung-text); }
    .todo-prio-hoch { background-color: var(--lumen-gefahr-flaeche); color: var(--lumen-gefahr-text); }
    /* Die vier Dunkelmodus-Zeilen von hier sind entfallen: die
       Statustokens tragen ihre dunkle Fassung selbst (siehe den
       [data-bs-theme="dark"]-Block weiter unten). Sie hier ein zweites
       Mal zu setzen waere genau die Doppelpflege, die der Baukasten
       beseitigt. */
    /* To-do-Karte auf dem Board: die Beschreibung darf hoechstens zwei
       Zeilen einnehmen. Eine Karte, die eine halbe Seite Text ausbreitet,
       macht die Spalte unlesbar - gekuerzt wird zusaetzlich bereits
       serverseitig (truncatechars). */
    .todo-karte-text {
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .todo-karte-zeitstempel { opacity: .75; font-size: .68rem; }
    /* Checkliste auf der Detailseite: die gezogene Zeile tritt zurueck,
       damit die Luecke sichtbar ist, in die sie faellt. */
    .todo-schritt-griff { cursor: grab; }
    .todo-schritt-zieht { opacity: .4; }
    /* Gestaltungsflaeche der Editoren (static/js/editor/canvas.js,
       Feedback v0.4.0 §7, verallgemeinert in v0.4.2/AP-2). Die Flaeche
       traegt einen eigenen Grund: ohne ihn ist bei einem weissen Blatt
       auf weissem Grund nicht zu sehen, wo das Papier aufhoert.

       Die Namen heissen seit AP-2 .lumen-editor-*, weil dieselben Regeln
       jetzt Trauerdruck UND Formulargenerator bedienen. Die alten
       .trauerdruck-*-Namen standen uebergangsweise als Alias daneben,
       solange der Trauerdruck-Editor noch auf sie zeigte; mit AP-3 sind
       sie entfallen (siehe weiter unten). */
    .lumen-editor-buehne { overflow: auto; padding: .5rem; background: rgba(0,0,0,.03); border-radius: .5rem; }
    .lumen-editor-flaeche {
      position: relative; margin: 0 auto; background-color: #fff;
      background-size: cover; background-position: center;
      box-shadow: 0 .3rem 1rem rgba(31,35,41,.18);
      touch-action: none; /* sonst scrollt das Ziehen die Seite */
    }
    .lumen-editor-element { position: absolute; cursor: move; outline: 1px dashed rgba(31,35,41,.25); }
    .lumen-editor-element.gewaehlt { outline: 2px solid var(--lumen-primary); }
    .lumen-editor-element .lumen-editor-text { width: 100%; height: 100%; overflow: visible; white-space: pre-wrap; }
    .lumen-editor-element .lumen-editor-bild { width: 100%; height: 100%; background-size: cover; background-position: center; }

    /* Auswahlrahmen mit den acht Griffen und dem Drehgriff. Der Rahmen
       selbst faengt keine Zeigerereignisse (sonst waere das Element unter
       ihm nicht mehr anklickbar) - nur die Griffe tun es. */
    .lumen-editor-rahmen {
      position: absolute; pointer-events: none; z-index: 5;
      outline: 1px solid var(--lumen-primary);
    }
    /* TREFFERFLAECHE 16x16 px und vollstaendig AUSSERHALB des Rahmens.
       Bis v0.4.1 sass der einzige Griff mit right:-5px;bottom:-5px zur
       Haelfte AUF dem Element: jeder Griff in Eckennaehe landete auf dem
       Griff statt auf dem Element, und das Element liess sich dort nicht
       mehr verschieben. Die sichtbare Marke ist kleiner als die
       Trefferflaeche (::after) und sitzt an deren innerer Ecke, damit sie
       optisch am Rahmen klebt, die Flaeche zum Treffen aber gross bleibt. */
    .lumen-editor-griff, .lumen-editor-drehgriff {
      position: absolute; width: 16px; height: 16px; pointer-events: auto;
      display: block;
    }
    .lumen-editor-griff::after, .lumen-editor-drehgriff::after {
      content: ""; position: absolute; width: 9px; height: 9px;
      background: var(--lumen-primary); border: 1px solid #fff; border-radius: 2px;
      box-shadow: 0 0 0 1px rgba(31,35,41,.25);
    }
    .lumen-editor-griff-nw { left: -16px; top: -16px; cursor: nwse-resize; }
    .lumen-editor-griff-nw::after { right: 0; bottom: 0; }
    .lumen-editor-griff-ne { right: -16px; top: -16px; cursor: nesw-resize; }
    .lumen-editor-griff-ne::after { left: 0; bottom: 0; }
    .lumen-editor-griff-se { right: -16px; bottom: -16px; cursor: nwse-resize; }
    .lumen-editor-griff-se::after { left: 0; top: 0; }
    .lumen-editor-griff-sw { left: -16px; bottom: -16px; cursor: nesw-resize; }
    .lumen-editor-griff-sw::after { right: 0; top: 0; }
    .lumen-editor-griff-n { top: -16px; left: 50%; margin-left: -8px; cursor: ns-resize; }
    .lumen-editor-griff-n::after { bottom: 0; left: 3px; }
    .lumen-editor-griff-s { bottom: -16px; left: 50%; margin-left: -8px; cursor: ns-resize; }
    .lumen-editor-griff-s::after { top: 0; left: 3px; }
    .lumen-editor-griff-w { left: -16px; top: 50%; margin-top: -8px; cursor: ew-resize; }
    .lumen-editor-griff-w::after { right: 0; top: 3px; }
    .lumen-editor-griff-e { right: -16px; top: 50%; margin-top: -8px; cursor: ew-resize; }
    .lumen-editor-griff-e::after { left: 0; top: 3px; }
    /* Der Drehgriff sitzt bewusst deutlich abgesetzt ueber der Oberkante:
       ein Drehgriff, der wie ein Groessengriff aussieht und daneben liegt,
       wird verwechselt - und das Verwechseln von Drehen und Skalieren war
       genau der gemeldete Fehler.

       DER ABSTAND STEHT ALS VARIABLE, WEIL IHN DREI REGELN UND EINE
       MESSUNG BRAUCHEN (v0.6.10, Befund B7): die Ruhelage hier, die
       geklappte Lage darunter - und static/js/editor/canvas.js, das ihn
       aus der berechneten Formatvorlage LIEST, um zu entscheiden, ob er
       ueber dem Element ueberhaupt noch Platz hat. Am oberen Blattrand
       hatte er keinen und war dort nicht anklickbar; die Begruendung der
       drei Lagen steht bei drehgriffLegen() in jener Datei. */
    .lumen-editor-drehgriff {
      --lumen-drehgriff-abstand: 40px;
      top: calc(-1 * var(--lumen-drehgriff-abstand));
      left: 50%; margin-left: -8px; cursor: grab;
    }
    /* Geklappt. Beide Regeln stehen NACH der Ruhelage, weil sie dieselbe
       Spezifitaet haben und sonst nicht gewaennen. */
    .lumen-editor-drehgriff-unten {
      top: auto; bottom: calc(-1 * var(--lumen-drehgriff-abstand));
    }
    /* Nach INNEN nur, wenn weder oben noch unten Platz ist. Der Wert
       liegt unter der Trefferflaeche des n-Griffs (der endet an der
       Oberkante), damit sich beide nicht ueberlagern - zwei Griffe
       uebereinander waeren genau die Verwechslung, die der Abstand oben
       vermeiden soll. */
    .lumen-editor-drehgriff-innen { top: 22px; }
    .lumen-editor-drehgriff::after {
      left: 3px; top: 3px; border-radius: 50%;
      background: var(--lumen-surface); border: 2px solid var(--lumen-primary);
    }
    /* Fanglinien und Aufziehrahmen. Beide sind reine Anzeige und duerfen
       nie einen Klick abfangen. */
    .lumen-editor-fanglinie { position: absolute; z-index: 6; pointer-events: none; background: #E0115F; }
    .lumen-editor-fanglinie-x { top: 0; bottom: 0; width: 1px; }
    .lumen-editor-fanglinie-y { left: 0; right: 0; height: 1px; }
    .lumen-editor-aufzieh {
      position: absolute; z-index: 6; pointer-events: none;
      border: 1px dashed var(--lumen-primary); background: rgba(182,255,46,.12);
    }

    /* Die Alias-Regeln auf die alten .trauerdruck-*-Namen der Gestaltungs-
       flaeche sind mit AP-3 entfallen: der Trauerdruck-Editor montiert
       seither auf der gemeinsamen Engine und benutzt .lumen-editor-*.
       Geblieben ist nur die Bildauswahl - sie gehoert zur Bibliotheks-
       palette und nicht zur Flaeche, hat also nie ein Gegenstueck unter
       den Editor-Namen gehabt.

       Der frueher hier stehende .trauerdruck-griff ist ausdruecklich NICHT
       nach .lumen-editor-griff uebernommen worden: er sass mit
       right:-5px/bottom:-5px auf dem Element und fing damit jeden Griff in
       Eckennaehe ab, statt zu verschieben - eine der vier Ursachen des
       gemeldeten Move/Resize-Fehlers. */
    .trauerdruck-bildauswahl {
      display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr));
      gap: .4rem; max-height: 18rem; overflow-y: auto;
    }
    .trauerdruck-bildkachel {
      padding: 0; border: 1px solid var(--lumen-line); border-radius: .35rem;
      background: none; overflow: hidden; aspect-ratio: 1;
    }
    .trauerdruck-bildkachel:hover { border-color: var(--lumen-primary); }
    .trauerdruck-bildkachel img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .lumen-mehrfachauswahl { position: relative; }
    .lumen-mehrfachauswahl-treffer {
      position: absolute; left: 0; right: 0; z-index: 1080;
      max-height: 14rem; overflow-y: auto;
      box-shadow: 0 .5rem 1rem rgba(31,35,41,.12);
    }
    .lumen-tab-zaehler {
      background-color: rgba(0,0,0,.07);
      color: var(--lumen-muted);
      font-size: .7rem; font-weight: 600;
      padding: .18em .5em; line-height: 1.2;
    }
    .lumen-falltabs .nav-link.active .lumen-tab-zaehler {
      background-color: var(--lumen-primary); color: var(--lumen-on-primary);
    }
    .tab-pane.fade {
      transition: opacity .14s ease, transform .14s ease;
      transform: translateY(4px);
    }
    .tab-pane.fade.show { transform: translateY(0); }
    /* NUR die Deckkraft, KEIN transform (Befund vom 27.08.: "Es oeffnet
       sich kurz versetzt und dann ist es an der korrekten Position").

       Bootstrap positioniert jedes Dropdown ueber Popper, und Popper
       schreibt das Ergebnis als inline "transform: translate3d(x, y, 0)"
       an das Menue. Eine Animation, die transform anfasst, gewinnt
       gegen ein Inline-Style - fuer die Dauer der Animation stand das
       Menue also an seinem statischen Platz statt am Aufklappknopf und
       sprang erst danach dorthin. Kein Zufall und keine Wackelei der
       Maschine, sondern eine Zeile, die genau das anweist.

       Wer hier eine Bewegung will, nimmt eine Eigenschaft, die Popper
       nicht benutzt (opacity, clip-path, filter) - transform gehoert
       ihm. */
    .dropdown-menu.show { animation: lumen-dropdown-in .1s ease; }
    @keyframes lumen-dropdown-in {
      from { opacity: 0; }
      to { opacity: 1; }
    }
    @media (prefers-reduced-motion: reduce) {
      /* #nav-primary-links stand hier bis v0.4.1 mit drin - das Element
         gibt es in der Topbar seit dem Umbau auf die Seitenleiste nicht
         mehr. Eine Regel fuer ein nicht existierendes Element sieht beim
         naechsten Lesen aus wie eine Zusicherung, die es nicht gibt. */
      #search-expand, #search-toggle-btn, .tab-pane.fade, .dropdown-menu.show {
        transition: none !important; animation: none !important;
      }
    }

    /* Fall-Chat: @Erwaehnungen im Eingabefeld farblich mit der
       Kalenderfarbe des erwaehnten Mitarbeiters markieren (siehe
       Feedback: "sollte die auch farblich... mit seiner Hintergrundfarbe
       beim Kalender markiert werden") - ein <textarea> kann keine
       Inline-Farben rendern, daher liegt ein unsichtbares Highlight-Div
       exakt deckungsgleich (position:absolute, inset:0) darunter; das
       Textarea selbst bleibt mit transparentem Text/Hintergrund oben
       (Karet bleibt sichtbar), sichtbarer Text kommt vollstaendig aus
       dem Div. Bewusst NICHT per CSS-Grid ueberlagert (frueherer Ansatz):
       dort bestimmte der (unbegrenzt wachsende) Inhalt beider Elemente
       gemeinsam die Zeilenhoehe, wodurch sich die Box bei jedem Tippen
       staendig vergroesserte (siehe Feedback: "ich muss das immer
       manuell wieder kleinziehen") und Text neben dem Cursor leicht
       versetzt erschien. Mit position:absolute bestimmt einzig die
       Textarea (normaler Fluss) die Hoehe des Wrappers, das Highlight-
       Div liegt garantiert deckungsgleich darueber. */
    .fall-chat-input-wrap { position: relative; flex: 1 1 auto; }
    .fall-chat-highlight {
      position: absolute; inset: 0; margin: 0; overflow: hidden; pointer-events: none;
      white-space: pre-wrap; word-wrap: break-word; background: transparent !important;
      border-color: transparent !important; box-shadow: none !important; color: var(--lumen-ink);
    }
    .fall-chat-textarea,
    .fall-chat-textarea:focus {
      position: relative; background: transparent !important; color: transparent !important;
      caret-color: var(--lumen-ink);
      /* Textareas haben browserseitig standardmaessig einen Resize-Griff
         (CSS resize: vertical/both) - einmal groesser gezogen, bleibt das
         Feld dauerhaft so gross, bis man es manuell wieder verkleinert
         (siehe Feedback: "ich muss ihn immer kleiner ziehen"). Da dieses
         Feld bewusst kompakt bleiben soll (laengere Historie scrollt statt
         das Eingabefeld selbst zu vergroessern), wird der Griff hier ganz
         deaktiviert statt nur das Auto-Wachstum beim Tippen zu verhindern. */
      resize: none;
    }
    .fall-chat-mention { border-radius: .2rem; padding: 0 .15rem; font-weight: 600; }
    [data-bs-theme="dark"] .fall-chat-highlight { color: #e9ecef; }
    [data-bs-theme="dark"] .fall-chat-textarea { caret-color: #e9ecef; }

    /* FullCalendar ins Design-System einbinden statt Standard-Look */
    .fc {
      --fc-button-bg-color: var(--lumen-primary);
      --fc-button-border-color: var(--lumen-primary);
      /* Ohne diese Zeile setzt FullCalendar weissen Buttontext - auf der
         hellen Limette unlesbar. */
      --fc-button-text-color: var(--lumen-on-primary);
      --fc-button-hover-bg-color: var(--lumen-primary);
      --fc-button-hover-border-color: var(--lumen-primary);
      --fc-button-active-bg-color: var(--lumen-primary);
      --fc-button-active-border-color: var(--lumen-primary);
      /* Der heutige Tag traegt die Systemfarbe, nicht mehr fest Limette:
         mit Waldgruen als Auslieferungsfarbe waere ein limettener Streifen
         der einzige Rest der alten Palette im ganzen Kalender. */
      --fc-today-bg-color: color-mix(in srgb, var(--lumen-primary) 12%, transparent);
      --fc-border-color: var(--lumen-line);
      font-size: .85rem;
    }
    .fc .fc-button { padding: .3rem .65rem; font-size: .8rem; box-shadow: none !important; }
    .fc .fc-button:hover { filter: brightness(0.92); }
    .fc .fc-button:disabled { opacity: .45; cursor: not-allowed; filter: none; }
    .fc .fc-button:focus { box-shadow: 0 0 0 .2rem rgba(0, 0, 0, .1) !important; }
    .fc .fc-button-primary:not(:disabled).fc-button-active {
      box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .25) !important;
    }
    .fc .fc-toolbar-title { font-size: 1.15rem; }
    .fc .fc-toolbar.fc-header-toolbar { margin-bottom: .75rem; }
    .fc .fc-col-header-cell-cushion, .fc .fc-daygrid-day-number { padding: 3px 6px; }
    .fc-event { cursor: pointer; }
    .fc-event.termin-abgesagt { opacity: .55; text-decoration: line-through; }
    /* Termine mit 2-4 zugewiesenen Mitarbeitern: der Punkt in der
       Monatsansicht wird von einem duennen Ring zu einem kleinen
       gefuellten Quadrat, damit das per JS gesetzte Streifenmuster
       (siehe calendar.js) ueberhaupt sichtbar ist. */
    .fc-event.termin-gestreift .fc-daygrid-event-dot {
      width: 12px; height: 12px; border-radius: 3px; border-width: 0;
    }
    /* eventDisplay:"block" (siehe calendar.js) macht jeden Termin in der
       Monatsansicht zu einem vollflaechig eingefaerbten Balken statt eines
       kleinen Punkts mit Text daneben - Schriftgroesse/Innenabstand leicht
       angepasst, damit mehrere Termine pro Tag nicht zu gedraengt wirken
       (siehe Feedback: "Farben schlecht erkennbar in der Monatsansicht"). */
    .fc-daygrid-event { font-size: .76rem; padding: 1px 4px; font-weight: 500; }
    /* KERN der Rueckmeldung "Monatsansicht: Uhrzeit nicht korrekt lesbar"
       (zweimal gemeldet).

       FullCalendar baut den Terminbalken der Monatsansicht als Flexzeile:
       .fc-event-main-frame{flex-direction:row;overflow:hidden} mit
       .fc-event-time{max-width:100%;overflow:hidden} - also OHNE
       flex-shrink:0 - und daneben .fc-event-title-container{flex-grow:1;
       flex-shrink:1;min-width:0}. Beide Kinder duerfen schrumpfen; wer
       mehr Platz verlangt, drueckt den anderen weg.

       Die frueher gegen abgeschnittene TITEL eingefuehrte Regel (Titel
       ueber zwei Zeilen, siehe unten) hat genau das getan: der Titel
       beanspruchte Breite, und weggeschnitten wurde stattdessen die
       Uhrzeit. Der Mangel war damit nicht behoben, sondern verschoben -
       deshalb kam er ein zweites Mal zurueck. In der Zeitachsen-Ansicht
       tritt er nicht auf, dort setzt FullCalendar selbst
       .fc-timegrid-event .fc-event-time{flex-grow:0;flex-shrink:0}.

       Die Uhrzeit ist die kuerzeste und am staerksten normierte Angabe im
       Balken (immer fuenf Zeichen, siehe eventTimeFormat in calendar.js) -
       sie bekommt ihren Platz zuerst, der Titel den Rest. */
    .fc-daygrid-event .fc-event-time {
      flex-shrink: 0;
      white-space: nowrap;
      overflow: visible;
    }
    /* Titel in der Monatsansicht: eine Zeile mit Auslassungspunkten.

       Der zweizeilige Umbruch weiter unten war fuer schmale Tagesspalten
       gedacht, ist dort aber die Ursache des Gedraenges - zwei Zeilen
       Titel neben einer einzeiligen Uhrzeit lassen die Zeile hoeher
       werden und die Uhrzeit zusammenschrumpfen. Bewusste Ruecknahme fuer
       den Monat: ein zu langer Betreff wird hier wieder gekuerzt, dafuer
       sauber am Wortende mit "..." statt hart mitten im Wort, und der
       vollstaendige Betreff steht im Tooltip (siehe calendar.js
       eventDidMount). Eine unlesbare Uhrzeit ist der schwerere Mangel:
       ein gekuerzter Betreff bleibt erkennbar, eine halbe Uhrzeit ist
       schlicht falsch. */
    .fc-daygrid-event .fc-event-title {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      display: block;
      line-height: 1.2;
    }
    /* In der Wochen-/Tagesansicht bleibt der zweizeilige Titel: dort ist
       der Terminkasten hoch statt breit, die Uhrzeit steht in einer
       eigenen Zeile darueber und kann durch den Titel gar nicht
       verdraengt werden (siehe Feedback: "kann man nicht so gut die
       Termine im Kalender... sehen... leicht abgeschnitten"). */
    .fc-timegrid-event .fc-event-title {
      white-space: normal;
      overflow: hidden;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      line-height: 1.2;
    }
    /* Ganztagestermine sollen sich nicht nur durch das fehlende
       Uhrzeit-Praefix von Terminen mit Uhrzeit unterscheiden (siehe
       Feedback: "Ganztagestermine klar unterscheidbar") - die Klasse
       kommt aus dem Kalender-Feed (events/views.py).

       Mit eventDisplay:"block" sieht ein Ganztagestermin sonst exakt aus
       wie ein Termin mit Uhrzeit, nur ohne die fuenf Zeichen davor - das
       faellt nur auf, wenn beide Sorten direkt untereinander stehen.
       Breite helle Kante links plus Kursivsatz kosten keine Textbreite
       und wirken auch bei gleicher Mitarbeiterfarbe.

       Bewusst nicht in der Listenansicht (Mini-Kalender der Sterbefall-
       Uebersicht): dort schreibt FullCalendar in der Zeitspalte ohnehin
       "Ganztägig" aus, eine zusaetzliche Kante an der Tabellenzeile waere
       nur Zierrat. */
    .fc-daygrid-event.termin-ganztaegig,
    .fc-timegrid-event.termin-ganztaegig {
      border-left: 4px solid rgba(255, 255, 255, .75);
      font-style: italic;
    }
    /* Zusaetzlich das Wort selbst - aber nur, wo die Tagesspalte breit
       genug ist. Bei einer Monatsspalte von rund 150 px (1280 px
       Fensterbreite) waeren "Ganztägig · " schon die halbe Zeile und
       wuerden den Betreff auffressen; unterhalb dieser Grenze traegt die
       Kante allein, und der volle Wortlaut steht im Tooltip (siehe
       calendar.js eventDidMount). Genau der Fall aus Punkt 4 der
       Rueckmeldung: schmale Spalten mitpruefen. */
    @media (min-width: 1400px) {
      .fc-daygrid-event.termin-ganztaegig .fc-event-title::before {
        content: "Ganztägig · ";
        font-style: normal;
        font-weight: 700;
        opacity: .85;
      }
    }
    /* "+n weitere" (dayMaxEvents in calendar.js) ist ein Bedienelement und
       kein Termin - deutlich genug, um nicht uebersehen zu werden, aber
       ohne Terminfarbe, damit es nicht wie ein weiterer Termin aussieht. */
    .fc-daygrid-more-link {
      font-size: .72rem;
      font-weight: 600;
      color: var(--lumen-ink-600);
      padding: 1px 4px;
    }
    .fc-daygrid-day-frame { min-height: 5.5rem; }
    .fc-timegrid-event .fc-event-main { padding: 1px 3px; }
    /* Uhrzeiten in der Zeitachse (Wochen-/Tagesansicht, Dashboard-
       Wochenausschnitt) waren mit FullCalendars Standard-Blassgrau kaum
       lesbar (siehe Feedback: "ich kann die Uhrzeit nicht lesen") -
       kraeftigere Textfarbe + etwas groesser/fetter. */
    .fc-timegrid-slot-label-cushion {
      color: var(--lumen-ink-600);
      font-size: .8rem;
      font-weight: 600;
    }
    [data-bs-theme="dark"] .fc-timegrid-slot-label-cushion { color: #ced4da; }
    .mitarbeiter-option { cursor: pointer; }
    .mitarbeiter-option:hover { background-color: rgba(0, 0, 0, .04); }
    .mitarbeiter-option .form-check-label { cursor: pointer; }
    .datetime-pair input[type="date"] { flex: 1.3 1 0; min-width: 0; }
    .datetime-pair input[type="time"] { flex: 1 1 0; min-width: 0; }

    #termine-karussell { scroll-behavior: smooth; scrollbar-width: none; }
    #termine-karussell::-webkit-scrollbar { display: none; }

    /* Stammdaten-Reiter (siehe directory/_stammdaten_tabs.html): nur
       horizontal scrollbar (bei vielen Kategorien), kein vertikaler
       Scrollbalken - "overflow: auto" auf beiden Achsen erzeugte vorher
       durch minimale Rundungsdifferenzen einen kaum sichtbaren, aber
       hässlichen vertikalen Scrollbalken (siehe Feedback: "ich kann hier
       drin rumstrholen... das muss weg, weil das sieht schlimm aus"). */
    .stammdaten-tabs { overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
    .stammdaten-tabs::-webkit-scrollbar { height: 4px; }

    /* Kanban-Board fuer aktive Sterbefaelle (siehe cases/sterbefall_
       kanban.html + static/js/sterbefall-kanban.js; Feedback: "die
       Sterbefaelle, die nur aktiv sind, hin- und herschieben... Neu ist
       halt noch am Tatort... in Bearbeitung ist, sobald er 'n Transfer
       ist"). */
    .kanban-board { display: flex; gap: 1rem; overflow-x: auto; padding-bottom: .5rem; align-items: flex-start; }
    .kanban-column { flex: 0 0 260px; background-color: rgba(0,0,0,.025); border-radius: .6rem; padding: .6rem; }
    .kanban-column-header { font-weight: 600; margin-bottom: .5rem; display: flex; align-items: center; gap: .4rem; font-size: .9rem; }
    .kanban-column-body { min-height: 60px; display: flex; flex-direction: column; gap: .5rem; transition: background-color .12s ease; border-radius: .4rem; }
    .kanban-column-body.kanban-dragover { background-color: rgba(0,0,0,.05); outline: 2px dashed rgba(0,0,0,.15); }
    .kanban-column-empty { padding: .5rem .25rem; }
    .kanban-card {
      background-color: var(--lumen-surface); border: 1px solid var(--lumen-line); border-radius: .5rem;
      padding: .55rem .65rem; cursor: grab; box-shadow: 0 1px 2px rgba(0,0,0,.03);
      transition: box-shadow .12s ease, transform .12s ease;
    }
    .kanban-card:hover { box-shadow: 0 .3rem .7rem rgba(0,0,0,.1); transform: translateY(-1px); }
    .kanban-card.kanban-dragging { opacity: .4; }
    .kanban-card-title { font-weight: 600; font-size: .88rem; }
    .kanban-card-meta { font-size: .74rem; color: var(--lumen-muted); }
    .kanban-context-menu { display: none; position: fixed; z-index: 1100; min-width: 220px; }
    [data-bs-theme="dark"] .kanban-column { background-color: rgba(255,255,255,.04); }
    [data-bs-theme="dark"] .kanban-card { background-color: var(--lumen-surface); border-color: var(--lumen-line); }
    [data-bs-theme="dark"] .kanban-column-body.kanban-dragover { background-color: rgba(255,255,255,.06); outline-color: rgba(255,255,255,.2); }

    /* Termine-Timeline auf der Sterbefall-Uebersicht: horizontal
       scrollbare Punkte-mit-Verbindungslinie-Darstellung (wie ein
       Ablauf-Stepper, nur je Punkt ein tatsaechlicher Termin statt
       fixer Phasen) - Punktfarbe kommt aus Termin.farben_liste bzw.
       Termin.farbe (siehe common_extras.stripe_gradient). Breite als
       Prozentsatz des Karussells (nicht fix in px) - dadurch sind auf
       einer normal breiten Fallseite ca. 5 Termine gleichzeitig sichtbar
       statt der vorher gedrängten ~10, min-width sorgt fuer horizontales
       Scrollen auf schmaleren Bildschirmen statt Umbruch. */
    .termine-timeline-item {
      flex: 0 0 20%; min-width: 170px; text-align: center; position: relative;
      padding-top: 2px; cursor: pointer;
    }
    .termine-timeline-item:not(:last-child)::after {
      content: ""; position: absolute; top: 15px; left: 50%; width: 100%; height: 2px;
      background: rgba(0, 0, 0, .12); z-index: 0;
    }
    .termine-timeline-item .dot {
      width: 26px; height: 26px; border-radius: 50%; display: inline-block;
      border: 2px solid rgba(0, 0, 0, .15); position: relative; z-index: 1;
    }
    /* Betreff bewusst umbrechen statt (wie vorher per Bootstrap
       "text-truncate") einzeilig mit "..." abzuschneiden - bei mehreren
       nebeneinander liegenden Terminen war so kaum noch zu erkennen, wo
       ein Betreff endet und der naechste beginnt (siehe Feedback: "das
       wichtig, das dort ein Zeilenumbruch reinkommt, damit man den
       Betreff sieht"). Ein zu langer Betreff darf dabei ruhig ueber
       mehrere Zeilen laufen. */
    .termine-timeline-item .label {
      margin-top: .4rem; font-size: .8rem; font-weight: 600;
      white-space: normal; overflow-wrap: break-word;
    }
    .termine-timeline-item .date { font-size: .72rem; color: var(--lumen-muted); }
    /* Status-Badge zusaetzlich zur (i.d.R. mitarbeiterbasierten) Punktfarbe
       - macht den Terminstatus (bestaetigt/abgesagt/geplant) auch bei
       gleicher Mitarbeiterfarbe auf einen Blick unterscheidbar. */
    .termine-timeline-item .status-badge { margin-top: .3rem; font-size: .65rem; }
    /* Bereits vergangene Termine (per JS anhand data-termin-start markiert,
       siehe cases/sterbefall_detail.html) abgedunkelt darstellen, damit auf
       einen Blick erkennbar ist, was schon erledigt/vorbei ist. */
    .termine-timeline-item.vergangen { opacity: .45; }
    [data-bs-theme="dark"] .termine-timeline-item:not(:last-child)::after { background: rgba(255, 255, 255, .15); }

    /* Zeitleiste der Einwilligungserklaerung (Feedback v0.4.4 §2, E24):
       die SENKRECHTE Fassung der .termine-timeline-item darueber -
       dieselbe Bildsprache (Punkt mit Verbindungslinie), nur gedreht.
       Gedreht werden muss sie, weil §2 "aktuellster Eintrag immer oben"
       verlangt: eine waagerechte Leiste hat kein Oben.

       Die Einrueckung der Liste ist zugleich die zweite Ebene des
       "baumartigen" Aufbaus: die Aeste sind die Aufklapp-Bereiche je
       Dokument (Bootstrap-Accordion), die Blaetter diese Punkte. */
    .einwilligung-timeline { list-style: none; margin: 0; padding: 0; }
    .einwilligung-timeline-item { position: relative; padding: 0 0 1rem 1.75rem; }
    .einwilligung-timeline-item:not(:last-child)::after {
      content: ""; position: absolute; left: 7px; top: 20px; bottom: 0; width: 2px;
      background: rgba(0, 0, 0, .12);
    }
    .einwilligung-timeline-item .dot {
      position: absolute; left: 0; top: 4px; width: 16px; height: 16px;
      border-radius: 50%; border: 2px solid rgba(0, 0, 0, .15);
      background: var(--lumen-surface);
    }
    /* Der oberste Punkt ist der aktuelle Stand des Vorgangs - er traegt
       als einziger Fuellung, damit beim Aufklappen sofort sichtbar ist,
       wo die Erklaerung gerade steht. */
    .einwilligung-timeline-item.aktuell .dot { background: var(--lumen-accent); }
    .einwilligung-timeline-item .kopf { font-size: .85rem; font-weight: 600; }
    .einwilligung-timeline-item .meta { font-size: .75rem; color: var(--lumen-muted); }
    [data-bs-theme="dark"] .einwilligung-timeline-item:not(:last-child)::after { background: rgba(255, 255, 255, .15); }

    /* ------------------------------------------------------------------
       Seitenkopf: einheitliche Kopfzeile (Titel + Aktion) fuer alle
       Listen-/Verwaltungsseiten - ersetzt die bisher je Seite von Hand
       zusammengesetzten d-flex-justify-content-between-Bloecke, die
       untereinander leicht unterschiedliche Abstaende hatten.
       ------------------------------------------------------------------ */
    .seiten-kopf {
      display: flex; flex-wrap: wrap; gap: .75rem 1rem;
      justify-content: space-between; align-items: flex-start; margin-bottom: 1.25rem;
    }

    /* ------------------------------------------------------------------
       Leerzustaende: eine einzige Darstellung fuer "hier ist gerade
       nichts" - egal ob leere Liste, kein Suchtreffer oder eine gar nicht
       vorhandene Seite (siehe templates/404.html). Vorher war jede leere
       Flaeche anders gestaltet oder schlicht leer.
       ------------------------------------------------------------------ */
    .leerzustand {
      display: flex; flex-direction: column; align-items: center; text-align: center;
      gap: .5rem; padding: 2.5rem 1.25rem; color: var(--lumen-muted);
    }
    .leerzustand--seite {
      background-color: var(--lumen-surface); border: 1px solid var(--lumen-line);
      border-radius: .75rem; padding: 4rem 1.5rem; max-width: 640px; margin: 2rem auto;
    }
    .leerzustand-symbol {
      font-size: 2rem; line-height: 1; color: var(--lumen-primary-text);
      background-color: color-mix(in srgb, var(--lumen-primary) 12%, transparent);
      width: 4rem; height: 4rem; border-radius: 50%;
      display: flex; align-items: center; justify-content: center; margin-bottom: .5rem;
    }
    .leerzustand-titel { font-size: 1.15rem; font-weight: 600; color: var(--lumen-ink); margin: 0; }
    [data-bs-theme="dark"] .leerzustand-titel { color: #E6E9ED; }
    .leerzustand-text { margin: 0; max-width: 46ch; }
    .leerzustand-aktionen { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin-top: .75rem; }
    .leerzustand-hinweis { font-size: .82rem; margin: .75rem 0 0; }
    /* Kompakte Variante fuer Leerzustaende INNERHALB einer Karte, eines
       Reiters oder einer Tabelle - dort ist der Rahmen schon gesetzt, ein
       zweiter grosser Weissraum darin wirkt wie ein Layoutfehler. */
    .leerzustand--kompakt { padding: 1.5rem 1rem; gap: .35rem; }
    .leerzustand--kompakt .leerzustand-symbol {
      font-size: 1.25rem; width: 2.5rem; height: 2.5rem; margin-bottom: .25rem;
    }
    .leerzustand--kompakt .leerzustand-titel { font-size: .95rem; }
    .leerzustand--kompakt .leerzustand-text { font-size: .85rem; }
    /* Die Zelle traegt in einer Tabelle sonst die Zellenraender der
       Nachbarzeilen mit - der Leerzustand soll aber als eine ruhige
       Flaeche wirken, nicht als Datenzeile. */
    .leerzustand-zeile td { padding: 0 !important; border-bottom: 0 !important; background: transparent; }

    /* ------------------------------------------------------------------
       Ladezustand (Feedback v0.2.2 §11: "Ladezustände und Fehlerbehandlung
       vereinheitlichen"). Eine Liste, die gerade nachgeladen wird, wird
       gedimmt und nimmt keine Klicks an, statt entweder unveraendert
       stehenzubleiben (der Nutzer haelt sie fuer aktuell) oder ganz zu
       verschwinden (die Seite springt). Genutzt von der Bibliothekssuche
       und allen weiteren Live-Listen - eine Klasse, ein Verhalten.
       ------------------------------------------------------------------ */
    .ist-ladend { opacity: .45; pointer-events: none; transition: opacity .12s ease; }
    @media (prefers-reduced-motion: reduce) { .ist-ladend { transition: none; } }
    /* Fehlerhinweis einer Live-Liste - bewusst ruhig und an Ort und
       Stelle statt als Fehlerseite: ein fehlgeschlagener Nachladeversuch
       ist kein Grund, die Arbeit des Nutzers zu unterbrechen. */
    .lade-fehler {
      display: flex; align-items: center; gap: .5rem; justify-content: center;
      padding: 1rem; color: var(--lumen-muted); font-size: .88rem;
    }

    /* Fehlgeschlagene SCHREIBENDE Aktion (siehe Lumen.aktionFehler in
       static/js/lade-hilfe.js). Anders als beim Nachladen einer Liste darf
       das nicht ruhig im Seitenfluss stehen: der Nutzer glaubt, gespeichert
       zu haben, und arbeitet weiter. Der z-index liegt bewusst ueber dem
       Bootstrap-Modal (1055) - mehrere der betroffenen Aktionen laufen
       innerhalb eines offenen Modals ab und waeren sonst verdeckt. */
    .lumen-aktions-meldung {
      position: fixed; z-index: 2000; top: 1rem; left: 50%;
      transform: translateX(-50%); max-width: min(34rem, calc(100vw - 2rem));
      margin: 0; font-size: .9rem;
    }

    /* ------------------------------------------------------------------
       Moduleseite: 60 Schalter (siehe common/modules.py) brauchen eine
       ruhige, gut scanbare Zeile mit sichtbarer Hierarchie.
       ------------------------------------------------------------------ */
    /* Seit v0.4.1 (Feedback §14) ist der Aufklapper kein Kartenkopf mehr,
       sondern ein kleiner Pfeil-Knopf IN der Zeile des Hauptmoduls - der
       Ein-/Aus-Schalter des Hauptmoduls sitzt in derselben Zeile und darf
       nicht mit dem Auf-/Zuklappen zusammenfallen (ein Kartenkopf, der
       beides tut, waere genau die Falle). Die Klassennamen bleiben, weil
       static/js/modul-filter.js sie kennt. */
    .modul-gruppe-kopf { cursor: pointer; text-decoration: none; color: var(--lumen-muted); }
    .modul-gruppe-kopf:hover { color: var(--lumen-primary-text); }
    .modul-gruppe-pfeil { display: inline-block; transition: transform .15s ease; }
    .modul-gruppe-kopf[aria-expanded="true"] .modul-gruppe-pfeil { transform: rotate(180deg); }
    .modul-zeile {
      display: flex; align-items: center; justify-content: space-between;
      gap: 1rem; padding: .7rem 1rem;
    }
    /* Das Hauptmodul traegt die Kartenkopf-Optik, die vorher der
       Gruppenkopf hatte - sonst saehe eine Karte ohne Unterfunktionen
       (Kalender, To-dos, Trauerdruck) aus wie eine verirrte Einzelzeile. */
    .modul-zeile--eltern { padding: .85rem 1rem; }
    .modul-zeile--eltern .modul-zeile-name { font-weight: 600; }
    .modul-gruppe:has(.collapse) .modul-zeile--eltern {
      border-bottom: 1px solid var(--lumen-line);
    }
    /* Untergeordnete Features werden eingerueckt und bekommen eine
       Fuehrungslinie - dadurch ist die Hierarchie sichtbar, ohne dass die
       Zeile mehr Platz braucht. */
    .modul-zeile--kind { padding-left: 2rem; border-left: 2px solid var(--lumen-line); margin-left: 1rem; }
    .modul-zeile-text { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
    .modul-zeile-name { font-weight: 500; }
    .modul-zeile-beschreibung { font-size: .8rem; color: var(--lumen-muted); }
    .modul-zeile-hinweis { font-size: .78rem; color: var(--lumen-primary-text); margin-top: .15rem; }

    /* ------------------------------------------------------------------
       Rollenverwaltung (Feedback v0.2.2 §2: "Auch raeumlich/visuell ist
       die Rollenverwaltung aktuell nicht ausgearbeitet. Komplett neu
       gestalten."): Karten statt Tabelle in der Liste, echte Matrix im
       Formular.
       ------------------------------------------------------------------ */
    .rollen-raster {
      display: grid; gap: 1rem;
      grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    }
    .rollen-karte .card-body { gap: .6rem; }
    .rollen-karte-notiz { font-size: .85rem; color: var(--lumen-muted); margin: 0; }
    .rollen-karte-profil { font-size: .8rem; color: var(--lumen-muted); display: flex; align-items: center; }
    /* Farbpunkte statt Text-Badges: das Kurzprofil soll die Karte nicht
       dominieren, sondern nur die Groessenordnung zeigen. */
    .rechte-punkt {
      display: inline-block; width: .55rem; height: .55rem; border-radius: 50%;
      margin-right: .3rem; flex-shrink: 0;
    }
    .rechte-punkt--voll { background-color: var(--lumen-primary); }
    /* Der Zwischenzustand traegt die Akzentfarbe der Instanz, nicht
       mehr ein festes Gold: nur so bleibt die Rechtematrix bei
       umgestellter Farbe lesbar (und drei Punkte in Primaer, Akzent und
       Grau sind ohnehin besser unterscheidbar als zwei Gruentoene). */
    .rechte-punkt--lesen { background-color: var(--lumen-accent); }
    .rechte-punkt--keine { background-color: var(--lumen-muted); }
    .rollen-chips { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .3rem; }
    .rollen-chip {
      font-size: .72rem; padding: .15rem .5rem; border-radius: 999px;
      border: 1px solid var(--lumen-line); color: var(--lumen-muted);
    }
    /* Die Stufe steckt im Klassennamen (voll/lesen/keine), damit die Karte
       ohne zweites Auslesen im Template farbig wird. */
    .rollen-chip--voll {
      border-color: color-mix(in srgb, var(--lumen-primary) 45%, transparent);
      background-color: color-mix(in srgb, var(--lumen-primary) 14%, transparent);
      color: var(--lumen-primary-text);
    }
    .rollen-chip--lesen { border-color: rgba(199, 160, 8, .5); background-color: rgba(199, 160, 8, .12); }
    .rollen-chip--keine { opacity: .6; text-decoration: line-through; }
    .rollen-karte-aktionen {
      display: flex; gap: .4rem; margin-top: auto; padding-top: .6rem;
      border-top: 1px solid var(--lumen-line);
    }

    /* Berechtigungsmatrix: 60 Zeilen x 5 Spalten. Ohne mitlaufenden
       Spaltenkopf waere nach dem ersten Scrollen nicht mehr erkennbar,
       welche Spalte welches Recht ist - genau die Unklarheit, die §2
       ("auf einen Blick verstaendlich") ausschliesst. Der Versatz von
       3.2rem ist die Hoehe der klebenden Topbar. */
    .matrix-kopf-werkzeuge { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
    .matrix-kopf-werkzeuge input[type="search"] { min-width: 200px; }
    /* Auf schmalen Schirmen sprengte die feste Mindestbreite von 200px
       zusammen mit dem Zaehler-Abzeichen die Kartenbreite - im Mobile-Test
       als 104px Ueberhang der GESAMTEN Seite nachgemessen. Das Suchfeld
       nimmt dort stattdessen die volle Zeile ein. */
    @media (max-width: 575.98px) {
      .matrix-kopf-werkzeuge { width: 100%; }
      .matrix-kopf-werkzeuge > .position-relative { flex: 1 1 100%; }
      .matrix-kopf-werkzeuge input[type="search"] { min-width: 0; width: 100%; }
    }

    /* Breite Diagramme scrollen in ihrem eigenen Kasten (siehe
       dashboard/index.html) - der Seitenkoerper darf nie waagerecht
       scrollen. */
    .diagramm-scroll { overflow-x: auto; overflow-y: hidden; scrollbar-width: thin; }
    .diagramm-scroll::-webkit-scrollbar { height: 4px; }
    .diagramm-balken { min-width: 34rem; }
    /* Kein overflow auf Desktop-Breite, sonst klebt der Spaltenkopf am
       (nicht scrollenden) Container statt am Fenster und steht faktisch
       still. Unterhalb von 992px ist die Matrix breiter als der Schirm -
       dort ist seitliches Scrollen wichtiger als der klebende Kopf. */
    .matrix-scroll { overflow-x: visible; }
    @media (max-width: 991.98px) {
      .matrix-scroll { overflow-x: auto; }
      .rechte-matrix { min-width: 40rem; }
    }
    .rechte-matrix { border-collapse: separate; border-spacing: 0; }
    .rechte-matrix thead th {
      position: sticky; top: 3.2rem; z-index: 2;
      background-color: var(--lumen-surface);
      border-bottom: 2px solid var(--lumen-line);
      vertical-align: bottom; white-space: nowrap;
    }
    .matrix-spalte-bereich { min-width: 16rem; width: 45%; }
    .matrix-spalte-recht { text-align: center; font-size: .78rem; }
    .matrix-spalte-label { display: block; font-weight: 500; }
    .rechte-matrix tbody th, .rechte-matrix tbody td { border-bottom: 1px solid var(--lumen-line); }
    /* Gruppenzeile klebt unter dem Spaltenkopf und muss deshalb DECKEND
       sein - mit halbtransparentem Ton wuerden die daruntergescrollten
       Zeilen durchscheinen. Deshalb der Farbton als Verlaufsflaeche ueber
       der deckenden Kartenfarbe statt als transparente Farbe. */
    .matrix-gruppe th, .matrix-gruppe td {
      background-color: var(--lumen-surface);
      background-image: linear-gradient(
        color-mix(in srgb, var(--lumen-primary) 9%, transparent),
        color-mix(in srgb, var(--lumen-primary) 9%, transparent)
      );
      position: sticky; top: 6.4rem; z-index: 1;
    }
    .matrix-gruppe-name { font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; }
    .matrix-bereich { font-weight: 400; }
    .matrix-bereich-name { font-weight: 500; }
    /* Einrueckung nach Registry-Ebene - dieselbe Hierarchie wie auf der
       Moduleseite, damit beide Seiten gleich gelesen werden. */
    .matrix-bereich--ebene1 { padding-left: 2rem !important; }
    .matrix-bereich--ebene1 .matrix-bereich-name { font-weight: 400; }
    .matrix-bereich-beschreibung, .matrix-bereich-hinweis {
      display: block; font-size: .75rem; color: var(--lumen-muted);
    }
    .matrix-bereich-hinweis { color: var(--lumen-primary-text); }
    .matrix-zelle { text-align: center; }
    .matrix-zelle .form-check-input { margin: 0; cursor: pointer; }
    .matrix-zeile:hover > * { background-color: rgba(0, 0, 0, .025); }
    [data-bs-theme="dark"] .matrix-zeile:hover > * { background-color: rgba(255, 255, 255, .04); }
    /* Gesperrte Zeile: sichtbar bleiben, aber klar als "hier ist nichts zu
       holen" lesbar - ausblenden waere schlechter, weil die Rolle sonst
       unvollstaendig wirkt. */
    .matrix-zeile--gesperrt > * { opacity: .5; }
    .matrix-alle {
      background: none; border: 0; padding: 0 .2rem; font-size: .7rem;
      color: var(--lumen-primary-text); text-decoration: underline; cursor: pointer;
    }
    .matrix-alle:hover { text-decoration: none; }
    .matrix-alle--zeile { margin-left: .4rem; opacity: 0; transition: opacity .12s ease; }
    /* Der Zeilenschalter erscheint erst beim Ueberfahren/Fokussieren -
       60 dauerhaft sichtbare "alle"-Links wuerden die Namensspalte
       unruhig machen. */
    .matrix-zeile:hover .matrix-alle--zeile,
    .matrix-alle--zeile:focus-visible { opacity: 1; }
    /* Aktionsleiste bleibt am unteren Rand stehen: nach 60 Zeilen ist der
       Speichern-Knopf sonst weit weg. */
    .rollen-form-aktionen {
      position: sticky; bottom: 0; z-index: 3;
      display: flex; justify-content: flex-end; gap: .5rem;
      padding: .75rem 0; background-color: var(--lumen-canvas);
      border-top: 1px solid var(--lumen-line);
    }

    /* ------------------------------------------------------------------
       Bibliothek: Kartenraster (siehe bibliothek/_eintrag_karten.html).
       Grid statt Bootstrap-Spalten, damit die Karten unabhaengig von ihrem
       Inhalt gleich hoch bleiben - ein Gedenkspruch und ein Foto standen
       in der bisherigen Darstellung sonst unterschiedlich hoch nebeneinander.
       ------------------------------------------------------------------ */
    .bibliothek-raster {
      display: grid; gap: 1rem;
      grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    }
    .bibliothek-karte {
      display: flex; flex-direction: column; overflow: hidden;
      background-color: var(--lumen-surface); border: 1px solid var(--lumen-line);
      border-radius: .75rem; transition: box-shadow .15s ease, transform .15s ease;
    }
    .bibliothek-karte:hover { box-shadow: 0 .5rem 1.4rem rgba(0,0,0,.08); transform: translateY(-2px); }
    .bibliothek-karte-vorschau {
      height: 150px; display: flex; align-items: center; justify-content: center;
      overflow: hidden; background-color: var(--lumen-canvas); flex-shrink: 0;
    }
    .bibliothek-karte-vorschau img { width: 100%; height: 100%; object-fit: cover; }
    .bibliothek-karte-vorschau i { font-size: 2.4rem; color: var(--lumen-muted); }
    /* Textbausteine zeigen den Anfang ihres Textes statt eines nichts-
       sagenden Datei-Icons - bei einem Gedenkspruch ist der Text die
       eigentliche Information. */
    .bibliothek-karte-vorschau--text {
      align-items: flex-start; padding: .8rem .9rem;
      background: linear-gradient(180deg, var(--lumen-canvas), transparent);
    }
    .bibliothek-karte-textauszug {
      font-size: .8rem; line-height: 1.45; color: var(--lumen-ink-600);
      margin: 0; font-style: italic;
      display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
    }
    [data-bs-theme="dark"] .bibliothek-karte-textauszug { color: #B9C0C9; }
    .bibliothek-karte-koerper { padding: .7rem .9rem .3rem; flex: 1 1 auto; min-width: 0; }
    .bibliothek-karte-name {
      font-size: .92rem; font-weight: 600; margin: 0 0 .35rem;
      overflow-wrap: anywhere;
    }
    .bibliothek-karte-chip {
      display: inline-block; font-size: .7rem; padding: .12rem .5rem; border-radius: 1rem;
      background-color: color-mix(in srgb, var(--lumen-primary) 14%, transparent);
      color: var(--lumen-primary-text); font-weight: 600;
    }
    .bibliothek-karte-meta { font-size: .72rem; color: var(--lumen-muted); margin: .4rem 0 0; }
    .bibliothek-karte-fuss {
      display: flex; justify-content: flex-end; gap: .3rem; flex-wrap: wrap;
      padding: .5rem .9rem .7rem;
    }
    .bibliothek-leer { grid-column: 1 / -1; }

    /* ------------------------------------------------------------------
       Variablen in Textbausteinen (AP-7, Feedback v0.4.3 §5)
       ------------------------------------------------------------------
       Palette und Auswahl stehen in einem MODAL-Formular, nicht im
       Editor - deshalb hier und nicht in static/css/editor.css, die auf
       normalen Seiten gar nicht geladen wird. Eigene Klassennamen statt
       der lumen-variablen-* des Editors: dieselben Namen in zwei Dateien
       waeren auf den Editorseiten (die beide Stylesheets laden) zwei
       Definitionen fuer dieselbe Regel, und welche gewinnt, haenge dann
       an der Reihenfolge der <link>-Zeilen. */
    .bibliothek-variablen-palette,
    .bibliothek-vorschau,
    .bibliothek-textbaustein-panel {
      border: 1px solid var(--lumen-line);
      border-radius: .5rem;
      padding: .6rem .7rem;
      margin-top: .5rem;
    }
    .bibliothek-variablen > .d-flex { margin-top: .5rem; }
    /* Hoehenbegrenzung mit Bildlauf: der Katalog hat ueber hundert
       Eintraege. Ohne sie schoebe die Palette den Speichern-Knopf aus dem
       Dialog - man muesste durch die gesamte Variablenliste scrollen, um
       den Eintrag ueberhaupt sichern zu koennen. */
    .bibliothek-variablen-liste,
    .bibliothek-textbaustein-liste {
      max-height: 16rem;
      overflow-y: auto;
      margin-top: .4rem;
    }
    .bibliothek-variablen-titel {
      font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
      color: var(--lumen-muted); margin: .5rem 0 .2rem;
    }
    .bibliothek-variablen-eintrag {
      display: flex; align-items: baseline; gap: .4rem;
      width: 100%; text-align: left; border: 0; background: transparent;
      padding: .15rem .3rem; border-radius: .25rem; font-size: .8rem;
      color: inherit;
    }
    .bibliothek-variablen-eintrag:hover,
    .bibliothek-variablen-eintrag:focus-visible {
      background: color-mix(in srgb, var(--lumen-ink) 8%, transparent);
    }
    .bibliothek-variablen-label { flex: 1 1 auto; }
    /* Der Schluessel klein und ruhig daneben: gebraucht wird er beim
       Nachschlagen, gesucht wird nach der Beschriftung. */
    .bibliothek-variablen-name { flex: 0 0 auto; font-size: .7rem; opacity: .6; }
    /* Waehrend nachgeladen wird bleibt das alte Ergebnis stehen, nur
       abgeblendet - ein Leerblitzen bei jedem Tastendruck waere unruhiger
       als das kurze Warten. */
    /* Der frueher eigene Ladezustand der Bibliothek nutzt jetzt die
       systemweite Klasse .ist-ladend (siehe oben) - eine Regel statt einer
       je Liste (Feedback §11: "Ladezustände ... vereinheitlichen"). */

    /* ------------------------------------------------------------------
       Modale (Feedback §9: "sehen grundsaetzlich gut aus, sind aber
       durchgehend schlecht formatiert. Abstaende, Ausrichtung,
       Buttonpositionen, Kopf und Fussbereiche, Scrollverhalten bei langem
       Inhalt").

       Kern des Problems war das Scrollverhalten: der Fussbereich liegt aus
       technischen Gruenden im modal-body (siehe common/_modal_footer.html)
       und scrollte deshalb bei langen Formularen mit aus dem Bild. Mit
       position:sticky bleibt er unten stehen, ohne dass der Absende-Knopf
       das Formular verlassen muesste.
       ------------------------------------------------------------------ */
    .modal-header {
      padding: 1rem 1.25rem; border-bottom: 1px solid var(--lumen-line);
      align-items: flex-start;
    }
    .modal-title { font-size: 1.05rem; font-weight: 600; line-height: 1.35; }
    /* Kopf eines Dialogs (§15, E35): Ueberschrift und darunter eine
       ruhige Zeile fuer den Zusammenhang ("Aenderungshistorie zu ...").
       Die Zeile steht im Kopf und nicht im Koerper, weil sie sonst beim
       Scrollen verschwindet - und weil der Koerper sonst in jedem
       zweiten Dialog ein Stueck weiter unten anfaengt. */
    .lumen-modal-kopf { min-width: 0; }
    .lumen-modal-untertitel {
      margin: .15rem 0 0; font-size: .8rem; line-height: 1.35;
      color: var(--lumen-muted);
    }
    .modal-body { padding: 1.25rem; }
    /* Ein Bild fuer "laedt" und eines fuer "ging schief" - gesetzt von
       static/js/modal-forms.js (zustandMarkup) und von der Huelle selbst
       (partials/modal_shell.html). Vorher gab es dafuer vier leicht
       verschiedene Markup-Schnipsel; welcher erschien, haing davon ab,
       an welcher Stelle es schieflief. */
    .lumen-modal-zustand {
      display: flex; flex-direction: column; align-items: center;
      justify-content: center; gap: .75rem;
      padding: 3rem 1rem; text-align: center; color: var(--lumen-muted);
    }
    .lumen-modal-zustand-fehler { color: var(--bs-danger, #dc3545); }
    .lumen-modal-zustand-fehler .bi { font-size: 1.75rem; }
    .lumen-modal-footer {
      display: flex; justify-content: flex-end; gap: .5rem;
      margin-top: 1.5rem; padding-top: .85rem;
      border-top: 1px solid var(--lumen-line);
    }
    /* Klebend NUR im Modal. Dieselben Formular-Partials werden bei einem
       Direktaufruf auch als normale Seite gerendert (siehe
       common/_modal_form_page.html) - dort gibt es keinen scrollenden
       Container, und die negativen Seitenraender wuerden den Balken aus der
       Karte herauslaufen lassen. */
    .modal-body .lumen-modal-footer {
      position: sticky; bottom: 0; z-index: 5;
      /* Negative Seitenraender heben den Innenabstand des modal-body auf,
         damit der Balken echte Kante-zu-Kante-Breite bekommt - sonst
         entstuende links und rechts ein heller Streifen, unter dem der
         Inhalt sichtbar durchscrollt. */
      margin: 1.5rem -1.25rem -1.25rem; padding: .85rem 1.25rem;
      background-color: var(--lumen-surface);
    }
    /* Schmale Schirme: Schaltflaechen auf volle Breite, damit sie sich
       sicher treffen lassen (siehe Mobile-Pruefung, §9). */
    @media (max-width: 575.98px) {
      .modal-body { padding: 1rem; }
      .modal-body .lumen-modal-footer {
        margin: 1.25rem -1rem -1rem; padding: .75rem 1rem;
      }
      .lumen-modal-footer { flex-direction: column-reverse; }
      .lumen-modal-footer .btn { width: 100%; }
      /* me-auto (Loeschen-Knopf im Termin-Modal) hat in der Spalte keine
         Wirkung - der Knopf wandert stattdessen ans Ende. */
      .lumen-modal-footer .me-auto { margin-right: 0 !important; order: 1; }
    }
    /* Vereinheitlichte Abstaende innerhalb von Modal-Formularen: vorher
       setzte jedes Formular eigene mt-/mb-Werte, wodurch die Abschnitte
       unterschiedlich weit auseinander lagen. */
    .modal-body > form > .row + .row { margin-top: 1rem; }
    .modal-body h6, .modal-body .form-abschnitt {
      font-size: .78rem; text-transform: uppercase; letter-spacing: .05em;
      color: var(--lumen-muted); font-weight: 700;
      margin: 1.5rem 0 .5rem; padding-bottom: .3rem;
      border-bottom: 1px solid var(--lumen-line);
    }
    .modal-body > form > .row:first-child h6:first-child { margin-top: 0; }

    /* Unterschrifts-Kennzeichnung (Feedback §5.2). Bewusst eine eigene,
       kraeftige Auszeichnung statt eines der blassen Bootstrap-Badges:
       "ist das Dokument unterschrieben?" ist beim Durchsehen einer
       Dokumentenliste die wichtigste Frage und muss ins Auge springen. */
    .badge-unterschrieben {
      display: inline-flex; align-items: center; gap: .25rem;
      font-size: .72rem; font-weight: 600; padding: .15rem .5rem; border-radius: 1rem;
      background-color: var(--lumen-erfolg-flaeche); color: var(--lumen-erfolg-text);
      border: 1px solid var(--lumen-erfolg-linie);
      white-space: nowrap; vertical-align: middle; margin-left: .35rem;
    }
    /* Der eigene Dunkelmodus-Block ist entfallen - das Erfolgspaar
       bringt seine dunkle Fassung mit (siehe den Baukasten). */

    /* Dark Mode: Bootstrap 5.3 uebernimmt die meisten Komponenten
       automatisch ueber data-bs-theme, hier nur die eigenen
       Hartcodierungen nachziehen. */
    /* Im Dunkelmodus liegt die Arbeitsflaeche bewusst dunkler als die
       Shell, damit Sidebar/Topbar weiterhin als eigene Ebene lesbar
       bleiben (im Hellmodus ist es genau andersherum). */
    [data-bs-theme="dark"] {
      --lumen-canvas: #14171A;
      --lumen-surface: #22272E;
      --lumen-line: rgba(255, 255, 255, .09);
      --lumen-muted: #98A1AC;
      /* --lumen-shell und die uebrigen Shell-Werte stehen seit dem 27.08.
         weiter oben in der gemeinsamen Regel fuer die dunkle Fassung -
         [data-bs-theme="dark"] ist dort einer der beiden Selektoren. Ein
         zweiter Wert an dieser Stelle waere die Doppelpflege, die die
         Zusammenfassung gerade beseitigt hat. */
      /* Auf dunklem Grund muss die Primaerfarbe aufgehellt statt
         abgedunkelt werden, sonst verschwinden die dunklen Palettentoene
         (Olive/Graphit) im Hintergrund. */
      --lumen-primary-text: color-mix(in srgb, var(--lumen-primary) 72%, #FFFFFF);
      /* Der Mischgrund des Baukastens (siehe :root): hier die
         Kartenflaeche statt Weiss. Damit stimmen alle abgeleiteten
         Toene - Abzeichenflaechen, Reiterunterlagen, Tabellenkoepfe -
         ohne dass eine einzige davon zweimal geschrieben werden muss. */
      --lumen-mischgrund: var(--lumen-surface);
      --lumen-accent-text: color-mix(in srgb, var(--lumen-accent) 78%, #FFFFFF);
      --lumen-schatten: 0 1px 2px rgba(0, 0, 0, .28);
      /* Die Statusfarben werden nicht gemischt, sondern eigens gesetzt:
         eine sehr helle Flaeche waere hier ein Leuchtfleck. Gleiche
         Bedeutung, andere Helligkeit - Flaeche dunkel und
         durchscheinend, Text aufgehellt. */
      --lumen-neutral-flaeche: rgba(255, 255, 255, .06);
      --lumen-neutral-linie: rgba(255, 255, 255, .14);
      --lumen-neutral-text: #A7B0BB;
      --lumen-info-flaeche: rgba(90, 168, 209, .14);
      --lumen-info-linie: rgba(90, 168, 209, .32);
      --lumen-info-text: #7FC0E0;
      --lumen-erfolg-flaeche: rgba(78, 184, 126, .14);
      --lumen-erfolg-linie: rgba(78, 184, 126, .32);
      --lumen-erfolg-text: #6FCF97;
      --lumen-warnung-flaeche: rgba(214, 165, 62, .14);
      --lumen-warnung-linie: rgba(214, 165, 62, .32);
      --lumen-warnung-text: #E0B457;
      --lumen-gefahr-flaeche: rgba(214, 92, 84, .14);
      --lumen-gefahr-linie: rgba(214, 92, 84, .32);
      --lumen-gefahr-text: #EE8F88;
    }
    [data-bs-theme="dark"] body { background-color: var(--lumen-canvas); color: #E6E9ED; }
    [data-bs-theme="dark"] .card { border-color: var(--lumen-line); background-color: var(--lumen-surface); }
    [data-bs-theme="dark"] a:hover { color: #FFFFFF; }
    [data-bs-theme="dark"] .list-row:hover,
    [data-bs-theme="dark"] .mitarbeiter-option:hover { background-color: rgba(255, 255, 255, .05); }
    [data-bs-theme="dark"] .stat-tile:hover { box-shadow: 0 .6rem 1.2rem rgba(0, 0, 0, .35); }
    [data-bs-theme="dark"] .search-result-group-label { color: var(--lumen-muted); }
    [data-bs-theme="dark"] .theme-swatch { border-color: var(--lumen-canvas); }
    /* --fc-page-bg-color ist FullCalendars Standardweiss und faerbt u.a.
       die (sticky) Wochentagszeile. Ohne diese Zeile blieb der Kopf des
       Kalenders im Dunkelmodus weiss, waehrend die Beschriftung hell
       wurde - die Wochentage waren dadurch praktisch unlesbar. */
    [data-bs-theme="dark"] .fc {
      --fc-today-bg-color: color-mix(in srgb, var(--lumen-primary) 10%, transparent);
      --fc-border-color: rgba(255, 255, 255, .1);
      --fc-page-bg-color: var(--lumen-surface);
      --fc-neutral-bg-color: rgba(255, 255, 255, .05);
      color: #E6E9ED;
    }
    [data-bs-theme="dark"] .fc-event.termin-abgesagt { opacity: .4; }
    /* Die helle Kante der Ganztagestermine steht im Hellmodus auf einer
       kraeftigen Terminfarbe und traegt dort. Im Dunkelmodus sind die
       Terminfarben dieselben, der Rest der Flaeche ist aber dunkel -
       eine fast weisse Kante wirkt dann wie ein Fremdkoerper, deshalb
       hier etwas zurueckgenommen. */
    [data-bs-theme="dark"] .fc-daygrid-event.termin-ganztaegig,
    [data-bs-theme="dark"] .fc-timegrid-event.termin-ganztaegig {
      border-left-color: rgba(255, 255, 255, .55);
    }
    /* "+n weitere" nimmt im Hellmodus die dunkle Textfarbe des Systems -
       die waere hier auf dunklem Grund unlesbar. */
    [data-bs-theme="dark"] .fc-daygrid-more-link { color: #CED4DA; }
    /* Sidebar/Topbar sind bereits im Hellmodus dunkel (siehe .app-sidebar)
       und brauchen hier keine eigenen Farben mehr - nur die Trennkante zur
       nun dunkleren Arbeitsflaeche wird etwas deutlicher. */
    [data-bs-theme="dark"] .app-sidebar { border-right-color: rgba(255,255,255,.12); }
    [data-bs-theme="dark"] .app-topbar { border-bottom-color: rgba(255,255,255,.12); }

    /* ------------------------------------------------------------------
       Variablenkatalog im E-Mail-Vorlagen-Editor (Feedback v0.2.2 §4:
       Variablen erschienen objekttyp-uebergreifend gemischt). Der Katalog
       ist jetzt nach Gruppen geordnet und durchsuchbar - er wird dadurch
       laenger als der bisherige Chip-Streifen und braucht eine feste
       Hoehe mit eigenem Scrollbereich, sonst waechst das Modal ueber den
       Bildschirm hinaus und der Speichern-Knopf rutscht weg.
       ------------------------------------------------------------------ */
    .variablen-katalog { max-height: 15rem; overflow-y: auto; }
    .variablen-gruppe + .variablen-gruppe { margin-top: .75rem; }
    .variablen-gruppe-titel {
      font-size: .72rem; font-weight: 600; letter-spacing: .04em;
      text-transform: uppercase; color: var(--lumen-muted);
      padding-bottom: .2rem; margin-bottom: .3rem;
      border-bottom: 1px solid var(--lumen-line);
    }
    /* Zeilen statt Chips: der Variablenname allein sagt zu wenig, das
       Label muss danebenstehen und ausgeschrieben lesbar bleiben. */
    .variablen-eintrag {
      display: flex; align-items: baseline; gap: .5rem; width: 100%;
      padding: .2rem .35rem; border: 0; border-radius: .35rem;
      background: transparent; text-align: left; color: inherit;
    }
    .variablen-eintrag:hover, .variablen-eintrag:focus-visible {
      background-color: color-mix(in srgb, var(--lumen-primary) 12%, transparent);
    }
    .variablen-eintrag code {
      color: var(--lumen-primary-text); font-size: .78rem; white-space: nowrap;
    }
    .variablen-eintrag-label {
      font-size: .78rem; color: var(--lumen-muted);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* Vorschau: bewusst wie ein Brief gesetzt (Serifen-freier Fliesstext,
       Betreff hervorgehoben), damit auf einen Blick erkennbar ist, was
       beim Empfaenger ankommt - eine Vorschau in Formularoptik wuerde
       diesen Zweck verfehlen. */
    .vorlage-vorschau {
      border: 1px solid var(--lumen-line); border-radius: .5rem;
      padding: .75rem; background-color: var(--lumen-canvas);
      max-height: 18rem; overflow-y: auto;
    }
    .vorlage-vorschau-betreff {
      font-weight: 600; margin-bottom: .5rem;
      padding-bottom: .5rem; border-bottom: 1px solid var(--lumen-line);
    }
    .vorlage-vorschau-text { white-space: pre-wrap; font-size: .9rem; }

    /* ------------------------------------------------------------------
       Kopfzeilen-Editor (formulare/kopfzeile_form.html): links bauen,
       rechts pruefen. Das Vorschaupanel bleibt beim Scrollen stehen,
       damit die Wirkung einer geaenderten Massangabe sichtbar ist, ohne
       jedes Mal hoch- und runterzuspringen.
       ------------------------------------------------------------------ */
    #kopfzeile-editor textarea { font-size: .85rem; line-height: 1.45; }
    /* Unterhalb von XL stehen beide Spalten UNTEREINANDER - ein
       klebendes Vorschaupanel wuerde dort dauerhaft die Formularfelder
       verdecken, statt zu helfen. */
    @media (max-width: 1199.98px) {
      #kopfzeile-editor .sticky-top { position: static; }
      #kopfzeile-vorschau-iframe { height: 60vh; }
    }

    /* ------------------------------------------------------------------
       Zwischenueberschrift innerhalb einer Detailansicht (siehe
       cases/_stammdaten_detail.html). Mit den amtlichen Angaben aus
       v0.3.0 (Todesbescheinigung, Sterbeurkunde, Ueberfuehrung, Nachlass)
       waere die Stammdatenliste sonst auf ueber 40 Zeilen angewachsen -
       darin findet niemand mehr etwas. Die Ueberschrift trennt die
       Bloecke, ohne dafuer eigene Karten oder Reiter zu brauchen.
       ------------------------------------------------------------------ */
    .detail-abschnitt {
      margin: 1.5rem 0 .6rem; padding-bottom: .3rem;
      font-size: .78rem; font-weight: 600; text-transform: uppercase;
      letter-spacing: .05em; color: var(--lumen-muted);
      border-bottom: 1px solid var(--lumen-line);
    }

    /* ------------------------------------------------------------------
       Tastenkuerzel-Hilfe (siehe partials/tastenkuerzel.html, Feedback
       §11). Zweispaltig, damit Taste und Bedeutung auf einer Zeile
       nebeneinander stehen - eine untereinander laufende Definitionsliste
       waere bei neun Eintraegen unnoetig lang.
       ------------------------------------------------------------------ */
    .kuerzel-liste {
      display: grid; grid-template-columns: auto 1fr; gap: .5rem 1rem; align-items: baseline;
    }
    .kuerzel-liste dt { white-space: nowrap; }
    .kuerzel-liste dd { margin: 0; color: var(--lumen-muted); }
    .kuerzel-liste kbd {
      background-color: var(--lumen-ink-700); color: #fff; border-radius: .3rem;
      padding: .1rem .4rem; font-size: .78rem; box-shadow: 0 1px 0 rgba(0,0,0,.35);
    }

    /* ------------------------------------------------------------------
       Verzeichnis-Suchfeld (siehe common/_verzeichnis_suchfeld.html).

       HIER STANDEN BIS ZUM 30.08.2026 zwei Regeln fuer eine Lupe IM
       Feld (§6.1). Sie lag als Overlay ueber dem linken Feldrand und
       damit ueber dem Anfang des Platzhaltertextes; der Auftraggeber hat
       sie entfernen lassen. Die Lupe der erweiterten Suche steht rechts
       NEBEN dem Feld und ist ein Knopf, kein Bild - sie braucht keine
       eigene Regel.
       ------------------------------------------------------------------ */

/* Pfeil-Navigation im Stammdaten-Formular (Feedback v0.4.3 §1).
   Sie klebt oben im Modal, weil sie sonst genau dann aus dem Bild waere,
   wenn man sie braucht - beim Blaettern durch die Abschnitte. Der
   Hintergrund ist noetig, damit die Karten nicht darunter durchscheinen. */
.stammdaten-navigation {
  position: sticky;
  top: -1rem;
  z-index: 5;
  background: var(--bs-body-bg);
  border-bottom: 1px solid var(--bs-border-color);
}

/* ====================================================================
   Bedienflaeche der Editoren · Klappgriffe, zweiter Splitter, kompakte
   Werkzeugleiste (v0.4.6, Auftrag 1.6 und 1.8, Entscheidungen E18/E19)
   ====================================================================

   WARUM HIER UND NICHT IN static/css/editor.css: die uebrigen
   .lumen-editor-*-Regeln des Blattes stehen ebenfalls in dieser Datei
   (siehe den Abschnitt "Gestaltungsflaeche der Editoren" weiter oben);
   editor.css traegt die Grundaufteilung, die hier nur ERGAENZT wird.
   Beide Dateien werden von templates/base_editor.html geladen, die
   Reihenfolge ist lumen.css vor editor.css - deshalb sind die Regeln
   unten so geschrieben, dass sie nichts aus editor.css ueberstimmen
   muessen, sondern nur Zustaende beschreiben, die es dort nicht gibt.

   Gemessen wurde der Anlass: bei 1280 px Fensterbreite blieben der
   Buehne 736 px, waehrend ein A4-Blatt bei 96 dpi 794 px misst. Die
   Seite liess sich also nicht ohne waagerechtes Rollen ueberblicken -
   genau die Meldung aus dem Auftrag ("Auf einem 13-Zoll-Laptop muss
   aktuell horizontal gescrollt werden"). */

/* Eine eingeklappte Spalte ist NICHT display:none - sie behaelt ihren
   Platz im Flex-Raster und schrumpft auf null. Mit display:none verloere
   sie ihre Masse, und die Paletten darin meldeten beim Ausklappen
   kurzzeitig Hoehe 0 an die Montagen zurueck (die Vorschau rechnet mit
   ihrer Breite). */
.lumen-editor-reihe .lumen-editor-spalte.ist-eingeklappt {
  flex: 0 0 0 !important;
  width: 0 !important;
  min-width: 0;
  padding-left: 0;
  padding-right: 0;
  border-left-width: 0;
  border-right-width: 0;
  overflow: hidden;
}

/* Der Klappgriff sitzt auf dem 6px schmalen Splitter und ragt bewusst
   ueber ihn hinaus - ein Griff in Splitterbreite waere nicht zu treffen.
   Er faengt seine Zeigerereignisse selbst ab; static/js/editor/chrome.js
   laesst den Splitterzug gar nicht erst anlaufen, wenn der Druck auf dem
   Griff beginnt. */
.lumen-editor-klappgriff {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 14px;
  height: 46px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--lumen-line, #dee2e6);
  border-radius: 4px;
  background: var(--lumen-surface, #fff);
  color: var(--lumen-muted, #6c757d);
  font-size: .6rem;
  line-height: 1;
  cursor: pointer;
  z-index: 3;
}
.lumen-editor-klappgriff:hover {
  background: var(--lumen-primary);
  border-color: var(--lumen-primary);
  color: var(--lumen-on-primary, #fff);
}
/* Ein Splitter neben einer eingeklappten Spalte darf nicht mehr ziehbar
   aussehen - dort gibt es nichts zu bemessen, nur noch etwas
   aufzuklappen. */
.lumen-editor-splitter.ist-eingeklappt { cursor: default; }
/* Ist die RECHTE Spalte eingeklappt, steht ihr Splitter am Fensterrand;
   ein mittig gesetzter Griff ragte dort zur Haelfte hinaus und waere
   angeschnitten. Gemessen: 4 px ausserhalb des Sichtfeldes. */
.lumen-editor-splitter[data-editor-splitter="rechts"].ist-eingeklappt
  .lumen-editor-klappgriff {
  left: auto;
  right: 2px;
  transform: translateY(-50%);
}

/* --------------------------------------------------------------------
   Werkzeugleiste in einer Zeile
   --------------------------------------------------------------------
   Die Huelle ist so hoch wie eine Zeile (den Wert setzt chrome.js nach
   der Messung als Inline-Hoehe, weil er von Schriftgroesse und
   Bedienelementen abhaengt und keine Zahl im Stylesheet ihn treffen
   koennte). Die Leiste selbst liegt darin absolut - aufgeklappt waechst
   sie ueber die Buehne, statt sie nach unten zu schieben: ein Raster,
   das beim Aufklappen springt, verliert die Stelle, auf die man gerade
   gezeigt hat. */
.lumen-editor-leiste-huelle { position: relative; }
.lumen-editor-leiste-huelle.ist-kompakt {
  height: var(--lumen-leiste-zeile);
  overflow: visible;
}
.lumen-editor-leiste-huelle.ist-kompakt > .lumen-editor-leiste {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  max-height: var(--lumen-leiste-zeile);
  overflow: hidden;
  /* Ohne diese Zeile verteilt der Flex-Umbruch die Zeilen auf die
     festgelegte Hoehe, statt sie oben beginnen zu lassen - zugeklappt
     saehe man dann Reste mehrerer Zeilen statt der ersten. */
  align-content: flex-start;
  /* Oben statt mittig (editor.css setzt align-items:center): eine
     Montage kann einen mehrzeilig umbrechenden Behaelter in die Leiste
     stellen (static/js/formular-editor.js: "leiste-layout"). Steht in
     derselben Flex-Zeile daneben eine einzeilige Gruppe, ruecke die
     Mitte-Ausrichtung sie in die Mitte dieses hohen Bandes - also
     zugeklappt unter die sichtbare Kante. */
  align-items: flex-start;
  /* Platz fuer den Mehr-Knopf, damit die letzte Gruppe der ersten Zeile
     nicht unter ihm verschwindet. */
  padding-right: 6rem;
  z-index: 1032;
}
.lumen-editor-leiste-huelle.ist-kompakt.ist-offen > .lumen-editor-leiste {
  max-height: 70vh;
  overflow-y: auto;
  box-shadow: 0 .5rem 1rem rgba(31, 35, 41, .18);
  /* Die letzte Zeile der aufgeklappten Tafel klebte an der Kante: die
     Leiste bringt unten .35rem Polster mit (editor.css), und das ist die
     Hoehe eines Abstands zwischen zwei Zeilen, nicht die eines
     Abschlusses. Der Auftrag (5.3) nennt das "abgeschnittener Bereich" -
     eine Tafel ohne sichtbaren Abschluss liest sich, als ginge es
     darunter weiter. */
  padding-bottom: .75rem;
  border-bottom-left-radius: .375rem;
  border-bottom-right-radius: .375rem;
}
.lumen-editor-leiste-mehr {
  position: absolute;
  top: .3rem;
  right: .5rem;
  z-index: 1033;
  white-space: nowrap;
}
.lumen-editor-leiste-mehr[hidden] { display: none; }
/* Der Pfeil dreht sich beim Aufklappen (Auftrag 5.3: "Klarer Pfeil nach
   unten als Affordanz, der beim Aufklappen rotiert").

   Die Drehung haengt am Symbol IM Knopf und nicht am Knopf selbst: der
   traegt eine Beschriftung daneben, und die stuende sonst auf dem Kopf.
   Welches Symbol es ist, entscheidet templates/base_editor.html - drei
   Punkte, um 180 Grad gedreht, sehen aus wie drei Punkte. */
.lumen-editor-leiste-mehr .bi {
  display: inline-block;
  transition: transform .15s ease-in-out;
}
.lumen-editor-leiste-mehr[aria-expanded="true"] .bi { transform: rotate(180deg); }

/* DAS DREI-PUNKTE-MENUE UEBER DIE WERKZEUGLEISTE (Auftrag 3.2).

   Gemessen: im Kopf-/Fussnoten-Editor liess sich kein Menueeintrag
   anklicken - Playwright meldete
   "<div data-editor-leiste> ... intercepts pointer events", 60
   Versuche lang. Der Grund steht in lumen.css: die zugeklappte
   Werkzeugleiste liegt als `position: absolute` mit `z-index: 1032`
   ueber die volle Breite unter dem Kopf, der Mehr-Knopf darin bei
   1033. Eine Bootstrap-Dropdownliste hat 1000. Das Menue klappt also
   auf, liegt aber UNTER der Leiste - genau der gemeldete Befund
   "es oeffnet fehlerhaft". Im Formulargenerator faellt das erst auf,
   wenn die Leiste in den kompakten Modus geht; sichtbar ist das Menue
   trotzdem, nur unbedienbar.

   1040 und nicht hoeher: der Bootstrap-Modalhintergrund liegt bei
   1050, und ein Menue ueber einem offenen Dialog waere der naechste
   Fehler dieser Art.

   Steht hier und nicht in editor.css, weil die Stylesheets in diesem
   Durchgang einem anderen Arbeitspaket gehoeren. */
#editor-menue .dropdown-menu { z-index: 1040; }

/* Vorrangkennzeichnung fuer die Werkzeugleiste: eine so ausgezeichnete
   Gruppe sortiert sich ans Ende ihres Flex-Behaelters und landet damit
   in den Zeilen, die zugeklappt hinter "Mehr" liegen. Die Auszeichnung
   ist OPTIONAL - ohne sie bleibt die Reihenfolge des Dokuments, und
   zugeklappt sieht man die erste Zeile. */
.lumen-editor-leiste [data-leiste-rang="sekundaer"] { order: 2; }

/* Anklickbare Objektzeile in der Fallakte (Feedback P1, Drilldown).
   Ohne einen sichtbaren Hinweis waere die Zeile eine Flaeche, die
   heimlich etwas tut - der Zeiger und die leichte Aufhellung beim
   Ueberfahren sind das, woran man eine Schaltflaeche im Web erkennt.
   Die Farbe kommt aus der Bootstrap-Variablen und nicht aus einem festen
   Wert, damit sie dem dunklen Erscheinungsbild folgt. */
.objekt-zeile { cursor: pointer; }
.objekt-zeile:hover { background-color: var(--bs-secondary-bg, rgba(0, 0, 0, .04)); }

/* ==========================================================================
   Ablegeflaeche der Bibliothek und Bildeditor (v0.4.7, Block B)
   ========================================================================== */

/* Die Rueckmeldung beim Ueberziehen liegt UEBER der ganzen Seite, weil seit
   v0.4.7 auch die ganze Seite Dateien annimmt (siehe
   static/js/bibliothek-anlegen.js). Ohne eine solche Flaeche waere die
   einzige Rueckmeldung ein Rahmen an einem Kasten, der beim Ziehen ueber
   das Kartenraster gar nicht im Blick ist - genau der Grund, warum "keine
   Reaktion" gemeldet wurde.

   pointer-events: none ist hier keine Feinheit, sondern Bedingung: eine
   Flaeche, die Zeigerereignisse annimmt, wuerde beim Ueberfahren selbst
   dragenter/dragleave ausloesen und damit den Zaehler im Skript verwirren -
   die Anzeige begaenne zu flackern, also genau der behobene Fehler in
   neuer Gestalt. */
.bib-ablage-overlay {
  position: fixed;
  inset: 0;
  z-index: 1050;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  background: rgba(31, 35, 41, .35);
}
.bib-ablage-overlay-inhalt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .5rem;
  padding: 2rem 3rem;
  border: 2px dashed var(--bs-primary, #0d6efd);
  border-radius: .75rem;
  background: var(--bs-body-bg, #fff);
  color: var(--bs-body-color, #212529);
  font-weight: 600;
  text-align: center;
}
.bib-ablage-overlay-inhalt .bi { font-size: 2.5rem; }

/* --------------------------------------------------------------------------
   Bildeditor
   -------------------------------------------------------------------------- */
/* Zweispaltig, sobald Platz ist: Bild links, Werkzeuge rechts. Auf schmalen
   Geraeten untereinander - ein Zuschnittrahmen, der neben einer Reglerspalte
   auf 320 Pixel Breite zusammengedrueckt wird, laesst sich nicht mehr
   ziehen. */
.bildeditor {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 992px) {
  .bildeditor {
    grid-template-columns: minmax(0, 3fr) minmax(14rem, 1fr);
    grid-template-areas:
      "flaeche leiste"
      "fassungen leiste"
      "fuss fuss";
  }
  .bildeditor-flaeche { grid-area: flaeche; }
  .bildeditor-leiste { grid-area: leiste; }
  .bildeditor-fassungen { grid-area: fassungen; }
  .bildeditor .lumen-modal-footer { grid-area: fuss; }
}

/* position: relative traegt den Zuschnittrahmen: er wird in Prozent der
   Buehne positioniert, nicht in Pixeln - so bleibt er beim Verkleinern des
   Fensters an derselben Stelle des Bildes. */
.bildeditor-buehne {
  position: relative;
  display: inline-block;
  max-width: 100%;
  line-height: 0;
}
.bildeditor-canvas {
  max-width: 100%;
  height: auto;
  border-radius: .375rem;
  /* Schachbrett waere ehrlicher, ist aber unruhig; ein neutrales Grau
     zeigt den weichen Rand nach unten als das, was er im Druck ist. */
  background: var(--bs-secondary-bg, #e9ecef);
}
.bildeditor-zuschnitt {
  position: absolute;
  border: 1px solid #fff;
  outline: 1px dashed rgba(0, 0, 0, .6);
  /* Der Schatten dunkelt alles AUSSERHALB des Rahmens ab, ohne dass es
     dafuer vier eigene Elemente braucht. */
  box-shadow: 0 0 0 100vmax rgba(31, 35, 41, .45);
  cursor: move;
}
.bildeditor-griff {
  position: absolute;
  width: 14px;
  height: 14px;
  background: #fff;
  border: 1px solid rgba(31, 35, 41, .7);
  border-radius: 2px;
}
.bildeditor-griff[data-griff="nw"] { top: -7px; left: -7px; cursor: nwse-resize; }
.bildeditor-griff[data-griff="ne"] { top: -7px; right: -7px; cursor: nesw-resize; }
.bildeditor-griff[data-griff="sw"] { bottom: -7px; left: -7px; cursor: nesw-resize; }
.bildeditor-griff[data-griff="se"] { bottom: -7px; right: -7px; cursor: nwse-resize; }

.bildeditor-gruppe { margin-bottom: 1rem; }
.bildeditor-legende {
  font-size: .8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--bs-secondary-color, #6c757d);
  margin-bottom: .35rem;
}

/* --------------------------------------------------------------------
   „In Entwicklung“ (Leitprinzip P2, v0.5.0)
   --------------------------------------------------------------------
   Gehoert zu templates/partials/_in_entwicklung.html. Hier und nicht
   seitenlokal, weil das Teilstueck an mehreren Stellen eingebunden wird
   und eine zweite Fassung der Regel genau die Sorte Abweichung ist, die
   man erst bemerkt, wenn ein Schloss an einer Stelle fehlt (siehe die
   Vorgeschichte von .lumen-leiste-bereich in static/css/editor.css).

   Das Schloss sitzt in der unteren rechten Ecke des Knopfes und nicht
   mittig darueber: mittig verdeckte es das Symbol, das sagt, worum es
   ueberhaupt geht. */
.lumen-in-entwicklung {
    opacity: .55;
    /* Bootstrap setzt an :disabled bereits "pointer-events: none" fuer
       Links, nicht aber fuer <button>. Ohne diese Zeile faenge der Knopf
       den Zeiger ab und zeigte den Verbotscursor - der Tooltip, der
       erklaert warum, erschiene dann nie. */
    cursor: not-allowed;
    pointer-events: auto;
}

.lumen-in-entwicklung-schloss {
    position: absolute;
    right: -.15rem;
    bottom: -.15rem;
    font-size: .62em;
    line-height: 1;
    padding: .1em;
    border-radius: 50%;
    background: var(--bs-body-bg, #fff);
}

    /* ==================================================================
       BAUKASTEN (Auftrag vom 27.08.2026, Designvorlage)
       ==================================================================
       „Übernehme die Design-Aspekte ... Alle Modelle, alle Fenster,
        einfach alles! Es soll einheitlich, mit den setzbaren Farben
        immer passen und leicht und übersichtlich sein. Man muss sich
        leicht durchnavigieren können."

       WARUM DAS EIN STYLESHEET-ABSCHNITT IST UND KEIN UMBAU DER
       VORLAGEN. Die 147 Vorlagen dieses Projekts benutzen fast
       durchgehend Bootstrap-Klassen: 323-mal .btn, rund 60 .table,
       knapp 400 Formularfelder, ein gutes Dutzend .badge-Varianten.
       Das ist die Gelegenheit - wer diese Klassen an EINER Stelle
       umdefiniert, vereinheitlicht die ganze Anwendung, ohne 147
       Dateien anzufassen. Ein Durchgang durch die Vorlagen haette
       dieselbe Wirkung mit hundertfachem Risiko: jede Datei ein
       moeglicher Flüchtigkeitsfehler, und die Testsuite prueft an
       vielen Stellen Markup.

       DREI REGELN, die dieser Abschnitt durchhaelt:

       1. KEIN HEXWERT, der zur Systemfarbe gehoert. Alles wird aus
          --lumen-primary/--lumen-accent gemischt (siehe die Tokens
          oben). Stellt jemand die Instanzfarbe um, wandert die ganze
          Oberflaeche mit.
       2. STATUS IST KEINE MARKE. Die fuenf Statuspaare sind fest -
          "Fehler" bleibt rot, auch wenn die Marke rot wird.
       3. RUHIG STATT LAUT. Duenne Linien statt Schatten, kleine
          Radien, kleine graue Beschriftungen, gefuellte Flaechen nur
          fuer die eine wichtigste Aktion je Bereich. Das ist der
          eigentliche Unterschied zur Vorlage: dort traegt die Seite
          den Inhalt, nicht ihre Verzierung.

       Der Abschnitt steht am DATEIENDE, damit er die Bestandsregeln
       darueber schlaegt, ohne dass irgendwo ein !important noetig
       waere. Die Dunkelmodus-Regeln stehen davor und gewinnen ueber
       ihre hoehere Spezifitaet - genau so soll es sein.
       ================================================================== */

    /* --- Grundton der Seite -------------------------------------------
       Die Grundschrift steht auf dem Regler --lumen-basis (siehe oben),
       nicht auf einem festen Wert. Voreinstellung ist Bootstraps 16px -
       der erste Wurf hatte 15px, und das war zusammen mit den
       verkleinerten Nebengroessen bereits zu wenig.

       Was die Oberflaeche dicht macht, sind die ABSTAENDE: engere
       Zeilenhoehen in Tabellen, kleinere Innenabstaende an Karten und
       Knoepfen. Die stehen weiter unten und sind von der Schriftgroesse
       unabhaengig. */
    body {
      font-size: var(--lumen-basis);
      line-height: 1.5;
    }

    /* Links tragen die Systemfarbe. Bis hierher stand ueberall Bootstraps
       Blau (#0d6efd) - auf einer waldgruenen Oberflaeche der einzige
       blaue Fleck, und bei jeder anderen Instanzfarbe erst recht daneben.
       --lumen-primary-text ist die auf hellem Grund lesbare Fassung
       (siehe ihre Definition oben). */
    a, .btn-link, .text-lumen {
      color: var(--lumen-primary-text);
      text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
    }
    a:hover, .btn-link:hover { color: var(--lumen-primary); }
    a.dropdown-item, a.list-group-item, a.nav-link, a.page-link { color: inherit; }

    /* --- Überschriften ------------------------------------------------
       Eine Seitenüberschrift trägt die Systemfarbe, so wie in der
       Vorlage. Sie ist der einzige Punkt der Seite, an dem die Marke im
       Inhaltsbereich auftaucht - alles darunter bleibt neutral, sonst
       wäre die Farbe kein Hinweis mehr, sondern Tapete. */
    main h1, main .h1, main h2, main .h2 {
      color: var(--lumen-primary-text);
      font-weight: 600;
      letter-spacing: -.01em;
    }
    main h1, main .h1 { font-size: 1.5rem; }
    main h2, main .h2 { font-size: 1.25rem; }
    main h3, main .h3 { font-size: 1.0625rem; font-weight: 600; }

    /* --- Abzeichen ----------------------------------------------------
       DER GRÖSSTE EINZELGEWINN dieses Abschnitts. Im Bestand standen
       über zwanzig Kombinationen nebeneinander: text-bg-secondary,
       text-bg-light border, text-bg-success, bg-secondary-subtle,
       badge-lumen, rounded-pill … Nebeneinander auf einer Seite sah das
       aus wie drei verschiedene Anwendungen.

       Sie tragen jetzt ALLE dieselbe Form - klein, 1px Linie, sehr
       helle Fläche, kräftiger Text - und unterscheiden sich nur noch in
       der Farbe. Genau so macht es die Vorlage: der Status ist ein
       Wort, keine Leuchtreklame. Vorher war „In Bearbeitung" ein
       vollflächig gelber Klotz, der jede Tabellenzeile dominierte. */
    .badge {
      display: inline-flex; align-items: center; gap: .3rem;
      padding: .2em .5em;
      font-size: var(--lumen-text-label);
      font-weight: 600;
      letter-spacing: .02em;
      line-height: 1.5;
      border-radius: var(--lumen-radius-klein);
      border: 1px solid transparent;
      vertical-align: baseline;
      white-space: nowrap;
    }
    .badge.rounded-pill { border-radius: 10rem; }
    /* Die Grundfassung: neutral. Sie gilt auch fuer ein blankes
       <span class="badge"> ohne Farbklasse - im Bestand vierzehnmal
       vorhanden und bis hierher praktisch unsichtbar (Bootstrap gibt ihm
       ohne text-bg-* keine Flaeche). */
    .badge,
    .badge.text-bg-light, .badge.text-bg-secondary, .badge.bg-secondary,
    .badge.bg-secondary-subtle, .badge.text-bg-secondary-subtle {
      background-color: var(--lumen-neutral-flaeche) !important;
      border-color: var(--lumen-neutral-linie);
      color: var(--lumen-neutral-text) !important;
    }
    .badge.text-bg-primary, .badge.bg-primary, .badge.badge-lumen,
    .badge.text-bg-info, .badge.bg-info, .badge.bg-info-subtle {
      background-color: var(--lumen-primary-weich) !important;
      border-color: var(--lumen-primary-linie);
      color: var(--lumen-primary-text) !important;
    }
    .badge.text-bg-success, .badge.bg-success,
    .badge.bg-success-subtle, .badge.text-bg-success-subtle {
      background-color: var(--lumen-erfolg-flaeche) !important;
      border-color: var(--lumen-erfolg-linie);
      color: var(--lumen-erfolg-text) !important;
    }
    .badge.text-bg-warning, .badge.bg-warning,
    .badge.bg-warning-subtle, .badge.text-bg-warning-subtle {
      background-color: var(--lumen-warnung-flaeche) !important;
      border-color: var(--lumen-warnung-linie);
      color: var(--lumen-warnung-text) !important;
    }
    .badge.text-bg-danger, .badge.bg-danger,
    .badge.bg-danger-subtle, .badge.text-bg-danger-subtle {
      background-color: var(--lumen-gefahr-flaeche) !important;
      border-color: var(--lumen-gefahr-linie);
      color: var(--lumen-gefahr-text) !important;
    }
    .badge.text-bg-dark, .badge.bg-dark {
      background-color: var(--lumen-accent-weich) !important;
      border-color: var(--lumen-accent-linie);
      color: var(--lumen-accent-text) !important;
    }
    /* Der Zaehler an der Glocke bleibt die eine Ausnahme: er meldet
       etwas Neues und soll auffallen. Eine dezente Fassung hier waere
       das Gegenteil seines Zwecks. */
    #nav-bell-badge.badge {
      background-color: var(--lumen-gefahr-text) !important;
      border-color: var(--lumen-gefahr-text);
      color: #FFFFFF !important;
    }

    /* --- Tabellen -----------------------------------------------------
       Der wichtigste Baustein der Anwendung und der Vorlage. Drei
       Aenderungen gegenueber dem Bestand:

       * Der Spaltenkopf war fett und schwarz und wog damit schwerer als
         die Daten darunter. Jetzt klein, grau, gesperrt - er benennt die
         Spalte, er ist nicht ihr Inhalt.
       * Zeilen tragen eine 1px-Linie statt Bootstraps Zebra-Rahmen.
       * Die Zeilenhoehe ist enger. Eine Liste, die zwoelf statt acht
         Zeilen zeigt, erspart einen Bildlauf - genau das meint
         „uebersichtlich". */
    .table {
      --bs-table-bg: transparent;
      --bs-table-color: var(--lumen-ink);
      font-size: var(--lumen-text-klein);
      margin-bottom: 0;
    }
    .table > thead > tr > th {
      font-size: var(--lumen-text-label);
      font-weight: 600;
      /* KEIN uppercase, obwohl es naheliegt. In der Vorlage sind
         Spaltenkoepfe normal geschrieben ("Teil | Stk | Kunde |
         Gebinde"), und der Grund ist praktisch: Grossbuchstaben lassen
         sich schlechter ueberfliegen, und eine Tabelle wird genau
         ueberflogen. Gross geschrieben bleibt nur, was Abschnitte
         TRENNT - die Sektionslabels der Seitenleiste und die
         Abschnittsueberschriften in Formularen. */
      color: var(--lumen-muted);
      background-color: transparent;
      border-bottom: 1px solid var(--lumen-line);
      padding: .55rem .75rem;
      white-space: nowrap;
    }
    .table > tbody > tr > td, .table > tbody > tr > th {
      padding: .55rem .75rem;
      border-bottom: 1px solid var(--lumen-line);
      vertical-align: middle;
    }
    .table > tbody > tr:last-child > td { border-bottom: none; }
    .table-hover > tbody > tr:hover > * {
      --bs-table-accent-bg: transparent;
      background-color: var(--lumen-primary-weich);
    }
    /* Zahlen gehoeren rechts und in gleiche Ziffernbreiten - sonst
       stehen Betraege in einer Spalte nicht untereinander und lassen
       sich nicht vergleichen. Die Vorlage macht das durchgehend so. */
    .table .zahl, .table .text-end { text-align: right; font-variant-numeric: tabular-nums; }
    /* Zweite Zeile in einer Tabellenzelle: die Nebeninformation
       („N: 9.489 | T: 1.00" in der Vorlage). Klein und grau, damit die
       Zeile trotzdem EINE Zeile bleibt. */
    .table .neben, .zeile-neben {
      display: block; font-size: var(--lumen-text-label); color: var(--lumen-muted);
    }

    /* --- Karten -------------------------------------------------------
       1px Linie, kleiner Radius, kein Schatten. Der Kartenkopf traegt
       eine sehr helle Flaeche statt Bootstraps Grau, damit er zur
       Systemfarbe gehoert und nicht daneben steht. */
    .card {
      border: 1px solid var(--lumen-line);
      border-radius: var(--lumen-radius-gross);
      box-shadow: none;
    }
    .card > .card-header {
      background-color: var(--lumen-primary-weich);
      border-bottom: 1px solid var(--lumen-line);
      font-weight: 600;
      font-size: .9375rem;
      padding: .6rem .9rem;
    }
    .card-body { padding: .9rem; }
    .card-body > h5:first-child, .card-body > h6:first-child {
      font-size: .9375rem; font-weight: 600; margin-bottom: .75rem;
    }

    /* --- Knöpfe -------------------------------------------------------
       Vier Rollen, wie im Komponentenblatt der Vorlage: gefuellt
       (die eine wichtigste Aktion), umrandet (alles Uebrige),
       gefaehrlich, textnah. Dazu Icon links/rechts/allein - dafuer
       genuegt hier ein gap, weil die Vorlagen das Symbol ohnehin als
       Geschwister des Textes setzen. */
    .btn {
      --bs-btn-border-radius: var(--lumen-radius);
      display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
      font-size: var(--lumen-text-klein);
      font-weight: 500;
      padding: .4rem .75rem;
      border-radius: var(--lumen-radius);
      line-height: 1.4;
    }
    .btn-sm { font-size: var(--lumen-text-label); padding: .3rem .55rem; }
    .btn-lg { font-size: 1rem; padding: .55rem 1.1rem; }
    .btn i { font-size: 1em; line-height: 1; }
    .btn-primary, .btn-lumen {
      border-color: var(--lumen-primary);
    }
    .btn-primary:hover, .btn-lumen:hover,
    .btn-primary:focus-visible, .btn-lumen:focus-visible {
      background-color: color-mix(in srgb, var(--lumen-primary) 86%, var(--lumen-ink)) !important;
      border-color: color-mix(in srgb, var(--lumen-primary) 86%, var(--lumen-ink));
      color: var(--lumen-on-primary) !important;
    }
    /* Der meistgenutzte Knopf der Anwendung (85 Vorkommen). Bootstraps
       Grau daneben liess jede Werkzeugleiste unbeteiligt wirken; jetzt
       nimmt er beim Ueberfahren die Systemfarbe an. */
    .btn-outline-secondary {
      --bs-btn-color: var(--lumen-ink);
      --bs-btn-border-color: var(--lumen-line);
      --bs-btn-hover-color: var(--lumen-primary-text);
      --bs-btn-hover-bg: var(--lumen-primary-weich);
      --bs-btn-hover-border-color: var(--lumen-primary-linie);
      --bs-btn-active-color: var(--lumen-primary-text);
      --bs-btn-active-bg: var(--lumen-primary-hell);
      --bs-btn-active-border-color: var(--lumen-primary-linie);
      background-color: var(--lumen-surface);
    }
    .btn-danger, .btn-outline-danger {
      --bs-btn-bg: var(--lumen-gefahr-text);
      --bs-btn-border-color: var(--lumen-gefahr-text);
      --bs-btn-hover-bg: color-mix(in srgb, var(--lumen-gefahr-text) 85%, var(--lumen-ink));
      --bs-btn-hover-border-color: color-mix(in srgb, var(--lumen-gefahr-text) 85%, var(--lumen-ink));
      --bs-btn-color: #FFFFFF;
      --bs-btn-hover-color: #FFFFFF;
    }
    .btn-outline-danger {
      --bs-btn-bg: transparent;
      --bs-btn-color: var(--lumen-gefahr-text);
      --bs-btn-border-color: var(--lumen-gefahr-linie);
    }
    .btn:disabled, .btn.disabled { opacity: .45; }
    .btn-group > .btn { border-radius: var(--lumen-radius); }

    /* --- Formulare ----------------------------------------------------
       Die Vorlage setzt die Beschriftung klein und grau ueber das Feld,
       den Pflichtstern in die Systemfarbe und die Fehlermeldung als rote
       Zeile darunter. Das ist keine Zier: eine fette schwarze
       Beschriftung wiegt schwerer als der Wert, den sie beschreibt. */
    .form-label {
      font-size: var(--lumen-text-label);
      font-weight: 500;
      color: var(--lumen-muted);
      margin-bottom: .25rem;
    }
    .form-label .pflicht, .form-label .required { color: var(--lumen-gefahr-text); }
    .form-control, .form-select {
      font-size: var(--lumen-text-klein);
      border-radius: var(--lumen-radius);
      border-color: var(--lumen-line);
      padding: .4rem .6rem;
    }
    .form-control:focus, .form-select:focus {
      border-color: var(--lumen-primary);
      box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--lumen-primary) 18%, transparent);
    }
    .form-control::placeholder { color: var(--lumen-muted); opacity: .75; }
    .form-text { font-size: var(--lumen-text-label); color: var(--lumen-muted); }
    .form-check-input:checked {
      background-color: var(--lumen-primary);
      border-color: var(--lumen-primary);
    }
    .form-check-input:focus {
      border-color: var(--lumen-primary);
      box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--lumen-primary) 18%, transparent);
    }
    .input-group-text {
      font-size: var(--lumen-text-klein);
      background-color: var(--lumen-neutral-flaeche);
      border-color: var(--lumen-line);
      color: var(--lumen-muted);
    }
    .is-invalid ~ .invalid-feedback, .invalid-feedback {
      font-size: var(--lumen-text-label); color: var(--lumen-gefahr-text);
    }

    /* --- Reiter -------------------------------------------------------
       Unterstrich statt Kaestchen. Ein Reiter, der als Kasten mit
       Rahmen gezeichnet wird, konkurriert mit den Karten darunter -
       auf der Fallakte standen so zwei Rahmenarten uebereinander. */
    .nav-tabs {
      border-bottom: 1px solid var(--lumen-line);
      gap: .25rem;
    }
    .nav-tabs .nav-link {
      border: none;
      border-bottom: 2px solid transparent;
      border-radius: 0;
      padding: .5rem .8rem;
      font-size: var(--lumen-text-klein);
      font-weight: 500;
      color: var(--lumen-muted);
    }
    .nav-tabs .nav-link:hover {
      border-bottom-color: var(--lumen-primary-linie);
      color: var(--lumen-primary-text);
      background-color: transparent;
    }
    .nav-tabs .nav-link.active {
      background-color: transparent;
      border-bottom-color: var(--lumen-primary);
      color: var(--lumen-primary-text);
      font-weight: 600;
    }
    .nav-pills .nav-link.active { background-color: var(--lumen-primary); color: var(--lumen-on-primary); }

    /* --- Listen, Menüs, Seitenzähler ---------------------------------- */
    .list-group-item { border-color: var(--lumen-line); font-size: var(--lumen-text-klein); }
    .list-group-item-action:hover { background-color: var(--lumen-primary-weich); }
    .list-group-item.active { background-color: var(--lumen-primary); border-color: var(--lumen-primary); color: var(--lumen-on-primary); }
    .dropdown-menu {
      border-color: var(--lumen-line);
      border-radius: var(--lumen-radius);
      box-shadow: 0 .5rem 1.5rem rgba(31, 35, 41, .10);
      font-size: var(--lumen-text-klein);
      padding: .3rem;
    }
    .dropdown-item { border-radius: var(--lumen-radius-klein); padding: .4rem .6rem; }
    .dropdown-item:active { background-color: var(--lumen-primary); color: var(--lumen-on-primary); }
    .dropdown-item:hover, .dropdown-item:focus { background-color: var(--lumen-primary-weich); }
    .dropdown-header {
      font-size: var(--lumen-text-label); text-transform: uppercase;
      letter-spacing: .05em; color: var(--lumen-muted);
    }
    .page-link { color: var(--lumen-primary-text); font-size: var(--lumen-text-klein); }
    .page-item.active .page-link { background-color: var(--lumen-primary); border-color: var(--lumen-primary); color: var(--lumen-on-primary); }

    /* --- Hinweise und Fortschritt ------------------------------------- */
    .alert {
      border-radius: var(--lumen-radius);
      border-width: 1px;
      font-size: var(--lumen-text-klein);
      padding: .6rem .85rem;
    }
    .alert-success { background-color: var(--lumen-erfolg-flaeche); border-color: var(--lumen-erfolg-linie); color: var(--lumen-erfolg-text); }
    .alert-danger { background-color: var(--lumen-gefahr-flaeche); border-color: var(--lumen-gefahr-linie); color: var(--lumen-gefahr-text); }
    .alert-warning { background-color: var(--lumen-warnung-flaeche); border-color: var(--lumen-warnung-linie); color: var(--lumen-warnung-text); }
    .alert-info, .alert-primary { background-color: var(--lumen-primary-weich); border-color: var(--lumen-primary-linie); color: var(--lumen-primary-text); }
    .alert-secondary, .alert-light { background-color: var(--lumen-neutral-flaeche); border-color: var(--lumen-neutral-linie); color: var(--lumen-neutral-text); }
    .progress { background-color: var(--lumen-neutral-flaeche); border-radius: 10rem; height: .375rem; }
    .progress-bar { background-color: var(--lumen-primary); }

    /* --- Modale Fenster ----------------------------------------------- */
    .modal-content { border: 1px solid var(--lumen-line); border-radius: var(--lumen-radius-gross); }
    .modal-header { border-bottom: 1px solid var(--lumen-line); padding: .8rem 1rem; }
    .modal-title { font-size: 1rem; font-weight: 600; color: var(--lumen-primary-text); }
    .modal-footer { border-top: 1px solid var(--lumen-line); padding: .7rem 1rem; }

    /* --- Text-Hilfsklassen aus Bootstrap -------------------------------
       .text-primary/.text-success und die Uebrigen zeigten bis hierher
       Bootstraps Palette. Eine gruene Oberflaeche mit blauem
       .text-primary daneben ist genau die Uneinheitlichkeit, die dieser
       Abschnitt beseitigen soll. */
    .text-primary { color: var(--lumen-primary-text) !important; }
    .text-success { color: var(--lumen-erfolg-text) !important; }
    .text-danger { color: var(--lumen-gefahr-text) !important; }
    .text-warning { color: var(--lumen-warnung-text) !important; }
    .text-info { color: var(--lumen-info-text) !important; }
    .text-secondary, .text-muted { color: var(--lumen-muted) !important; }
    .border-primary { border-color: var(--lumen-primary-linie) !important; }
    .bg-light { background-color: var(--lumen-neutral-flaeche) !important; }

    /* --- Dunkelmodus: was der Baukasten nachziehen muss -----------------
       Die Tokens erledigen fast alles (siehe --lumen-mischgrund). Hier
       bleibt nur, was auf einen festen hellen Wert zeigte. */
    [data-bs-theme="dark"] .btn-outline-secondary { background-color: transparent; }
    [data-bs-theme="dark"] .table { --bs-table-color: #E6E9ED; }
    [data-bs-theme="dark"] .dropdown-menu { box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .45); }
    [data-bs-theme="dark"] .input-group-text { color: var(--lumen-muted); }

    /* --- Nacharbeiten am Baukasten ------------------------------------ */

    /* Das Markenband geht in der Fassung "marke" ueber die VOLLE Breite,
       also auch ueber den Markenbereich der Seitenleiste hinweg. So ist
       es in der Vorlage, und es ist mehr als Geschmack: mit weissem
       Markenfeld neben gruener Kopfzeile hat die Seite oben zwei
       Streifen unterschiedlicher Farbe auf gleicher Hoehe, und das Auge
       sucht die Kante statt die Navigation. */
    /* Ein durchgehendes Band hat keine Naht. Die aufgehellte Trennlinie
       aus der hellen Fassung lief hier quer durch die Markenflaeche und
       endete an der Kante zur Kopfzeile - ein heller Strich ueber genau
       die Breite der Seitenleiste, der aussieht wie ein Fehler, weil er
       einer ist (Befund vom 27.08.: "Das ist nen weisser Strich, der
       sollte da net sein").

       Beide Kanten fallen weg, die des Markenfelds und die der
       Kopfzeile: die Farbe trennt hier schon, eine Linie zusaetzlich
       traegt nichts bei. */
    [data-shell="marke"] .app-sidebar-brand {
      background-color: var(--lumen-bar);
      border-bottom-color: transparent;
    }
    /* DIE SENKRECHTE TRENNLINIE ENTFAELLT IN DIESER FASSUNG.

       Sie gehoert zur Seitenleiste und laeuft ueber deren ganze Hoehe -
       also mitten durch das Markenband, wo sie als heller Strich
       zwischen Marke und Kopfzeile stand. Gemeldet als "das muss
       durchgehen. Das ist 'n Fehler."

       Der erste Anlauf hat versucht, sie am Markenfeld zu ueberdecken
       (box-shadow in Bandfarbe). Das griff nicht: .app-sidebar traegt
       overflow-y:auto, und ein Schatten, der ueber die Elementkante
       hinausragt, wird davon abgeschnitten. Eine Linie ueberdecken zu
       wollen, die man auch weglassen kann, war ohnehin der Umweg.

       Getrennt wird hier schon durch die Farbe: die Leiste ist weiss,
       die Arbeitsflaeche daneben getoent (--lumen-canvas). In den
       Fassungen "hell" und "dunkel" bleibt die Linie, dort steht kein
       Band darueber.
       Und sie muss WEG sein, nicht durchsichtig: ein transparenter
       Rahmen belegt weiterhin sein Pixel, und dort scheint der
       Untergrund der Seitenleiste durch - in dieser Fassung also Weiss,
       neben dem gruenen Band. Genau dieser eine Pixel war der gemeldete
       Strich; "border-right-color: transparent" hat ihn nicht beseitigt,
       sondern nur die Farbe des Rahmens gegen die des Untergrunds
       getauscht. */
    [data-shell="marke"] .app-sidebar { border-right: none; }
    [data-shell="marke"] .app-topbar { border-bottom-color: transparent; }
    [data-shell="marke"] .app-sidebar-brand .app-sidebar-brand-name { color: var(--lumen-bar-strong); }
    [data-shell="marke"] .app-sidebar-close { color: var(--lumen-bar-text); }

    /* Ein Abzeichen bleibt ein Abzeichen. Die Statuszeile der Fallakte
       traegt im Markup fs-6 (= 1rem !important) und war damit als
       einziges Abzeichen der Anwendung so gross wie Fliesstext - genau
       der Klotz, den die Vereinheitlichung beseitigen soll. Etwas
       groesser als in einer Tabellenzeile darf es sein, es ist die
       Hauptaussage der Seite; 1rem ist es nicht.

       Als Regel und nicht als Aenderung an cases/sterbefall_detail.html:
       greift auch fuer die naechste Vorlage, die fs-6 an ein Abzeichen
       schreibt. */
    .badge.fs-6, .badge.fs-5 {
      font-size: var(--lumen-text-klein) !important;
      padding: .3em .6em;
    }

    /* Beschreibungslisten (dl.row) sind das Label-Wert-Muster dieser
       Anwendung - allein die Fallakte hat gut zwanzig davon. Bootstrap
       setzt dt auf 700, damit wog die Beschriftung schwerer als der
       Wert daneben. In der Vorlage ist es umgekehrt. */
    dl.row > dt {
      font-size: var(--lumen-text-klein);
      font-weight: 500;
      color: var(--lumen-muted);
    }
    dl.row > dd { font-size: var(--lumen-text-klein); margin-bottom: .35rem; }

    /* --- Tastaturnavigation --------------------------------------------
       „Man muss sich leicht durchnavigieren koennen." Ohne sichtbaren
       Fokus gilt das nur fuer die Maus: Chromiums Standardring ist auf
       gefuellten Flaechen kaum zu sehen, und an mehreren Stellen war er
       durch eigene Regeln ganz weg. Ein Ring in der Systemfarbe,
       ueberall gleich, mit Abstand zum Element - damit er auch auf einem
       gefuellten Knopf sichtbar bleibt.

       :focus-visible und nicht :focus: ein Mausklick soll keinen Ring
       hinterlassen, ein Tabulatorsprung schon. Das entscheidet der
       Browser, und er entscheidet es besser als eine eigene Heuristik. */
    a:focus-visible, button:focus-visible, .btn:focus-visible,
    .form-control:focus-visible, .form-select:focus-visible,
    .nav-link:focus-visible, .dropdown-item:focus-visible,
    .list-group-item-action:focus-visible, .app-sidebar-link:focus-visible,
    [tabindex]:focus-visible {
      outline: 2px solid var(--lumen-primary);
      outline-offset: 2px;
      border-radius: var(--lumen-radius-klein);
    }
    /* Auf dem Markenband hat die Systemfarbe keinen Kontrast zu sich
       selbst - dort ist der Ring die Textfarbe der Leiste. */
    .app-topbar a:focus-visible, .app-topbar button:focus-visible,
    [data-shell="marke"] .app-sidebar-brand a:focus-visible {
      outline-color: var(--lumen-bar-strong);
    }

    /* Der Sprung an den Inhalt vorbei an der Navigation. Sichtbar erst
       beim Tabulator - er ist fuer Tastatur und Screenreader da, nicht
       als Knopf fuer alle. */
    .lumen-sprunglink {
      position: absolute; left: .5rem; top: -3rem; z-index: 1100;
      background-color: var(--lumen-primary); color: var(--lumen-on-primary);
      padding: .5rem .9rem; border-radius: var(--lumen-radius);
      font-size: var(--lumen-text-klein); font-weight: 600; text-decoration: none;
      transition: top .12s ease;
    }
    .lumen-sprunglink:focus { top: .5rem; color: var(--lumen-on-primary); }

    /* Abschnittsueberschriften in Formularen und Detailansichten
       (.detail-abschnitt, .modal-body h6, .form-abschnitt) waren bisher
       klein, grau und in Grossbuchstaben - und die Feldbeschriftungen
       daneben nach dem ersten Wurf dieses Durchgangs ebenfalls. Damit
       sahen Gruppe und Feld gleich aus, und die Gliederung eines langen
       Formulars war nur noch an der Trennlinie zu erkennen.

       Aufgeloest wurde es an der ANDEREN Stelle: die Feldbeschriftung
       ist jetzt normal geschrieben (so auch in der Vorlage), die
       Abschnittsueberschrift behaelt ihre Grossbuchstaben. Damit tragen
       beide dieselbe Farbe und Groesse und sind trotzdem auf einen Blick
       zu unterscheiden - ohne dass irgendwo eine zweite Farbe noetig
       waere. */
    .detail-abschnitt, .modal-body h6, .modal-body .form-abschnitt,
    .form-abschnitt {
      font-size: var(--lumen-text-label);
      letter-spacing: .06em;
    }

    /* ==================================================================
       INLINE-KARTEN (Auftrag vom 27.08.2026)
       ==================================================================
       „mach da Felder rein wo ich sofort rein schreiben kann und ich
        immer nach jeder Aenderung auf Speichern klicken muss, also ich
        kann aendern wie ich will aber ohne auf Speichern zu klicken geht
        es alles verschwunden."

       Der Fussbereich ist die Antwort auf die zweite Haelfte des Satzes.
       Er klebt am unteren Rand des Fensters, solange die Karte laenger
       ist als der Bildschirm - das Stammdatenformular hat rund vierzig
       Felder, und ein Speichern-Knopf, den man erst herunterscrollen
       muss, ist bei „ohne Speichern ist alles weg" die falsche Bauart.
       Im Modal loest .modal-body .lumen-modal-footer dasselbe Problem;
       hier scrollt die SEITE, deshalb position: sticky am Fussbereich
       selbst statt am Container.
       ================================================================== */
    .lumen-inline-footer {
      position: sticky; bottom: 0; z-index: 3;
      display: flex; align-items: center; justify-content: flex-end;
      gap: .5rem; flex-wrap: wrap;
      margin-top: 1.5rem; padding: .85rem 0;
      border-top: 1px solid var(--lumen-line);
      background-color: var(--lumen-surface);
    }
    /* Der Hinweis steht LINKS und die Knoepfe rechts: er beschreibt einen
       Zustand, sie sind Aktionen - stuenden sie nebeneinander, laese man
       den Hinweis als Beschriftung des Knopfes daneben. */
    .lumen-inline-hinweis {
      margin-right: auto;
      font-size: var(--lumen-text-klein);
      font-weight: 600;
      color: var(--lumen-warnung-text);
      display: inline-flex; align-items: center; gap: .35rem;
    }
    /* Eine Karte mit ungespeicherten Aenderungen bekommt eine Kante in
       der Warnfarbe. Kein Hintergrund und kein Schatten: die Karte steht
       voller Eingabefelder, und ein eingefaerbter Grund darunter macht
       genau die schlechter lesbar. Die Warnfarbe ist eine der fuenf
       Statusfarben und wandert deshalb ausdruecklich NICHT mit der
       Systemfarbe mit (siehe die Regeln des Baukastens oben). */
    .lumen-inline-karte.ist-geaendert {
      border-color: var(--lumen-warnung-linie);
      box-shadow: inset 3px 0 0 0 var(--lumen-warnung-text);
    }
    /* Das Tastenkuerzel steht IM Knopf und nicht daneben: es ist keine
       zweite Aktion, sondern der zweite Weg zu derselben. Auf schmalen
       Schirmen faellt es weg - dort gibt es keine Strg-Taste, und ein
       Hinweis auf eine Taste, die niemand hat, ist Betrieb. */
    .lumen-inline-kuerzel {
      font-size: var(--lumen-text-label);
      padding: .05em .35em;
      border-radius: var(--lumen-radius-klein);
      background-color: color-mix(in srgb, var(--lumen-on-primary) 18%, transparent);
      color: inherit;
      font-weight: 500;
    }
    /* Das Verwerfen-X ist die Nebenhandlung und traegt deshalb kein Wort.
       Es steht RECHTS vom Speichern-Knopf, weil es das Gegenstueck zum
       Schliessen-X eines Fensters ist - und dort sucht man es. */
    .lumen-inline-verwerfen { line-height: 1; padding-left: .5rem; padding-right: .5rem; }
    @media (max-width: 575.98px) {
      .lumen-inline-footer { flex-wrap: wrap; }
      .lumen-inline-hinweis { margin-right: 0; width: 100%; justify-content: center; }
      .lumen-inline-kuerzel { display: none; }
    }

    /* ------------------------------------------------------------------
       VORSCHLAGSLISTEN LEGEN SICH UEBER DIE SEITE (v0.6.3)

       GEMELDET WURDE: "das Problem ist, es passiert halt, dass die
       Staatsangehoerigkeit und der Familienstand uebelst nach unten
       rutschen, weil dieses Fenster sich oeffnet."

       Die Liste aus static/js/feld-vorschlaege.js war ein gewoehnlicher
       Block im Formularfluss. Ihr Elternelement bekam zwar
       position:relative, aber die Liste selbst blieb im Fluss und schob
       alles darunter weg - bei der Konfession also genau die beiden
       Felder daneben.

       Das Gegenstueck in static/js/directory-search.js hatte die Regel
       von Anfang an, allerdings INLINE im Template
       (common/templates/common/_verzeichnis_suchfeld.html). Sie steht
       jetzt hier fuer beide: zwei Listen, die sich unter den Fingern
       gleich anfuehlen sollen, duerfen nicht zwei Fassungen derselben
       Geometrie haben.

       z-index 1090: ueber dem Formular, aber unter Bootstraps Modal
       (1055) waere zu wenig - die Felder stehen selbst in Modalen. Der
       Wert ist derselbe, den das Verzeichnis-Suchfeld schon benutzt hat.
       ------------------------------------------------------------------ */
    .feld-vorschlaege {
      position: absolute;
      z-index: 1090;
      left: 0;
      right: 0;
      margin-top: .125rem;
      max-height: 240px;
      overflow-y: auto;
    }
    /* Der markierte Eintrag der Tastaturbedienung. Bootstrap faerbt
       .active in der Systemfarbe ein; hier steht nur, was Bootstrap
       nicht mitbringt - ein sichtbarer Rand, damit die Markierung auch
       bei hoher Kontrasteinstellung erkennbar bleibt. */
    .feld-vorschlaege .feld-vorschlag-aktiv,
    .directory-search-results .directory-search-active {
      outline: 2px solid var(--lumen-accent);
      outline-offset: -2px;
    }
    .directory-search-results {
      position: absolute;
      z-index: 1090;
      left: 0;
      right: 0;
      margin-top: .125rem;
      max-height: 240px;
      overflow-y: auto;
    }

    /* ------------------------------------------------------------------
       DIE VORLAGENZEILE IM FENSTER "Dokumente erzeugen" (v0.6.8)

       Gemeldet: "dann auch die Sternchen so passend leider nicht. Also
       das ist nicht alles perfekt in einer Reihe."

       Die Zeile besteht aus ZWEI Knoepfen (cases/_vorlage_zeile.html):
       links ein .list-group-item-action, rechts der Stern. Das ist kein
       Versehen, sondern Absicht - ein <button> in einem <button> ist
       kein gueltiges HTML, der Browser bricht das aeussere davor ab.

       Nur sahen die beiden Haelften nicht wie eine Zeile aus: das
       .list-group-item bringt seine eigene Polsterung und seinen eigenen
       Hover mit, der Stern als .btn-link seine eigenen - beim Ueberfahren
       leuchtete die linke Haelfte auf und die rechte blieb, wo sie war,
       und der Stern sass auf einer anderen Grundlinie.

       Geloest wird das an der ZEILE und nicht an den beiden Knoepfen:
       die Flaeche traegt den Hover, die Knoepfe geben ihren ab. Der
       Stern bekommt ausserdem eine FESTE Spalte - ohne sie richtet er
       sich am Textende aus, und in einer Liste mit verschieden langen
       Vorlagennamen steht er dann in jeder Zeile woanders. */
    .lumen-vorlagenzeile {
      border-radius: var(--lumen-radius, .375rem);
    }
    .lumen-vorlagenzeile:hover,
    .lumen-vorlagenzeile:focus-within {
      background-color: var(--lumen-primary-weich);
    }
    /* Die beiden Knoepfe geben ihren eigenen Hover ab - sonst faerbte
       sich beim Ueberfahren nur die Haelfte, ueber der der Zeiger steht. */
    .lumen-vorlagenzeile .list-group-item-action:hover,
    .lumen-vorlagenzeile .list-group-item-action:focus {
      background-color: transparent;
    }
    .lumen-vorlagenzeile .list-group-item {
      background-color: transparent;
      border: 0;
    }
    /* Die feste Sternspalte. Breite in rem und nicht in Prozent: sie
       richtet sich am Symbol aus, nicht an der Fensterbreite. */
    .lumen-vorlagenzeile-stern {
      flex: 0 0 2.25rem;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
    }
    /* Die Favoritengruppe blendet sich ueber das Attribut aus (v0.6.8).
       `[hidden]` steht nur im Browser-Stylesheet und verliert gegen jede
       Autorenregel mit `display` - hier gaebe es zwar keine, aber die
       Gruppe traegt Bootstrap-Klassen und bekommt beim naechsten
       Umbau leicht eine. Die Regel dazuzuschreiben kostet nichts; sie zu
       vergessen kostete in v0.6.7 einen Browser-Durchlauf. */
    [data-favoriten-gruppe][hidden] { display: none; }

    /* ==================================================================
       SCHMALE UND MITTLERE FENSTER (v0.6.11, Auftrag §6.1 und §6.3)
       ==================================================================
       „Die Anwendung muss auf dem Handy ohne Einschraenkungen bedienbar
        sein ... Design muss auf dem Handy sauber aussehen, nicht nur
        funktionieren" und „13 Zoll: alle Hauptansichten muessen bei
        1280, 1024 und 768 Pixeln brauchbar sein."

       WARUM DIESER ABSCHNITT UEBERHAUPT NOETIG WAR. Das Stylesheet hatte
       dreizehn @media-Bloecke und darin genau vier Grenzen: 575.98 (sm),
       991.98 (lg), 1199.98 (xl) und 1400 (xxl). Die md-Grenze bei 767.98
       kam NIRGENDS vor - zwischen 576 und 992 Pixeln war schlicht nichts
       geregelt. Genau dort liegen das Tablet und das schmale Fenster auf
       einem 13-Zoll-Schirm, und dort standen die breiten Listen als
       Querscroller.

       DIE VIER GRENZEN, mit denen dieser Abschnitt arbeitet - es sind
       weiterhin die Bootstrap-Grenzen und keine eigenen, damit die
       d-*-Klassen der 147 Vorlagen dieselbe Aussage treffen wie das
       Stylesheet:

         bis  767.98  Handy und schmales Tablet: Listen werden zu Karten
         bis  991.98  Seitenleiste ist Off-Canvas (Bestand, unveraendert)
         bis 1199.98  mittlere Breiten: Seitenleiste startet eingeklappt
                      (die Entscheidung faellt in static/js/sidebar.js,
                      weil sie einen gemerkten Zustand kennt)
         ab  1200     unveraendert

       UND WARUM ALS BAUKASTEN-REGEL UND NICHT JE LISTE: dieselbe
       Ueberlegung wie am Kopf des Baukastens weiter oben. Es gibt rund
       zwanzig Listen mit .table-responsive; eine Regel an dieser einen
       Stelle erfasst sie alle - auch die, die einem anderen Verzeichnis
       gehoeren, und auch die naechste, die jemand schreibt.
       ================================================================== */

    /* Der waagerechte Ueberlauf des Dokuments ist der Messpunkt fuer
       „sauber auf dem Handy". Hier steht deshalb KEIN overflow-x:hidden
       am Rumpf: das versteckt einen Ueberlauf, statt ihn zu vermeiden,
       und es macht den umschliessenden Kasten zum Scrollcontainer -
       damit stuende der klebende Fussbereich der Inline-Karten
       (.lumen-inline-footer, siehe oben) auf dem Handy nicht mehr am
       Fensterrand, sondern irgendwo im Inhalt. Stattdessen: die Spalte
       neben der Seitenleiste darf nicht breiter werden als das Fenster,
       und breite Inhalte bekommen weiter unten ihre eigene Loesung. */
    .app-content { max-width: 100%; }
    .app-content > main { min-width: 0; max-width: 100%; }

    /* ------------------------------------------------------------------
       LISTEN WERDEN AUF SCHMALEN SCHIRMEN ZU KARTEN

       Ausgeloest wird das an ZWEI Stellen, und beide sagen dasselbe:

         .table-karten          - ausdruecklich so ausgezeichnet,
         .table-responsive > .table - der Bestandsmarker fuer „diese
                                  Tabelle ist breiter als ihr Platz".
                                  Genau diese Tabellen sind gemeint; wer
                                  .table-responsive schreibt, sagt bereits,
                                  dass hier sonst quer gescrollt wuerde.

       .table-fest ist der Ausstieg fuer den Fall, dass eine Tabelle eine
       MATRIX ist und ihre Zeilen einzeln nichts bedeuten. Im Bestand
       braucht ihn niemand: die eine Matrix dieser Anwendung, die
       Rechtematrix der Rollenverwaltung, traegt aus einem anderen Grund
       schon kein .table-responsive (siehe accounts/rolle_form.html -
       dessen overflow-x haette den klebenden Spaltenkopf ausgehebelt).
       Der Ausstieg steht trotzdem hier, weil die naechste Matrix sonst
       eine zweite Regel braeuchte statt eines Wortes im Markup.

       :is() fasst beide Ausloeser zusammen, damit die Regel einmal
       dasteht. Ohne wuerde jeder der folgenden acht Selektoren doppelt
       geschrieben, und zwei Fassungen derselben Geometrie laufen
       auseinander (dieselbe Ueberlegung wie bei den Vorschlagslisten
       weiter oben).
       ------------------------------------------------------------------ */
    @media (max-width: 767.98px) {
      /* Der Spaltenkopf wird nicht geloescht, sondern nur aus dem Bild
         genommen: er ist die Beschriftung, die td[data-label] unten
         wieder einsetzt, und fuer Screenreader bleibt die Tabelle damit
         eine Tabelle. display:none naehme sie auch denen weg. */
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > thead {
        position: absolute; width: 1px; height: 1px;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
      }
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)),
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody,
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr,
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr > td {
        display: block;
        width: 100%;
      }
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr {
        border: 1px solid var(--lumen-line);
        border-radius: var(--lumen-radius);
        background-color: var(--lumen-surface);
        margin-bottom: .6rem;
        padding: .35rem 0;
      }
      /* Beschriftung links, Wert rechts - und beide auf einer Zeile,
         solange sie passen. Eine Zelle ohne data-label traegt keine
         Beschriftung und nimmt die volle Breite: das ist der Fall der
         Aktionsspalte und der Leerzustandszeile. */
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr > td {
        display: flex;
        gap: .75rem;
        align-items: baseline;
        justify-content: space-between;
        border-bottom: none;
        padding: .3rem .75rem;
        text-align: left;
        overflow-wrap: anywhere;
      }
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr > td[data-label]::before {
        content: attr(data-label);
        flex: 0 0 8rem;
        font-size: var(--lumen-text-label);
        color: var(--lumen-muted);
      }
      /* Die Aktionsspalte ist die letzte Zeile der Karte und traegt ihre
         Knoepfe rechts - dort, wo sie in der Tabelle auch stehen. */
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr > td.text-end {
        justify-content: flex-end;
        flex-wrap: wrap;
        gap: .35rem;
        padding-top: .5rem;
      }
      /* Die Leerzustandszeile spannt ueber alle Spalten und ist keine
         Karte, sondern eine Aussage. Ohne diese Zeile bekaeme sie den
         Kartenrahmen einer Zeile, die es gar nicht gibt. */
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) > tbody > tr:has(> td[colspan]) {
        border: none;
        background-color: transparent;
      }
      /* Fingergrosse Ziele. In der Tabellenzeile sind das kleine
         Symbolknoepfe nebeneinander; als Karte stehen sie einzeln da und
         werden mit dem Daumen getroffen. */
      :is(.table-karten:not(.table-fest), .table-responsive > .table:not(.table-fest)) .btn-sm {
        min-height: 2.25rem;
        min-width: 2.25rem;
      }
    }

    /* ------------------------------------------------------------------
       WAS AUF DEM HANDY SONST NOCH ZU ENG WIRD
       ------------------------------------------------------------------ */
    @media (max-width: 767.98px) {
      /* Reiterleisten (Stammdaten, Fallakte) rollen in SICH, statt die
         Seite breiter zu machen. Umbrechen waere die Alternative - dann
         steht die Fallakte auf dem Handy mit vier Reiterzeilen da, bevor
         der Inhalt anfaengt. */
      .nav-tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: thin;
      }
      .nav-tabs .nav-link { white-space: nowrap; }
      /* Ein Menue darf nie breiter sein als das Fenster: Bootstrap setzt
         es mit position:absolute, es traegt also nicht von selbst zum
         Ueberlauf des Rumpfes bei - wohl aber, sobald es offen ist. */
      .dropdown-menu { max-width: calc(100vw - 1rem); }
      /* Lange E-Mail-Adressen und Aktenzeichen sind der haeufigste Grund
         fuer einen zu breiten Kasten. */
      .card-body, .list-group-item, dl.row > dd { overflow-wrap: anywhere; }
      .card-body { padding: .75rem; }
      .seiten-kopf { margin-bottom: 1rem; }
      .pagination { flex-wrap: wrap; }
      /* Das Off-Canvas-Menue nimmt fast die ganze Breite und bekommt
         hoehere Zeilen: es wird mit dem Daumen bedient, nicht mit dem
         Zeiger. Die Breite in min() und nicht fest, damit auf einem
         320px-Schirm der Streifen daneben (zum Zumachen) bleibt. */
      .app-sidebar { width: min(86vw, 20rem); }
      .app-sidebar-link { padding: .7rem .8rem; min-height: 2.75rem; }
    }

    /* ------------------------------------------------------------------
       MITTLERE BREITEN (bis 1199.98 - 13 Zoll, halbierter grosser Schirm)
       ------------------------------------------------------------------ */
    @media (max-width: 1199.98px) {
      /* Das Suchfeld nimmt ab 992px seine 22rem und drueckt bei 1024px
         die Bereichsanzeige aus der Zeile. Es darf hier kleiner starten;
         geoeffnet wird es ohnehin erst per Lupe. */
      .app-topbar #global-search-input { flex: 0 1 16rem; width: 16rem; }
    }

    /* ------------------------------------------------------------------
       DER ORDNERBAUM DER FORMULARLISTEN (Auftrag §6.3)

       Er stand in einer Spalte, die unterhalb von lg auf volle Breite
       ging und die eigentliche Liste damit unter den Bildschirmrand
       schob. Er klappt jetzt zu und wird ueber seinen Kopf wieder
       geoeffnet - Bootstraps eigenes .collapse, kein zweiter
       Mechanismus, und ab lg schaltet .d-lg-block ihn dauerhaft auf.
       ------------------------------------------------------------------ */
    .lumen-ordner-klapper[aria-expanded="true"] i { transform: rotate(180deg); }
    .lumen-ordner-klapper i { transition: transform .15s ease; }

    /* ------------------------------------------------------------------
       DAS DREI-PUNKTE-MENUE (Auftrag §6.4)

       Gemeldet: „das Menue ist zu schmal, die Beschriftungen werden
       abgeschnitten." Bootstraps .dropdown-menu startet bei 10rem, und
       Eintraege wie „Fallakte einlesen" oder „Als JSON exportieren"
       stehen darin auf der Kante.

       Angesetzt wird an der MENUEART und nicht an einer eigenen Klasse:
       .dropdown-menu-end ist das rechtsbuendig geoeffnete Aktionsmenue
       (Drei-Punkte-Menues, Benutzermenue, Glocke) - also genau die
       Menues mit Beschriftungen. Die Vorschlagslisten der Suche sind
       KEINE .dropdown-menu (#search-results-dropdown ist eine
       .list-group, .feld-vorschlaege und .directory-search-results haben
       ihre eigenen Regeln weiter oben) und bleiben unberuehrt. */
    .dropdown-menu-end { min-width: 13rem; }
    /* Bootstrap setzt .dropdown-item auf nowrap. Ein langer Eintrag
       macht das Menue dadurch beliebig breit - auf dem Handy breiter als
       das Fenster. Umbrechen statt abschneiden ist die einzige Fassung,
       die auf beiden Schirmgroessen dasselbe Wort zeigt. */
    .dropdown-menu-end .dropdown-item { white-space: normal; }

/* Der Ansichtsumschalter Liste/Board/Archiv nimmt auf dem Handy die volle
   Breite (v0.6.11, Auftrag 6.4). Gemeldet war, dass er "nach rechts weg
   rutscht" - .seiten-kopf bricht zwar um, aber drei Symbolknoepfe von je
   knapp zwei Zentimetern am rechten Rand einer umgebrochenen Zeile sind
   mit dem Daumen schlecht zu treffen. Volle Breite und gleiche Anteile
   machen daraus drei Flaechen, die man nicht zielen muss.

   Die Klasse sitzt am Fragment cases/_ansicht_umschalter.html und damit
   an EINER Stelle fuer alle drei Ansichten - dieselbe Ueberlegung, aus
   der das Fragment ueberhaupt entstanden ist (Plan v0.4.4, E26). */
@media (max-width: 767.98px) {
  .lumen-ansicht-umschalter {
    width: 100%;
  }

  .lumen-ansicht-umschalter .btn {
    flex: 1 1 0;
    min-height: 2.5rem;
  }
}
