:root {
    /* Firmenfarben */
    --farbe-marke-gelb: #ffdc2d;
    --farbe-marke-gelb-dunkel: #e0bf16;
    --farbe-marke-grau: #848484;

    --farbe-rot: #c4251c;
    --farbe-gelb: #dfd212;
    --farbe-gruen: #1eb34a;
    /* --farbe-gruen selbst ist als Flaeche (Ampel-Punkt) gedacht, nicht als Text - als Schriftfarbe auf
       Weiss (z.B. "Erledigt"-Status) reicht der Kontrast nicht (~2.8:1). Eigener, dunklerer Ton fuer
       Text-Verwendung, siehe .termin-status-erledigt weiter unten. */
    --farbe-gruen-text: #146c31;
    /* Rot/Gelb auf dem dunklen Sidebar-/Bottom-Nav-Hintergrund (--farbe-sidebar): im Normalzustand bewusst
       weiterhin das normale --farbe-rot (Markenfarbe/Wiedererkennung), obwohl das gegen --farbe-sidebar
       nur ~1.9:1 Kontrast hat - die kontrastreichere Variante gibt es gezielt ueber den "Erhoehter
       Kontrast"-Schalter (siehe body.hoher-kontrast unten), nicht als Standard fuer alle. Siehe
       .sidebar-nav-punkt-rot/-gelb und .badge-punkt-rot/-gelb (mobile.css). */
    --farbe-rot-auf-dunkel: var(--farbe-rot);
    --farbe-gelb-auf-dunkel: #dfd212;
    --farbe-blau: #2f6fd6;
    --farbe-blau-dunkel: #23509e;
    --farbe-grau: #8a8f96;
    --farbe-text: #262626;
    --farbe-text-schwach: #636363;
    --farbe-link: #4a4a4a;
    --farbe-rand: #c4c4c4;
    --farbe-hintergrund: #ececec;
    --farbe-akzent: var(--farbe-marke-gelb);
    --farbe-akzent-text: #2b2b2b;
    --farbe-akzent-dunkel: var(--farbe-marke-gelb-dunkel);
    --farbe-sidebar: #3d3d3d;
    --farbe-sidebar-hover: #4d4d4d;
    --farbe-sidebar-text: #d6d6d6;
    --radius: 2px;
}

/* "Erhoehter Kontrast"-Einstellung (siehe hoherKontrastUmschalten() in app.js, umschaltbar auf
   profil.html) - rein clientseitig per localStorage. Ersetzt gezielt die Farbtoene, die im Kontrast-
   Audit als nicht ideal aufgefallen sind, durch deutlich dunklere/kontrastreichere Varianten. Wirkt
   automatisch ueberall dort, wo bereits var(--farbe-...) verwendet wird (praktisch die gesamte Datei) -
   keine einzelnen Regeln pro Stelle noetig. Am auffaelligsten: --farbe-gelb war mit ca. 1.6:1 Kontrast
   zu Weiss vorher kaum zu erkennen (v.a. als Ampel-Warndreieck/-Punkt betroffen). */
body.hoher-kontrast {
    --farbe-gelb: #7a6a00;
    --farbe-grau: #5a5e64;
    --farbe-text-schwach: #454545;
    --farbe-rot: #a01f17;
    --farbe-sidebar-text: #f2f2f2; /* auf der dunklen Sidebar (--farbe-sidebar: #3d3d3d) faellt das bisherige #d6d6d6 bei manchen Kontrast-Pruefungen durch */
    --farbe-gruen-text: #0f5426;
    --farbe-rot-auf-dunkel: #ffab9c;
    --farbe-gelb-auf-dunkel: #f0e64a;
}

* { box-sizing: border-box; }

/* Verdeckt den rohen Seitenaufbau bis baueLayoutInnen() fertig ist (js/app.js) - sonst blitzt kurz das
   ungestylte HTML-Geruest auf, bevor die Sidebar existiert. Rein CSS-basiert (kein JS noetig), damit es
   ab dem allerersten Seiten-Paint wirkt, nicht erst nach dem ersten Skript-Tick - und wirkt in JEDEM
   Browser (ergaenzt die @view-transition-Regel oben, die nur in Chromium/Safari greift). */
body:not(.app-bereit) > main,
body:not(.app-bereit) > dialog {
    visibility: hidden;
}
/* Balken in exakt der Breite der spaeteren echten .app-sidebar (212px), inkl. Logo an derselben
   Position wie .sidebar-logo/.sidebar-logo-bild dort - wenn baueLayoutInnen() fertig ist, erscheint die
   echte Sidebar an genau dieser Stelle "nahtlos" statt den Balken zu ersetzen. Logo per zweiter
   Hintergrundebene (weisses Rechteck via linear-gradient) nachgebildet, da ein Pseudo-Element kein
   eigenes verschachteltes Element fuer die weisse Box haben kann. */
body:not(.app-bereit)::before {
    content: "";
    position: fixed;
    inset: 0 auto 0 0;
    width: 212px;
    background-color: var(--farbe-sidebar);
    background-image: url('../assets/Logo_Brugger4.png'), linear-gradient(#fff, #fff);
    background-repeat: no-repeat, no-repeat;
    background-position: 28px 22px, 18px 14px;
    background-size: 156px auto, 176px 95px;
    z-index: 9999;
}
body:not(.app-bereit)::after {
    content: "";
    position: fixed;
    top: 50%;
    left: calc((100% + 212px) / 2);
    width: 32px;
    height: 32px;
    margin: -16px 0 0 -16px;
    border: 3px solid var(--farbe-rand);
    border-top-color: var(--farbe-marke-gelb-dunkel);
    border-radius: 50%;
    animation: app-lade-dreh .7s linear infinite;
    z-index: 10000;
}
@keyframes app-lade-dreh {
    to { transform: rotate(360deg); }
}

body {
    font-family: "Segoe UI", Tahoma, Arial, sans-serif;
    margin: 0;
    display: flex;
    min-height: 100dvh;
    background: var(--farbe-hintergrund);
    color: var(--farbe-text);
    font-size: 13px;
    overflow-x: hidden;
}

/* ---- Sidebar (App-Schale) ---- */

.app-sidebar {
    width: 212px;
    flex-shrink: 0;
    background: var(--farbe-sidebar);
    color: var(--farbe-sidebar-text);
}

.sidebar-sticky {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
    position: sticky;
    top: 0;
}

.sidebar-logo {
    padding: 14px 18px;
    border-bottom: 1px solid rgba(255,255,255,.14);
}
.sidebar-logo-bild {
    display: block;
    max-width: 100%;
    height: auto;
    background: #fff;
    border-radius: var(--radius);
    padding: 8px 10px;
}

.sidebar-nav {
    flex: 1;
    padding: 6px 0;
    display: flex;
    flex-direction: column;
}

.sidebar-nav a {
    display: block;
    padding: 8px 18px;
    color: var(--farbe-sidebar-text);
    text-decoration: none;
    font-size: 13px;
    border-left: 3px solid transparent;
}

.sidebar-nav a:hover { background: rgba(255,255,255,.08); color: #fff; }
.sidebar-nav a.aktiv { background: rgba(255,255,255,.1); color: #fff; border-left-color: var(--farbe-marke-gelb); font-weight: 600; }

.sidebar-nav-block + .sidebar-nav-block {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid rgba(255,255,255,.12);
}

.sidebar-nav-punkt {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-left: 7px;
    vertical-align: middle;
}
.sidebar-nav-punkt-rot { background: var(--farbe-rot-auf-dunkel); }
.sidebar-nav-punkt-gelb { background: var(--farbe-gelb-auf-dunkel); }

.sidebar-footer {
    padding: 12px 18px 16px;
    border-top: 1px solid rgba(255,255,255,.14);
}
.sidebar-footer label {
    color: var(--farbe-sidebar-text);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .04em;
    margin: 0 0 5px;
}
.sidebar-footer-name {
    display: block;
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 8px;
    overflow-wrap: break-word;
    text-decoration: none;
}
/* Fuer den Namens-Link zur Profilseite auf login.html (dort ohne die feste weisse Sidebar-Schrift). */
.profil-link { color: inherit; text-decoration: none; }
.sidebar-footer-knoepfe {
    display: flex;
    gap: 6px;
}
/* Ghost-Buttons statt der hellen Standard-.sekundaer-Optik - passt damit zur dunklen Sidebar, gleiche
   Sprache wie .sidebar-nav a (transparent, dezenter Rand/Hover statt Flaeche). Selektoren bewusst mit
   ".sekundaer" statt nur "button", damit die Spezifitaet ueber der globalen button.sekundaer-Regel liegt. */
.sidebar-footer-knoepfe .knopf.sekundaer,
.sidebar-footer-knoepfe button.sekundaer {
    flex: 1;
    font-size: 12px;
    padding: 6px 4px;
    text-align: center;
    background: transparent;
    color: var(--farbe-sidebar-text);
    border: 1px solid rgba(255,255,255,.25);
}
.sidebar-footer-knoepfe button.sekundaer:disabled { opacity: .35; }
@media (hover: hover) {
    .sidebar-footer-knoepfe .knopf.sekundaer:hover,
    .sidebar-footer-knoepfe button.sekundaer:hover:not(:disabled) {
        background: rgba(255,255,255,.08);
        color: #fff;
    }
}

.app-hauptbereich {
    flex: 1;
    min-width: 0;
}

/* Volle Fehlerseite bei einem Absturz waehrend des Seitenaufbaus, siehe zeigeVollstaendigenFehler() in js/app.js */
.app-fehlerseite {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 100vh;
    padding: 24px;
}
.app-fehlerseite .karte {
    max-width: 420px;
    text-align: center;
}

main {
    padding: 8px 26px 4px;
}

/* margin-top nicht mehr 0: auf den meisten Unterseiten (Berichte, Alle Fotos/Berichte, Frist,
   Projekthistorie, ...) steht die Ueberschrift NICHT in einer .karte mit eigenem Padding, sondern direkt
   im Seiteninhalt - seit main{} weniger padding-top hat (siehe main-Regel oben), sass sie dadurch fast am
   oberen Rand. h1.m-0/.historie-titel-h1 (dieselben Faelle) und .karte h1 (Titel, die sehr wohl in einer
   .karte stecken, z.B. Projekt-/Paket-/Termin-Kopf) setzen es unten gezielt wieder zurueck, damit dort
   keine doppelte Karte-Padding-plus-Margin-Luecke entsteht. */
h1 { font-size: 19px; margin: 8px 0 14px; font-weight: 600; }
h2 { font-size: 14px; margin: 20px 0 8px; font-weight: 600; color: var(--farbe-text-schwach); text-transform: uppercase; letter-spacing: .04em; }
h3 { font-size: 12px; margin: 14px 0 5px; color: var(--farbe-text-schwach); text-transform: uppercase; letter-spacing: .03em; font-weight: 600; }
h4 { font-size: 12px; margin: 14px 0 5px; color: var(--farbe-text-schwach); font-weight: 600; }

.karte {
    position: relative;
    background: #fff;
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    padding: 14px 16px;
    margin-bottom: 14px;
    overflow-x: auto;
}

/* Sicherheits-Notfallbereich (systemeinstellungen.html) - optisch deutlich von den harmlosen
   Zahlenwerten oben abgesetzt, da die Aktionen dort sofort und ohne Bestaetigungsformular wirken. */
.karte-notfall { border-color: var(--farbe-rot); background: #f7e3e1; }
.karte-notfall h3 { color: var(--farbe-rot); margin-top: 0; }
.notfall-zeile { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; }
.notfall-zeile + .notfall-zeile { border-top: 1px solid #e5b7b2; }
.notfall-status { font-size: 13px; color: var(--farbe-text-schwach); }

/* Einklappbare Karten (siehe initKartenEinklappen in app.js): eigene Kopfzeile mit nur der
   Ueberschrift + Pfeil direkt daneben - alles andere (auch Buttons) steckt in .karte-inhalt und
   verschwindet mit beim Zuklappen. */
.karte-kopf-klickbar { display: flex; align-items: center; gap: 6px; cursor: pointer; user-select: none; }
.karte-kopf-klickbar h3 { margin: 0; }
.karte-einklapp-pfeil { font-size: 18px; line-height: 1; color: var(--farbe-text-schwach); }
.karte-inhalt { margin-top: 10px; }
.karte-inhalt.eingeklappt { display: none; }

/* Buttons, die frueher im selben Toolbar wie die (jetzt herausgeloeste) Kartenueberschrift standen
   (z.B. "+ Problem melden"): am Desktop oben rechts, wie vor dem Einklappbar-Umbau. Mobil bleiben sie
   normal im Fluss unter dem Titel (siehe mobile.css) - bei absoluter Positionierung wuerden sie dort
   ueber Titel/Inhalt liegen, sobald der Button (mobil groessere Tap-Flaeche) breiter als der reservierte
   Platz ist. Eine Ausnahme gibt es gezielt fuer "Meine Aktionen" (siehe .dashboard-umschalt-btn in
   mobile.css), deren Buttons klein genug sind, um das auch mobil zu vertragen. */
@media (min-width: 769px) {
    .karte-kopf-aktionen { position: absolute; top: 14px; right: 16px; margin: 0; }
    /* Der Button ist herausgeloest (position:absolute, kein Platzbedarf im normalen Fluss mehr) - ohne
       diesen Abstand wuerde der folgende Inhalt direkt darunter/darueber liegen. */
    .karte-inhalt.hat-kopf-aktionen { padding-top: 12px; }
}

.toolbar {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 12px;
}

.spacer { flex: 1; }
/* Generisches Utility fuer "dieses Element soll den restlichen Platz einer Flex-Zeile einnehmen" -
   ersetzt das frueher verbreitete inline style="flex:1;" (siehe z.B. terminKarteHtml() in js/app.js). */
.flex-1 { flex: 1; }

/* Generisches kleines Dropdown-Menue an einem Button (z.B. "+ Kontakt ▾" in js/termin_abschliessen.js) -
   buendelt mehrere seltener genutzte Aktionen hinter einem einzigen Button statt mehrerer nebeneinander,
   damit die Toolbar (besonders mobil) nicht durch viele gleichrangige Buttons ueberladen wirkt. Auf-/
   Zuklappen per [hidden]-Attribut, gleiches Prinzip wie css/skizze.css' #sk-mehr-optionen (dort nur
   mobil aktiv, hier bewusst auf jeder Bildschirmgroesse). position:absolute mit Seiten-Koordinaten
   (inkl. window.scrollY, siehe initKontaktMenue()) statt "top:100%;right:0" relativ zu einem
   .dropdown-Wrapper: der Button steckt in .karte, die per overflow-x:auto (fuer scrollbare Tabellen)
   jeden ueberstehenden position:absolute-Nachfahren abschneiden wuerde - das Panel liegt deshalb als
   statisches Markup ausserhalb von .karte (siehe termin_abschliessen.html) und wird nur beim Oeffnen per
   JS ueber den Button positioniert. Bewusst :absolute statt :fixed, damit das Menue beim Scrollen mit
   der Seite mitwandert (an der Stelle unter dem Button "kleben" bleibt) statt am Viewport fixiert zu
   erscheinen. */
.dropdown-menue[hidden] { display: none; }
.dropdown-menue:not([hidden]) {
    display: flex;
    flex-direction: column;
    gap: 4px;
    position: absolute;
    z-index: 50;
    background: #fff;
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    box-shadow: 0 4px 16px rgba(0,0,0,.18);
    padding: 8px;
    min-width: 200px;
}
.dropdown-menue button { width: 100%; text-align: left; }

/* Ampel */
.ampel-punkt {
    display: inline-block;
    vertical-align: middle;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    flex-shrink: 0;
    border: 1px solid rgba(0,0,0,.15);
}
.ampel-rot { background: var(--farbe-rot); }
.ampel-gelb { background: var(--farbe-gelb); }
.ampel-gruen { background: var(--farbe-gruen); }
/* Bewusst kein grauer Punkt mehr (sah auf den ersten Blick dem gruenen zu aehnlich) - stattdessen ein
   graues Haekchen-Icon statt Kreisflaeche, daher kein Hintergrund/Rand wie bei den drei Status-Punkten.
   Die Form kommt als mask-image (schwarze SVG-Silhouette, Farbe egal) statt als background-image mit
   fest einkodierter Farbe - dadurch liefert ganz normal background-color die sichtbare Farbe und reagiert
   automatisch auf die "Erhoehter Kontrast"-Einstellung (siehe body.hoher-kontrast weiter unten in dieser
   Datei), ohne die SVG dafuer duplizieren zu muessen. */
.ampel-abgeschlossen {
    background-color: var(--farbe-grau);
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5 6.5 12 13 4' fill='none' stroke='black' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5 6.5 12 13 4' fill='none' stroke='black' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-size: contain; mask-size: contain;
    border: none;
    border-radius: 0; /* sonst clippt das geerbte border-radius:50% von .ampel-punkt das Haekchen rund */
}

/* "Ampel-Punkte als Formen"-Einstellung (siehe ampelFormenUmschalten() in app.js, umschaltbar auf
   profil.html) - rein clientseitig per localStorage, fuer Nutzer, die Rot/Gelb/Gruen nicht zuverlaessig
   allein am Farbton unterscheiden koennen (z.B. Rot-Gruen-Sehschwaeche). Kein kleines Symbol AUF dem
   farbigen Punkt (war zu winzig/schwer erkennbar) - stattdessen IST das Symbol selbst die farbige Flaeche
   (rotes Kreuz, gelbes Warndreieck), wieder per mask-image (siehe .ampel-abgeschlossen-Kommentar oben)
   statt fest einkodierter SVG-Farbe. Gruen bleibt der schlichte volle Kreis (schon maximal sichtbar,
   kein Symbol noetig), Grau/abgeschlossen bleibt das bestehende Haekchen. */
body.ampel-formen .ampel-rot,
body.ampel-formen .ampel-gelb {
    border: none;
    /* .ampel-punkt hat border-radius:50% fuer die drei Kreis-Punkte - ohne diesen Reset wuerde das
       Icon (Kreuz/Dreieck) an einen runden Kreis-Ausschnitt geclippt und wirkte faelschlich abgerundet. */
    border-radius: 0;
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
    -webkit-mask-position: center; mask-position: center;
    -webkit-mask-size: contain; mask-size: contain;
}
body.ampel-formen .ampel-rot {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3 13 13M13 3 3 13' fill='none' stroke='black' stroke-width='3.2' stroke-linecap='round'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3 13 13M13 3 3 13' fill='none' stroke='black' stroke-width='3.2' stroke-linecap='round'/%3E%3C/svg%3E");
}
body.ampel-formen .ampel-gelb {
    /* Klassisches Achtung-Dreieck (Warndreieck-Silhouette) statt Ausrufezeichen. */
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0.5 L15.5 15 L0.5 15 Z' fill='black'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0.5 L15.5 15 L0.5 15 Z' fill='black'/%3E%3C/svg%3E");
}

/* Zeitangaben-Farbcodierung in terminKarteHtml() (js/app.js) - "Meine Aktionen" + Paketseite. */
.termin-status-erledigt { color: var(--farbe-gruen-text); }
.termin-status-ueberfaellig { color: var(--farbe-rot); }
.termin-status-heute { color: var(--farbe-rot); font-weight: 600; }

.ampel-zeile {
    display: flex;
    align-items: center;
    gap: 8px;
}

.projekt-badges { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Status-Feld auf der Projektseite (js/projekt.js): faerbt sich nach der Projekt-Ampel, wird bei
   gruen gar nicht erst angezeigt. */
.projekt-status-feld {
    margin-top: 14px;
    padding: 10px 12px;
    border-radius: var(--radius);
    border: 1px solid transparent;
    font-size: 13px;
}
.projekt-status-feld.rot { background: #f7e3e1; color: var(--farbe-rot); border-color: #e5b7b2; }
.projekt-status-feld.gelb { background: #faf6d0; color: #7a6a00; border-color: #ece0a0; }
.projekt-status-feld.abgeschlossen { background: #ececec; color: var(--farbe-text-schwach); border-color: var(--farbe-rand); }

.badge {
    display: inline-block;
    font-size: 11px;
    padding: 2px 7px;
    border-radius: var(--radius);
    background: #eaeaea;
    color: var(--farbe-text-schwach);
    border: 1px solid var(--farbe-rand);
    font-weight: 600;
}
.badge.dringend { background: #f7e3e1; color: var(--farbe-rot); border-color: #e5b7b2; }

/* Schnellauswahl-Chip fuer Freitextfelder (z.B. Schadensart/Leitung im Schadensbericht) - Klick
   fuellt/ersetzt das zugehoerige Textfeld, dieses bleibt frei ueberschreibbar. */
.chip-vorschlag { font-size: 12px; padding: 3px 10px; min-height: 0; }

/* Tabelle / Listen */
table { width: 100%; max-width: 100%; border-collapse: collapse; border: 1px solid var(--farbe-rand); }
th, td { text-align: left; padding: 7px 9px; border-bottom: 1px solid var(--farbe-rand); border-right: 1px solid #e6e6e6; font-size: 13px; overflow-wrap: break-word; word-break: break-word; }
/* Spalten mit kurzem, immer gleich langem Inhalt (Datum, Zahl, Code, ...) nicht umbrechen lassen -
   table-layout:auto verteilt sonst uebrigen Platz anteilig auch an diese Spalten, statt ihn der
   Haupttext-Spalte (Bezeichnung/Name/...) zu ueberlassen. */
.sp-schmal { white-space: nowrap; }
/* Spaltenkopf ohne Text = reine Button-Spalte (X entfernen, Speichern, ...) - soll nie breiter sein
   als der Button selbst, nicht anteilig am uebrigen Platz beteiligt werden. */
th:empty { width: 1px; white-space: nowrap; }
th:last-child, td:last-child { border-right: none; }
th {
    white-space: nowrap;
    font-weight: 600;
    color: var(--farbe-text-schwach);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: .02em;
    background: #e6e6e6;
    border-bottom: 1px solid var(--farbe-rand);
}
tbody tr:nth-child(even) { background: #f4f4f4; }
.klickbar { cursor: pointer; }

.sortierbar { cursor: pointer; user-select: none; }
.sortierbar:hover { background: #d8d8d8; }
/* Feste Breite (statt sich am Inhalt zu orientieren) - sonst veraendert sich beim Ein-/Ausblenden des
   Pfeils (aktive vs. inaktive Sortierspalte) die Spaltenbreite der ganzen Tabelle (table-layout:auto
   orientiert sich am tatsaechlichen Inhalt jeder Zelle), betrifft "Alle Projekte" und Messprotokoll
   gleichermassen, da beide dieselbe Klasse verwenden. */
.sort-pfeil { display: inline-block; width: 10px; margin-left: 4px; text-align: center; }
/* Ampel-Spalte hat keine Beschriftung vor dem Pfeil (siehe projekte.html) - der linke Abstand oben
   wuerde ihn dort aus der Spaltenmitte schieben, wo die Ampel-Punkte der Zeilen darunter zentriert sind. */
th[data-sort="ampel"] { text-align: center; }
th[data-sort="ampel"] .sort-pfeil { margin-left: 0; }

.ampel-zelle { text-align: center; }
.ampel-zelle-mitte { display: flex; align-items: center; justify-content: center; height: 100%; }

/* Spalten, die nur bei genuegend Bildschirmbreite angezeigt werden (z.B. Projekt-Uebersichtstabelle) */
@media (max-width: 1200px) {
    .sp-breit { display: none; }
}
.klickbar:hover { background: #fdf6d9; }

.liste-karten { display: flex; flex-direction: column; gap: 6px; }
.eintrag-karte {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    background: #fff;
    cursor: pointer;
    text-decoration: none;
    color: inherit;
}
.eintrag-karte:hover { border-color: var(--farbe-marke-gelb-dunkel); background: #fdf6d9; }
.eintrag-karte .titel { font-weight: 600; font-size: 13px; }
.eintrag-karte .neben { font-size: 12px; color: var(--farbe-text-schwach); }

.rechte-erklaerung-zeile { padding: 8px 0; border-bottom: 1px solid var(--farbe-rand); }
.rechte-erklaerung-zeile:last-child { border-bottom: none; }
.rechte-erklaerung-zeile .titel { font-weight: 600; font-size: 13px; }
.rechte-erklaerung-zeile .neben { font-size: 12px; color: var(--farbe-text-schwach); margin-top: 2px; }

.titel-badge-zeile { display: flex; align-items: center; gap: 8px; }

.problem-aktionen { display: flex; gap: 8px; flex-shrink: 0; }

/* Formulare */
label { display: block; font-size: 12px; font-weight: 600; margin: 10px 0 4px; color: var(--farbe-text-schwach); }
input, select, textarea {
    width: 100%;
    padding: 7px 8px;
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    font-size: 13px;
    font-family: inherit;
    background: #fff;
    color: var(--farbe-text);
}
input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--farbe-marke-gelb-dunkel);
    outline-offset: -1px;
    border-color: var(--farbe-marke-gelb-dunkel);
}
input[type="checkbox"]:focus, input[type="radio"]:focus {
    outline: none;
}
/* Einheitliche Standardhoehe von ca. drei Zeilen (13px Schrift, line-height 1.4, + Padding/Rand) -
   fest statt nur min-height, damit die Groesse ueberall vorhersagbar bleibt (siehe .audio-start-btn
   weiter unten, der genau auf diese Hoehe abgestimmt ist); resize:vertical erlaubt weiterhin manuelles
   Vergroessern bei Bedarf. */
textarea { resize: vertical; height: 72px; line-height: 1.4; }
.feld-zeile { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; }
.feld-zeile.drei { grid-template-columns: 1fr 1fr 1fr; }
.feld-zeile.vier { grid-template-columns: 1fr 1fr 1fr 1fr; }
/* Adresse/Top/Ort im Kontakt-Formular (siehe kontaktFelderHtml() in app.js) - Top braucht deutlich
   weniger Platz als Adresse/Ort. */
.feld-zeile.feld-zeile-adresse { grid-template-columns: 2fr 1fr 2fr; }

/* Stammdaten-Anzeige (Projekt/Paket/Termin - allgemeiner Teil): alle Feld-Ueberschriften ohne eigenen
   Top-Abstand, damit der Abstand innerhalb einer Zeile (Grid-Gap) und zwischen den Zeilen (hier
   explizit) ueberall gleich ist - sonst addiert sich je nach Zeile mal der h3-Standardabstand mal
   nicht dazu (mobil gestapelt, dort sonst Grid-Gap + h3-Abstand zusammen statt nur Grid-Gap). */
.stammdaten-anzeige h3 { margin-top: 0; }
.stammdaten-anzeige .feld-zeile + .feld-zeile { margin-top: 14px; }

button, .knopf {
    display: inline-block;
    background: var(--farbe-akzent);
    color: var(--farbe-akzent-text);
    border: 1px solid var(--farbe-akzent-dunkel);
    padding: 7px 14px;
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
}
button.sekundaer, .knopf.sekundaer { background: #eaeaea; color: var(--farbe-text); border: 1px solid var(--farbe-rand); }
button.gefahr { background: var(--farbe-rot); color: #fff; border-color: #8f1e18; }
button:disabled { opacity: .5; cursor: not-allowed; }
/* :hover nur auf Geraeten mit echtem Zeigegeraet (Maus) - auf Touch-Geraeten bleibt ein simuliertes
   :hover nach dem Antippen sonst haengen, bis woanders hingetippt wird (bekanntes Mobile-Safari-
   Verhalten). Faellt sonst z.B. bei abgewaehlten Ergebnis-Chips (.chip-auswahl in
   termin_abschliessen.js) auf: die haben selbst keine :hover-Regel, gewinnen also gegen das globale
   button:hover nicht per Spezifitaet und blieben faelschlich gelb eingefaerbt. */
@media (hover: hover) {
    button:hover, .knopf:hover { background: var(--farbe-akzent-dunkel); }
    button.sekundaer:hover, .knopf.sekundaer:hover { background: #dadada; }
    button.gefahr:hover { background: #8f1e18; }
}

.notiz { border-bottom: 1px solid var(--farbe-rand); padding: 7px 0; font-size: 13px; }
.notiz .meta { color: var(--farbe-text-schwach); font-size: 11px; margin-top: 2px; }

.leer { color: var(--farbe-text-schwach); font-size: 13px; padding: 8px 0; }
/* .leer in einer Tabellenzelle (z.B. "Noch keine Messwerte erfasst." im Messprotokoll, "Keine Projekte
   gefunden" bei "Alle Projekte") - .leer's eigenes padding:8px 0 ueberschreibt sonst das normale
   td-Padding und die Nachricht klebt am linken Tabellenrand. */
td.leer { padding-left: 9px; }
.fehler { background: #f7e3e1; color: var(--farbe-rot); border: 1px solid #e5b7b2; border-radius: var(--radius); padding: 9px 11px; margin-bottom: 12px; font-size: 13px; }

.filter-leiste { display: flex; gap: 8px; flex-wrap: wrap; }
.filter-leiste select { width: auto; min-width: 150px; }
.projekte-suchfeld { max-width: 420px; }
/* Das "X leeren"-Feature (siehe .tf-clear-wrap) wickelt das Suchfeld in einen Span - der wird dadurch
   zum eigentlichen Flex-Kind der Toolbar, muss die Breitenvorgabe also selbst bekommen (analog zum
   .text-mit-audio-Fix weiter unten). */
.filter-leiste .tf-clear-wrap { flex: 1; max-width: 420px; }

/* ---- Kalender (Wochen-Zeitleiste) ---- */

/* Kalenderseite nimmt exakt die Displayhoehe ein; #inhalt/.kalender-scroll teilen sich das ueber
   Flexbox auf, damit das Tagesraster die unter den Auswahlelementen verbleibende Hoehe ausfuellt. */
.kalender-main { height: 100dvh; display: flex; flex-direction: column; }
.kalender-main #inhalt { flex: 1; display: flex; flex-direction: column; min-height: 0; }

.kalender-filter { display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-end; margin-bottom: 14px; flex-shrink: 0; }
.kalender-filter .gruppe { display: flex; flex-direction: column; gap: 4px; }
.kalender-filter label { font-size: 11px; font-weight: 600; color: var(--farbe-text-schwach); text-transform: uppercase; letter-spacing: .03em; }
.kalender-filter select { width: auto; }

.kalender-scroll { flex: 1; min-height: 0; overflow: auto; border: 1px solid var(--farbe-rand); border-radius: var(--radius); background: #fff; }
.kalender-grid { display: inline-block; min-width: 100%; }

.kalender-kopf-zeile { display: flex; position: sticky; top: 0; background: #fff; z-index: 3; border-bottom: 1px solid var(--farbe-rand); }
.kalender-ecke { flex: 0 0 150px; position: sticky; left: 0; z-index: 4; background: #fff; border-right: 1px solid var(--farbe-rand); }
.kalender-tage { position: relative; flex-shrink: 0; height: 48px; }
.kalender-tag { position: absolute; top: 0; bottom: 0; box-sizing: border-box; }
.kalender-tag-titel { font-size: 11px; font-weight: 600; white-space: nowrap; padding: 4px 6px 2px; }
.kalender-stunden-ticks { position: relative; height: 20px; }
.kalender-stunde-tick { position: absolute; top: 0; font-size: 9px; color: var(--farbe-text-schwach); transform: translateX(-50%); text-align: center; }

.kalender-zeile { display: flex; border-bottom: 1px solid var(--farbe-rand); height: 46px; }
.kalender-mitarbeiter-name {
    flex: 0 0 150px; position: sticky; left: 0; z-index: 2; background: #fff;
    border-right: 1px solid var(--farbe-rand); padding: 0 10px; font-size: 13px; font-weight: 600;
    display: flex; align-items: center;
}
.kalender-zeitleiste { position: relative; flex-shrink: 0; cursor: pointer; }
/* pointer-events:none, damit Klicks auf leere Flaeche (-> neuer Termin) durch die rein
   dekorativen Linien hindurch bei .kalender-zeitleiste/.kalender-outlook-flaeche ankommen. */
.kalender-tag-linie { position: absolute; top: 0; bottom: 0; border-right: 1px solid var(--farbe-rand); pointer-events: none; }
.kalender-stunde-linie { position: absolute; top: 0; bottom: 0; border-right: 1px dotted #ececec; pointer-events: none; }
.kalender-termin {
    position: absolute; top: 5px; bottom: 5px; background: var(--farbe-akzent); border: 1px solid var(--farbe-akzent-dunkel);
    border-radius: var(--radius); padding: 2px 6px; font-size: 11px; color: var(--farbe-akzent-text);
    overflow: hidden; cursor: pointer;
    display: flex; flex-direction: column; justify-content: center; gap: 0;
}
/* 1. Zeile (Paket - Beschreibung) und Zustaendige entfallen bewusst, weil beides schon aus dem
   Kalender selbst ersichtlich ist (Uhrzeit/Position bzw. Mitarbeiter-Zeile/-Spalte bzw. Gruppenfarbe). */
.kalender-termin-titel, .kalender-termin-projekt { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.kalender-termin-titel { font-weight: 600; }
.kalender-termin-projekt { font-size: 10px; opacity: .85; }
.kalender-termin:hover { background: var(--farbe-akzent-dunkel); }
.kalender-termin.erledigt { opacity: .5; }
.kalender-termin.frist { background: #eaeaea; border-color: var(--farbe-rand); color: var(--farbe-text); }
.kalender-termin.keine-uhrzeit { background: var(--farbe-rot); border-color: #8f1e18; color: #fff; }
.kalender-termin.keine-uhrzeit:hover { background: #8f1e18; }
/* Gruppentermin (siehe termin_zustaendige.mitarbeitergruppe_id) - eigene Farbe, damit auf einen
   Blick erkennbar ist, dass der Termin nicht einer einzelnen Person, sondern der ganzen
   Mitarbeitergruppe gehoert. */
.kalender-termin.gruppe { background: var(--farbe-blau); border-color: var(--farbe-blau-dunkel); color: #fff; }
.kalender-termin.gruppe:hover { background: var(--farbe-blau-dunkel); }

/* Mitarbeiter-Chip (Einzelne Zustaendige eines Termins, siehe terminZustaendigeFelderHtml() in app.js) -
   feste Groesse fuer ein ordentliches Raster bei ca. 30 Mitarbeitern; zu lange Namen werden abgeschnitten
   (Vollname per title-Attribut beim Hover). Auswahlzustand folgt der versteckten Checkbox rein per CSS. */
.mitarbeiter-chip {
    position: relative;
    display: inline-flex; align-items: center; margin: 0;
    width: 130px; height: 36px; flex: 0 0 auto; padding: 0 10px;
    border: 1px solid var(--farbe-rand); border-radius: var(--radius);
    background: #fff; color: var(--farbe-text);
    font-size: 13px; font-weight: 600; cursor: pointer; user-select: none;
}
/* position:relative oben ist notwendig, sonst positioniert sich diese Checkbox (position:absolute) an
   einem entfernten Vorfahren statt am 130px breiten Chip - die globale width:100%-Regel fuer input
   (siehe input,select,textarea weiter oben) macht sie dann riesig, was .karte weit ueber den
   sichtbaren Bereich hinaus aufblaeht (Scrollbar + leerer weisser Bereich rechts). */
.mitarbeiter-chip input { position: absolute; opacity: 0; pointer-events: none; }
.mitarbeiter-chip span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.mitarbeiter-chip:has(input:checked) {
    background: var(--farbe-marke-gelb); border-color: var(--farbe-marke-gelb-dunkel); color: #1a1a1a;
}

/* Radiobuttons "Einzelne Zustaendige" / "Mitarbeitergruppe" (terminZustaendigeFelderHtml() in app.js) -
   komplett selbst gestaltet statt native Optik/accent-color, da Windows-Chrome dort einen unschoenen
   schwarzen Ring um den ausgewaehlten Radiobutton zeichnet. */
.zust-radio {
    appearance: none; -webkit-appearance: none; margin: 0; padding: 0;
    width: 16px; height: 16px; min-width: 0; min-height: 0; flex: 0 0 auto;
    border: 2px solid var(--farbe-rand); border-radius: 50%;
    cursor: pointer; position: relative;
}
.zust-radio:checked { border-color: var(--farbe-marke-gelb-dunkel); }
.zust-radio:checked::after {
    content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 8px; height: 8px; border-radius: 50%; background: var(--farbe-marke-gelb-dunkel);
}

/* Ausfaelle (Urlaub, Krankenstand, ...): ganztaegiger grauer Block hinter den Terminen. */
.kalender-ausfall {
    position: absolute; top: 1px; bottom: 1px;
    background: repeating-linear-gradient(45deg, rgba(138,143,150,.22), rgba(138,143,150,.22) 6px, rgba(138,143,150,.34) 6px, rgba(138,143,150,.34) 12px);
    border: 1px solid var(--farbe-grau);
    border-radius: var(--radius);
    padding: 3px 6px; font-size: 10px; color: var(--farbe-text-schwach); font-weight: 600;
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.kalender-ausfall-outlook { bottom: auto; white-space: normal; line-height: 1.25; }

/* ---- Kalender (Tagesraster / Outlook-Stil) ---- */

.kalender-outlook-grid { display: flex; }
.kalender-outlook-stunden-spalte { flex: 0 0 40px; flex-shrink: 0; position: sticky; left: 0; z-index: 4; background: #fff; border-right: 1px solid var(--farbe-rand); }
.kalender-outlook-ecke { height: 68px; border-bottom: 1px solid var(--farbe-rand); position: sticky; top: 0; z-index: 5; background: #fff; }
.kalender-outlook-stunden-liste { position: relative; }
.kalender-outlook-stunde-label { position: absolute; left: 0; right: 4px; text-align: right; font-size: 10px; color: var(--farbe-text-schwach); transform: translateY(2px); }

.kalender-outlook-inhalt { position: relative; flex-shrink: 0; }
.kalender-outlook-kopf-zeile { position: sticky; top: 0; z-index: 3; background: #fff; height: 68px; border-bottom: 1px solid var(--farbe-rand); }
.kalender-outlook-tag { position: absolute; top: 0; bottom: 0; box-sizing: border-box; overflow: hidden; }
.kalender-outlook-mitarbeiter-kopf { display: flex; margin-top: 2px; }
.kalender-outlook-mitarbeiter-spalte-kopf {
    font-size: 10px; line-height: 1.15; text-align: center; padding: 3px 2px; border-right: 1px dotted #e2e2e2; box-sizing: border-box;
    white-space: normal; word-break: break-word; overflow: hidden;
}

/* Blassgelb = ausserhalb der Geschaeftszeiten (inkl. ganzes Wochenende), weisser Block = Mo-Fr
   Geschaeftszeiten (siehe OUTLOOK_GESCHAEFT_START/ENDE in kalender.js). */
.kalender-outlook-flaeche { position: relative; background: #fdf6d9; cursor: pointer; }
/* pointer-events:none, damit Klicks auf leere Flaeche (-> neuer Termin) durch diese rein
   dekorativen Elemente hindurch bei .kalender-outlook-flaeche selbst ankommen. */
.kalender-outlook-geschaeftszeit { position: absolute; background: #fff; pointer-events: none; }
.kalender-outlook-stunde-linie { position: absolute; left: 0; right: 0; border-top: 1px solid #d5d5d5; pointer-events: none; }
.kalender-outlook-halbstunde-linie { position: absolute; left: 0; right: 0; border-top: 1px dashed rgba(0,0,0,.06); pointer-events: none; }
.kalender-outlook-tag-linie { position: absolute; top: 0; bottom: 0; border-right: 1px solid var(--farbe-rand); pointer-events: none; }
.kalender-outlook-mitarbeiter-linie { position: absolute; top: 0; bottom: 0; border-right: 1px dotted #e2e2e2; pointer-events: none; }

.kalender-termin-outlook { bottom: auto; padding: 2px 4px; font-size: 10px; white-space: normal; line-height: 1.25; }

/* Eingabefeld-Wrapper des Kontaktfelds (siehe kontaktFeldHtml() in app.js) - eigene Klasse statt
   Inline-Style, damit die mobile Ueberschreibung (siehe mobile.css) per CSS-Spezifitaet greifen kann. */
.kontakt-feld-input-wrap { position: relative; flex: 1; }

.autocomplete-liste {
    /* position: fixed statt absolute, damit die Liste nicht vom overflow:auto einer umgebenden .karte
       abgeschnitten wird; Position/Breite werden in kontaktFeldInit() per JS anhand des Eingabefelds gesetzt. */
    position: fixed;
    z-index: 1000;
    background: #fff;
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    box-shadow: 0 3px 8px rgba(0,0,0,.15);
    max-height: 220px;
    overflow-y: auto;
}
.autocomplete-eintrag { padding: 7px 9px; cursor: pointer; font-size: 13px; }
.autocomplete-eintrag:hover { background: #fdf6d9; }
.autocomplete-hinweis { padding: 7px 9px; font-size: 12px; color: var(--farbe-text-schwach); }

/* Wie .autocomplete-liste, aber position:absolute statt fixed: reicht innerhalb eines <dialog>
   (kein umgebendes overflow:auto, das sonst per JS umgangen werden muesste). */
.kn-projekt-liste {
    position: absolute; top: 100%; left: 0; right: 0; z-index: 1000;
    background: #fff; border: 1px solid var(--farbe-rand); border-radius: var(--radius);
    box-shadow: 0 3px 8px rgba(0,0,0,.15); max-height: 220px; overflow-y: auto;
}

.feld-clear-btn {
    position: absolute;
    right: 4px;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 20px;
    min-height: 0;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--farbe-text-schwach);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    border-radius: var(--radius);
}
.feld-clear-btn:hover { background: #dadada; color: var(--farbe-text); }

/* Generisches "X"-Leeren-Icon in Textfeldern/Textareas (siehe initTextfeldClear() in app.js) -
   .tf-clear-wrap umschliesst dabei nur das Feld selbst (nicht sein Label/umgebendes Feld-Div), daher
   hier keine Breiten-/Flex-Vorgaben noetig - der Wrapper ist ein einfacher Block wie das Feld davor. */
.tf-clear-wrap { position: relative; display: block; }
/* display:block auf dem Feld selbst (statt dem Default inline-block) verhindert den unsichtbaren
   Zeilenbox-Abstand unterhalb, der das X sonst leicht ausserhalb der Vertikalmitte zeigt. */
.tf-clear-wrap input[type="text"], .tf-clear-wrap textarea { padding-right: 28px; display: block; }
/* Bei Textareas (mehrzeilig, hoehenveraenderlich per resize:vertical) sitzt das X oben statt vertikal
   zentriert - eine Mitte waere bei variabler Hoehe optisch falsch und stoert nicht mit dem
   Resize-Griff unten rechts. */
.tf-clear-wrap-textarea .tf-clear-btn { top: 10px; transform: none; }

/* Einheitlicher quadratischer "X entfernen"-Button - ueberall im Projekt gleich (Notizen, Dokumente,
   Kontakte, Tabellenzeilen, ...), unabhaengig von der globalen (nicht quadratischen) Button-Groesse
   mobil/Desktop. Zusaetzlich zu .sekundaer fuer die Grau-Optik. */
.entfernen-btn {
    width: 24px; height: 24px; min-height: 0; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1; flex-shrink: 0;
}

.breadcrumb { font-size: 12.5px; margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; }
/* row-gap statt gap: sorgt fuer Abstand zwischen den Zeilen, wenn die Chips bei wenig Platz umbrechen,
   ohne zusaetzlichen horizontalen Abstand einzufuehren (der kommt schon vom Trennpfeil-margin unten). */
.breadcrumb > span:first-child { display: flex; flex-wrap: wrap; align-items: center; row-gap: 6px; }
.breadcrumb a { text-decoration: none; }

/* Trennpfeil vor jedem Breadcrumb-Segment, ausser vor dem jeweils ersten SICHTBAREN (manche Segmente
   werden je nach Zugriffsrecht per .versteckt ausgeblendet, siehe aktualisiereBreadcrumbTrenner() in
   app.js - reines CSS kennt kein "erstes sichtbares Element", daher die JS-gesetzte .breadcrumb-vorne-
   Klasse). Sitzt auf der aeusseren .breadcrumb-teil-Huelle, NIE auf dem Chip selbst (siehe .breadcrumb-chip
   unten) - jedes Chip-Segment (auch das aktuelle) ist deshalb in ein eigenes .breadcrumb-teil gewrappt,
   damit der Pfeil immer ZWISCHEN den Kaestchen erscheint statt (bei einem einzelnen Element mit beiden
   Klassen) versehentlich INNERHALB des Kaestchens zu landen. */
.breadcrumb-teil::before { content: "›"; color: var(--farbe-text-schwach); margin: 0 5px; font-size: 11px; }
.breadcrumb-teil.breadcrumb-vorne::before { content: ""; margin: 0; }

/* Jeder Breadcrumb-Abschnitt als eigener Chip statt reinem Text - auf dem Link (Projekt/Paket-Segmente)
   oder direkt auf dem aktuellen, nicht verlinkten Segment. Inaktiv = grau/klickbar; .breadcrumb-aktuell
   bekommt bewusst KEINE volle Gelbflaeche (das waere optisch nicht von einem echten primaeren Button zu
   unterscheiden, die nutzen dieselbe Akzentfarbe, siehe button/.knopf) - stattdessen dieselbe Bildsprache
   wie der aktive Sidebar-Eintrag: helle Flaeche + duenne gelbe Akzentkante, hier unten statt links. */
.breadcrumb-chip {
    display: inline-flex;
    align-items: center;
    padding: 3px 9px;
    border-radius: var(--radius);
    background: #eaeaea;
    color: var(--farbe-text-schwach);
    border: 1px solid var(--farbe-rand);
}
a.breadcrumb-chip:hover { background: #ddd; }
.breadcrumb-chip.breadcrumb-aktuell {
    background: #fff;
    color: var(--farbe-text);
    font-weight: 600;
    border-bottom-width: 2.5px;
    border-bottom-color: var(--farbe-marke-gelb-dunkel);
    padding-bottom: 2.5px; /* 1.5px weniger, um die dickere Unterkante optisch auszugleichen */
    cursor: default;
}

/* "..."-Chip zum Ausklappen der Breadcrumb-Vorfahren, nur auf Mobile sichtbar/genutzt (siehe
   aktualisiereBreadcrumbTrenner() in app.js, das ihn einfuegt, und die Sichtbarkeitsregeln in
   mobile.css) - am Desktop ist immer genug Platz fuer die volle Kette. */
.breadcrumb-mehr { display: none; cursor: pointer; }
.breadcrumb-mehr:hover { background: #ddd; }

/* Fix angeheftete "Lasche" oben, unabhaengig vom Scroll-Stand sichtbar (siehe zeigeSeitenLasche() in
   app.js) - ergaenzt den Breadcrumb um eine staendige Orientierung, welcher Seitentyp gerade offen ist.
   Bewusst nur innerhalb von .app-hauptbereich (rechts neben der 212px breiten Sidebar, siehe
   .app-sidebar) positioniert, nicht ueber die volle Fensterbreite. Vier feste Positionen (nicht nach
   Breadcrumb-Tiefe, sondern nach Wichtigkeit im Alltag): Projekt/Paket/Termin je eine eigene Stelle,
   alle uebrigen Unterseiten (Berichte, Frist, Alle Fotos, ...) teilen sich die vierte Stelle - dort
   unterscheidet nur noch das Label. --lasche-start/-ende sind exakte, EXAKT gleich grosse Randabstaende
   zur Sidebar bzw. zum rechten Fensterrand - 52px (mehr als das horizontale main-Padding von 26px, siehe
   main{padding:18px 26px 32px}, bewusst zusaetzlicher Abstand); --lasche-frac (0 bis 1) interpoliert
   linear dazwischen - Position 1 (frac 0) und Position 4 (frac 1) landen dadurch bei jeder Fensterbreite
   exakt auf diesen beiden Randwerten, nicht nur bei zufaellig passender Breite. */
.lasche {
    position: fixed;
    top: 0;
    /* Breite skaliert mit der Fensterbreite (10%), damit die Lasche auf breiten Monitoren nicht winzig
       neben dem restlichen, ebenfalls breiteren Seiteninhalt wirkt - clamp() haelt sie zwischen 160px
       (Untergrenze bei normalen/schmaleren Desktop-Fenstern) und 260px (verhindert eine unangemessen
       grosse Lasche auf Ultrawide-Monitoren). */
    --lasche-breite: clamp(160px, 10%, 260px);
    --lasche-start: calc(212px + 52px);
    /* 100% statt 100vw: vw schliesst laut Spezifikation die Breite eines eingeblendeten
       Scrollbalkens mit ein, % fuer ein fixed-positioniertes Element loest dagegen gegen die tatsaechlich
       sichtbare Fensterbreite (ohne Scrollbalken) auf - bei 100vw waere die Lasche auf langen Seiten mit
       sichtbarem Scrollbalken (z.B. mietschein.html) um dessen Breite zu weit rechts gelandet, praktisch
       ohne Randabstand. */
    --lasche-ende: calc(100% - var(--lasche-breite) - 52px);
    left: clamp(var(--lasche-start), calc(var(--lasche-start) + (var(--lasche-ende) - var(--lasche-start)) * var(--lasche-frac, 0)), var(--lasche-ende));
    width: var(--lasche-breite);
    height: 25px;
    background: var(--farbe-marke-gelb);
    color: var(--farbe-akzent-text);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 700;
    box-shadow: 0 3px 8px rgba(0,0,0,.18);
    border: 1px solid var(--farbe-marke-gelb-dunkel);
    border-top: none;
    z-index: 500;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    padding: 0 6px;
    transition: left .35s ease;
}
.lasche.lasche-projekt  { --lasche-frac: 0; }
.lasche.lasche-paket    { --lasche-frac: 0.333; }
.lasche.lasche-termin   { --lasche-frac: 0.667; }
.lasche.lasche-sonstige { --lasche-frac: 1; }

/* Extra Abstand oben, nur auf Seiten mit Lasche (Klasse von zeigeSeitenLasche() gesetzt) - sonst
   ueberlappt die 25px hohe, an top:0 angeheftete Lasche den Breadcrumb/"Zurueck"-Button darunter. */
body.hat-lasche main { padding-top: 25px; }

/* Einheitlicher "eine Ebene hoch"-Button ("← zum Projekt"/"← zum Paket"/"← Alle Projekte" etc.) in
   Breadcrumb-Zeile oder Titel-Toolbar - darf nie durch Nachbar-Inhalte (langer Breadcrumb-Text, langer
   Titel) zusammengequetscht werden und seinen Text intern umbrechen. */
.zurueck-btn { white-space: nowrap; flex-shrink: 0; }

/* Geteiltes Foto-Grid (Paket/Termin/Projekthistorie/Alle Fotos) - einheitliches System: quadratische
   Kacheln, Bildbeschreibung+Datum zentriert darunter, Klick oeffnet die geteilte navigierbare Lightbox
   (fotoLightboxOeffnen() in app.js). Spaltenzahl automatisch (auto-fill) - ausser bei Alle Fotos, das
   per .af-manuell eine vom User gewaehlte feste Spaltenzahl erzwingt (siehe render() in alle_fotos.js).
   Standard object-fit ist cover; nur Alle Fotos schaltet per .contain auf das ganze (nicht
   beschnittene) Foto um. Obergrenze 1fr statt einer festen Breite, damit auch unbesetzte
   auto-fill-Spuren ihren Anteil an der Zeilenbreite abbekommen und die Kacheln die Zeile immer
   vollstaendig ausfuellen (bei wenigen Fotos bleiben die Kacheln trotzdem normal gross, siehe
   MDN "auto-fill vs. auto-fit"). */
.foto-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }
.foto-grid.af-manuell { grid-template-columns: repeat(var(--af-spalten, 4), 1fr); }
.foto-grid figure { margin: 0; min-width: 0; }
.foto-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius); cursor: pointer; display: block; }
.foto-grid.contain img { object-fit: contain; }
.foto-grid figcaption { font-size: 11px; color: var(--farbe-text-schwach); margin-top: 4px; text-align: center; }

.foto-grid-bild-wrap { position: relative; }
.foto-entfernen-btn {
    position: absolute; top: 4px; right: 4px;
    width: 24px; height: 24px; min-height: 0; padding: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; line-height: 1;
    background: rgba(0,0,0,.55); color: #fff; border: none; border-radius: var(--radius); cursor: pointer;
}
.foto-entfernen-btn:hover { background: rgba(0,0,0,.75); }

/* Foto-Upload-Zeile (siehe fotoUploadFormularHtml() in app.js) - Desktop: Datei-Auswahl/Bildbeschreibung/
   Hochladen nebeneinander, Tag-Zeile darunter unter der Bildbeschreibung-Spalte. Mobil wird daraus eine
   einzige Spalte (siehe mobile.css) - drei Spalten waeren dort zu schmal, die Bildbeschreibung wuerde
   neben die (mobil breiteren) Auswahl/Aufnehmen-Knoepfen gequetscht und aus der Karte ragen. */
.foto-upload-zeile { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; align-items: end; }
.foto-upload-tags-zeile { grid-column: 2; }

/* Tag-Auswahl im Foto-Upload-Formular (siehe fotoUploadTagsHtml() in app.js) - unter den Bildern selbst
   werden Tags nicht mehr als Chips angezeigt, sondern nur noch als Text in der Bildunterschrift (siehe
   fotoBeschreibungText()). Echte, klickbare <button class="chip-auswahl"> in genau der gleichen Optik
   wie alle anderen klickbaren Chips im Projekt (z.B. die Ergebnis-Chips bei "Termin abschliessen"). */
.foto-tags { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px; margin-top: 6px; }
/* Feste 22x22px, exakt passend zur Hoehe der echten Tag-Chips (.chip-auswahl: line-height 14px +
   padding 3px oben/unten + border 1px oben/unten = 22px, siehe dort) - keine geschaetzte Groesse mehr,
   sondern rechnerisch aus denselben Werten abgeleitet. Selektor mit zwei Klassen ist spezifischer als
   .chip-auswahl allein (das steht spaeter im Stylesheet und wuerde bei gleicher Spezifitaet gewinnen). */
.foto-tags .foto-tag-hinzufuegen-btn {
    width: 22px; height: 22px; min-height: 0; padding: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; line-height: 1;
}

/* Filterleiste "Alle Fotos" (js/alle_fotos.js) - Label immer ueber dem Feld, wie bei den Hinzufuegen/
   Bearbeiten-Modals (siehe kontaktFelderHtml()), fuer Einheitlichkeit mit den anderen Formularen im
   Projekt. Am Desktop stehen alle vier Felder in einer Zeile nebeneinander (umbricht nur bei zu wenig
   Platz); mobil erzwingt ein 2-Spalten-Raster - siehe mobile.css. */
.af-filter-felder { display: flex; flex-wrap: wrap; gap: 12px; }
.af-filter-feld { display: flex; flex-direction: column; gap: 4px; }
.af-filter-feld label { margin: 0; }
.af-filter-feld select, .af-filter-feld input { width: auto; }

/* Favoriten-Herz oben rechts auf jeder Kachel (nur "Alle Fotos", siehe afFavoritUmschalten() in
   js/alle_fotos.js) - FOTO_FAVORIT_TAG ist ein ganz normaler Tag, nur eingefaerbt statt textuell
   angezeigt. Gleiche Ueberlagerungs-Position wie .foto-entfernen-btn, eigener Wrapper (.af-bild-wrap)
   da afKachelnHtml() nicht die geteilte .foto-grid-bild-wrap-Struktur aus fotoGridRendern() nutzt. */
.af-bild-wrap { position: relative; }
.af-favorit-btn {
    position: absolute; top: 4px; right: 4px;
    width: 20px; height: 20px; min-height: 0; padding: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 11px; line-height: 1;
    background: rgba(0,0,0,.30); color: rgba(255,255,255,.30); border: none; border-radius: var(--radius); cursor: pointer;
    opacity: 0;
}
.af-favorit-btn:hover { background: rgba(0,0,0,.45); }
.af-favorit-btn.aktiv { color: #e8534a; opacity: 1; }
.af-bild-wrap:hover .af-favorit-btn { opacity: 1; }

/* Herz-Icon im "Favorit"-Tag-Filterchip (siehe afTagOptionen() in js/alle_fotos.js) - links vom Text,
   gleiche Farbe wie das aktive Herz auf den Kacheln. */
.af-favorit-herz-icon { color: #e8534a; }

/* Entfernbare Tag-Chips im Bearbeiten-Modal (#dialog-foto-bearbeiten) - einziger Ort, an dem ein Tag
   wieder entfernt werden kann (siehe fbTagsRendern() in js/alle_fotos.js). */
.fb-tag { display: inline-flex; align-items: center; gap: 4px; }
.fb-tag-entfernen-btn { background: none; border: none; color: inherit; cursor: pointer; padding: 0; font-size: 12px; line-height: 1; }

/* Skizze (messprotokoll.js): anklickbare Vorschau (Vollbild weiterhin per Klick ueber die Lightbox,
   fotoLightboxOeffnen()), so gross wie moeglich ohne zu dominieren - width:100% + max-width sorgt
   automatisch dafuer, dass sie mobil (Container schmaler als max-width) die volle Breite einnimmt und
   am Desktop bei max-width gedeckelt bleibt, ohne eigene Media-Query. height:auto statt einer festen
   Hoehe, da die Vorschau seit dem automatischen Zuschnitt (skizzeInhaltsBox() in skizze.js) ein
   variables Seitenverhaeltnis hat - object-fit:cover wuerde davon sichtbar etwas abschneiden. */
.skizze-bild { margin: 0; }
.skizze-bild img { display: block; width: 100%; max-width: 480px; height: auto; border-radius: var(--radius); border: 1px solid var(--farbe-rand); cursor: pointer; }

/* Bild-Feld (mobile.js: bildFeldHtml): "Foto aufnehmen" ist nur mobil sichtbar (siehe mobile.css). */
.bild-feld-knoepfe { display: flex; gap: 8px; }
.bild-feld-kamera-btn { display: none; }
.bild-feld-vorschau { font-size: 12px; color: var(--farbe-text-schwach); margin-top: 4px; display: flex; flex-wrap: wrap; gap: 6px; }
.bild-feld-datei {
    display: inline-flex; align-items: center; gap: 4px;
    background: var(--farbe-hintergrund); border: 1px solid var(--farbe-rand); border-radius: var(--radius);
    padding: 2px 6px;
}
.bild-feld-datei button {
    width: 18px; height: 18px; min-height: 0; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    border: none; background: none; cursor: pointer; color: var(--farbe-text-schwach); flex-shrink: 0;
}

/* Geteilte Foto-Lightbox (siehe fotoLightboxOeffnen() in app.js) - Vollbild mit Vor/Zurueck-Navigation
   per Klick oder Pfeiltasten durch alle Fotos der jeweiligen Liste (Paket/Termin/Bericht/Alle Fotos),
   Klick auf das Bild oeffnet es in neuem Tab, Klick auf den Hintergrund oder Escape schliesst. */
.foto-lightbox-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,.9); z-index: 2000;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.foto-lightbox-overlay img { max-width: 88vw; max-height: 74vh; border-radius: var(--radius); cursor: zoom-in; }
.foto-lightbox-info { text-align: center; color: #fff; margin-top: 12px; max-width: 88vw; }
.foto-lightbox-info .neben { color: #ccc; }
.foto-lightbox-schliessen {
    position: absolute; top: 16px; right: 16px; width: 40px; height: 40px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,.1); color: #fff; border: none; border-radius: 50%;
    font-size: 18px; line-height: 1; cursor: pointer;
}
/* Favoriten-Herz in der Lightbox (nur "Alle Fotos", siehe fotoLightboxOeffnen()s optionaler dritter
   Parameter) - bleibt per .versteckt-Klasse ausgeblendet, wenn keine Favoriten-Funktion uebergeben wurde. */
.foto-lightbox-favorit-btn {
    position: absolute; top: 16px; right: 64px; width: 40px; height: 40px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,.1); color: #fff; border: none; border-radius: 50%;
    font-size: 15px; line-height: 1; cursor: pointer;
}
.foto-lightbox-favorit-btn.aktiv { color: #e8534a; }
.foto-lightbox-pfeil {
    position: absolute; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; padding: 0 0 8px;
    display: flex; align-items: center; justify-content: center;
    background: rgba(255,255,255,.1); color: #fff; border: none; border-radius: 50%;
    font-size: 28px; line-height: 1; cursor: pointer;
}
.foto-lightbox-pfeil-links { left: 16px; }
.foto-lightbox-pfeil-rechts { right: 16px; }
.foto-lightbox-schliessen:hover, .foto-lightbox-pfeil:hover, .foto-lightbox-favorit-btn:hover { background: rgba(255,255,255,.25); }

/* .audio-aufnahme (Wrapper aus audioAufnahmeHtml()) UND der leere Slot-Div darum (in jeder Host-Seite
   z.B. <div id="ta-ergebnis-audio">, immer als letztes von genau zwei Kindern in .text-mit-audio - siehe
   dessen Regel unten) werden per display:contents "aufgeloest": ihre eigentlichen Kinder (Start/Stopp-
   Toolbar, Player-Zeile) werden dadurch selbst zu Flex-Items von .text-mit-audio, koennen also
   unabhaengig voneinander angeordnet werden, statt zusammen in einer schmalen Spalte rechts von der
   Textarea zu haengen. */
.audio-aufnahme { display: contents; }
.audio-aufnahme .toolbar { flex-shrink: 0; }
/* Aufgenommene Audiodatei in einer eigenen, vollbreiten Zeile unter Textarea+Toolbar (flex-basis:100%
   erzwingt zusammen mit .text-mit-audio's flex-wrap den Zeilenumbruch), Entfernen-Button (kleines "✕",
   siehe .entfernen-btn) rechts daneben statt im Toolbar oben. */
.audio-player-zeile { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-basis: 100%; }
.audio-player-zeile audio { flex: 1; max-width: 360px; height: 32px; }
/* Quadratischer Icon-Button statt Textlabel ("Audioaufnahme erstellen"/"Neu aufnehmen" stehen
   stattdessen im title-Tooltip, siehe audioAufnahmeInit() in app.js). */
.audio-aufnahme .toolbar button.audio-start-btn {
    width: 38px;
    height: 38px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* Ergebnis-Chips bei "Termin abschliessen" (siehe chipDefinitionen()/chipKlick() in
   termin_abschliessen.js) - gleicher dezenter Stil wie .chip-vorschlag (Schadensbericht): kleine,
   neutral-graue Buttons statt auffaelliger gelber Pillen, direkt unter dem Textfeld statt darueber.
   Ausgewaehlt wird ueber eine dunkelgraue Flaeche statt einer Akzentfarbe angezeigt - bleibt so
   optisch zurueckhaltend, auch bei vielen gleichzeitig ausgewaehlten Chips. */
.chip-auswahl { font-size: 12px; line-height: 14px; padding: 3px 10px; min-height: 0; background: #eaeaea; color: var(--farbe-text); border: 1px solid var(--farbe-rand); cursor: pointer; }
.chip-auswahl.chip-ausgewaehlt { background: var(--farbe-marke-grau); color: #fff; border-color: var(--farbe-marke-grau); font-weight: 600; }
.chip-auswahl:disabled { opacity: .4; cursor: not-allowed; }
/* "Storniert" ist immer der erste Chip (siehe chipDefinitionen()) und optisch dezent hervorgehoben
   (rote Schrift/Rand statt neutral), da er alle anderen Chips deaktiviert (siehe
   aktualisiereChipSperre()). */
.chip-storno { color: var(--farbe-rot); border-color: var(--farbe-rot); }
.chip-storno.chip-ausgewaehlt { background: var(--farbe-rot); color: #fff; border-color: #8f1e18; }

/* Ergebnis/Protokoll-Eingabe: wirkt wie EIN Textfeld, ist aber zwei Teile - die Praefix-Zeile
   (#ta-ergebnis-praefix, automatisch aus den ausgewaehlten Chips generiert) ist bewusst nicht
   editierbar, nur das Textfeld darunter ist es. Entfernen eines Tags geht daher ausschliesslich ueber
   Abwaehlen des Chips, nie durch Hineinschreiben in die Praefix-Zeile. */
.ergebnis-eingabe { border: 1px solid var(--farbe-rand); border-radius: var(--radius); overflow: hidden; }
.ergebnis-eingabe:focus-within { border-color: var(--farbe-marke-gelb-dunkel); }
.ergebnis-eingabe .ergebnis-praefix { padding: 8px 8px 0; font-weight: 600; color: var(--farbe-text-schwach); white-space: pre-wrap; }
.ergebnis-eingabe .ergebnis-praefix:empty { display: none; }
.ergebnis-eingabe textarea { border: none; border-radius: 0; }
.ergebnis-eingabe textarea:focus { outline: none; }

/* Unterschrift-Pad (siehe unterschriftPadHtml() in app.js) - touch-action:none verhindert Scrollen
   beim Zeichnen auf dem Canvas. Bewusst niedrig (statt z.B. 180px), da der Dialog im Querformat auf
   einem Handy nur wenig Hoehe zur Verfuegung hat (siehe #dialog-unterschrift unten) - sonst werden die
   Aktions-Buttons darunter abgeschnitten. */
.unterschrift-canvas { width: 100%; height: 110px; border: 1px solid var(--farbe-rand); border-radius: 8px; background: #fff; touch-action: none; display: block; }
.unterschrift-bild { max-width: 100%; max-height: 180px; border: 1px solid var(--farbe-rand); border-radius: 8px; background: #fff; }

/* Unterschriebener Abnahmebericht: Fotos bleiben sichtbar, aber nicht mehr entfernbar (siehe
   js/abnahmebericht.js render()). */
.fotos-gesperrt .foto-entfernen-btn { display: none; }

/* Skizze-Testseite (Fabric.js-Integration, siehe js/skizze.js): eigene Stylesheet-Datei css/skizze.css,
   nur auf skizze.html eingebunden, statt die globale style.css mit den vielen Skizze-spezifischen Regeln
   zu belasten. */

/* Unterschrift-Dialog: bewusst breiter als andere Dialoge (braucht Platz fuer die Zeichenflaeche) und
   IMMER im Querformat nutzbar - auf einem hochkant gehaltenen Mobilgeraet wird statt der Zeichenflaeche
   nur ein Dreh-Hinweis gezeigt (siehe .quer-hinweis/.quer-inhalt), erst nach echtem Drehen erscheint
   das Signatur-Feld. Bewusst KEIN CSS-transform:rotate() auf den ganzen Dialog - das wuerde zwar
   optisch drehen, aber Pointer-Events/getBoundingClientRect() der Canvas liefern weiterhin
   Bildschirm- statt Canvas-lokale Koordinaten, das Zeichnen liefe dann schraeg/versetzt. */
#dialog-unterschrift { max-width: 640px; }
#dialog-unterschrift .inhalt { padding: 12px 18px; }
/* Nebeneinander statt untereinander (Standard bei .aktionen) - spart Hoehe, die im Querformat auf
   einem Handy knapp ist. */
#dialog-unterschrift .aktionen { flex-direction: row; }
#dialog-unterschrift .aktionen button { flex: 1; }
#dialog-unterschrift .quer-hinweis { display: none; text-align: center; padding: 60px 20px; }
@media (max-width: 768px) and (orientation: portrait) {
    #dialog-unterschrift .quer-hinweis { display: block; }
    #dialog-unterschrift .quer-inhalt { display: none; }
}

/* Textfeld + Audioaufnahme-Button nebeneinander (Notizen, Ergebnis/Protokoll), siehe audioAufnahmeHtml() in app.js.
   flex-wrap:wrap + .audio-player-zeile's flex-basis:100% (s.o.) lassen die Player-Zeile bei Bedarf in
   eine eigene, vollbreite zweite Zeile umbrechen, statt neben der Textarea eingequetscht zu werden. */
.text-mit-audio { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.text-mit-audio textarea { flex: 1; }
/* Das "X leeren"-Feature (siehe .tf-clear-wrap) wickelt die Textarea in einen Span - der wird dadurch
   zum eigentlichen Flex-Kind, muss also selbst flex:1 bekommen, sonst schrumpft er auf Inhaltsbreite. */
.text-mit-audio .tf-clear-wrap { flex: 1; }
/* Der leere Slot-Div, in den audioAufnahmeHtml() per innerHTML eingesetzt wird (z.B. #ta-ergebnis-audio),
   ist in allen drei Verwendungen (Termin abschliessen, Notizen, Notiz-bearbeiten-Dialog) das zweite und
   letzte Kind hier - display:contents loest ihn analog zu .audio-aufnahme (s.o.) auf. */
.text-mit-audio > *:last-child { display: contents; }
/* Kleiner als die Textarea, aber ueber align-items:center (s.o.) vertikal zu ihr zentriert. */
.text-mit-audio .audio-aufnahme .toolbar button.audio-start-btn {
    width: 44px;
    height: 44px;
}

/* Projekthistorie: vertikale Zeitleiste */
.historie-zeile { display: flex; gap: 12px; }
.historie-datum { flex: 0 0 108px; font-size: 12px; color: var(--farbe-text-schwach); text-align: right; padding-top: 3px; }
.historie-spur { flex: 0 0 16px; display: flex; flex-direction: column; align-items: center; }
.historie-punkt { width: 11px; height: 11px; border-radius: 50%; background: var(--farbe-akzent-dunkel); flex-shrink: 0; margin-top: 3px; border: 2px solid #fff; box-shadow: 0 0 0 1px var(--farbe-rand); }
.historie-punkt.abgeschlossen { background: var(--farbe-gruen); }
.historie-punkt.frist { background: var(--farbe-grau); }
.historie-strich { flex: 1; width: 2px; background: var(--farbe-rand); margin-top: 2px; }
.historie-inhalt { flex: 1; padding-bottom: 18px; min-width: 0; margin-left: calc(var(--historie-ebene, 0) * 12px); }
.historie-inhalt summary { cursor: pointer; list-style: none; }
.historie-inhalt summary::-webkit-details-marker { display: none; }
.historie-inhalt summary:hover .historie-titel { text-decoration: underline; }
.historie-titel { font-weight: 600; }
.historie-inhalt .neben { font-size: 12px; color: var(--farbe-text-schwach); margin-top: 2px; }
.historie-details { margin-top: 8px; padding: 10px 12px; background: var(--farbe-hintergrund); border-radius: var(--radius); }

dialog {
    border: 1px solid var(--farbe-rand);
    border-radius: var(--radius);
    padding: 0;
    max-width: 560px;
    width: 90%;
    max-height: 85dvh;
    overflow-y: auto;
    box-shadow: 0 6px 20px rgba(0,0,0,.25);
}
dialog::backdrop { background: rgba(0,0,0,.6); }
dialog .inhalt { padding: 18px; }
dialog .aktionen { display: flex; flex-direction: column; gap: 8px; margin-top: 16px; }

/* Kleines X oben rechts zum Abbrechen, zusaetzlich zum bestehenden Abbrechen-Button in .aktionen -
   direktes Kind von <dialog> (nicht von .inhalt), damit es unabhaengig vom Innenabstand des Inhalts
   oben rechts an der Dialog-Box selbst sitzt (dialog ist per UA-Stylesheet bereits position:absolute,
   dient also ohne Zusatzregel als positionierender Vorfahre). Ruft dieselbe Aktion wie der jeweilige
   Abbrechen-Button auf. */
.dialog-x {
    position: absolute;
    top: 10px;
    right: 10px;
}

/* Dateien hochladen (dateien_hochladen.html/js/dateien_hochladen.js) - Drag-&-Drop-Upload + Zuordnungsliste fuer Fotos/
   Dokumente ohne Projekt. */
.dh-dropzone {
    border: 2px dashed var(--farbe-rand);
    border-radius: var(--radius);
    padding: 28px 16px;
    text-align: center;
    color: var(--farbe-text-schwach);
}
.dh-dropzone p { margin: 0 0 10px; }
/* Aktiv waehrend ein Drag ueber der Flaeche schwebt (siehe dragenter/dragover in dhDropzoneInit()). */
.dh-dropzone-aktiv { border-color: var(--farbe-marke-gelb-dunkel); background: #fdf6d9; }

.dh-eintrag {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--farbe-rand);
}
.dh-eintrag:last-child { border-bottom: none; }
.dh-eintrag select { width: auto; }
/* Projekt-Dropdown (ggf. mit Hinweistext darunter, siehe dhErkennungsHinweisHtml() in
   js/dateien_hochladen.js) und Paket-Dropdown sollen immer auf gleicher Hoehe beginnen, auch wenn der
   Hinweistext das Projekt-Feld hoeher macht als das Paket-Feld - align-self:flex-start statt des
   geerbten align-items:center auf .dh-eintrag (das wuerde stattdessen die MITTE beider Felder
   ausrichten, wodurch die Dropdowns selbst gegeneinander verrutschen). Bewusst NICHT ueber
   position:absolute geloest (fruehere Variante) - das haette den Hinweistext aus dem Layoutfluss
   genommen und liess ihn bei umgebrochenen Zeilen (schmaler Bildschirm, .dh-eintrag hat flex-wrap)
   unterhalb der border-bottom-Trennlinie des Eintrags haengen. */
.dh-projekt-feld, .dh-eintrag > select { align-self: flex-start; }
.dh-erkennung-hinweis { margin-top: 2px; }
.dh-vorschau-bild { width: 56px; height: 56px; object-fit: cover; border-radius: var(--radius); flex-shrink: 0; }
.dh-vorschau-icon {
    width: 56px; height: 56px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 11px;
}
.dh-info { flex: 1; min-width: 160px; }

/* ---- Ersatz fuer frueher inline vergebene style="..."-Attribute in generierten HTML-Strings (siehe
   js/app.js) - Umstellung auf CSS-Klassen, siehe [[feedback_kein_inline_onclick_style]]. Generische
   Utilities oben in der Datei ergaenzen sich hier um seitenuebergreifend genutzte Klassen. ---- */
.icon-svg-block { display: block; }
.m-0 { margin: 0; }
/* .m-0 setzt auch bei einer <h1> jeden Rand auf 0 - die soll aber trotzdem den h1-margin-top von oben
   bekommen, ausser sie steckt in einer .karte (siehe h1{}-Kommentar weiter oben in dieser Datei). Beide
   Selektoren haben dieselbe Spezifitaet (Element+Klasse) - die Reihenfolge hier entscheidet, .karte h1
   muss daher NACH h1.m-0 stehen, damit Karten-Titel korrekt bei 0 bleiben. */
h1.m-0 { margin-top: 8px; }
.karte h1 { margin-top: 0; }
.mt-8 { margin-top: 8px; }
.mt-16 { margin-top: 16px; }
.mt-20 { margin-top: 20px; }
.mb-10 { margin-bottom: 10px; }
.es-eingabe-zeile { display: flex; align-items: center; gap: 6px; }
.es-wert-input { width: 70px; }
.es-einheit { font-size: 12px; color: var(--farbe-text-schwach); white-space: nowrap; }
.ampel-punkt-inline { vertical-align: middle; }
.hinweistext { color: var(--farbe-text-schwach); font-size: 14px; }
.checkbox-auto { width: auto; }
.checkbox-zeile { display: flex; align-items: center; gap: 6px; font-weight: 400; padding: 3px 0; }
/* Bereits als Klassen-Hook im Markup vorhanden (siehe kontaktFeldHtml() in js/app.js), bisher aber ohne
   zugehoerige CSS-Regel - die Positionierung/das Layout kam bisher ausschliesslich aus Inline-Styles. */
.autocomplete-wrapper { position: relative; }
.kontakt-feld-reihe { display: flex; gap: 6px; }
.foto-tags-upload { justify-content: flex-start; margin-top: 0; }
.feld-anzeige-readonly { padding: 8px 0; }
.zustaendige-modus-toolbar { margin: 0 0 6px; }
.zustaendige-modus-label { display: inline-flex; align-items: center; gap: 4px; font-weight: 400; margin: 0; }
.zustaendige-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.benachrichtigung-audio { display: block; margin-top: 4px; height: 32px; max-width: 300px; }
.mt-0 { margin-top: 0; }
.td-nowrap { white-space: nowrap; }
.fw-400 { font-weight: 400; }
.float-right { float: right; }
.checkbox-zeile-eng { padding: 2px 0; }
.projekt-titel-klickbar { margin: -14px -16px; padding: 14px 16px; }
.ampel-punkt-titel { position: relative; top: 2px; }
.projekt-titel-h1 { margin: 0; font-size: 24px; font-weight: 700; }
.abschnitt-trenner { border-top: 1px solid var(--farbe-rand); margin-top: 24px; padding-top: 20px; }
.label-inline { margin: 0; white-space: nowrap; }
.notiz-empfaenger-zeile { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.notiz-audio { display: block; margin-top: 6px; height: 32px; max-width: 360px; }
.ml-4 { margin-left: 4px; }
.ebene-zeile { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; padding: 4px 6px; border-radius: var(--radius); }
.ebene-zeile-aktuell { background: #fdf6d9; }
.ebene-label { font-size: 11px; font-weight: 600; color: var(--farbe-text-schwach); min-width: 52px; }
.ebene-leer-hinweis { font-size: 12px; color: var(--farbe-text-schwach); }
.zust-ebene-label { font-size: 11px; font-weight: 600; color: var(--farbe-text-schwach); margin-bottom: 4px; }
.zust-feld-zeile { grid-template-columns: 1fr 1fr; align-items: center; margin-bottom: 6px; }
.karte-warnung { border-color: var(--farbe-marke-gelb-dunkel); }
.paket-inaktiv-hinweis { font-size: 13px; color: var(--farbe-text-schwach); margin-top: 0; }
.flex-align-end { display: flex; align-items: end; }
.mt-10 { margin-top: 10px; }
.mt-12 { margin-top: 12px; }
.dokument-formular-zeile { margin-top: 10px; display: flex; gap: 8px; align-items: end; }
.mb-12 { margin-bottom: 12px; }
.mb-14 { margin-bottom: 14px; }
.bereits-angelegt-hinweis { font-size: 13px; color: var(--farbe-text-schwach); margin: 0 0 8px; }
.cursor-default { cursor: default; }
.opacity-gedaempft { opacity: 0.6; }
.nq-entwurf-zeile { grid-template-columns: 1fr 1fr auto; gap: 8px; align-items: center; margin-top: 10px; }
.frist-checkbox-label { display: flex; align-items: center; gap: 6px; font-weight: 400; margin-top: 12px; }
.btn-full-width { width: 100%; }
.kw-label { margin-left: 6px; font-weight: 600; }
.leer-padding { padding: 12px; }
.w-80 { width: 80px; }
.w-140 { width: 140px; }
/* Chart.js braucht mit maintainAspectRatio:false einen Elternknoten mit eigener Hoehe, sonst faellt die
   Canvas auf 0px zusammen - siehe Verlaufsgrafik in messprotokoll.js. */
#verlauf-chart-wrap { position: relative; height: 320px; }
.mb-8 { margin-bottom: 8px; }
.oder-hinweis { font-size: 12px; color: var(--farbe-text-schwach); margin: 10px 0; }
.mt-26 { margin-top: 26px; }
.label-tight { margin: 0 0 4px; }
.mt-14 { margin-top: 14px; }
.chip-vorschlaege { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.checkbox-gruppe-zeile { display: flex; gap: 24px; margin-top: 10px; }
.checkbox-inline { display: flex; align-items: center; gap: 6px; font-weight: 400; }
.karte-erfolg { border-color: var(--farbe-gruen); }
.termin-titel-h1 { margin: 0 0 10px; }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: 2px; }
.chips-zeile-mt8 { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chips-zeile { display: flex; flex-wrap: wrap; gap: 6px; }
.hinweistext-mb6 { font-size: 13px; color: var(--farbe-text-schwach); margin: 0 0 6px; }
.mb-3 { margin-bottom: 3px; }
.w-auto { width: auto; }
.chips-zeile-mt10 { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.historie-titel-h1 { margin: 0 0 12px; }
h1.historie-titel-h1 { margin-top: 8px; } /* nicht in einer .karte, siehe h1.m-0-Kommentar oben */
.knopf-inline-mt8 { margin-top: 8px; display: inline-block; }
.termin-berichte-toolbar { margin: 0 0 8px; }
.historie-ebene-0 { --historie-ebene: 0; }
.historie-ebene-1 { --historie-ebene: 1; }
.historie-ebene-2 { --historie-ebene: 2; }
.versteckt { display: none !important; }

/* "Bitte X anlegen/aktualisieren"-Aufforderungen bei Termin abschliessen (Schritt "Berichte") - farblich
   hervorgehoben, aber bewusst kein voller .karte-warnung-Rahmen (waere als verschachtelte Karte-in-Karte
   zu schwer), daher eigene, leichtere Box im selben Firmengelb-Ton wie .eintrag-karte:hover. */
.berichte-aufforderungen { background: #fdf6d9; border: 1px solid var(--farbe-marke-gelb-dunkel); border-radius: var(--radius); padding: 9px 11px; margin-bottom: 12px; font-size: 13px; }
.berichte-aufforderungen p { margin: 0; }
.berichte-aufforderungen p + p { margin-top: 4px; }
.berichte-aufforderungen-erledigt { background: #e2f5e8; border-color: var(--farbe-gruen); color: var(--farbe-gruen-text); }
