/* ==========================================================================
   Breuer App — Design-System
   Aufbau und Formensprache nach dtf-express-hub: alles Bedienbare in der
   Seitenleiste (Navigation oben, Nutzer-Card unten), Seitentitel im Inhalt,
   weiche Radien (8 px an Bedienelementen, 16 px an Karten), eine humanistische
   Sans in normaler Schreibweise — keine Versalien, keine gesperrte Laufweite.
   Farben: hellgraue Flaeche, weisse Karten, Schrift #212121. Blau (#009cd8,
   dominante Logo-Farbe) ausschliesslich als Akzent.
   ========================================================================== */

:root {
    /* Akzent — nur fuer Aktionen, aktive Zustaende und Hervorhebungen.

       Die drei Toene kommen seit Feedback #13114 aus einem PRESET
       (`html[data-akzent="…"]`, weiter unten); was hier steht, ist der
       Auslieferungszustand „Breuer-Blau" und zugleich die Rueckfallebene
       fuer den Fall, dass gar kein Akzent gesetzt ist.

       ⚠️ `--accent-rgb` ist das Tripel OHNE `rgb()` drumherum. Nur damit
       lassen sich `--accent-soft` und `--accent-line` EINMAL definieren
       statt in jedem Preset erneut — und nur damit folgt der Farbverlauf
       des Glas-Themas dem gewaehlten Akzent, statt blau zu bleiben. */
    --accent-rgb: 0, 156, 216;
    --accent: #009cd8;
    --accent-bright: #18a9d9;
    --accent-dark: #0079a8;
    --accent-soft: rgba(var(--accent-rgb), 0.10);
    --accent-line: rgba(var(--accent-rgb), 0.30);

    /* Signalfarben (Verlauf im Logo-Signet) — sparsam fuer Status */
    --signal-orange: #e8850a;
    --signal-red: #c1391b;
    --signal-green: #2f8f57;

    /* Flaechen — Hellgrau und Rahmen aus dohmen-sensorview
       (Tailwind primary-50 / primary-100), damit die Apps gleich wirken. */
    --bg: #f5f7f8;
    --surface: #ffffff;
    --surface-hover: #eef1f2;
    --border: #e8ecee;
    --border-strong: #d2d9dc;
    /* ⚠️ Dieselben Flaechen, aber DECKEND — und bewusst so benannt, dass
       das Glas-Thema sie nicht anfasst. Die Vorschau-Kacheln im Waehler
       „Darstellung" (Feedback #13114) brauchen sie: die Kachel „Standard"
       muss deckend aussehen, auch waehrend die App gerade glasig ist. */
    --paper: #ffffff;
    --paper-line: #e8ecee;

    /* Text */
    --text: #212121;
    --text-muted: #5c5c5c;
    /* 4.9:1 auf Weiss — der kleine Text bleibt lesbar */
    --text-dim: #6f6f6f;

    /* Struktur */
    --sidebar-w: 256px;   /* w-64 */
    /* Breite der EINGEFAHRENEN Leiste (Feedback #13098). 72 px ist die
       Zahl aus der pvwebapp (`COLLAPSED_WIDTH` in `MiniDrawer.js`) — sie
       traegt ein 32-px-Symbol mit Luft und laesst in der Nutzer-Card zwei
       davon nebeneinander. */
    --sidebar-rail: 72px;
    /* wie dtf-express: rounded-lg an Bedienelementen, rounded-2xl an Karten */
    --radius: 8px;
    --radius-lg: 16px;

    /* Systemschrift wie dtf-express — bewusst kein Webfont */
    --font-body: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto,
                 sans-serif;

    --shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.05);
}

/* ==========================================================================
   Erscheinungsbild — Akzentfarbe und Hintergrund (Feedback #13114)
   ==========================================================================
   Zwei weitere Achsen neben dem Thema, nach dem Vorbild der pvwebapp
   (`styles/appearance.css@release`: je Wert ein Preset-Block, der nur
   Variablen setzt). Vier Entscheidungen tragen den Abschnitt:

   1. **Nur VARIABLEN, keine zweite Kopie der Regeln.** Dieselbe Bauart wie
      `--glas`/`--glanz`/`--flaeche` beim Glas-Thema und aus demselben
      Grund: was ueber die Variablen laeuft, faellt in jede Rueckfallebene
      mit — Druck, `prefers-reduced-transparency`, alte Browser.
   2. **Ein Preset faerbt zugleich seine VORSCHAU.** Jeder Block gilt fuer
      `html[data-akzent="x"]` UND fuer `.swatch--x` bzw. `.ground--x`. Der
      Farbkreis im Waehler zeigt damit buchstaeblich dieselben Werte, die
      er waehlt; eine Vorschau mit eigenen Hexwerten liefe beim naechsten
      Nachschaerfen davon weg.
   3. **Der Block steht VOR dem Glas-Thema.** `html[data-grund="…"]` und
      `html[data-thema="glass"]` haben dieselbe Spezifitaet — bei
      Gleichstand entscheidet die Reihenfolge. So bleiben die Flaechen im
      Glas durchscheinend, und der Hintergrund faerbt das, was durch sie
      hindurch zu sehen ist. Umgedreht waere Glas kein Glas mehr.
   4. **Alle Hintergruende sind HELL.** Die drei dunklen der pvwebapp sind
      bewusst nicht mitgekommen — Begruendung in `app/appearance.py`.
   ========================================================================== */

/* --- Akzentfarben ---------------------------------------------------------
   `--accent-dark` traegt Text auf hellem Grund (Links, Abzeichen) und liegt
   bei allen acht ueber 4,8:1. `--accent` traegt WEISSE Schrift; die
   schwaechste erlaubte Paarung ist das Logo-Blau mit 3,11:1 — ein neuer Ton
   wird also nie heller gewaehlt als dieser.
   -------------------------------------------------------------------------- */

html[data-akzent="blau"],
.swatch--blau {
    --accent-rgb: 0, 156, 216;
    --accent: #009cd8;
    --accent-bright: #18a9d9;
    --accent-dark: #0079a8;
}

html[data-akzent="petrol"],
.swatch--petrol {
    --accent-rgb: 13, 127, 140;
    --accent: #0d7f8c;
    --accent-bright: #258c98;
    --accent-dark: #0a636d;
}

html[data-akzent="marine"],
.swatch--marine {
    --accent-rgb: 31, 78, 140;
    --accent: #1f4e8c;
    --accent-bright: #356098;
    --accent-dark: #183d6d;
}

html[data-akzent="indigo"],
.swatch--indigo {
    --accent-rgb: 76, 81, 191;
    --accent: #4c51bf;
    --accent-bright: #5e62c5;
    --accent-dark: #3b3f95;
}

html[data-akzent="violett"],
.swatch--violett {
    --accent-rgb: 109, 84, 224;
    --accent: #6d54e0;
    --accent-bright: #7c65e3;
    --accent-dark: #5542af;
}

html[data-akzent="beere"],
.swatch--beere {
    --accent-rgb: 181, 70, 138;
    --accent: #b5468a;
    --accent-bright: #bc5896;
    --accent-dark: #8d376c;
}

html[data-akzent="terra"],
.swatch--terra {
    --accent-rgb: 209, 96, 47;
    --accent: #d1602f;
    --accent-bright: #d67044;
    --accent-dark: #a34b25;
}

html[data-akzent="graphit"],
.swatch--graphit {
    --accent-rgb: 74, 85, 104;
    --accent: #4a5568;
    --accent-bright: #5c6677;
    --accent-dark: #3a4251;
}

/* --- Hintergruende --------------------------------------------------------
   `hellgrau` ist der Ton, mit dem die App angefangen hat — er steht hier
   ausgeschrieben und nicht als „nichts tun", damit auch seine Kachel im
   Waehler eine Vorschau hat.

   Im Glas-Thema wirkt von diesen Bloecken nur `--bg`: die uebrigen Flaechen
   sind dort durchscheinend (Punkt 3 oben). Genau so ist es gemeint — der
   Hintergrund ist das, was durch das Glas hindurch zu sehen ist.
   -------------------------------------------------------------------------- */

html[data-grund="hellgrau"],
.ground--hellgrau {
    --bg: #f5f7f8;
    --surface: #ffffff;
    --surface-hover: #eef1f2;
    --border: #e8ecee;
    --border-strong: #d2d9dc;
    --paper: #ffffff;
    --paper-line: #e8ecee;
}

html[data-grund="schnee"],
.ground--schnee {
    --bg: #fbfcfd;
    --surface: #ffffff;
    --surface-hover: #f1f4f6;
    --border: #e9edf0;
    --border-strong: #d5dbe0;
    --paper: #ffffff;
    --paper-line: #e9edf0;
}

html[data-grund="sand"],
.ground--sand {
    --bg: #faf5ec;
    --surface: #fffdf9;
    --surface-hover: #f4ede0;
    --border: #ece3d3;
    --border-strong: #d8ccb6;
    --paper: #fffdf9;
    --paper-line: #ece3d3;
}

html[data-grund="nebel"],
.ground--nebel {
    --bg: #eceff3;
    --surface: #ffffff;
    --surface-hover: #e6eaef;
    --border: #e0e5ea;
    --border-strong: #cbd2da;
    --paper: #ffffff;
    --paper-line: #e0e5ea;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* Muss nach den Komponenten-Regeln greifen: `display: flex` einer Klasse
   schlaegt sonst das `hidden`-Attribut, und Modal wie Menue-Hintergrund
   stuenden beim Laden offen. */
[hidden] {
    display: none !important;
}

html,
body {
    margin: 0;
    padding: 0;
}

body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 14px;
    line-height: 22px;
    -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
    font-weight: 700;
    margin: 0;
}

a {
    color: var(--accent-dark);
    text-decoration: none;
}

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

/* --------------------------------------------------------------------------
   Anmeldung
   -------------------------------------------------------------------------- */

.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px 20px;
    background: var(--bg);
}

.login-card {
    width: 100%;
    max-width: 420px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    padding: 42px 40px 34px;
    text-align: center;
}

.login-card .logo {
    width: 116px;
    height: auto;
    margin-bottom: 24px;
}

.login-card h1 {
    font-size: 24px;
    line-height: 1.25;
    margin-bottom: 6px;
}

.login-card .subline {
    color: var(--text-dim);
    font-size: 13px;
    margin: 0 0 28px;
}

.login-hint {
    color: var(--text-muted);
    font-size: 13px;
    line-height: 21px;
    margin: 0 0 20px;
}

/* Der ausgewiesene Weg zur Plattform-Anmeldung (#15100). Er erscheint erst,
   wenn der Mitarbeiter-Knopf „keine laufende Anmeldung" meldet — deshalb als
   eigener Block unter dem Knopf und nicht als Teil des Formulars. */
.login-weiter {
    display: block;
    margin: 14px 0 0;
    /* `--accent-dark` ist die Textfarbe fuer Links auf hellem Grund (siehe
       Farbtabelle oben). In `--text-muted` sah der Link wie ein Hinweis aus
       und niemand haette ihn angeklickt. */
    color: var(--accent-dark);
    font-size: 12px;
    line-height: 19px;
    text-align: center;
    text-decoration: underline;
}

.login-weiter[hidden] {
    display: none;
}

/* Die Buchungsseite fuer den Kunden (Feedback #13600) — dieselbe Karte wie
   die Anmeldung, die Auswahl der Tage linksbuendig: eine zentrierte Liste
   von Radioknoepfen liest sich wie ein Gedicht, nicht wie eine Auswahl. */
.buchung__tage {
    border: 0;
    margin: 0 0 16px;
    padding: 0;
    text-align: left;
}

.buchung__tag {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    margin-top: 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
}

.buchung__tag:has(input:checked) {
    border-color: var(--accent);
}

.buchung .field {
    text-align: left;
}

.login-card .meta {
    margin: 24px 0 0;
    padding-top: 18px;
    border-top: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 12px;
    line-height: 19px;
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
    width: 100%;
    padding: 11px 20px;
    background: var(--accent);
    color: #ffffff;
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.18s ease, border-color 0.18s ease;
}

.btn:hover {
    background: var(--accent-bright);
    border-color: var(--accent-bright);
    color: #ffffff;
}

.btn:focus-visible {
    outline: 2px solid var(--accent-dark);
    outline-offset: 2px;
}

/* Breite nur so gross wie noetig — fuer Knopfreihen */
.btn--auto {
    width: auto;
}

.btn--secondary {
    width: auto;
    background: var(--surface);
    color: var(--text-muted);
    border-color: var(--border-strong);
}

.btn--secondary:hover {
    background: var(--surface-hover);
    border-color: var(--border-strong);
    color: var(--text);
}

/* Icon-Knopf — Nutzer-Card, Menue, Modal */
.iconbtn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius);
    color: var(--text-dim);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.iconbtn:hover {
    background: var(--surface-hover);
    color: var(--text);
}

.iconbtn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.iconbtn.is-active {
    background: var(--accent-soft);
    color: var(--accent-dark);
}

.iconbtn svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
}

.iconbtn--sm {
    width: 28px;
    height: 28px;
}

.iconbtn__badge {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 9999px;
    background: var(--signal-red);
    color: #ffffff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* --------------------------------------------------------------------------
   App-Huelle
   -------------------------------------------------------------------------- */

.shell {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    /* Passt der Inhalt nicht (alle Gruppen offen), scrollt die Leiste selbst.
       Ohne das stand er einfach ueber den unteren Rand hinaus — und weil die
       Leiste `sticky` mit fester Hoehe ist, holte ihn auch kein Seiten-Scroll
       zurueck: die Nutzer-Card mit Glocke, Einstellungen und Abmelden war
       nicht erreichbar (Feedback #12851). Das ist eine Frage der HOEHE, nicht
       der Breite — gemessen ebenso auf einem 1440x900-Laptop wie auf dem
       Telefon, die Regel steht deshalb hier und nicht im Mobil-Block. Passt
       der Inhalt, erscheint keine Bildlaufleiste und nichts aendert sich. */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.sidebar__brand {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    border-bottom: 1px solid var(--border);
    color: var(--text);
    transition: background 0.15s ease;
}

.sidebar__brand:hover {
    background: var(--surface-hover);
    color: var(--text);
}

.sidebar__brand img {
    height: 34px;
    width: auto;
}

.sidebar__brand span {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 700;
}

/* Anheften/Loesen — sitzt im Kopf der Leiste, wie in der pvwebapp. Er
   erscheint erst ab 861 px: darunter ist die Leiste ein Overlay und es
   gibt nichts anzuheften. */
.sidebar__pin {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    flex-shrink: 0;
    background: none;
    border: none;
    border-radius: var(--radius);
    color: var(--text-dim);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.sidebar__pin:hover {
    background: var(--surface-hover);
    color: var(--text);
}

/* Angeheftet ist der Knopf AN — dieselbe Aussage wie `aria-pressed="true"`,
   nur sichtbar. Ohne die Faerbung waere am Knopf nicht abzulesen, in
   welchem der beiden Zustaende die Leiste gerade steht. */
.sidebar__pin[aria-pressed="true"] {
    color: var(--accent);
}

.sidebar__pin svg {
    width: 16px;
    height: 16px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.8;
}

.sidebar__close {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: none;
    border: none;
    border-radius: var(--radius);
    color: var(--text-dim);
    cursor: pointer;
}

.sidebar__close svg {
    width: 18px;
    height: 18px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.8;
}

.sidebar__backdrop {
    display: none;
}

.nav {
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
    overflow-y: auto;
}

.nav a {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 12px;
    border-radius: var(--radius);
    color: var(--text-muted);
    font-size: 14px;
    border-left: 2px solid transparent;
    transition: background 0.15s ease, color 0.15s ease;
}

.nav a:hover {
    background: var(--surface-hover);
    color: var(--text);
}

.nav a.is-active {
    background: var(--accent-soft);
    border-left-color: var(--accent);
    color: var(--text);
    font-weight: 600;
}

.nav a svg {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
}

.nav a.is-active svg {
    stroke: var(--accent);
}

/* Zaehler am Menuepunkt — heute die offenen Urlaubsantraege (Feedback #13007).
   `margin-left: auto` schiebt ihn an den rechten Rand der Zeile, damit er
   nicht am Text klebt und bei unterschiedlich langen Beschriftungen an
   derselben Stelle steht. Dieselbe Form wie das Abzeichen an der Glocke. */
.nav__count {
    margin-left: auto;
    flex-shrink: 0;
    min-width: 18px;
    padding: 0 5px;
    border-radius: 9999px;
    background: var(--signal-red);
    color: #ffffff;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
}

/* Kopf einer Menue-Gruppe („Organisation", „Verwaltung"): ordnet die Punkte
   UND klappt sie ein (Feedback #12818). Die ganze Zeile ist die Schaltflaeche,
   nicht nur der Winkel — ein 14-px-Pfeil ist kein Ziel, das man trifft. */
.nav__toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    margin: 0;
    padding: 7px 12px;
    background: none;
    border: none;
    border-radius: var(--radius);
    /* Etwas kraeftiger als --text-dim, seit die Beschriftung groesser ist
       (Feedback #12851). Die Farbe steht bewusst HIER und nicht an
       `.nav__label`: dort schluege sie die `.is-active`-Faerbung unten, und
       der eingeklappte Gruppenkopf zeigte nicht mehr, wo man ist. */
    color: var(--text-muted);
    text-align: left;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.nav__toggle:hover {
    background: var(--surface-hover);
    color: var(--text);
}

/* Steckt die offene Seite in einer EINGEKLAPPTEN Gruppe, ist ihr Eintrag nicht
   zu sehen — dann muss wenigstens der Kopf zeigen, wo man ist. Eingeklappt
   bleibt eingeklappt: eine Gruppe, die sich beim Navigieren von selbst wieder
   oeffnet, macht den Schalter wertlos. */
.nav__toggle.is-active {
    color: var(--accent);
}

/* Die Beschriftung der Gruppe. 11 px waren die kleinste Schrift der ganzen App
   und auf dem Telefon nicht mehr zu lesen (Feedback #12851) — sie steht jetzt
   auf 13 px, bleibt aber unter den Punkten darunter (14 px): der Kopf ordnet,
   er ist kein Eintrag. Genau diesen Abstand haelt auch die mobile Stufe ein. */
.nav__label {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.02em;
}

/* Das Symbol eines Gruppenkopfes. Aufgeklappt UNSICHTBAR: dort ordnet die
   Schrift, und ein Symbol davor haette die Koepfe wie Eintraege aussehen
   lassen. Sichtbar wird es allein im eingefahrenen Menue — dort steht es an
   der Stelle der Beschriftung, sonst waere die Gruppe eine leere Zeile. */
.nav__groupicon {
    display: none;
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.7;
}

.nav__chevron {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    transition: transform 0.15s ease;
}

/* Eingeklappt zeigt der Winkel nach rechts. */
.nav__toggle[aria-expanded="false"] .nav__chevron {
    transform: rotate(-90deg);
}

.nav__items {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* `hidden` allein reicht nicht — das `display: flex` darueber schlaegt es. */
.nav__items[hidden] {
    display: none;
}

/* Die Hauptnavigation waechst NICHT mit: der freie Platz gehoert dem
   Organisations-Block darunter, damit er direkt an Dashboard und Feedback
   anschliesst statt ans untere Ende zu rutschen. Gibt es ihn nicht (niemand
   hat ein Organisations-Recht), haelt `.userbar { margin-top: auto }` die
   Nutzer-Card trotzdem unten. */
.nav--main {
    flex: 0 0 auto;
    overflow: visible;
}

/* Feedback als letzter Eintrag der Struktur, unmittelbar ueber der
   Nutzer-Card (Feedback #12818). */
.nav--last {
    flex: 0 0 auto;
    padding: 0 12px 12px;
    overflow: visible;
}

/* Nutzer-Card unten in der Leiste */

.userbar {
    display: flex;
    align-items: center;
    gap: 4px;
    border-top: 1px solid var(--border);
    padding: 12px;
    /* Bleibt unten, auch wenn ueber ihr nichts waechst. */
    margin-top: auto;
}

.userbar__id {
    flex: 1;
    min-width: 0;
    padding: 4px 8px;
}

.userbar__name,
.userbar__role {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.userbar__name {
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
}

.userbar__role {
    font-size: 12px;
    line-height: 16px;
    color: var(--text-dim);
}

/* Hauptbereich */

.main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.mobilebar {
    display: none;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.mobilebar img {
    height: 26px;
    width: auto;
}

.mobilebar span {
    font-size: 15px;
    font-weight: 700;
}

.content {
    flex: 1;
    padding: 24px;
}

/* Seitenkopf im Inhalt — ersetzt die fruehere Kopfzeile */
.pagehead {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 24px;
}

/* ⚠️ Die Ueberschriften stehen EINE Stufe groesser als der Fliesstext-Kanon
   von dtf-express (Feedback #14120): Seitentitel 28 px, Abschnittskopf 18 px.
   Gemeldet wurde das an der Projektakte, geaendert ist es hier — beides sind
   die einzigen Definitionen ihrer Stufe, damit jede Seite gleich zieht. */
.pagehead h1 {
    font-size: 28px;
    line-height: 1.25;
}

.pagehead__sub {
    margin: 4px 0 0;
    font-size: 13px;
    color: var(--text-dim);
}

/* --------------------------------------------------------------------------
   Karten, Leerzustand, Datenliste
   -------------------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-card);
}

.card--pad {
    padding: 24px 26px;
}

.section-title {
    font-size: 18px;
    margin-bottom: 14px;
}

.datalist {
    display: grid;
    grid-template-columns: minmax(0, 190px) minmax(0, 1fr);
    gap: 7px 20px;
    margin: 0;
    font-size: 13px;
}

.datalist dt {
    color: var(--text-dim);
}

.datalist dd {
    margin: 0;
    color: var(--text);
}

.hint {
    margin: 20px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 12px;
    line-height: 19px;
}

/* Hinweis unter einer Karte statt darin — dann ohne Trennlinie */
.hint--standalone {
    border-top: none;
    padding-top: 0;
    margin: 14px 2px 0;
    max-width: 760px;
}

/* Leerer Bereich mit Begruendung, warum hier nichts steht — nach dem
   EmptyState aus dtf-express-hub. */
.empty-state {
    padding: 62px 32px;
    text-align: center;
}

.empty-state__icon {
    width: 56px;
    height: 56px;
    margin: 0 auto 16px;
    border-radius: 9999px;
    background: var(--accent-soft);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Ohne feste Groesse und `fill: none` rendert der Browser das Symbol in
   Standardgroesse und fuellt die Pfade schwarz — es fuellt dann die ganze
   Karte. Diese Regel ist nicht kosmetisch. */
.empty-state__icon svg {
    width: 25px;
    height: 25px;
    flex-shrink: 0;
    /* accent-dark statt accent: auf dem hellblauen Hauch erreicht der hellere
       Ton zu wenig Kontrast und das Symbol verschwimmt mit der Flaeche. */
    stroke: var(--accent-dark);
    fill: none;
    stroke-width: 1.6;
}

/* Gleiche Stufe wie `.section-title` — der Leerzustand steht an derselben
   Stelle wie ein Abschnitt und darf ihm nicht davonlaufen. */
.empty-state h2 {
    font-size: 18px;
    margin-bottom: 6px;
}

.empty-state p {
    color: var(--text-dim);
    font-size: 13px;
    max-width: 400px;
    margin: 0 auto;
}

/* --------------------------------------------------------------------------
   Tabelle — Aufbau wie die Nutzerliste in dtf-express-hub
   -------------------------------------------------------------------------- */

/* ⚠️ `overflow-x: auto`, NICHT `hidden` — und das auf JEDER Breite (Feedback
   #13056). Die Karte klippt hier die Ecken einer randlosen Tabelle; mit
   `hidden` schnitt sie dabei alles ab, was breiter war als sie selbst, OHNE
   jede Scrollmoeglichkeit. Betroffen war immer die rechte Aktionsspalte:
   „Bearbeiten", „Archivieren", „Erledigt", „Korrigieren" waren nicht etwa
   klein, sondern unerreichbar (gemessen /kunden 171 px bei 1280 px Viewport,
   551 px bei 900 px; /aufgaben, /lager, /produkte ebenso).

   Die Rettung stand schon da — aber in `@media (max-width: 860px)`, also nur
   fuer Telefone. Genau darin lag der Fehler: eine Tabelle wird nicht erst auf
   dem Telefon zu breit, sondern immer dann, wenn ihr Inhalt breiter ist als
   ihr Kasten — und der Kasten ist neben der 256 px breiten Seitenleiste auch
   auf einem Laptop schmal. `auto` klippt die Ecken weiterhin und legt einen
   Scrollbalken darunter, sobald (und nur dann, wenn) er gebraucht wird. */
.card--flush {
    overflow-x: auto;
    overflow-y: hidden;
    /* Ein duenner, aber SICHTBARER Balken. „Erreichbar" und „auffindbar" sind
       zweierlei: ein Nutzer, der nicht sieht, dass es rechts weitergeht, sucht
       den Knopf nicht — er meldet ihn als verschwunden. Beide Werte greifen
       nur, wenn ueberhaupt ein Balken noetig ist; `--border-strong` folgt dem
       Thema mit (Standard wie Glas). */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}

.table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
    font-size: 14px;
}

/* Kopfzeile: hellgrau hinterlegt, klein und in Versalien — die einzige
   Stelle, an der dtf-express Versalien verwendet. */
.table thead {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.table thead th {
    padding: 12px 16px;
    font-size: 12px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-dim);
    white-space: nowrap;
}

.table tbody td {
    padding: 12px 16px;
    vertical-align: middle;
}

/* Trennlinien nur ZWISCHEN den Zeilen (divide-y), nicht unter der letzten */
.table tbody tr + tr td {
    border-top: 1px solid var(--border);
}

.table__name {
    margin: 0;
    font-weight: 500;
    color: var(--text);
}

.table__sub {
    margin: 0;
    font-size: 12px;
    line-height: 17px;
    color: var(--text-dim);
}

/* ⚠️ Nur die FARBE, kein `white-space` mehr (Feedback #13056). Die Klasse sagt
   „gedaempft" — sie sagt nichts darueber, ob der Inhalt zusammenbleiben muss,
   und beides in einer Klasse zu fuehren ging in beide Richtungen schief:

   * Sie sitzt an FREITEXT-Zellen (Anschrift, Notiz, Absage-Grund, Kommentar).
     Umbruchfrei machte die Anschrift die Ortsspalte der Kundenliste 305 px
     breit — die Tabelle sprengte damit ihren Kasten um genau die 63 px, die
     ihr auf einem 1280-px-Bildschirm fehlten.
   * Sie sitzt auch an ganzen `<tr>` (Kundenakte, Projektakte) — als reine
     Einfaerbung einer erledigten Zeile. Dort vererbte sich `nowrap` auf JEDE
     Zelle der Zeile, was so nie gemeint war.

   Was wirklich zusammenbleiben muss, sagt jetzt `.table__nowrap`. */
.table__muted {
    color: var(--text-muted);
}

/* Ein Wert, der nur als Ganzes lesbar ist: „08:00–16:00" (der Gedankenstrich
   ist eine Umbruchgelegenheit), „25.08.2026, 19:16", „5 Tage". Ein reines
   Datum braucht das nicht — „25.08.2026" hat keine Stelle zum Umbrechen. */
.table__nowrap {
    white-space: nowrap;
}

/* Status */

.badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 9999px;
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
}

.badge--active {
    background: var(--accent-soft);
    color: var(--accent-dark);
}

.badge--blocked {
    background: var(--border);
    color: var(--text-muted);
}

/* „Alles abgehakt" (Feedback #13418). Gruen ist in dieser App die Farbe von
   „erledigt"; ein vollstaendig abgehakter Zaehler ist die einzige Stelle, an
   der eine Checkliste ueberhaupt etwas MELDET. Dunkler Ton auf heller
   Toenung wie bei den uebrigen Abzeichen — ein dunkler Grund ist bewusst
   nirgends vorgesehen. */
.badge--ok {
    background: rgba(47, 143, 87, 0.13);
    color: var(--signal-green);
}

/* Zeilen-Aktionen: auf dem Desktop erst beim Ueberfahren sichtbar, auf
   Touch-Geraeten dauerhaft (dort gibt es kein Hover). Fuer die Tastatur
   blendet focus-within sie ein. */
.rowactions {
    display: flex;
    /* ⚠️ Umbrechen, nicht ueberlaufen (Feedback #13056). `.btn--sm` traegt
       `flex: 0 0 auto` — die Knoepfe schrumpfen also nicht. Ohne `wrap` war
       eine Reihe damit so breit wie ihre Beschriftungen zusammen, egal wie
       schmal der Bildschirm war: die vier Kopf-Knoepfe der Kundenakte
       massen auf einem Telefon 439 px bei 390 px Viewport, „Projekt anlegen"
       ragte links aus dem Bild und „Archivieren" rechts. Zwei Zeilen sind
       haesslicher als eine — ein Knopf, den man nicht sieht, ist schlimmer. */
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 2px;
}

@media (hover: hover) and (min-width: 861px) {
    .rowactions {
        opacity: 0;
        transition: opacity 0.15s ease;
    }

    tr:hover .rowactions,
    tr:focus-within .rowactions {
        opacity: 1;
    }

    /* In einem VERWALTUNGS-Dialog sind die Knoepfe der Inhalt, nicht das
       Beiwerk einer Datenzeile — dort waere „erscheint beim Ueberfahren"
       genau das Suchen, das der Dialog abschaffen soll. */
    .rowactions--fixed {
        opacity: 1;
    }
}

/* Spalten, die auf schmalen Viewports entfallen */
@media (max-width: 700px) {
    .col-sm {
        display: none;
    }
}

@media (min-width: 701px) {
    .col-sm-only {
        display: none;
    }
}

@media (max-width: 900px) {
    .col-md {
        display: none;
    }
}

/* Rueckmeldung ueber einer Liste */
.notice {
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: var(--radius);
    font-size: 13px;
}

.notice--ok {
    background: var(--accent-soft);
    color: var(--accent-dark);
}

.notice--error {
    background: rgba(193, 57, 27, 0.10);
    color: var(--signal-red);
}

/* Etwas stimmt nicht ganz, aber nichts ist schiefgegangen — der Tagesplan
   ohne eigene Zuteilung (Feedback #13144). Bewusst NICHT `--error`: der
   Rueckfall funktioniert, er ist nur nicht das, was gemeint war. */
.notice--warn {
    background: rgba(232, 133, 10, 0.12);
    color: #9a5806;
}

/* Eine Auskunft ohne Bewertung — der Tourenplan ueber der Wartungsliste.
   Weder Erfolg noch Fehler, deshalb weder Akzent noch Signalfarbe. */
.notice--quiet {
    background: var(--border);
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   Mein Tag — der erste Termin gross (Feedback #13144)
   --------------------------------------------------------------------------
   Die Seite wird morgens auf dem Telefon geoeffnet, und die einzige Frage
   lautet „wo muss ich zuerst hin?". Deshalb steht der erste Termin als eigene
   Karte ueber der Liste und traegt die groesste Schrift der App — er soll
   ohne Scrollen und ohne Suchen lesbar sein.
   -------------------------------------------------------------------------- */

.tagesplan__pfeile {
    margin-bottom: 16px;
}

.tagesplan__erster {
    border-left: 3px solid var(--accent);
}

.tagesplan__zeit {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 4px;
    font-size: 30px;
    font-weight: 700;
    line-height: 1.1;
}

.tagesplan__titel {
    margin: 0 0 2px;
    font-size: 17px;
    font-weight: 600;
}

.tagesplan__kunde,
.tagesplan__ort {
    margin: 0 0 4px;
    font-size: 14px;
}

.tagesplan__ort {
    color: var(--text-muted);
}

/* Die Personenauswahl der Leitung sitzt rechts in der Blaetterleiste und
   bricht auf dem Telefon mit ihr um (`.monthbar` ist `flex-wrap`). */
.tagesplan__wer {
    min-width: 0;
    max-width: 100%;
}

.tagesplan__wer .field__input {
    max-width: 100%;
}

/* Woche: sieben Spalten ab Tablet, darunter untereinander — sieben Spalten
   auf 390 px waeren je 50 px breit und kein Titel mehr lesbar. */
.woche {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

.woche__tag {
    min-height: 160px;
    min-width: 0;
    padding: 6px;
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.woche__tag:last-child {
    border-right: 0;
}

.woche__kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px;
    min-width: 0;
    margin-bottom: 2px;
    color: var(--text-muted);
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
}

.woche__leer {
    margin: 0;
    color: var(--text-dim);
    font-size: 11px;
}

/* Aufgabe im Kalenderblatt: gestrichelte Kante statt Terminfarbe — eine
   Frist ist kein Termin, man faehrt nicht zu einer bestimmten Uhrzeit hin.
   Doppelte Klasse, weil `.cal__event` weiter unten steht und die Kante per
   Kurzform `border-left` wieder ueberschriebe. */
.cal__event.cal__event--aufgabe {
    border-left-style: dashed;
    border-left-color: var(--text-dim);
}

.cal__event--erledigt .cal__eventtitle {
    color: var(--text-dim);
    text-decoration: line-through;
}

.cal__eventwer {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-muted);
    font-size: 10px;
}

.cal__daylink {
    color: inherit;
    text-decoration: none;
}

.cal__more {
    color: var(--text-muted);
    font-size: 10px;
    text-decoration: none;
}

@media (max-width: 860px) {
    .woche {
        grid-template-columns: minmax(0, 1fr);
    }

    .woche__tag {
        min-height: 0;
        border-right: 0;
        border-bottom: 1px solid var(--border);
    }

    .woche__tag:last-child {
        border-bottom: 0;
    }
}

/* --------------------------------------------------------------------------
   Feedback-Knopf und Kurzmeldung — beide auf JEDER Seite (Feedback #12933)
   -------------------------------------------------------------------------- */

/* Fest an der unteren rechten Ecke, wie der Knopf des IT-Beratungs-Service.
   `z-index` bewusst UNTER dem Modal (60) und unter der ausgefahrenen
   Seitenleiste (65/70): der Knopf oeffnet den Dialog, er darf nicht darauf
   liegen. */
.fab {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 50;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 18px;
    border: 0;
    border-radius: 9999px;
    background: var(--accent);
    color: #fff;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    /* Der farbige Schein folgt dem Akzent (Feedback #13114) — ein blauer
       Schein unter einem beerenfarbenen Knopf saehe aus wie ein Fehler. */
    box-shadow: 0 6px 18px rgba(var(--accent-rgb), 0.35),
                0 2px 6px rgba(17, 28, 39, 0.15);
}

.fab:hover {
    background: var(--accent-bright);
}

.fab svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
}

/* Bestaetigung fuer Seiten ohne eigene Meldezeile — ueber dem Knopf, damit
   sie ihn nicht verdeckt. */
.toast {
    position: fixed;
    right: 24px;
    bottom: 84px;
    z-index: 55;
    max-width: min(360px, calc(100vw - 48px));
    margin: 0;
    padding: 12px 16px;
    border-radius: var(--radius);
    background: var(--text);
    color: #fff;
    font-size: 13px;
    line-height: 20px;
    box-shadow: 0 6px 18px rgba(17, 28, 39, 0.25);
}

.toast--error {
    background: var(--signal-red);
}

/* --------------------------------------------------------------------------
   Benachrichtigungs-Modal
   -------------------------------------------------------------------------- */

.modal {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px 16px;
}

.modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(17, 28, 39, 0.45);
}

.modal__box {
    position: relative;
    width: 100%;
    max-width: 460px;
    /* Die volle verfuegbare Hoehe, nicht vier Fuenftel davon: `.modal`
       polstert bereits 24 px oben und unten, `100%` ist hier also
       `100vh - 48px`. Die frueheren `80vh` verschenkten ein Fuenftel des
       Bildschirms und schnitten den Inhalt trotzdem ab (Feedback #13099). */
    max-height: 100%;
    display: flex;
    flex-direction: column;
    /* Die Flaeche EINMAL benannt, damit die angeheftete Knopfreihe unten
       denselben Grund bekommt — in beiden Themen (siehe `.modal__buttons`). */
    --modal-flaeche: var(--surface);
    background: var(--modal-flaeche);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22);
    overflow: hidden;
}

.modal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 12px 13px 18px;
    border-bottom: 1px solid var(--border);
    font-size: 15px;
    font-weight: 700;
}

.modal__headactions {
    display: flex;
    align-items: center;
    gap: 8px;
}

.modal__action {
    background: none;
    border: none;
    padding: 0;
    color: var(--accent-dark);
    font-family: inherit;
    font-size: 13px;
    font-weight: 400;
    cursor: pointer;
}

.modal__action:hover {
    color: var(--accent);
    text-decoration: underline;
}

.modal__box--sm {
    max-width: 400px;
}

/* Ein Dialog, der eine TABELLE traegt statt zweier Eingabefelder — die
   Uebersicht der Produktgruppen. In den 460 px eines Eingabe-Dialogs brach
   jeder Gruppenname ueber drei Zeilen um, und die Tabelle war mit 467 px
   sieben Pixel breiter als ihr Kasten. Die Aktionsknoepfe lagen dabei noch
   INNERHALB (gemessen: rechte Kante 872 bei einem Kasten bis 950) — unsichtbar
   waren sie aus einem anderen Grund, siehe `.rowactions--fixed`. */
.modal__box--wide {
    max-width: 680px;
}

/* Dieselbe Lehre wie bei `.card--flush` (siehe dort): eine Tabelle in einem
   Kasten mit `overflow: hidden` wird nicht schmal, sondern ABGESCHNITTEN —
   ohne jede Scrollmoeglichkeit. Auf einem Telefon ist der Kasten keine 680 px
   breit; `overflow-x: auto` macht daraus eine Scroll-Flaeche, statt die
   Aktionsspalte wegzuschneiden. */
.modal__table {
    overflow-x: auto;
}

/* ⚠️ Gescrollt wird HIER, nicht im Kasten: der traegt `overflow: hidden`,
   damit seine runden Ecken den Kopf und die Tabelle beschneiden. Ohne diese
   Zeile war ein Dialog, dessen Inhalt hoeher wurde als der Bildschirm, nicht
   etwa kurz — sondern unten ABGESCHNITTEN, ohne jede Scrollmoeglichkeit.
   Gemessen im Feedback-Dialog (#13099): der Absenden-Knopf lag bei 800 px
   Fensterhoehe 79 px, bei 700 px 159 px unterhalb des Kastens und war mit
   keiner Geste erreichbar. Dieselbe Lehre wie bei `.card--flush` und
   `.modal__table` — ein klippender Kasten muss sich scrollen lassen. */
.modal__pad {
    padding: 18px;
    overflow-y: auto;
}

.modal__pad p {
    margin: 0;
    font-size: 14px;
    line-height: 21px;
    color: var(--text-muted);
}

/* Die Knopfreihe bleibt stehen, waehrend der Inhalt darueber wegscrollt.
   Der Melder von #13099 hat nicht „zu wenig Platz" gemeldet, sondern dass
   der Absenden-Knopf VERSCHWINDET, sobald das Eingabefeld groesser wird
   (`.field__input--area` laesst sich am Griff ziehen). Scrollbarkeit allein
   haette ihn erreichbar gemacht, aber weiterhin unsichtbar — und man muss
   von einem Knopf wissen, um zu ihm zu scrollen.

   Die negativen Aussenabstaende heben die 18 px Polsterung von
   `.modal__pad` auf, damit der Grund von Kante zu Kante traegt; `bottom`
   spiegelt sie, damit die Reihe buendig unten klebt. Bewusst OHNE
   Trennlinie: in einem kurzen Dialog klebt hier nichts, und eine Linie
   waere dort eine sichtbare Aenderung an 32 Dialogen, die niemand
   bestellt hat. */
.modal__buttons {
    position: sticky;
    bottom: -18px;
    z-index: 1;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin: 20px -18px -18px;
    padding: 12px 18px 18px;
    background: var(--modal-flaeche);
    -webkit-backdrop-filter: var(--glas, none);
    backdrop-filter: var(--glas, none);
}

.modal__body {
    overflow-y: auto;
}

.modal__empty {
    margin: 0;
    padding: 30px 16px;
    text-align: center;
    color: var(--text-dim);
    font-size: 13px;
}

.note {
    display: block;
    width: 100%;
    text-align: left;
    padding: 12px 18px;
    background: none;
    border: none;
    border-bottom: 1px solid var(--border);
    border-left: 3px solid transparent;
    font-family: inherit;
    cursor: pointer;
}

.note:last-child {
    border-bottom: none;
}

.note:hover {
    background: var(--surface-hover);
}

.note--warn {
    border-left-color: var(--signal-orange);
}

.note--critical {
    border-left-color: var(--signal-red);
}

.note--ok {
    border-left-color: var(--signal-green);
}

/* Ungelesen: kraeftiger Titel — die Farbkante traegt bereits die Stufe. */
.note--unread .note__title {
    font-weight: 600;
    color: var(--text);
}

.note__title {
    display: block;
    font-size: 13px;
    line-height: 19px;
    color: var(--text-muted);
}

.note__message {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    line-height: 18px;
    color: var(--text-dim);
}

.note__time {
    display: block;
    margin-top: 4px;
    font-size: 11px;
    color: var(--text-dim);
}

/* --------------------------------------------------------------------------
   Angeheftet oder geloest (Feedback #13098)
   --------------------------------------------------------------------------
   Vorbild ist der `MiniDrawer` der pvwebapp: angeheftet steht die Leiste
   dauerhaft offen (der bisherige Stand), geloest faehrt sie zu einer
   Symbolspalte ein und kommt beim Ueberfahren wieder heraus.

   ⚠️ Geloest liegt die Leiste UEBER dem Inhalt, sie schiebt ihn nicht.
   Deshalb `position: fixed` plus ein `padding-left` an `.shell`, das den
   Platz der Symbolspalte freihaelt: wuechse die Leiste im Fluss, ruecke der
   ganze Inhalt bei jedem Ueberfahren mit — genau das, was die pvwebapp mit
   ihrem reservierten Slot verhindert.

   ⚠️ Alles hier steht ab 861 px. Darunter ist die Leiste ohnehin ein
   Overlay mit eigenem Oeffner; ein zweiter Mechanismus daneben ergaebe zwei
   Wahrheiten darueber, ob das Menue gerade zu sehen ist.
   -------------------------------------------------------------------------- */

@media (min-width: 861px) {
    html[data-nav-pin="0"] .shell {
        padding-left: var(--sidebar-rail);
    }

    html[data-nav-pin="0"] .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 60;
        height: 100vh;
        width: var(--sidebar-rail);
        transition: width 0.18s ease, box-shadow 0.18s ease;
    }

    /* `focus-within` gehoert dazu: wer sich mit der Tastatur durch die
       Leiste bewegt, faehrt sie sonst nie aus und tabbt blind durch
       Symbole ohne Beschriftung. */
    html[data-nav-pin="0"] .sidebar:hover,
    html[data-nav-pin="0"] .sidebar:focus-within {
        width: var(--sidebar-w);
        box-shadow: var(--shadow);
    }

    /* --- eingefahren: nur Symbole ------------------------------------- */

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .sidebar__brand {
        justify-content: center;
        padding: 16px 0;
    }

    /* Der Anheft-Knopf ist eingefahren selbst weg — zum Wiederanheften
       faehrt man die Leiste erst aus. Dieselbe Bedingung wie in der
       pvwebapp: neben dem Logo ist in 72 px kein Platz, und ein Knopf, der
       sich beim Ueberfahren unter den Mauszeiger schiebt, ist schlechter zu
       treffen als einer, der mit der Leiste erscheint. */
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .sidebar__brand span,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .sidebar__pin,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__text,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__label,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__chevron,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .userbar__id {
        display: none;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__groupicon {
        display: block;
    }

    /* Die EINTRAEGE einer Gruppe bleiben eingefahren weg — auch die einer
       offenen Gruppe. Eine Reihe gleich aussehender Symbole ohne den Kopf
       darueber ist nicht zu lesen; die Gruppe selbst ist der Einstieg, und
       ihre Punkte kommen beim Ueberfahren. */
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__items {
        display: none;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav {
        padding: 12px 8px;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav a,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__toggle {
        position: relative;
        justify-content: center;
        padding-left: 0;
        padding-right: 0;
    }

    /* ⚠️ JEDER Zaehler wird zum Punkt — der am Gruppenkopf (`.nav__count`)
       UND der an der Glocke (`.iconbtn__badge`). Die Zahl passt neben ein
       Symbol nicht: an der Glocke deckte der zweistellige Zaehler das
       Symbol fast vollstaendig zu (gemessen, 30-px-Knopf gegen ein
       16-px-Abzeichen). Das ist ein anderer Fehler als ein Ueberlauf und
       `e2e_layout.py` sieht ihn nicht — es faellt nichts aus seinem Kasten,
       es liegt nur uebereinander.

       Wie viele es sind, sagt das ausgefahrene Menue. Ein Signal ohne Zahl
       ist besser als eine Zahl ohne Symbol. Wer ein drittes Abzeichen
       einfuehrt, gehoert in diese Liste. */
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__count,
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .iconbtn__badge {
        position: absolute;
        margin: 0;
        min-width: 8px;
        width: 8px;
        height: 8px;
        padding: 0;
        font-size: 0;
        line-height: 0;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .nav__count {
        top: 3px;
        right: 12px;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .iconbtn__badge {
        top: 1px;
        right: 1px;
    }

    /* Vier Symbole in 72 px: zwei Reihen zu zweit. Untereinander waere die
       Karte 128 px hoch und schoebe die Leiste zum Scrollen.

       ⚠️ Die Rechnung geht knapp auf und ist im Browser GEMESSEN, nicht
       geschaetzt: von den 72 px gehen der 1-px-Rahmen rechts und die
       seitliche Polsterung ab. Mit den ueblichen 12 px Polsterung und
       32-px-Symbolen fielen die vier in VIER Reihen (gemessen: 149 px hoch)
       — und zwar OHNE dass irgendetwas ueberlaeuft, ein Layout-Test sieht
       das also nicht. 2 px Polsterung lassen 67 px, zwei 30er mit 4 px
       Abstand brauchen 64. */
    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .userbar {
        flex-wrap: wrap;
        justify-content: center;
        padding: 8px 2px;
    }

    html[data-nav-pin="0"] .sidebar:not(:hover):not(:focus-within) .userbar .iconbtn {
        width: 30px;
        height: 30px;
    }

    /* --- ausgefahren liegt die Leiste UEBER dem Inhalt ----------------- */

    /* Deckender als sonst: geloest scheint nicht mehr der Seitenhintergrund
       durch, sondern der Text daneben — und darauf ist die Leiste nicht mehr
       zu lesen. */
    html[data-thema="glass"][data-nav-pin="0"] .sidebar:hover,
    html[data-thema="glass"][data-nav-pin="0"] .sidebar:focus-within {
        background: rgba(255, 255, 255, 0.88);
    }
}

/* Unter 861 px ist die Leiste ein Overlay mit eigenem Oeffner — der
   Anheft-Knopf haette dort nichts zu tun. */
@media (max-width: 860px) {
    .sidebar__pin {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   Schmale Viewports — Leiste faehrt als Overlay ein
   -------------------------------------------------------------------------- */

@media (max-width: 860px) {
    .mobilebar {
        display: flex;
    }

    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 70;
        height: 100dvh;
        width: 288px;   /* w-72 */
        transform: translateX(-100%);
        /* `visibility` zusaetzlich zum Verschieben: sonst bleibt die
           eingeklappte Leiste im Tab-Fluss und am Screenreader haengen —
           der Fokus wandert dann in unsichtbare Bedienelemente. */
        visibility: hidden;
        transition: transform 0.2s ease-out, visibility 0.2s ease-out;
        border-right: 1px solid var(--border);
    }

    .sidebar.is-open {
        transform: translateX(0);
        visibility: visible;
    }

    .sidebar__backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 65;
        background: rgba(17, 28, 39, 0.45);
    }

    .sidebar__close {
        display: flex;
    }

    /* Die Verteilung des freien Platzes (`.nav--section` waechst, alle
       uebrigen stehen fest) ist eine DESKTOP-Regel — sie ordnet Luecken, die
       es auf dem Telefon gar nicht gibt. Dort drueckte sie stattdessen den
       einzigen wachsenden Bereich („Sonstiges") auf 4 px zusammen: seine
       Punkte waren faktisch weg. Ueber 860 px bleibt alles wie beschrieben. */
    .nav--main,
    .nav--last {
        flex: 0 0 auto;
        overflow: visible;
    }
    /* `.nav--section` wird weiter unten definiert und gewaenne hier gegen
       diese Regel — seine mobile Stufe steht deshalb dort. */

    /* Fingerbreite Ziele. 38 px (Punkt), 24 px (Gruppenkopf) und 32 px
       (Icon-Knopf) lagen alle unter den 44 px, die man sicher trifft. */
    .nav a {
        padding: 11px 12px;
        font-size: 15px;
    }

    .nav__toggle {
        padding: 12px;
    }

    /* Ein Schritt groesser als am Desktop — und weiterhin eine Stufe unter
       den Punkten darunter (15 px). */
    .nav__label {
        font-size: 14px;
    }

    .userbar .iconbtn,
    .mobilebar .iconbtn {
        width: 40px;
        height: 40px;
    }

    .content {
        padding: 16px;
    }

    /* Auf dem Handy nur das Symbol — ein Knopf mit Beschriftung deckt dort
       einen spuerbaren Teil der Liste ab, unter der er steht. */
    .fab {
        right: 16px;
        bottom: 16px;
        padding: 14px;
    }

    .fab__label {
        display: none;
    }

    .toast {
        right: 16px;
        left: 16px;
        bottom: 80px;
        max-width: none;
    }

    .pagehead h1 {
        font-size: 24px;
    }

    /* Das `overflow-x: auto` der Tabellenkarte stand frueher HIER — es galt
       damit nur auf dem Telefon, obwohl eine Tabelle auf jeder Breite zu breit
       werden kann. Es ist zur Grundregel von `.card--flush` geworden
       (Feedback #13056, Begruendung dort). */

    /* Weniger Polsterung heisst weniger zu scrollen. */
    .table thead th,
    .table tbody td {
        padding: 10px 12px;
    }

    /* Die 190-px-Beschriftungsspalte laesst neben sich keine 150 px fuer den
       Wert — auf dem Telefon steht die Angabe unter ihrer Beschriftung. */
    .datalist {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px 0;
    }

    .datalist dd + dt {
        margin-top: 10px;
    }
}

/* ==========================================================================
   Verwaltung — Gruppen und Rechte
   Rechte haengen an Gruppen (Vorbild pvwebapp, `group_management/`): je Gruppe
   eine Karte mit einem Schalter pro Recht aus dem Katalog.
   ========================================================================== */

/* Kopf einer Gruppen-Karte: Name links, Aktionen rechts */
.group + .group {
    margin-top: 16px;
}

.group__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    /* ⚠️ Umbrechen wie bei `.rowactions` (Feedback #13056). In einer HALBEN
       Karte des `.cardgrid` — „Verbrauchtes Material" seit Feedback #13418 —
       stehen ein zweizeiliger Titel und ein Knopf in rund 300 px nebeneinander
       und beruehren sich fast. Sie duerfen dann untereinander, statt auf den
       letzten Pixel zusammenzuruecken. In den breiten Karten aendert sich
       nichts: dort passt beides laengst in eine Zeile. */
    flex-wrap: wrap;
    gap: 8px 16px;
    margin-bottom: 4px;
}

.group__head .section-title {
    margin: 0;
}

/* ------------------------------------------------ Einklappbare Gruppen-Karte
   Feedback #15320: sieben Rollen mal knapp vierzig Rechte waren rund 280
   Schalter untereinander — die Seite beantwortete „welche Rollen gibt es?"
   nicht mehr. Jede Karte klappt deshalb zu; der Zustand steht im Cookie
   `gruppen_auf` und wird serverseitig gerendert (siehe `gruppen.html`).

   Die linke Haelfte des Kopfes waechst, die Aktionen rechts bleiben, wo sie
   sind — sonst sprang der Titel je nach Namenslaenge. `min-width: 0` haelt
   einen langen Gruppennamen im Kasten, statt die Knoepfe herauszudruecken. */
.group__title {
    flex: 1 1 220px;
    min-width: 0;
}

/* Die Ueberschrift traegt nur noch den Knopf — ihren Abstand nach unten
   bringt der Untertitel mit. */
.section-title--klapp {
    margin: 0;
}

/* Die ganze Titelzeile ist die Schaltflaeche, nicht nur der Winkel — dieselbe
   Ueberlegung wie bei `.nav__toggle` (Feedback #12818): ein 14-px-Pfeil ist
   kein Ziel, das man trifft. */
.group__toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 0;
    padding: 0;
    background: none;
    border: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.group__toggle:hover {
    color: var(--accent);
}

.group__chevron {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    transition: transform 0.15s ease;
}

/* Eingeklappt zeigt der Winkel nach rechts — wie in der Seitenleiste. */
.group__toggle[aria-expanded="false"] .group__chevron {
    transform: rotate(-90deg);
}

/* Eingeklappt ist der Untertitel alles, was die Karte noch sagt: dort steht
   deshalb auch, wie viele Rechte gesetzt sind. Ungespeichertes faellt farbig
   heraus — sonst verschwaende eine zugeklappte Karte eine angefangene
   Aenderung lautlos. */
.group__dirty {
    color: var(--signal-orange);
    font-weight: 600;
    /* Der Trennpunkt gehoert zum Wort: ohne das blieb er am Zeilenende
       haengen und „ungespeichert" rutschte allein in die naechste Zeile. */
    white-space: nowrap;
}

.group__body[hidden] {
    display: none;
}

/* ⚠️ Ein Abschnittskopf in einer RANDLOSEN Karte braucht seine Polsterung
   selbst. `.card--flush` hat bewusst keine — die Tabelle darin soll von Kante
   zu Kante laufen. Ein `.group__head` sass damit ohne jeden Abstand in der
   16 px runden Ecke: Titel und Knopf lasen sich, als staenden sie AUSSERHALB
   des Kastens (dieselbe Verwechslung wie in Feedback #13021), und die Rundung
   schnitt die Ueberschrift („Termine", „Aufgaben", „Rechnungen") oben an.
   Betroffen waren 16 Stellen in 9 Vorlagen, allein auf der Projektakte
   viermal. Der Kopf bringt sein Padding deshalb selbst mit, statt es der Karte
   zu geben (die es der Tabelle wieder wegnehmen muesste).

   Die 16 px SEITLICH sind nicht frei gewaehlt (Feedback #13056): die
   Kopfzellen der Tabelle darunter tragen `padding: 12px 16px`. Damit steht die
   Ueberschrift exakt ueber der ersten Spalte statt acht Pixel daneben — und
   genau darum ging es in dem Feedback.

   `position: sticky` haelt sie beim seitlichen Scrollen an Ort und Stelle: die
   Karte ist seit #13056 eine Scroll-Flaeche (siehe `.card--flush`), und eine
   Ueberschrift, die beim Scrollen nach rechts aus dem Bild laeuft, waere genau
   die Unruhe, die das Feedback abstellen sollte. */
.card--flush > .group__head {
    position: sticky;
    left: 0;
    padding: 20px 16px 14px;
    margin-bottom: 0;
}

/* Der Abstand steckt schon im Padding des Kopfes — beides zusammen risse eine
   Luecke zwischen Knopf und Tabelle auf. */
.card--flush > .group__head .rowactions--head {
    margin-bottom: 0;
}

/* Dieselbe Ueberlegung am anderen Ende: eine Fussnote UNTER der Tabelle einer
   randlosen Karte braucht ihre Polsterung ebenfalls selbst, sonst sitzt sie in
   der runden Ecke und wird angeschnitten (Feedback #13056). Seitlich wie der
   Kopf, damit sie unter der ersten Spalte beginnt. */
.card--flush > .cardnote {
    padding: 12px 16px 16px;
    margin: 0;
}

/* Aktionen ueber bzw. unter einer Karte — anders als `.rowactions` in einer
   Tabellenzeile dauerhaft sichtbar, sie haengen an keinem Hover. */
.rowactions--head {
    justify-content: flex-end;
    margin-bottom: 16px;
    opacity: 1;
}

/* ⚠️ Immer sichtbar, nicht erst beim Ueberfahren. `.rowactions` blendet auf
   dem Desktop bewusst aus (`opacity: 0`) — das passt fuer Zeilen-AKTIONEN am
   Rand, nicht fuer einen INHALT der Zelle. Die Terminvorschlaege auf
   /wartungen sind Knoepfe, aber sie sind zugleich die Auskunft der Spalte:
   unsichtbar bis zum Ueberfahren waere die Spalte scheinbar leer, und die
   Seite beantwortete ihre eigene Frage nicht mehr. Linksbuendig aus dem
   gleichen Grund — sie stehen in der Spalte, nicht am Zeilenende. */
.rowactions--immer {
    opacity: 1;
    justify-content: flex-start;
}

/* `flex-end` statt der geerbten Streckung: hier steht neben dem Knopf ein
   Eingabefeld MIT Beschriftung („Verlaufseintrag"), und gestreckt wurde
   der Knopf so hoch wie Beschriftung plus Feld zusammen — er stand dann 20 px
   ueber dem Feld, auf das er sich bezieht (Feedback #13056). Unten buendig
   sitzen beide auf einer Linie. */
.rowactions--foot {
    align-items: flex-end;
    justify-content: flex-end;
    margin-top: 16px;
    opacity: 1;
}

/* Liste aus Schaltern — fuer Rechte einer Gruppe und fuer die Gruppenauswahl
   eines Nutzers dieselbe Form. */
.perms {
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.perms__item + .perms__item {
    border-top: 1px solid var(--border);
}

.perms__row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 11px 2px;
    cursor: pointer;
}

.perms__row input[type='checkbox'] {
    flex: 0 0 auto;
    width: 17px;
    height: 17px;
    margin: 1px 0 0;
    accent-color: var(--accent);
    cursor: pointer;
}

/* Fest vergebene Rechte einer Systemgruppe: sichtbar, aber nicht bedienbar */
.perms__row input[type='checkbox']:disabled,
.perms__row input[type='checkbox']:disabled ~ span {
    cursor: default;
    opacity: 0.65;
}

.perms__label {
    display: block;
    font-size: 14px;
    font-weight: 500;
}

.perms__desc {
    display: block;
    margin-top: 1px;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 18px;
}

/* Gruppen-Abzeichen in der Nutzertabelle */
.grouptags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}

.badge--group {
    background: var(--surface-hover);
    color: var(--text-muted);
}

/* Einzelnes Eingabefeld in einem Dialog (Gruppenname) */
.field {
    display: block;
    margin-bottom: 4px;
}

.field__label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    font-weight: 500;
}

.field__input {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 14px;
}

.field__input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* iOS Safari zoomt beim Antippen in jedes Feld unter 16 px hinein und laesst
   die Seite danach verschoben stehen (Feedback #12851). Die Regel steht HIER
   und nicht im Mobil-Block weiter oben: dort stuende sie vor der Definition
   darueber und verloere gegen sie. */
@media (max-width: 860px) {
    .field__input {
        font-size: 16px;
    }
}

/* Fehler IM Dialog — er bleibt offen, damit die Eingabe nicht verloren geht */
.field__error {
    margin: 8px 0 0;
    color: var(--signal-red);
    font-size: 13px;
    line-height: 19px;
}

/* ==========================================================================
   Feedback — eigene Meldungen und ihr Stand
   ========================================================================== */

.fb {
    padding: 16px 20px;
}

.fb + .fb {
    border-top: 1px solid var(--border);
}

.fb__head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 8px;
}

.fb__meta {
    color: var(--text-dim);
    font-size: 12px;
}

.fb__message {
    margin: 0;
    font-size: 14px;
    line-height: 21px;
    white-space: pre-wrap;
}

/* Die Antwort der Entwickler ist der Grund, warum jemand hier nachsieht —
   deshalb abgesetzt mit blauer Kante statt als weiterer Absatz. */
.fb__answer {
    margin: 10px 0 0;
    padding: 10px 14px;
    border-left: 3px solid var(--accent);
    background: var(--accent-soft);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: 14px;
    line-height: 21px;
    white-space: pre-wrap;
}

.fb__change,
.fb__answered {
    margin: 8px 0 0;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 19px;
}

/* Eine offene Rueckfrage blockiert das Feedback — sie muss auffallen. */
.fb__clarify {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 14px;
    margin-top: 10px;
    padding: 12px 14px;
    border: 1px solid var(--signal-orange);
    border-radius: var(--radius);
    background: rgba(232, 133, 10, 0.07);
}

.fb__question {
    margin: 0;
    font-size: 13px;
    line-height: 20px;
}

/* Im Feedback-Dialog steht die Rueckfrage ueber dem Antwortfeld und braucht
   Luft — in der Liste sitzt sie in ihrer eigenen Box und bekommt keine. */
[data-feedback-nachfrage] .fb__question {
    margin-bottom: 14px;
    font-weight: 600;
}

.badge--done {
    background: rgba(47, 143, 87, 0.12);
    color: var(--signal-green);
}

/* ⚠️ `width: auto` gehoert dazu (Feedback #13056). `.btn` ist von Haus aus
   `width: 100%` — gedacht fuer den einen Knopf unter einem Formular. `--sm`
   gibt es aber ausschliesslich in Knopfreihen (das `flex: 0 0 auto` sagt es
   schon), und dort beanspruchte ein `.btn.btn--sm` ohne `--auto`/`--secondary`
   die volle Zeilenbreite fuer sich allein: in der Kundenakte drueckte
   „Projekt anlegen" die drei Knoepfe daneben aus dem Bild (439 px Reihe bei
   390 px Viewport). Von 63 Vorkommen war genau EINES nicht schon durch
   `--auto` oder `--secondary` gerettet — der Standardwert war der falsche. */
.btn--sm {
    flex: 0 0 auto;
    width: auto;
    padding: 5px 12px;
    font-size: 13px;
}

/* Mehrzeiliges Feld im Dialog (Feedback-Text, Rueckfrage-Antwort) */
.field__input--area {
    resize: vertical;
    min-height: 96px;
    line-height: 21px;
}

/* Die Rueckfrage im Antwort-Dialog — Zitat dessen, worauf geantwortet wird */
.clarify__question {
    margin: 0 0 16px;
    padding: 10px 14px;
    border-left: 3px solid var(--signal-orange);
    background: rgba(232, 133, 10, 0.07);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: 14px;
    line-height: 21px;
}

@media (max-width: 560px) {
    .fb__clarify {
        flex-direction: column;
    }
}


/* ===========================================================================
   Organisation — Kalender, Zeiterfassung, Lager, Aufgaben, Personal

   Alles hier baut auf den Bausteinen darueber auf (Karte, Tabelle, Abzeichen,
   Modal). Neu ist nur, was die fuenf Seiten wirklich brauchen: ein
   Monatsgitter, Kennzahlen-Kacheln, eine Filterzeile und Reiter.
   =========================================================================== */

/* Eine Zone der Seitenleiste (Verkauf, Finanzen, Projekte, Logistik,
   Verwaltung, Informationen, Sonstiges). Sie sitzt unter der Hauptnavigation
   und darf mitwachsen — sie ist der Arbeitsbereich, nicht der Anhang.

   ⚠️ Bewusst OHNE eigenes `overflow-y: auto` (Feedback #12851). Ein eigener
   Scroll-Bereich setzt `min-height` auf 0 — die Gruppe konnte damit unter
   ihren Inhalt schrumpfen und wurde, sobald die Leiste nicht mehr passte, als
   einzige nachgebende auf 4 px zusammengedrueckt: ihre Punkte waren da, aber
   in einem 4 px hohen Fenster nicht zu erreichen. Ohne die Regel greift wieder
   `min-height: auto`, die Gruppe behaelt ihre Hoehe, und der Ueberlauf landet
   bei der Leiste, die ihn scrollt. Waechst darf sie weiter (`flex: 1 1 auto`)
   — auf einem hohen Schirm nimmt sie den freien Platz wie zuvor. */
.nav--section {
    flex: 1 1 auto;
    padding: 0 12px 4px;
    /* Setzt das `overflow-y: auto` der Basisklasse `.nav` zurueck — wie es
       `.nav--main` und `.nav--section--fixed` daneben auch tun. Weglassen
       genuegt hier NICHT: geerbt bliebe es wirksam. */
    overflow: visible;
}

/* Von den sieben Zonen waechst nur die UNTERSTE („Sonstiges"). Wuerden
   mehrere wachsen, teilte sich der freie Platz auf sie auf und die Luecken
   stuenden mitten zwischen den Gruppen statt unter ihnen. Das Zusammenhalten
   von Feedback und Nutzer-Card am unteren Rand traegt die wachsende Gruppe
   darueber. */
.nav--section--fixed {
    flex: 0 0 auto;
    overflow: visible;
}

/* Beides gilt nur am DESKTOP. Es ordnet freien Platz — und den gibt es auf
   einem Telefon nicht: dort drueckte die Regel den einzigen wachsenden
   Bereich („Sonstiges") auf 4 px zusammen, seine Punkte waren faktisch weg,
   und weil `flex-shrink: 0` an allen uebrigen haengt, lief die Leiste unten
   aus dem Bild — mitsamt der Nutzer-Card (Feedback #12851). Auf schmalen
   Viewports scrollt stattdessen die ganze Leiste als eine Spalte
   (`.sidebar { overflow-y: auto }` im Mobil-Block weiter oben).

   Die Stufe steht HIER statt in jenem Block: dort stuende sie VOR diesen
   beiden Definitionen und verloere bei gleicher Spezifitaet gegen sie. */
@media (max-width: 860px) {
    .nav--section,
    .nav--section--fixed {
        flex: 0 0 auto;
        overflow: visible;
    }
}

/* --- Monatsleiste des Kalenders ------------------------------------------ */

.monthbar {
    display: flex;
    align-items: center;
    /* ⚠️ Umbrechend, wie `.rowactions` seit #13056: vier Elemente (zurück,
       Monatsname, weiter, heute) passen auf einem Telefon nicht in eine
       Zeile — gemessen ragte „Heute" bei 390 px 29 px über den Bildschirm,
       und die ganze Seite scrollte seitwärts. */
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 16px;
}

.monthbar__title {
    font-size: 16px;
}

.monthbar__today {
    margin-left: auto;
}

/* --- Monatsgitter --------------------------------------------------------- */

.cal {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

.cal__weekday {
    padding: 10px 12px;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 11px;
    font-weight: 600;
    text-transform: none;
}

.cal__day {
    min-height: 104px;
    padding: 6px;
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.cal__day:nth-child(7n + 7) {
    border-right: 0;
}

/* Tage der Nachbarmonate: sichtbar, aber zurueckgenommen — eine Woche mit
   Luecken laesst sich nicht lesen. */
.cal__day--out {
    background: var(--bg);
}

.cal__day--out .cal__daynum {
    color: var(--text-dim);
}

.cal__day--today {
    box-shadow: inset 0 0 0 2px var(--accent);
}

.cal__day--holiday {
    background: var(--accent-soft);
}

.cal__daynum {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
}

.cal__holiday {
    font-size: 10px;
    font-weight: 500;
    color: var(--accent-dark);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cal__event {
    display: block;
    width: 100%;
    text-align: left;
    padding: 3px 6px;
    border: 0;
    border-left: 3px solid var(--accent);
    border-radius: 4px;
    background: var(--surface-hover);
    color: var(--text);
    font: inherit;
    font-size: 11px;
    line-height: 1.3;
    cursor: pointer;
    /* Im Projekt-Kalender ist der Eintrag ein LINK in die Akte statt eines
       Knopfes (geaendert wird ein Termin dort, wo er gefuehrt wird) — ohne
       das traege er die Unterstreichung eines Links. */
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cal__event:hover {
    background: var(--border);
}

.cal__event--wartung { border-left-color: var(--signal-orange); }
.cal__event--termin { border-left-color: var(--signal-green); }
.cal__event--sonstiges { border-left-color: var(--border-strong); }

.cal__eventtime {
    display: block;
    color: var(--text-dim);
    font-size: 10px;
}

/* Der Titel kuerzt sich SELBST — `text-overflow` am Knopf erreichte ihn nicht,
   solange er als nackter Text neben dem Zeit-Block stand (siehe Vorlage).
   Ein Termin brach dadurch mitten im Wort ab, ohne dass man es sah; die volle
   Bezeichnung steht weiterhin im `title` des Knopfes. */
.cal__eventtitle {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.cal__absent {
    margin: auto 0 0;
    color: var(--text-dim);
    font-size: 10px;
}

/* --- Kennzahlen-Kacheln --------------------------------------------------- */

.statgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-bottom: 16px;
}

.stat__label {
    margin: 0;
    color: var(--text-dim);
    font-size: 12px;
    font-weight: 600;
}

.stat__value {
    margin: 4px 0 2px;
    font-size: 24px;
    font-weight: 700;
}

.stat__hint {
    margin: 0;
    color: var(--text-muted);
    font-size: 12px;
}

/* Nur wenn eine Zahl zum Handeln auffordert — sonst waere die Farbe Dekoration. */
.stat--warn .stat__value {
    color: var(--signal-red);
}

/* --- Dashboard ------------------------------------------------------------ */

/* Kacheln im Raster; eine breite Kachel nimmt zwei Spalten, solange es zwei
   gibt. `dense` fuellt die Luecke, die eine breite Kachel am Zeilenende
   hinterlaesst, mit der naechsten schmalen. */
.dash {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    grid-auto-flow: row dense;
    gap: 16px;
}

.dash__tile {
    min-width: 0;
}

@media (min-width: 700px) {
    .dash__tile--wide {
        grid-column: span 2;
    }
}

.dash__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.dash__title {
    margin: 0;
    font-size: 16px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash__link {
    flex: 0 0 auto;
    font-size: 13px;
    color: var(--accent-dark);
}

.dash__stats {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 24px;
}

.dash__rows {
    list-style: none;
    margin: 14px 0 0;
    padding: 0;
    border-top: 1px solid var(--border);
}

.dash__row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border);
    font-size: 13px;
}

.dash__rowtext {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash__rowside {
    flex: 0 0 auto;
    color: var(--text-muted);
}

.dash__row--warn .dash__rowside {
    color: var(--signal-red);
}

.dash__empty {
    margin: 14px 0 0;
    color: var(--text-muted);
    font-size: 13px;
}

/* Der Dialog „Anpassen" */
.dash-pick {
    list-style: none;
    margin: 0;
    padding: 0;
}

.dash-pick__row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 0;
    border-bottom: 1px solid var(--border);
}

.dash-pick__main {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    flex: 1 1 auto;
    min-width: 0;
    cursor: pointer;
}

.dash-pick__text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    font-size: 14px;
}

.dash-pick__desc {
    color: var(--text-muted);
    font-size: 12px;
}

.dash-pick__wide {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
    color: var(--text-muted);
    font-size: 12px;
}

.dash-pick__move {
    display: flex;
    gap: 4px;
    flex: 0 0 auto;
}

/* --- Filter- und Reiterzeile ---------------------------------------------- */

.filterbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 12px;
    margin-bottom: 16px;
}

.field--inline {
    margin: 0;
    min-width: 160px;
}

.field--grow {
    flex: 1;
}

.field--check {
    flex-direction: row;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding-bottom: 8px;
    font-size: 14px;
}

.field-row {
    display: flex;
    gap: 12px;
}

.field-row .field {
    flex: 1;
}

.tabbar {
    display: flex;
    /* Umbrechen statt abschneiden: die Rechnungsliste hat fuenf Reiter, und
       auf einem Handy passt die Zeile sonst nicht — der letzte („Alle“) lag
       ausserhalb der Karte. Bei drei Reitern aendert die Regel nichts. */
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 16px;
    padding: 6px;
}

.tabbar__tab {
    padding: 7px 14px;
    border-radius: var(--radius);
    color: var(--text-muted);
    font-size: 14px;
}

.tabbar__tab:hover {
    background: var(--surface-hover);
    color: var(--text);
}

.tabbar__tab.is-active {
    background: var(--accent-soft);
    color: var(--accent-dark);
    font-weight: 600;
}

/* --- Hinweiskarte mit Handlungsbedarf ------------------------------------- */

.card--warn {
    border-left: 3px solid var(--signal-orange);
    margin-bottom: 16px;
}

/* Erklaerung statt Handlungsbedarf: die blaue Kante ist der Akzent der App,
   die orange bleibt dem reserviert, wo jemand etwas tun muss. */
.card--info {
    border-left: 3px solid var(--accent);
    margin-bottom: 16px;
}

.lowlist {
    margin: 8px 0 0;
    padding-left: 18px;
    color: var(--text-muted);
    font-size: 14px;
}

.lowlist li + li {
    margin-top: 4px;
}

/* --- Abzeichen der fuenf Seiten ------------------------------------------- */

/* Terminarten */
.badge--einsatz { background: var(--accent-soft); color: var(--accent-dark); }
.badge--wartung { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--termin { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--sonstiges { background: var(--border); color: var(--text-muted); }

/* Zeiteintrags-Arten. Arbeitszeit ist der Normalfall und bleibt neutral —
   Farbe traegt nur, was vom Normalfall abweicht. */
.badge--type0 { background: var(--border); color: var(--text-muted); }
.badge--type1 { background: var(--accent-soft); color: var(--accent-dark); }
.badge--type2 { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }
.badge--type4,
.badge--type5 { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--type6,
.badge--type7 { background: var(--border); color: var(--text-muted); }

.badge--pending { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--system { background: var(--border); color: var(--text-dim); }

/* Kanaele im Kundenverlauf (Feedback #13425).
   ⚠️ Unterschieden wird die RICHTUNG, nicht das Medium: eingehend traegt den
   Akzent (jemand will etwas von uns — das ist die Zeile, die man sucht),
   ausgehend bleibt neutral. Anruf und E-Mail derselben Richtung gleich zu
   faerben ist Absicht — welches von beidem es war, steht im Text daneben, und
   vier Farben in einer Zeile ordnen nichts mehr. Messenger folgt demselben
   Schema, das richtungslose „Persönlich" (#15392) steht beim Akzent: es
   erlaubt wie ein eingehender Kontakt den Rückruf.
   Die Klasse kommt aus `channel|replace('_', '-')`; `notiz` bekommt gar kein
   Abzeichen (das Template blendet es aus), sonst waere jede Zeile markiert. */
.badge--anruf-ein,
.badge--mail-ein,
.badge--messenger-ein,
.badge--persoenlich { background: var(--accent-soft); color: var(--accent-dark); }
.badge--anruf-aus,
.badge--mail-aus,
.badge--messenger-aus { background: var(--border); color: var(--text-muted); }

/* Aufgaben-Prioritaet. „Normal" bekommt bewusst kein Abzeichen (das Template
   blendet es aus): waere alles markiert, hiesse nichts mehr etwas. */
.badge--prio1 { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--prio2 { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }

/* Gebiete der Wartungsrotation (Feedback #13143).
   ⚠️ BEWUSST alle vier gleich und neutral. Die naheliegende Loesung — je
   Himmelsrichtung eine Farbe — waere hier gleich zweimal falsch: Rot, Orange
   und Gruen sind in dieser App bereits vergeben („ueberfaellig", „steht an",
   „erledigt"), ein rotes „Sued" laese sich also als Warnung; und seit der
   frei waehlbaren Akzentfarbe (#13114) kann JEDE neue Farbe unter einem der
   acht Akzente stehen. Eine Himmelsrichtung ist ohnehin keine Bewertung —
   der TEXT traegt die Aussage, nicht der Farbton.
   „Nahbereich" ist heller, weil er das Gegenteil einer Zuordnung ist: er
   passt an jeden Tourtag. */
.badge--gebiet-nord,
.badge--gebiet-ost,
.badge--gebiet-sued,
.badge--gebiet-west { background: var(--border); color: var(--text-muted); }
.badge--gebiet-nahbereich { background: var(--border); color: var(--text-dim); }

/* Ein Terminvorschlag AUSSERHALB der Gebietsrotation. Gestrichelt statt
   farbig, aus demselben Grund wie oben — und er bleibt voll bedienbar: die
   Rotation ordnet, sie verbietet nicht. */
.btn--fremd {
    border-style: dashed;
}

.badge--status-offen { background: var(--border); color: var(--text-muted); }
.badge--status-laeuft { background: var(--accent-soft); color: var(--accent-dark); }
.badge--status-erledigt { background: rgba(47, 143, 87, 0.12); color: #226b41; }

/* Aufgaben-ART (Feedback #13136). Dieselben Farbwerte wie bei den
   Terminarten — dasselbe Signal soll nicht zweimal anders aussehen.
   „Sonstiges" bekommt keines: es ist der Auslieferungswert, das Template
   blendet es aus (wie „Normal" bei der Prioritaet). */
.badge--art-wartung { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--art-stoerung { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }
.badge--art-reparatur { background: var(--accent-soft); color: var(--accent-dark); }
.badge--art-einbau { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--art-aufmass { background: var(--border); color: var(--text-muted); }

/* --- Fotos an einer Aufgabe (Feedback #13136) ----------------------------- */

/* Das Dateifeld selbst ist unsichtbar; sichtbar ist die Flaeche darueber.
   Ein natives `input[type=file]` sieht auf jeder Plattform anders aus und
   laesst sich nicht gestalten — es bliebe der einzige Fremdkoerper in einer
   sonst durchgestalteten Oberflaeche. */
.filepick input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    /* NICHT `display: none` — dann ist das Feld fuer die Tastatur nicht mehr
       erreichbar und der Fokusrahmen unten wuerde nie erscheinen. */
}

.filepick {
    display: block;
    position: relative;
    cursor: pointer;
}

.filepick__face {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    /* 44 px hoch: das ist die Flaeche, die ein Daumen sicher trifft. Alles
       darunter ist auf einem Telefon eine Zielscheibe, kein Knopf. */
    min-height: 44px;
    padding: 10px 14px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    /* ⚠️ `--surface`, NICHT `--flaeche`: letzteres ist im Glas-Thema ein
       Verlaufs-BILD fuer die ganze Seite und ergaebe in einem 44-px-Kasten
       einen Farbfleck. */
    background: var(--surface);
    color: var(--text-dim);
    font-size: 14px;
}

.filepick:hover .filepick__face,
.filepick input[type="file"]:focus + .filepick__face {
    border-color: var(--accent);
    color: var(--accent-dark);
}

.filepick__face svg {
    width: 18px;
    height: 18px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
}

/* Hinweis unmittelbar unter einem Feld — ohne Trennlinie und ohne den
   grossen Abstand, den `.hint` unter einer Karte braucht. */
.hint--tight {
    border-top: none;
    padding-top: 0;
    margin: 6px 0 0;
}

/* Die Checkliste einer Aufgabe (Feedback #13418). Sie steht im Dialog
   zwischen den Eckdaten und der Galerie: sie sagt, was zu tun ist, die
   Fotos belegen, dass es getan wurde.

   Bewusst OHNE eigene Kartenflaeche — sie liegt bereits in `.modal__pad`,
   und ein Kasten im Kasten sieht auf einem Telefon nach einem Fehler aus. */
.checkliste {
    margin-top: 18px;
}

.checkliste__zeile {
    display: flex;
    align-items: baseline;
    /* ⚠️ Umbrechen wie bei `.rowactions` (Feedback #13056): der Text eines
       Punktes ist bis zu 200 Zeichen lang, daneben stehen zwei Knoepfe. Ohne
       `wrap` schoebe ein langer Punkt „Foto" und „Entfernen" aus dem
       Dialog. */
    flex-wrap: wrap;
    gap: 4px 10px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border);
}

.checkliste__haken {
    display: flex;
    align-items: baseline;
    gap: 9px;
    /* Der Text nimmt den Platz, die Knoepfe bekommen den Rest. */
    flex: 1 1 60%;
    cursor: pointer;
}

.checkliste__haken input {
    /* Groesser als der Browser-Standard: abgehakt wird mit dem Daumen auf
       einer Baustelle, nicht mit der Maus am Schreibtisch. */
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    accent-color: var(--accent);
    cursor: pointer;
}

/* Abgehakt wird durchgestrichen und blasser — auf einen Blick sichtbar, was
   noch offen ist, ohne die Zeile zu verschieben. */
.checkliste__zeile.is-done .checkliste__haken span {
    color: var(--text-dim);
    text-decoration: line-through;
}

.checkliste__knopf {
    flex-shrink: 0;
    font-size: 13px;
}

/* Die Belege zu GENAU diesem Punkt — klein, direkt darunter, ueber die ganze
   Zeilenbreite (`flex-basis: 100%` bricht sie unter den Text). */
.checkliste__belege {
    display: flex;
    flex-wrap: wrap;
    flex-basis: 100%;
    gap: 6px;
    margin-top: 2px;
}

.checkliste__belege img {
    display: block;
    width: 56px;
    height: 56px;
    border-radius: var(--radius);
    object-fit: cover;
}

.checkliste__neu {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 12px;
}

.checkliste__neu .field__input {
    flex: 1 1 180px;
}

/* Die Galerie. `auto-fill` statt fester Spalten: auf dem Telefon stehen zwei
   Bilder nebeneinander, auf dem Bildschirm vier — ohne eine zweite Regel je
   Breite. */
.fotos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 10px;
    margin-top: 16px;
}

/* Enger für die Fotos einer Anlage in der Kundenakte: sie stehen IN einer
   Tabellenzelle, und das 120-px-Raster zöge die Spalte auf, bis der Rest der
   Zeile nicht mehr lesbar wäre. */
.fotos--mini {
    grid-template-columns: repeat(auto-fill, minmax(64px, 72px));
    gap: 6px;
    margin-top: 8px;
}

.fotos__item {
    position: relative;
    margin: 0;
}

.fotos__blatt {
    display: block;
    /* In der Aufgabenansicht ist das ein `<a>` (Bild in voller Groesse), in
       der Baustellendokumentation der Projektakte ein `<button>` (fuehrt zur
       Aufgabe) — Feedback #13418. Ein Knopf bringt Rahmen, Polsterung und
       eine eigene Breite mit; ohne diese drei Zeilen saesse das Bild in einem
       grauen Kasten und waere schmaler als seine Spalte. */
    width: 100%;
    padding: 0;
    border: none;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg);
    cursor: pointer;
}

.fotos__blatt img {
    display: block;
    width: 100%;
    /* Quadratisch beschnitten: Hoch- und Querformat nebeneinander ergeben
       sonst eine Treppe statt einer Reihe. Das ganze Bild sieht, wer es
       antippt — der Blattlink oeffnet es in voller Groesse. */
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

.fotos__weg {
    position: absolute;
    top: 6px;
    right: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: none;
    border-radius: 9999px;
    background: rgba(33, 33, 33, 0.62);
    color: #fff;
    cursor: pointer;
}

.fotos__weg svg {
    width: 15px;
    height: 15px;
    fill: none;
    stroke: currentColor;
    stroke-width: 2.2;
}

.fotos__item figcaption {
    margin-top: 4px;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 16px;
    /* Eine lange Bildunterschrift darf die Spalte nicht aufziehen — sonst
       verschiebt EIN Bild das ganze Raster. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Anhaenge im Feedback-Dialog ------------------------------------------
   Die Kacheln sind dieselben wie bei den Fotos einer Anlage (`.fotos--mini`);
   hier steht nur, was der Dialog darueber hinaus braucht. */
.fb-anhang__knoepfe {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.fb-anhang__hinweis {
    margin: 8px 0 0;
}

/* Ein PDF hat kein Vorschaubild — eine Kachel in derselben Groesse, damit
   das Raster nicht springt. */
.fb-anhang__datei {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1 / 1;
    color: var(--text-muted);
    font-size: 12px;
    font-weight: 700;
}

.fb-anhang--laeuft {
    opacity: 0.45;
}

/* Das Kreuz ist hier Text statt SVG — das Kaestchen wird im Skript gebaut. */
.fb-anhang__weg {
    top: 3px;
    right: 3px;
    width: 22px;
    height: 22px;
    font-size: 16px;
    line-height: 1;
}

/* Die Leinwand zum Markieren. Breite UND Hoehe begrenzt: ein Hochkant-
   Bildschirmfoto vom Telefon waere sonst hoeher als der Dialog, und der
   Rahmen liesse sich unten nicht mehr ziehen. `touch-action: none`, sonst
   scrollt der Finger die Seite, statt einen Rahmen zu ziehen. */
.fb-markieren__leinwand {
    display: block;
    max-width: 100%;
    max-height: 62vh;
    margin: 0 auto;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    cursor: crosshair;
    touch-action: none;
}

.fb-markieren__hinweis {
    margin: 0 0 10px;
}

/* Die Fotozahl in der Aufgabenliste — Symbol und Zahl gehoeren zusammen und
   duerfen nicht umbrechen. */
.table__photos {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: 6px;
    color: var(--text-dim);
    white-space: nowrap;
}

.table__photos svg {
    width: 13px;
    height: 13px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
}

/* --- Zeilen, die auffallen sollen ----------------------------------------- */

.table tbody tr.is-low td,
.table tbody tr.is-overdue td {
    background: rgba(232, 133, 10, 0.06);
}

/* Die eine Zeile, die den Vorgang entschieden hat: das angenommene Angebot in
   der Projektakte. Gruen statt orange — hier faellt etwas auf, weil es GILT,
   nicht weil es klemmt (dieselbe Farbe wie `badge--ang-angenommen`). */
.table tbody tr.is-accepted td {
    background: rgba(47, 143, 87, 0.08);
}

/* Derselbe ueberschrittene Termin, nur nicht in einer getoenten Zeile: in
   der Nachkalkulation steht er als Unterzeile in einer Zelle, die schon eine
   Aussage traegt (Feedback #13055). */
.meta--overdue {
    color: var(--signal-orange);
    font-weight: 600;
}

/* --- Unterweisungs-Matrix ------------------------------------------------- */

/* Sie waechst mit jeder Unterweisungsart nach rechts — auf einem schmalen
   Bildschirm scrollt sie, statt die Seite zu sprengen. */
.tablescroll {
    overflow-x: auto;
}

.table--matrix th,
.table--matrix td {
    vertical-align: top;
    white-space: nowrap;
}

/* --- Kleinteile ----------------------------------------------------------- */

/* Schaltflaeche, die wie ein Link aussieht — fuer Aktionen mitten im Text. */
.linkbtn {
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent-dark);
    font: inherit;
    font-size: inherit;
    text-align: left;
    cursor: pointer;
}

.linkbtn:hover {
    text-decoration: underline;
}

.material + .material {
    margin-top: 16px;
}

.modal__sub {
    margin: 0 0 12px;
    color: var(--text-muted);
    font-size: 13px;
}

.perms--compact {
    max-height: 220px;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0 10px;
}

.perms--compact .perms__row {
    padding: 8px 2px;
}

/* --- Verlauf eines Kunden ------------------------------------------------- */

/* Chronologische Eintraege unter dem Eingabefeld. Bewusst keine Sprechblasen
   wie in einem Chat: das hier ist eine Akte, kein Gespraech. */
.notelist {
    list-style: none;
    margin: 18px 0 0;
    padding: 0;
    border-top: 1px solid var(--border);
}

.notelist li {
    padding: 12px 2px;
    border-bottom: 1px solid var(--border);
}

.notelist__meta {
    margin: 0 0 4px;
    color: var(--text-dim);
    font-size: 12px;
}

/* `white-space: pre-line` erhaelt die Absaetze, die jemand eingetippt hat —
   ohne sie steht ein Verlaufseintrag als eine Textwurst da. */
.notelist__text {
    margin: 0;
    font-size: 14px;
    line-height: 21px;
    white-space: pre-line;
}

/* Dasselbe fuer Einleitung und Schlussbemerkung eines gesperrten Angebots
   bzw. einer gestellten Rechnung (`_blatttexte.html`). Auf dem PDF uebernimmt
   das je ein Absatz — der Renderer dort kennt `pre-line` nicht. */
.blatttext {
    margin: 0;
    white-space: pre-line;
    overflow-wrap: anywhere;
}

/* Auf schmalen Viewports wird aus dem Monatsgitter eine kompakte Uebersicht:
   die Tageszellen schrumpfen, Termine bleiben antippbar. */
@media (max-width: 860px) {
    .cal__day {
        min-height: 76px;
        padding: 4px;
    }

    .cal__weekday {
        padding: 8px 4px;
    }

    .cal__holiday {
        display: none;
    }

    .field-row {
        flex-direction: column;
        gap: 0;
    }
}

/* ===========================================================================
   Informationen — Wiki und Neuerungen
   =========================================================================== */

/* Suchzeile: das Feld nimmt den Platz, der Knopf steht daneben. */
.wiki__search {
    display: flex;
    flex: 1;
    align-items: flex-end;
    gap: 12px;
    min-width: 0;
}

/* Seitenbaum. Die Einrueckung MUSS die Gliederung zeigen — eine flache Liste
   waere genau das, wogegen ein Baum antritt. Die Linie links macht sichtbar,
   welche Eintraege zusammengehoeren. */
.wikitree {
    margin: 0;
    padding: 0;
    list-style: none;
}

.wikitree .wikitree {
    margin-left: 10px;
    padding-left: 14px;
    border-left: 1px solid var(--border);
}

.wikitree__item {
    padding: 6px 0;
}

.wikitree__link {
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

.wikitree__link:hover {
    color: var(--accent-dark);
    text-decoration: underline;
}

.wikitree__meta {
    margin-left: 8px;
    color: var(--text-dim);
    font-size: 12px;
}

/* Kurzhilfe zur Auszeichnung — zugeklappt, damit sie beim zweiten Mal nicht
   im Weg steht. */
.wikihelp {
    margin-bottom: 16px;
    padding: 8px 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 13px;
}

.wikihelp summary {
    cursor: pointer;
    color: var(--text-muted);
}

.wikihelp__list {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 12px;
    margin: 12px 0 4px;
}

.wikihelp__list dt {
    margin: 0;
}

.wikihelp__list dd {
    margin: 0;
    color: var(--text-muted);
}

/* Eingabefeld fuer Wiki-Text: dicktengleich, weil die Auszeichnung
   zeilenweise arbeitet und Einrueckung dann sichtbar bleibt. */
.field__input--code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.55;
}

/* Der gerenderte Artikel. Hier gilt ausnahmsweise Element- statt
   Klassen-Selektion: das HTML erzeugt `app/wikitext.py`, es kann also keine
   Klassen tragen — und was dort NICHT erzeugt wird, kann hier auch nicht
   auftauchen. */
.wiki {
    max-width: 74ch;
    line-height: 1.65;
}

.wiki h2,
.wiki h3,
.wiki h4 {
    margin: 24px 0 8px;
    font-weight: 700;
}

.wiki h2 { font-size: 20px; }
.wiki h3 { font-size: 17px; }
.wiki h4 { font-size: 15px; }

.wiki > :first-child {
    margin-top: 0;
}

.wiki p {
    margin: 0 0 12px;
}

.wiki ul,
.wiki ol {
    margin: 0 0 12px;
    padding-left: 22px;
}

.wiki li {
    margin-bottom: 4px;
}

.wiki blockquote {
    margin: 0 0 12px;
    padding: 10px 14px;
    background: var(--accent-soft);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius) var(--radius) 0;
}

.wiki code {
    padding: 1px 5px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.9em;
}

.wiki__code {
    margin: 0 0 12px;
    padding: 12px 14px;
    overflow-x: auto;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.55;
}

/* Weg von der Wurzel bis zum Artikel. */
.crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: 16px;
    color: var(--text-dim);
    font-size: 13px;
}

.crumbs a {
    color: var(--text-muted);
    text-decoration: none;
}

.crumbs a:hover {
    color: var(--accent-dark);
    text-decoration: underline;
}

.crumbs__sep {
    color: var(--border-strong);
}

.crumbs__here {
    color: var(--text);
    font-weight: 600;
}

/* --- Neuerungen ---------------------------------------------------------- */

.release__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.release__list {
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

.release__item {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 8px 0;
    border-top: 1px solid var(--border);
}

/* Feste Spalte fuer das Abzeichen — so beginnt jeder Titel an derselben
   Stelle und die Liste liest sich als Liste (Vorbild: die Chip-Spalte in
   `AppVersionPage`). */
.release__item .badge {
    flex-shrink: 0;
    width: 124px;
    text-align: center;
}

.release__title {
    min-width: 0;
    word-break: break-word;
}

/* Ueberschrift eines Fachbereichs innerhalb eines Releases (Feedback #12995).
   Kein Versalsatz, keine gesperrte Laufweite — schlicht fett wie jede andere
   Ueberschrift der App; die blaue Kante links ordnet sie der Gruppe darunter
   zu, ohne eine zweite Karte aufzumachen. */
.release__bereich {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 22px 0 0;
    padding-left: 10px;
    border-left: 3px solid var(--accent);
    font-size: 14px;
    font-weight: 700;
}

/* Die erste Ueberschrift steht direkt unter dem Release-Kopf und braucht
   dessen Abstand nicht doppelt. */
.release__bereich:first-of-type {
    margin-top: 14px;
}

.release__bereich a {
    color: inherit;
    text-decoration: none;
}

.release__bereich a:hover {
    color: var(--accent);
    text-decoration: underline;
}

.release__anzahl {
    color: var(--text-muted);
    font-size: 12px;
    font-weight: 600;
}

/* ===========================================================================
   Sonstiges — Bestenliste, Bewertungen, Visitenkarte
   =========================================================================== */

/* Die eigene Zeile faellt aus der Tabelle heraus — man sucht sie ohnehin
   zuerst. */
.table tr.is-me {
    background: var(--accent-soft);
}

/* Die ersten drei Plaetze bekommen eine Medaille statt einer Zahl. */
.rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 9999px;
    color: #3a2c00;
    font-size: 13px;
    font-weight: 700;
}

.rank--1 { background: #f3cf5a; }
.rank--2 { background: #d6dade; }
.rank--3 { background: #ddab74; }

/* --- Bewertungen --------------------------------------------------------- */

.cardgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
    margin-bottom: 16px;
}

/* Steckbrief und Karte der Projektakte. Die Karte ist die schmalere Haelfte:
   der Steckbrief traegt zehn Zeilen Text, die Karte braucht nur genug Flaeche,
   um die Umgebung zu zeigen. Unterhalb der Umbruchbreite (`auto-fit`) stehen
   sie ohnehin untereinander, und dann steht der Steckbrief oben — die Frage
   „wer und was" kommt vor „wo". */
.cardgrid--akte {
    grid-template-columns: minmax(260px, 3fr) minmax(260px, 2fr);
}

@media (max-width: 900px) {
    .cardgrid--akte {
        grid-template-columns: 1fr;
    }
}

/* Die eingebettete OpenStreetMap-Karte (Feedback #13059). Ein `iframe`, kein
   JavaScript-Paket: diese App hat bewusst keinen Frontend-Build, und eine
   Kartenbibliothek waere ihre erste externe Abhaengigkeit im Browser.

   Die feste Hoehe ist Absicht statt eines Seitenverhaeltnisses: ein `iframe`
   hat keinen Inhalt, aus dem sich eine Hoehe ergeben koennte, und eine
   prozentuale Hoehe kollabiert im Gitter auf 0. */
.map {
    margin-top: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg);
}

.map__frame {
    display: block;
    width: 100%;
    height: 260px;
    border: 0;
}

/* Auf der Kartenseite ist die Karte der Inhalt und nicht die Beigabe — dort
   darf sie hoeher sein. */
.map--gross .map__frame {
    height: 420px;
}

/* Die gerade gezeigte Baustelle in der Liste darunter. Dieselbe Akzentkante
   wie am aktiven Navigationspunkt: sie sagt „hier stehst du", ohne die Zeile
   einzufaerben (getoente Zeilen bedeuten in dieser App „ueberfaellig"). */
.table tbody tr.is-selected td:first-child {
    box-shadow: inset 3px 0 0 var(--accent);
}

.qrcard {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.qrcard__text {
    margin: 0 0 16px;
    color: var(--text-muted);
    font-size: 14px;
}

.qrcard__code {
    margin-bottom: 16px;
}

/* Der QR-Code kommt als SVG ohne feste Groesse (siehe `app/vcard.qr_svg`) —
   die Groesse macht deshalb das CSS. */
.qr {
    display: block;
    width: 180px;
    height: 180px;
}

/* --- Visitenkarte -------------------------------------------------------- */

.vcard {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
}

.vcard__body {
    flex: 1;
    min-width: 220px;
}

.vcard__logo {
    height: 26px;
    margin-bottom: 12px;
}

.vcard__name {
    margin: 0;
    font-size: 22px;
    font-weight: 700;
    word-break: break-word;
}

.vcard__role {
    margin: 2px 0 20px;
    color: var(--text-muted);
}

.vcard__rows {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 8px 20px;
    margin: 0;
}

.vcard__rows dt {
    margin: 0;
    color: var(--text-dim);
    font-size: 13px;
}

.vcard__rows dd {
    margin: 0;
    font-weight: 500;
    word-break: break-word;
}

.vcard__qr {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}

/* Auf dem Telefon steht die Karte untereinander; der Code bleibt gross genug
   zum Abscannen vom Nachbargeraet. */
@media (max-width: 860px) {
    .vcard {
        flex-direction: column;
        align-items: stretch;
    }

    .vcard__qr {
        align-items: flex-start;
    }

    .release__item {
        flex-direction: column;
        gap: 4px;
    }

    .release__item .badge {
        width: auto;
    }
}

/* --- Finanzen ------------------------------------------------------------- */

/* Der Bereich stapelt mehrere Karten direkt untereinander (Liste, Kunden,
   Positionen, Zahlungen) — bis hierher trennte immer eine Zwischen-
   ueberschrift zwei Karten, deshalb gab es die Regel noch nicht.

   Bewusst nur fuer DIREKTE Kinder des Inhalts: die Kacheln in `.statgrid`
   sind Gitterzellen, ein Aussenabstand an ihnen verschoebe die Reihe. Bei
   Nachbarn, die schon einen Abstand mitbringen (`.card--warn`, `.material`),
   fallen die beiden Abstaende zusammen — es entsteht keine doppelte Luecke. */
.content > .card + .card {
    margin-top: 16px;
}

/* Zustand einer Rechnung. Der Entwurf bleibt neutral — er ist der Normalfall
   am Anfang; Farbe traegt nur, was eine Aussage macht. */
.badge--rg-entwurf { background: var(--border); color: var(--text-muted); }
.badge--rg-gestellt { background: var(--accent-soft); color: var(--accent-dark); }
.badge--rg-bezahlt { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--rg-storniert { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }

/* Angebote. Dieselben vier Toene wie bei der Rechnung und in derselben
   Bedeutung: grau = noch nicht heraus, Akzent = liegt beim Gegenueber,
   gruen = erledigt und gut, rot = erledigt und nicht gut. Ein eigener
   Praefix, weil die Status ANDERS heissen — `angenommen` ist nicht
   `bezahlt`, und eine gemeinsame Klasse waere beim naechsten Status
   stillschweigend falsch. */
.badge--ang-entwurf { background: var(--border); color: var(--text-muted); }
.badge--ang-versendet { background: var(--accent-soft); color: var(--accent-dark); }
.badge--ang-angenommen { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--ang-abgelehnt { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }

/* Zustand eines BELEGS (Eingangsrechnung, Feedback #13642). Dieselbe Regel
   wie bei der Rechnung: Farbe traegt nur, was eine Aussage macht — und hier
   macht schon der Ausgangszustand eine, denn „zur Freigabe" heisst „jemand
   muss etwas tun". Deshalb ist er als einziger Anfangszustand der App
   gefaerbt. */
.badge--bl-erfasst { background: rgba(232, 133, 10, 0.12); color: #8a4e05; }
.badge--bl-freigegeben { background: var(--accent-soft); color: var(--accent-dark); }
.badge--bl-bezahlt { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--bl-abgelehnt { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }

/* Die Skontofrist. ⚠️ „Verfallen" bleibt bewusst GRAU: es ist eine
   Vorhaltung, keine Aufforderung — rot geschrieben stuende an jedem aelteren
   Beleg ein Alarm fuer etwas, das niemand mehr aendern kann. Gefaerbt ist,
   was noch zu holen ist. */
.badge--sk-offen { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--sk-laeuft_ab { background: rgba(232, 133, 10, 0.12); color: #8a4e05; }
.badge--sk-verfallen { background: var(--border); color: var(--text-muted); }
.badge--sk-aus { background: var(--border); color: var(--text-muted); }

/* Zustand eines Kontoumsatzes. „Offen" ist der Normalfall direkt nach dem
   Einlesen und bleibt neutral; die Zahl der offenen steht ohnehin als
   Kennzahl ueber der Liste. */
.badge--tx-offen { background: var(--border); color: var(--text-muted); }
.badge--tx-zugeordnet { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--tx-ignoriert { background: var(--border); color: var(--text-muted); }

/* ⚠️ Ein Vorschlag ist KEINE Zuordnung — er sieht deshalb anders aus als
   „zugeordnet" (blau statt gruen). Waeren beide gleich, saehe die Liste so
   aus, als haette die App schon gebucht; gebucht hat sie nur, was eindeutig
   war (`app/abgleich.py`). */
.badge--vorschlag { background: var(--accent-soft); color: var(--accent-dark); }

/* Ein Abzug ist die einzige Zahl im Bereich, die man auf keinen Fall
   ueberlesen darf — sie geht dem Mitarbeiter vom Lohn ab. */
.is-negative {
    color: var(--signal-red);
}

/* Summenzeile unter einer Tabelle (Netto, Umsatzsteuer, Brutto). Sie steht
   bewusst IM selben Gitter wie die Positionen: eine Summe daneben muesste die
   Spaltenbreiten ein zweites Mal treffen. */
.table tfoot td {
    padding: 8px 14px;
    color: var(--text-muted);
    font-size: 14px;
}

.table tfoot tr:first-child td {
    border-top: 1px solid var(--border);
}

.table tfoot strong {
    color: var(--text);
}

/* Balken des Monatsverlaufs. Die Breite kommt fertig in Prozent aus der Route
   (`finanzen.py::umsatz`) — ein Diagramm-Paket waere der erste Frontend-Build
   dieser App, fuer zwoelf Zahlen. */
.bar {
    height: 8px;
    border-radius: 9999px;
    background: var(--border);
    overflow: hidden;
}

.bar__fill {
    height: 100%;
    border-radius: 9999px;
    background: var(--accent);
}

/* Erklaerender Satz unter einem Eingabefeld — der offene Rechnungsbetrag,
   die Bedeutung einer Lohn-Art. Bewusst kein Platzhaltertext: der
   verschwindet beim Tippen, gerade dann wird er gebraucht. */
.field__hint {
    display: block;
    margin-top: 4px;
    color: var(--text-muted);
    font-size: 12px;
}

/* ==========================================================================
   Thema „Glas" — Feedback #12942
   ==========================================================================
   Ein ZWEITES Thema, kein Ersatz: der Standard oben bleibt unveraendert,
   hier steht nur, was sich unter `<html data-thema="glass">` aendert.
   Vorbild ist Apples „Liquid Glass" — milchglasartige Flaechen, hinter
   denen der Untergrund durchscheint, mit einem hellen Lichtrand an der
   Oberkante.

   Drei Entscheidungen tragen den ganzen Block:

   1. **Der Effekt haengt an VARIABLEN, nicht an Regeln.** `--glas` (die
      Unschaerfe), `--glanz` (der Lichtrand) und `--flaeche` (der farbige
      Grund) werden weiter unten an genau EINER Stelle abgeschaltet — die
      Rueckfallebene braucht deshalb keine zweite Kopie der Regeln.
   2. **Glas nur auf NEUTRALEN Flaechen.** Alles Blaue bleibt deckend:
      weisse Schrift auf durchscheinendem Akzent verliert Kontrast, und
      der Knopf ist die Stelle, an der man das nicht bemerkt, bevor
      jemand ihn nicht mehr lesen kann.
   3. **Nicht auf Listen.** Unschaerfe kostet pro Flaeche Rechenzeit;
      `backdrop-filter` an jeder Tabellenzeile macht das Scrollen auf
      schwachen Geraeten sichtbar zaeh. Geglast wird die Huelle — Leiste,
      Karte, Dialog —, nicht ihr Inhalt.
   ========================================================================== */

html[data-thema="glass"] {
    /* Die Unschaerfe. `saturate` gehoert dazu: ohne sie wirkt das, was
       durchscheint, ausgewaschen statt gefiltert. */
    --glas: saturate(180%) blur(20px);
    /* Der Lichtrand an der Oberkante — das, was Glas als Glas lesbar
       macht. Wird IMMER als erster Eintrag einer Schattenliste gesetzt. */
    --glanz: inset 0 1px 0 rgba(255, 255, 255, 0.75);

    /* Der farbige Grund. Milchglas ueber Hellgrau sieht aus wie
       Hellgrau — es braucht etwas zum Durchscheinen.

       ⚠️ Zwei der drei Verlaeufe folgen seit Feedback #13114 dem GEWAEHLTEN
       Akzent (`--accent-rgb`), nicht mehr fest dem Logo-Blau. Ohne das
       laege unter einem Beeren-Akzent weiterhin eine blaue Flaeche — Akzent
       rot, Seite blau.

       Das Orange bleibt dagegen fest: es stammt aus dem Verlauf im
       Signet und gehoert damit zur Marke, nicht zur Wahl. Und weil
       „Breuer-Blau" der Auslieferungszustand ist, ergibt der Block
       unveraendert den Verlauf von vorher — wer nichts waehlt, sieht
       nichts Neues. */
    --flaeche:
        radial-gradient(60rem 45rem at 8% -8%, rgba(var(--accent-rgb), 0.26), transparent 62%),
        radial-gradient(45rem 40rem at 98% 4%, rgba(232, 133, 10, 0.16), transparent 60%),
        radial-gradient(55rem 45rem at 62% 108%, rgba(var(--accent-rgb), 0.18), transparent 62%);

    /* Flaechen werden durchscheinend, Rahmen zu hellen Kanten. */
    --surface: rgba(255, 255, 255, 0.72);
    --surface-hover: rgba(255, 255, 255, 0.92);
    --border: rgba(255, 255, 255, 0.62);
    /* Feldrahmen brauchen weiter eine sichtbare Linie — ein weisser Rand
       auf weisslichem Glas waere kein Rand. */
    --border-strong: rgba(96, 120, 136, 0.32);

    /* Der kleine Text steht jetzt auf einer getoenten statt auf einer
       weissen Flaeche. `#6f6f6f` kaeme dort unter 4,5:1 — dieser Wert
       bleibt darueber. */
    --text-dim: #545b60;

    /* Weiter und weicher: Glas wirft keinen harten Schatten. */
    --shadow: 0 10px 34px rgba(17, 40, 58, 0.12);
    --shadow-card: 0 8px 28px rgba(17, 40, 58, 0.10);
}

/* Der Grund, auf dem alles liegt. `fixed`, damit die mitscrollende
   Seitenleiste ueber der ganzen Seite denselben Farbverlauf filtert —
   ohne das verliert sie beim Scrollen ihre Faerbung und wirkt tot. */
html[data-thema="glass"] body,
html[data-thema="glass"] .login-page {
    background-color: var(--bg);
    background-image: var(--flaeche);
    background-attachment: fixed;
    background-repeat: no-repeat;
}

/* Die geglasten Flaechen — die Huelle der App, nicht ihr Inhalt. */
html[data-thema="glass"] .sidebar,
html[data-thema="glass"] .mobilebar,
html[data-thema="glass"] .card,
html[data-thema="glass"] .login-card,
html[data-thema="glass"] .modal__box {
    -webkit-backdrop-filter: var(--glas);
    backdrop-filter: var(--glas);
}

html[data-thema="glass"] .card,
html[data-thema="glass"] .login-card {
    box-shadow: var(--glanz), var(--shadow-card);
}

html[data-thema="glass"] .sidebar {
    /* Etwas durchsichtiger als eine Karte: sie ist die groesste Flaeche,
       und der Verlauf soll durch sie hindurch sichtbar bleiben. */
    background: rgba(255, 255, 255, 0.60);
    box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.55);
}

html[data-thema="glass"] .mobilebar {
    background: rgba(255, 255, 255, 0.68);
    box-shadow: var(--glanz);
}

/* Der Dialog liegt ueber einem abgedunkelten Hintergrund. Waere er so
   durchscheinend wie eine Karte, filterte er genau dieses Dunkel und
   wuerde grau — deshalb hier deckender. */
html[data-thema="glass"] .modal__box {
    /* Die angeheftete Knopfreihe deckt hier nicht, sie VERSCHLEIERT: sie
       traegt `backdrop-filter: var(--glas)`, der Inhalt scrollt also
       sichtbar unscharf unter ihr weg statt zu verschwinden. Deckend waere
       sie ein weisser Balken in einem durchscheinenden Dialog. */
    --modal-flaeche: rgba(255, 255, 255, 0.72);
    background: rgba(255, 255, 255, 0.88);
    box-shadow: var(--glanz), 0 16px 48px rgba(17, 40, 58, 0.28);
}

/* Der Schleier hinter dem Dialog verschwimmt mit, statt nur abzudunkeln —
   das ist der Effekt, den man von der Vorlage kennt. */
html[data-thema="glass"] .modal__backdrop {
    background: rgba(17, 28, 39, 0.30);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

/* Tabellenkopf: das Hellgrau des Standards waere ein deckender Balken
   mitten in einer durchscheinenden Karte. */
html[data-thema="glass"] .table thead {
    background: rgba(255, 255, 255, 0.45);
}

/* Eingabefelder deckender als ihre Karte — sonst verschwaeme das Feld
   mit dem Untergrund und man saehe nicht mehr, wo man tippt. */
html[data-thema="glass"] .field__input {
    background: rgba(255, 255, 255, 0.86);
}

/* Blau bleibt deckend (Punkt 2 oben) — nur der Lichtrand kommt dazu. */
html[data-thema="glass"] .fab {
    box-shadow: var(--glanz),
                0 10px 28px rgba(var(--accent-rgb), 0.32),
                0 2px 6px rgba(17, 28, 39, 0.15);
}

/* --------------------------------------------------------------------------
   Rueckfallebene — eine Stelle fuer drei Anlaesse
   --------------------------------------------------------------------------
   Weil der Effekt an `--glas`, `--glanz` und `--flaeche` haengt, genuegt
   es, diese drei stillzulegen und die Flaechen deckend zu machen. Die
   App bleibt vollstaendig bedienbar, sie sieht nur wieder aus wie der
   Standard.

   `--glanz` wird auf einen WIRKUNGSLOSEN Schatten gesetzt, nicht auf
   `none`: er steht in `box-shadow`-Listen, und `none` ist dort kein
   gueltiger Eintrag — die ganze Deklaration fiele aus.

   Warum jeweils:
   * `print`  — /rechnungen/<id> ist die Ansicht, aus der gedruckt wird.
                Milchglas wird auf Papier grau, und der Farbverlauf kostet
                Toner fuer nichts.
   * reduced-transparency — eine ausdrueckliche Ansage des Betriebssystems.
   -------------------------------------------------------------------------- */

@media print, (prefers-reduced-transparency: reduce) {
    html[data-thema="glass"] {
        --glas: none;
        --glanz: 0 0 rgba(0, 0, 0, 0);
        --flaeche: none;
        --surface: #ffffff;
        --surface-hover: #eef1f2;
        --border: #e8ecee;
        --border-strong: #d2d9dc;
        --text-dim: #6f6f6f;
        --shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
        --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.05);
    }

    html[data-thema="glass"] .sidebar,
    html[data-thema="glass"] .mobilebar,
    html[data-thema="glass"] .modal__box,
    html[data-thema="glass"] .field__input {
        background: var(--surface);
    }

    /* Ohne Unschaerfe muss die Knopfreihe wieder DECKEN — eine getoente
       Flaeche liesse den weggescrollten Text durchscheinen. */
    html[data-thema="glass"] .modal__box {
        --modal-flaeche: var(--surface);
    }

    html[data-thema="glass"] .table thead {
        background: var(--bg);
    }

    html[data-thema="glass"] .modal__backdrop {
        background: rgba(17, 28, 39, 0.45);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
    }
}

/* Browser ohne `backdrop-filter`: dieselbe Rueckfallebene. Ohne sie
   waeren die Flaechen einfach durchsichtig — Text auf Text. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
    html[data-thema="glass"] {
        --glas: none;
        --glanz: 0 0 rgba(0, 0, 0, 0);
        --surface: #ffffff;
        --surface-hover: #eef1f2;
        --border: #e8ecee;
        --border-strong: #d2d9dc;
        --text-dim: #6f6f6f;
    }

    html[data-thema="glass"] .sidebar,
    html[data-thema="glass"] .mobilebar,
    html[data-thema="glass"] .modal__box,
    html[data-thema="glass"] .field__input {
        background: var(--surface);
    }

    /* Ohne Unschaerfe muss die Knopfreihe wieder DECKEN — eine getoente
       Flaeche liesse den weggescrollten Text durchscheinen. */
    html[data-thema="glass"] .modal__box {
        --modal-flaeche: var(--surface);
    }

    html[data-thema="glass"] .table thead {
        background: var(--bg);
    }
}

/* --------------------------------------------------------------------------
   Die Auswahl unter /einstellungen
   --------------------------------------------------------------------------
   Zwei Kacheln mit einer Vorschau statt einer Auswahlliste: „Glas" laesst
   sich beschreiben, aber nicht so, dass jemand vorher weiss, was er
   bekommt. Die Vorschau zeigt es. Sie ist bewusst KEIN echtes Abbild der
   App — nur Flaeche, Leiste und Karte.
   -------------------------------------------------------------------------- */

.themes {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 0 0 4px;
}

.theme {
    flex: 1 1 200px;
    min-width: 180px;
    /* ⚠️ `flex` statt `block`, damit die Vorschau OBEN sitzt. Ein `button`
       zentriert seinen Inhalt senkrecht (UA-Stil), und weil die beiden
       Kacheln unterschiedlich lange Beschreibungen tragen, standen ihre
       Vorschauen dann auf verschiedenen Hoehen — nebeneinander im Dialog
       sieht das aus wie ein Ausrichtungsfehler. */
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 12px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    background: var(--surface);
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.theme:hover {
    border-color: var(--accent);
}

.theme.is-active {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ⚠️ Die Vorschau zeigt seit Feedback #13114 den GEWAEHLTEN Hintergrund und
   den gewaehlten Akzent (`var(--bg)`, `var(--accent-rgb)`), nicht mehr fest
   Hellgrau und Logo-Blau. Sonst behauptete die Kachel „Glas" ein Aussehen,
   das die App daneben gar nicht hat — und die drei Achsen sind ja gerade
   frei kombinierbar. */
.theme__preview {
    display: flex;
    height: 76px;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--bg);
}

.theme__preview--glass {
    background-color: var(--bg);
    background-image:
        radial-gradient(12rem 9rem at 6% -14%, rgba(var(--accent-rgb), 0.42), transparent 62%),
        radial-gradient(9rem 8rem at 104% 8%, rgba(232, 133, 10, 0.28), transparent 60%);
}

.theme__bar {
    width: 34%;
    background: var(--paper);
    border-right: 1px solid var(--paper-line);
}

.theme__preview--glass .theme__bar {
    background: rgba(255, 255, 255, 0.55);
    border-right-color: rgba(255, 255, 255, 0.7);
    -webkit-backdrop-filter: saturate(180%) blur(8px);
    backdrop-filter: saturate(180%) blur(8px);
}

.theme__body {
    flex: 1;
    padding: 10px;
}

.theme__card {
    height: 100%;
    border-radius: 6px;
    background: var(--paper);
    border: 1px solid var(--paper-line);
}

.theme__preview--glass .theme__card {
    background: rgba(255, 255, 255, 0.68);
    border-color: rgba(255, 255, 255, 0.75);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8),
                0 4px 14px rgba(17, 40, 58, 0.10);
    -webkit-backdrop-filter: saturate(180%) blur(8px);
    backdrop-filter: saturate(180%) blur(8px);
}

.theme__name {
    margin: 10px 0 0;
    font-weight: 600;
}

.theme__desc {
    margin: 2px 0 0;
    color: var(--text-dim);
    font-size: 12px;
    line-height: 18px;
}

/* --- Der Waehler „Darstellung" (Feedback #13114) ---------------------------
 *
 * Dieselben drei Gruppen an zwei Orten: im Dialog, den der Knopf in der
 * Nutzer-Card oeffnet, und in der Karte unter `/einstellungen`. Beide binden
 * `_darstellung.html` ein — eine Kopie liefe beim naechsten Wert
 * auseinander.
 *
 * ⚠️ Die Vorschauen faerben sich aus IHREM EIGENEN Preset, nicht aus dem
 * gerade aktiven: der Farbkreis traegt `.swatch--<kennung>`, die Kachel
 * `.ground--<kennung>` — dieselben Bloecke, die `html[data-akzent]` bzw.
 * `html[data-grund]` setzen. Deshalb kann eine Vorschau gar nicht etwas
 * anderes zeigen als das, was sie waehlt.
 * -------------------------------------------------------------------------- */

.waehler__titel {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
}

.waehler__gruppe + .waehler__gruppe {
    margin-top: 18px;
}

/* Akzent — Farbkreise. Ihre Farbe kommt aus dem eigenen Preset, das auf
   dem Knopf selbst liegt. */
.swatches {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.swatch {
    position: relative;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 0;
    border-radius: 9999px;
    background: var(--accent);
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(17, 28, 39, 0.12);
}

.swatch:hover {
    box-shadow: inset 0 0 0 1px rgba(17, 28, 39, 0.12),
                0 0 0 3px var(--accent-soft);
}

.swatch:focus-visible {
    outline: 2px solid var(--accent-dark);
    outline-offset: 2px;
}

/* Der Haken sagt „dieser ist es". Ein blosser Ring waere auf acht bunten
   Kreisen schwerer zu finden, und Farbe allein darf die Auskunft nicht
   tragen. Weiss auf dem Akzent — dieselbe Paarung wie auf den Knoepfen. */
.swatch.is-active::after {
    content: '';
    position: absolute;
    left: 13px;
    top: 8px;
    width: 8px;
    height: 15px;
    border: 2px solid #fff;
    border-top: 0;
    border-left: 0;
    transform: rotate(45deg);
}

/* Hintergrund — Kacheln mit Vorschau. Das Preset sitzt auf der VORSCHAU,
   nicht auf dem Knopf: sonst faerbte die Kachel „Sand" auch ihren eigenen
   Rahmen und ihre Beschriftung sandfarben und saehe nicht mehr wie ein
   Bedienelement der App aus. */
.grounds {
    display: grid;
    /* 88 px, damit die vier Kacheln im Dialog (rund 420 px Inhaltsbreite)
       in EINE Reihe passen. Bei 104 px brach die vierte um und stand
       allein unter den drei anderen. */
    grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
    gap: 12px;
}

.ground {
    display: block;
    padding: 8px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    background: var(--surface);
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.ground:hover {
    border-color: var(--accent);
}

.ground.is-active {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.ground__preview {
    display: block;
    height: 44px;
    padding: 8px;
    border-radius: 6px;
    background: var(--bg);
}

.ground__card {
    display: block;
    height: 100%;
    border-radius: 4px;
    background: var(--paper);
    border: 1px solid var(--paper-line);
}

.ground__name {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    font-weight: 600;
}

/* --- Projekte -------------------------------------------------------------
 *
 * Zustand eines Projekts. Wie bei der Rechnung traegt nur Farbe, was eine
 * Aussage macht: die Anfrage ist der Normalfall am Anfang und bleibt neutral,
 * „in Arbeit" ist der Akzent, „abgeschlossen" gruen, „abgesagt" rot.
 */
.badge--pr-anfrage { background: var(--border); color: var(--text-muted); }
.badge--pr-beauftragt { background: rgba(232, 133, 10, 0.12); color: #9a5806; }
.badge--pr-in_arbeit { background: var(--accent-soft); color: var(--accent-dark); }
.badge--pr-abgeschlossen { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--pr-abgesagt { background: rgba(193, 57, 27, 0.10); color: #8f2b14; }

/* --- Der Ablauf eines Auftrags --------------------------------------------
 *
 * Termin, Aufmass, Angebot, Auftrag, Ausfuehrung, Rechnung, Bezahlt — die
 * Kette aus `app/ablauf.py`. Aufbau wie der vertikale Stepper der pvwebapp
 * (`components/todos/CustomerTodos.js`): UNTEREINANDER. Sieben Punkte
 * nebeneinander passen auf kein Telefon, und ein seitwaerts scrollender
 * Fortschritt ist keiner.
 *
 * ⚠️ Nichts hiervon ist bedienbar. Die Punkte zeigen einen Zustand, sie
 * setzen keinen — abgehakt wird in dieser App nichts (Feedback #13059). Der
 * Knopf am aktiven Punkt fuehrt an die Stelle, an der die Sache passiert.
 */
.ablauf {
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
}

.ablauf__punkt {
    display: flex;
    gap: 12px;
    padding-bottom: 14px;
    /* Die Linie zum naechsten Punkt — sie sitzt am Punkt und nicht zwischen
       ihnen, damit sie mit der Zeilenhoehe mitwaechst. Am letzten faellt sie
       weg (`:last-child`), sonst endete die Kette im Nichts. */
    position: relative;
}

.ablauf__punkt::before {
    content: "";
    position: absolute;
    left: 11px;
    top: 24px;
    bottom: 0;
    width: 2px;
    background: var(--border);
}

.ablauf__punkt:last-child { padding-bottom: 0; }
.ablauf__punkt:last-child::before { display: none; }

/* Die Marke: gefuellt wenn erledigt, umrandet wenn offen, blass wenn
   uebersprungen oder entfallen. */
.ablauf__marke {
    flex: 0 0 auto;
    z-index: 1;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 2px solid var(--border-strong);
    background: var(--surface);
    color: var(--surface);
    font-size: 13px;
    font-weight: 700;
    line-height: 20px;
    text-align: center;
}

.ablauf__punkt--erledigt .ablauf__marke {
    border-color: var(--signal-green);
    background: var(--signal-green);
}

.ablauf__punkt--laeuft .ablauf__marke {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.ablauf__punkt--uebersprungen .ablauf__marke,
.ablauf__punkt--entfaellt .ablauf__marke {
    border-color: var(--border);
    color: var(--text-dim);
}

.ablauf__text { min-width: 0; }

.ablauf__titel {
    margin: 2px 0 0;
    font-size: 14px;
    font-weight: 600;
}

.ablauf__auskunft,
.ablauf__handlung {
    margin: 2px 0 0;
    color: var(--text-muted);
    font-size: 13px;
}

/* Der uebersprungene und der entfallene Punkt treten zurueck: sie sind
   Auskunft ueber die Vergangenheit, keine Aufforderung. */
.ablauf__punkt--uebersprungen .ablauf__titel,
.ablauf__punkt--entfaellt .ablauf__titel { color: var(--text-dim); }

/* Der aktive Punkt ist der einzige, der etwas will. */
.ablauf__punkt.is-aktiv .ablauf__titel { color: var(--text); }
.ablauf__punkt.is-aktiv .ablauf__auskunft { color: var(--text); }

/* Die Abzeichen der Zustaende — dieselbe Zurueckhaltung wie beim Projekt:
   Farbe traegt nur, was eine Aussage macht. */
.badge--ab-erledigt { background: rgba(47, 143, 87, 0.12); color: #226b41; }
.badge--ab-laeuft { background: var(--accent-soft); color: var(--accent-dark); }
.badge--ab-offen { background: var(--border); color: var(--text-muted); }
.badge--ab-uebersprungen { background: var(--border); color: var(--text-dim); }
.badge--ab-entfaellt { background: var(--border); color: var(--text-dim); }

/* --------------------------------------------------------------------------
   Akte — die zweispaltige Kundenseite

   Aufbau nach `Customer.js` der pvwebapp: links, schmal, WER jemand ist und
   was man mit ihm tut; rechts, breit, WAS bei ihm laeuft. Dort entscheidet
   ein `window.innerWidth < 1045`-Listener zwischen zwei getrennt geschriebenen
   Baeumen — hier tut es eine Media-Query ueber EINEM Baum: zwei Fassungen
   desselben Inhalts liefen beim naechsten Abschnitt auseinander, und die
   schmale bekaeme ihn nie.
   -------------------------------------------------------------------------- */

.akte {
    display: grid;
    grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
    align-items: start;
    gap: 16px;
}

/* ⚠️ Zwischen 861 px und der vollen Breite klippte `.card--flush` die rechten
   Tabellenspalten WEG — ihr `overflow: hidden` haelt die Tabelle von den
   Kartenecken fern, und ohne Scroll-Flaeche war die letzte Spalte damit
   unerreichbar statt nur schmal. Unterhalb von 860 px raeumt dieselbe Regel
   das app-weit schon aus (siehe dort); in der Akte faellt es frueher auf, weil
   fuenf Tabellen in einer um 340 px verschmaelerten Spalte stehen.

   Dass es auf den uebrigen Seiten oberhalb von 860 px weiter klippt, ist kein
   Versehen dieser Regel, sondern ein eigener Befund — er gehoert vor dem
   app-weiten Umstellen einmal angesehen. */
.akte .card--flush {
    overflow-x: auto;
}

.akte__side,
.akte__main {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-width: 0;
}

/* Dieselbe Schwelle wie im Vorbild. Darunter steht die schmale Spalte OBEN:
   wer den Kunden am Telefon aufschlaegt, braucht zuerst die Nummer, nicht die
   Auftragsliste. */
@media (max-width: 1044px) {
    .akte {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Kontaktsperre und Archiv-Hinweis stehen IN der Kundeninformation, nicht als
   eigener Kasten ueber der Seite: gelesen wird vor dem Anruf, und gelesen wird
   hier. Die Kante links statt einer Flaeche — eine rote Flaeche in der
   Seitenspalte wuerde die Karte zum Alarm machen. */
.akte__warn {
    margin: 14px 0 0;
    padding: 9px 12px;
    border-left: 3px solid var(--signal-red);
    background: rgba(193, 57, 27, 0.06);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: 13px;
    line-height: 19px;
    color: var(--signal-red);
}

.akte__warn--mute {
    border-left-color: var(--border-strong);
    background: var(--bg);
    color: var(--text-dim);
}

/* Die Aktionen fuellen die schmale Spalte je zur Haelfte — zwei
   unterschiedlich breite Knoepfe nebeneinander lesen sich wie eine Rangfolge,
   die es zwischen „Kontaktsperre" und „Archivieren" nicht gibt. */
.akte__actions {
    display: flex;
    gap: 8px;
}

.akte__actions .btn {
    flex: 1;
    justify-content: center;
}

/* Nur-lesende Notiz: Zeilenumbrueche des Eingebenen bleiben stehen. */
.akte__note {
    margin: 0;
    white-space: pre-wrap;
    font-size: 13px;
    line-height: 20px;
}

/* Enger als die Standard-Datenliste: in 340 px Breite haette eine 190-px-Spalte
   fuer die Bezeichnung kaum Platz fuer den Wert uebrig gelassen. */
.datalist--tight {
    grid-template-columns: minmax(0, 108px) minmax(0, 1fr);
    gap: 6px 12px;
}

.datalist--tight dd {
    word-break: break-word;
}

/* Vor/Zurueck im Seitenkopf. Der Knopf ohne Ziel bleibt STEHEN statt zu
   verschwinden: sonst rutschte der andere im Moment des Klickens unter den
   Mauszeiger. */
.pagenav {
    display: flex;
    gap: 6px;
}

.iconbtn.is-disabled {
    opacity: 0.35;
    cursor: default;
    pointer-events: none;
}


/* --- Kundenannahme (Feedback #13425) -------------------------------------

   Die Seite fuer die Hand am Telefon. Sie bekommt bewusst nur DREI Regeln:
   alles andere traegt das vorhandene Karten- und Feld-System, und was hier
   eigene Klassen bekaeme, muesste bei jeder Design-Aenderung mitgepflegt
   werden. */

/* Die Karten stehen untereinander mit demselben Abstand wie sonst. */
.annahme__treffer,
.annahme__erfassen,
.annahme__suche + .card,
[data-annahme-leer] {
    margin-top: 16px;
}

/* ⚠️ Das Suchfeld ist absichtlich groesser als ein normales `.field__input`.
   Es wird mit einer Hand bedient, waehrend die andere den Hoerer haelt — und
   die Zielflaeche einer Daumenspitze liegt bei etwa 44 px. Das gilt auf JEDER
   Breite: die Seite wird auch am Schreibtisch benutzt, und ein Feld, das nur
   auf dem Telefon gross ist, waere zweierlei Bedienung fuer dieselbe Sache. */
.annahme__feld {
    min-height: 48px;
    font-size: 17px;
}

/* Der Trefferblock ist eine Liste von Knoepfen, keine Tabelle: bei drei
   Meiers entscheidet die Anschrift, und die passt in keine Spalte. */
.annahme__treffer .notelist li + li {
    margin-top: 12px;
}

/* --- Anlagen -------------------------------------------------------------

   Die Typensuche im Anlagen-Dialog. Der Katalog hat knapp fuenfhundert
   Eintraege; eine `<select>`-Liste darueber waere unbedienbar, also sucht man
   und waehlt aus einer Trefferliste. Sie ist eine Liste von KNOEPFEN und
   keine Tabelle — wie die Kundenannahme und aus demselben Grund: was einen
   Typ vom naechsten unterscheidet (Baureihe, Kategorie, ob Doku dranhaengt),
   passt in keine Spalte. */

.anlage__treffer {
    /* Gedeckelt und scrollbar: fuenfzig Treffer schoeben die Knopfreihe des
       Dialogs sonst aus dem Bild — die Huelle scrollt zwar, aber dann sucht
       man den Speichern-Knopf hinter fuenfzig Zeilen. */
    max-height: 240px;
    margin: 0 0 12px;
    padding: 0;
    overflow-y: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    list-style: none;
}

.anlage__treffer li + li {
    border-top: 1px solid var(--border);
}

.anlage__treffer__knopf {
    display: block;
    width: 100%;
    padding: 10px 12px;
    border: none;
    background: none;
    color: var(--text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.anlage__treffer__knopf:hover,
.anlage__treffer__knopf:focus-visible {
    background: var(--bg);
}

.anlage__treffer__knopf .table__sub {
    margin: 2px 0 0;
}

.anlage__gewaehlt {
    margin: 0 0 12px;
    padding: 8px 12px;
    border-radius: var(--radius);
    background: var(--bg);
    color: var(--text-dim);
    font-size: 13px;
}

/* Die Geraete unter einem Wartungsvertrag in der Kundenakte: je Kategorie
   eine Plakette, darunter die eingebauten Geraete als Sprung auf ihre Anlage.
   `overflow-wrap`, weil ein Typ wie „Vaillant ecoTEC plus VC 206/5-5" in der
   schmalen Spalte eines Telefons sonst aus der Zelle ragt. */
.wartung__kategorien,
.wartung__geraete {
    margin: 0;
    padding: 0;
    list-style: none;
}

.wartung__kategorie {
    margin-top: 6px;
}

.wartung__geraete {
    margin: 2px 0 0 10px;
    font-size: 13px;
    font-weight: 400;
    line-height: 19px;
    overflow-wrap: anywhere;
}

/* Die angesprungene Anlage kurz kenntlich machen — sonst landet man in einer
   Liste von acht Geraeten und sucht das eine. `scroll-margin`, damit Kopf und
   Spaltentitel des Anlagen-Abschnitts ueber ihr stehen bleiben — mit 24 px
   klebte die Zeile an der Oberkante, und man sah nicht, WO man gelandet war. */
[data-anlage-row] {
    scroll-margin-top: 120px;
}

[data-anlage-row]:target {
    background: var(--accent-soft);
}

/* Der zweite Weg („Typ steht nicht im Katalog"). Eingeklappt, damit die Suche
   der Regelfall bleibt — aufgeklappt sind es vier weitere Felder, die in 95 %
   der Faelle niemand braucht. */
.anlage__neu {
    margin-bottom: 12px;
}

.anlage__neu > summary {
    padding: 6px 0;
    color: var(--text-dim);
    font-size: 13px;
    cursor: pointer;
}
