/* DSGVO: lokal gehostet statt Google-CDN/jsdelivr (06.06.) — CSP style-src 'self' erlaubt das, kein Tracking */
@import url('vendor/fonts.css');
@import url('vendor/phosphor-icons/phosphor.css');

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Haekchen, Auswahlknoepfe und Fortschrittsbalken folgen der Marke statt dem
   Systemblau von Windows. Betraf auch die Preisseite im Kaufpfad — die einzige
   Stelle, die aus dem Orange-Schema fiel (UX-Durchgang 31.07., Befund 6).
   Ein Wert reicht: der Browser leitet Rahmen und Haken selbst daraus ab. */
input[type="checkbox"], input[type="radio"], progress, input[type="range"] {
  accent-color: var(--primary);
}

/* Ohne color-scheme malt der Browser NATIVE Controls (Selects, Datumsfelder,
   Scrollbalken) hell, egal was die Seite tut — auf dem Handy stand die
   Betriebsrollen-Auswahl als weisser Kasten im dunklen Beteiligten-Tab
   (Bildbefund 12.08.). Muss zum data-theme-Schalter passen, nicht zum OS. */
:root, :root[data-theme="dark"] { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* Das `hidden`-Attribut MUSS verstecken — auch an Elementen mit eigenem
   `display`. Gefunden am 19.08.2026 im Bild: der Knopf „Übernehmen" am
   Mangel-Dropdown blieb stehen, obwohl das Skript ihn auf `hidden` gesetzt
   hatte. `.btn` setzt `display:inline-flex`, und Autor-CSS schlaegt die
   `display:none`-Regel des Browsers fuer `[hidden]`. Ohne diese Zeile ist
   `el.hidden = true` an jedem gestylten Element wirkungslos — still, ohne
   Fehlermeldung. */
[hidden] { display: none !important; }

:root {
  --primary:       #d97706;
  --primary-dark:  #b45309;
  --primary-light: #f59e0b;
  --primary-glow:  rgba(217,119,6,0.16);
  /* Schrift AUF Orange — Beas Marken-Entscheidung (27.08.2026): Orange bleibt
     #d97706, die Schrift darauf wird #1c1310 (5,73:1). Ersetzt fuenf Ad-hoc-
     Toene (#150c02/#0a0a0a/#1a0e02/#1a1a1a/#fff); Weiss hatte nur 3,19:1 und
     fiel bei Chip-Schriftgroessen durch WCAG AA. Kein Light-Override noetig:
     der Orange-Grund ist in beiden Modi derselbe. */
  --on-primary:    #1c1310;

  --bg:            #14100d;
  /* Flaechen-Treppe seit 12.08.2026 auf den Prototyp-Werten (Domis + Beas
     Freigabe: Prototyp wird Standard-Design). surface ist die Kartenflaeche
     (Prototyp --flaeche), surface3 die ANGEHOBENE Ebene fuer Chips und Hover
     (Prototyp --flaeche-2), surface2 die ABGESENKTE Innenflaeche (Eingaben,
     Notizkaesten). Wer hier Werte aendert, aendert die Trennung der ganzen App. */
  --surface:       #1c1815;
  --surface2:      #171310;
  --surface3:      #241f1b;
  /* Schwebende Elemente (Menues, Toasts, Tooltips): eigene, hellste Ebene plus
     shadow-lg — sie stehen oft ueber gleichfarbigen Karten. */
  --overlay:       #2c2621;
  --hover:         rgba(255,226,190,0.06);
  --border:        rgba(255,232,204,0.08);
  --border-strong: rgba(255,232,204,0.16);

  /* Textstufen aus dem Prototyp — gemessen, nicht gewaehlt: die Abstufung
     entsteht ueber den ABSTAND der beiden Grautoene, nicht dadurch, dass der
     untere im Grund verschwindet (#6e6e6e riss WCAG an 51 Stellen). */
  --text:          #ede7e0;
  --text-muted:    #b0a69c;   /* 7,0:1 auf --surface */
  /* War #8f857b, wie im Entwurf. Der Entwurf hatte gegen --surface gerechnet
     (4,9:1) — und genau dort steht dieser Ton am seltensten. Auf den drei
     ANGEHOBENEN Flaechen fiel er unter WCAG AA: eigene Chatblase 4,28 ·
     Statusmarke 4,27 · --overlay 4,13. Die Browser-Kontrastmessung fand nur
     die ersten beiden — die Overlay-Kombination kam auf den geprueften Seiten
     nicht vor. Ein Pruefer kennt eben nur seinen Suchraum; nachgerechnet wurde
     deshalb gegen ALLE Gruende, auf denen der Ton real steht.
     #a09589 gibt auf dem schlechtesten davon 5,09:1 und bleibt gedaempft. */
  --text-faint:    #a09589;

  --shadow-sm:     0 1px 3px rgba(0,0,0,0.4), 0 1px 2px rgba(0,0,0,0.3);
  --shadow:        0 4px 16px rgba(0,0,0,0.5), 0 2px 6px rgba(0,0,0,0.3);
  --shadow-lg:     0 20px 48px rgba(0,0,0,0.65), 0 8px 20px rgba(0,0,0,0.4);
  --shadow-glow:   0 4px 24px rgba(217,119,6,0.13);

  --radius:        12px;
  /* Toenungen, Schatten, Schleier (Farben-Plan Bea 02.11.2026) */
  --bad: #f87171;
  --orange-bg: rgba(217,119,6,.16); --ok-bg: rgba(95,181,132,.14); --bad-bg: rgba(248,113,113,.14); --info-bg: rgba(98,155,248,.14);
  --schatten: rgba(0,0,0,.35); --scrim: rgba(0,0,0,.55);
  /* Papier der Dokumentvorschau (Briefkopf auf /firma): bleibt in beiden Modi weiss, Schrift mind. 4,5:1.
     Vorher feste Toene im Template, #bbb (1,92:1), #999 (2,85:1) und #777 (4,48:1) fielen durch. */
  --papier: #ffffff; --papier-tx: #222222; --papier-mu: #666666; --papier-linie: #dddddd;
  /* Abstandsstufen (Bea 02.11.2026), wie in wd.css */
  --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:24px;--sp-6:32px;
  --radius-lg:     12px;
  --radius-xl:     20px;
  --navbar-bg:     rgba(15,12,10,0.85);

  /* Warmer Schein oben links — Beas Farbwahl vom 18.08.2026 ("nummer 3, warm
     + schimmer"). Als Variable und NICHT als eigene Regel, damit der Hellmodus
     ihn ueber denselben Namen abschaltet: zwei Regeln an zwei Orten waren
     schon zweimal der Grund, warum eine Aenderung nur halb ankam. */
  --schimmer:
    radial-gradient(900px 420px at 12% -8%, rgba(217,119,6,0.20), transparent 62%),
    radial-gradient(700px 380px at 88%  4%, rgba(180, 83,9,0.12), transparent 66%);

  /* Lesespalte (10.08.2026) — Breite fuer alles, was ZEILENWEISE gelesen wird:
     Chat, Termin-, Dokument-, Maengel- und Aufgabenliste, Bautagebuch,
     Projekteinstellungen, Wetter, Behinderungen, Firma.
     Gemessen bei 1440, warum es noetig ist: in der Dokumentzeile stand der
     Dateiname links und der "…"-Knopf 1200 px weiter rechts, in der
     Maengelkarte lief die Beschreibung ueber 120 Zeichen pro Zeile (lesbar
     sind 45-75). Breite hilft Gittern, sie schadet Zeilen.
     Der Wert ist gemessen, nicht gewaehlt: Erst standen hier 940 — die
     Inhaltsbreite von vor Stufe 3, hergeleitet statt geprueft. Im Bild brach
     daraufhin die Dokument-Filterleiste wieder auf ZWEI Zeilen um, also genau
     der Gewinn, den Stufe 3 gebracht hatte. Nachgemessen braucht sie 982 px
     (9 Chips + 8 px Abstand); 1000 laesst etwas Luft. Dieselbe Lehre wie bei
     1240 -> 1280: nach einer Breitenaenderung zaehlen, was UMBRICHT. */
  --lesespalte:    1000px;

  --danger:        #ef4444;
  --warning:       #f59e0b;
  --info:          #3b82f6;
  /* Prototyp-Zustandsfarben: --alarm fuer grosse Kennzahlen (ab 24px bold,
     WCAG-Large-Text) und die Verzugskante, --gut fuer "0 offene Maengel",
     --fertig fuer Erledigtes — zurueckgenommen, nicht bunt. */
  --alarm:         #e05252;
  --gut:           #4a9d6e;
  --fertig:        #4a4a4a;
  /* Bewegung (Bea 02.11.2026): drei Zeiten, eine Kurve — docs/styleguide.md „Bewegung".
     --tempo bleibt als Name fuer die bestehenden Stellen und zeigt auf --t2. */
  --t1:            120ms;
  --t2:            160ms;
  --t3:            200ms;
  --tempo:         var(--t2);
  --kurve:         cubic-bezier(.23, 1, .32, 1);
  /* Rot als *Schriftfarbe*. --danger ist als Flaechen-/Rahmenfarbe gedacht und
     erreicht als Text je nach Untergrund keine 4.5:1. Getrennt gefuehrt, damit
     der helle Modus einen dunkleren Ton bekommen kann. */
  /* Seit den helleren Flaechen (10.08.) braucht Text-Rot im Dunkeln die hellere
     Stufe: #ef4444 fiel auf --overlay (#2a2a2a) auf 3.81:1. */
  --danger-text:   #f87171;
  /* Orange als *Schriftfarbe*: --primary steht auf hellem Grund bei 3.1:1.
     Gleiche Trennung wie bei --danger-text.
     Dunkel seit 02.11.2026 #e08a1e wie --or-tx in wd.css (vorher #d97706): auf der Orange-Toenung ueber
     --surface (Zahlungshinweis, Hinweiskasten, Abnahme-Stand) nur 4,46:1, jetzt 5,29:1 (Kontrast-Uebergabe Bea). */
  --primary-text:  #e08a1e;
  /* Blau als *Schriftfarbe* — dritter Fall derselben Trennung. --info (#3b82f6)
     ist eine Flaechenfarbe und erreicht als Text auf dem hellen Hinweisgrund nur
     3.68:1. Gemessen 25.08.2026 gegen den echten Kastengrund (#232529 dunkel /
     #f4f8fe hell), mit Reserve gewaehlt: ein Kantenwert kippt beim naechsten
     Messlauf zurueck (Lehre vom 16.08.). */
  --info-text:     #629bf8;

  /* Dokumentarten (Block F, Beas Klickdummy 18.09.2026 — ihre Dunkelwerte).
     Ein Paar je Art: Zeichenfarbe + Kachelgrund. Die Semantik traegt die
     Kachel links in der Zeile, nicht der Text — der bleibt neutral.
     `foto`, `bedienungsanleitung` und `sonstige` nennt der Dummy nicht; sie
     bekommen bewusst das neutrale Grau des Berichts, keine erfundene Farbe.
     Vollstaendigkeit misst test_jede_art_hat_symbol_und_farbe. */
  --kind-angebot:              #a892f5;  --kind-angebot-bg:              #241f3a;
  --kind-auftragsbestaetigung: #4ec98a;  --kind-auftragsbestaetigung-bg: #16301f;
  --kind-rechnung:             #e0a94a;  --kind-rechnung-bg:             #332510;
  --kind-aufmass:              #5cc0d8;  --kind-aufmass-bg:              #122b33;
  --kind-bericht:              #9aa3b0;  --kind-bericht-bg:              #1f242d;
  --kind-plan:                 #7fa8d8;  --kind-plan-bg:                 #16212e;
  --kind-gewaehrleistung:      #d78ab8;  --kind-gewaehrleistung-bg:      #2b1624;
  --kind-foto:                 #9aa3b0;  --kind-foto-bg:                 #1f242d;
  --kind-bedienungsanleitung:  #9aa3b0;  --kind-bedienungsanleitung-bg:  #1f242d;
  --kind-sonstige:             #9aa3b0;  --kind-sonstige-bg:             #1f242d;
  /* Papier der Dokumente (Editor-Blatt, fester Text beim Ausfuellen): in beiden
     Modi weiss mit schwarzer Schrift, wie im PDF (Nico/Bea 02.11.2026). */
  --papier: #ffffff; --papier-tx: #000000;
}

/* ─── Light Mode ─────────────────────────────────────────────────────────── */
[data-theme="light"] {
  --bad: #b42318;
  --orange-bg: rgba(217,119,6,.14); --ok-bg: rgba(42,114,73,.12); --bad-bg: rgba(180,35,24,.10); --info-bg: rgba(10,91,222,.10);
  --schatten: rgba(0,0,0,.14); --scrim: rgba(0,0,0,.45);
  --bg:            #eceff3;
  --surface:       #ffffff;
  --surface2:      #f6f7f9;
  --surface3:      #e9ebef;
  --overlay:       #ffffff;
  --hover:         rgba(0,0,0,0.05);
  --border:        rgba(0,0,0,0.08);
  --border-strong: rgba(0,0,0,0.14);
  --text:          #111111;
  --text-muted:    #5a5a6a;
  /* War #aaaaaa — auf weissem Grund nur 2.3:1 und damit unter WCAG AA. Betraf
     jedes Datum in Feed und Projektkarten. "faint" heisst zurueckhaltend, nicht
     unlesbar. #6b6b78 genuegte auf Weiss, aber nicht auf dem waermeren
     Feed-Grund (4.33) — daher #676774: 4.6:1 dort, 5.4:1 auf Weiss. */
  --text-faint:    #676774;
  --danger-text:   #b91c1c;
  /* War #0a5bde: auf der Info-Toenung direkt auf --bg (Flash-Meldung) nur 4,42:1 (02.11.2026, Kontrast-
     Uebergabe Bea). #0954cc: 5,0:1 dort, 5,75:1 auf der Toenung ueber Weiss, Farbton gleich. */
  --info-text:     #0954cc;
  /* Zustandsfarben hell: dunklere Toene, weil sie auf Weiss stehen.
     Werte nach dem Einbau gegen den echten Grund messen (kontrast_messung.py). */
  --alarm:         #c03434;
  --gut:           #2a7249;
  --fertig:        #b5b5b5;
  /* War #b45309: auf dem hellen Seitengrund #f0f2f5 nur 4.48:1 — um 0.02 unter
     WCAG AA. Betraf jeden Link auf Impressum, Datenschutz und Barrierefreiheit,
     also ausgerechnet die Seiten, die Barrierefreiheit zusichern. Auf reinem
     Weiss reichte derselbe Wert; gemessen wurde gegen den echten Grund.
     #9c4708 gibt 5.64:1 auf #f0f2f5 und 6.0:1 auf Weiss. */
  --primary-text:  #9c4708;
  --navbar-bg:     rgba(255,255,255,0.92);
  --schimmer:      none;
  --shadow-sm:     0 1px 3px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.08);
  --shadow:        0 4px 16px rgba(0,0,0,0.10), 0 2px 6px rgba(0,0,0,0.07);
  --shadow-lg:     0 20px 48px rgba(0,0,0,0.14), 0 8px 20px rgba(0,0,0,0.09);
  /* Dokumentarten hell — Beas Hellwerte, dunklere Toene auf hellem Grund.
     Gruen, Amber, Tuerkis, Blau am 02.11.2026 abgedunkelt (Kontrast-Uebergabe Bea): auf ihrer Toenung
     (14 % der Farbe ueber --kasten) hielten sie nur 4,2 / 4,2 / 4,4 / 4,0:1, Blau auch auf --kind-plan-bg
     nur 4,43:1. Jetzt mind. 4,8:1 auf beiden Gruenden, Farbton gleich (tools/farbkontrast_rechnen.py). */
  --kind-angebot:              #6b46d6;  --kind-angebot-bg:              #eee9fb;
  --kind-auftragsbestaetigung: #0e6e3d;  --kind-auftragsbestaetigung-bg: #e4f4ea;
  --kind-rechnung:             #8b5200;  --kind-rechnung-bg:             #fbeedb;
  --kind-aufmass:              #0a6881;  --kind-aufmass-bg:              #dff1f6;
  --kind-bericht:              #4b5563;  --kind-bericht-bg:              #eceef1;
  --kind-plan:                 #386295;  --kind-plan-bg:                 #e6eef7;
  --kind-gewaehrleistung:      #8a3f6f;  --kind-gewaehrleistung-bg:      #f7e6f1;
  --kind-foto:                 #4b5563;  --kind-foto-bg:                 #eceef1;
  --kind-bedienungsanleitung:  #4b5563;  --kind-bedienungsanleitung-bg:  #eceef1;
  --kind-sonstige:             #4b5563;  --kind-sonstige-bg:             #eceef1;
}
[data-theme="light"] .card, [data-theme="light"] .karte { background: var(--surface); }
/* `background-color`, NICHT die Kurzform `background`: die haette das Pfeil-SVG
   der Auswahlfelder mitgeloescht — genau das passierte hier. Im Hellmodus sah die
   Status-Auswahl deshalb aus wie ein Textfeld, man erkannte nicht, dass man
   klicken kann (UX-Durchgang 31.07., Befund 17). Die Regel darunter stellte nur
   die Farbe wieder her, das Bild blieb weg. */
[data-theme="light"] .form-input { background-color: var(--surface); border-color: rgba(0,0,0,0.15); color: var(--text); }
[data-theme="light"] .form-input::placeholder { color: var(--text-faint); }
/* Der Hellmodus faerbt die Felder #fff statt --surface2 — der Autofill-Riegel
   unten muss denselben Ton nehmen, sonst sitzt im Hellmodus ploetzlich ein
   dunkles Feld zwischen hellen. */
[data-theme="light"] .form-input:-webkit-autofill,
[data-theme="light"] .form-input:-webkit-autofill:hover,
[data-theme="light"] .form-input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
  box-shadow: 0 0 0 1000px var(--surface) inset;
}
[data-theme="light"] .form-input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset, 0 0 0 3px var(--orange-bg);
  box-shadow: 0 0 0 1000px var(--surface) inset, 0 0 0 3px var(--orange-bg);
}
[data-theme="light"] .form-select,
[data-theme="light"] select.form-input { background-color: var(--surface); }
[data-theme="light"] .nav-link { color: rgba(0,0,0,0.55); }
[data-theme="light"] .nav-link:hover { background: var(--hover); color: rgba(0,0,0,0.9); }
[data-theme="light"] .navbar-brand { color: var(--text) !important; }
[data-theme="light"] .brand-sub { background: var(--hover); color: var(--text-faint); }
/* Weiss auf #f0f2f5 mit einem 8-%-Rahmen ist im Hellmodus kaum als eigene Flaeche
   zu erkennen — die Reiterleiste verschwamm mit dem Seitengrund (Befund 17).
   Kraeftigerer Rahmen statt anderer Fuellung: die weisse Flaeche ist richtig, sie
   war nur nicht abgegrenzt. */
[data-theme="light"] .tabs { background: var(--surface); }

/* Eigene Nachricht ohne Rahmen (Stufe 1): die Zugehoerigkeit traegt eine WARME,
   voll deckende Flaeche. Kein rgba-Orange auf Weiss — 8 % Deckkraft ergaben
   frueher ein vergilbtes Beige; #fff7ed ist derselbe Farbklang als gestalteter
   Vollton und bleibt neben weissen Fremd-Nachrichten klar unterscheidbar. */
[data-theme="light"] .feed-item-own {
  background: var(--orange-bg);
}
/* Stufe 2: die Textarea im Composer bleibt auch hell durchsichtig und randlos —
   sonst holt `[data-theme="light"] .form-input` (hoehere Spezifitaet als
   `.feed-input`) den weissen Kasten samt Kante zurueck, den Stufe 2 aufloest. */
[data-theme="light"] .feed-input {
  background-color: transparent;
  border-color: transparent;
}
[data-theme="light"] .feed-input::placeholder { color: var(--text-faint); }
[data-theme="light"] .tab { color: var(--text-muted); }
[data-theme="light"] .tab:hover { background: var(--surface3); }
[data-theme="light"] .login-form-side { background: var(--bg); }

/* ─── Lesbarkeit im hellen Modus (28.07.2026) ────────────────────────────────
   Befund einer Messung ueber alle Seiten in beiden Modi: der HELLE Modus hatte
   21 Kontrastverstoesse, der dunkle 7. Ursache ist durchgaengig dieselbe — das
   Farbsystem wurde fuer dunkel entworfen, die hellen Akzentfarben (#f59e0b,
   #f87171, #60a5fa …) stehen im hellen Modus auf ebenso hellem Grund.
   Auffaelligster Fall: `.brand-name` ist weiss und stand auf weissem Header —
   das Wort „Bau-" war auf jeder Seite unsichtbar, auch auf den Screenshots,
   die uns geschickt wurden. Gemessen mit ~/.claude/tools/kontrast_messung.py. */
[data-theme="light"] .brand-name { color: var(--text); }
[data-theme="light"] .brand-name span { color: var(--primary-dark); }
[data-theme="light"] .brand-sub { color: var(--text-muted); }
[data-theme="light"] .badge-success  { color: var(--primary-text); }
[data-theme="light"] .badge-warning  { color: var(--primary-text); }
[data-theme="light"] .badge-danger   { color: var(--danger-text); }
[data-theme="light"] .badge-info     { color: var(--info-text); }
[data-theme="light"] .badge-secondary{ background: var(--hover); color: var(--text-muted); }
[data-theme="light"] .btn-danger     { color: var(--danger-text); }
[data-theme="light"] .tab.active     { color: var(--primary-text); }
[data-theme="light"] .tab.active .tab-badge { color: var(--primary-text); }
[data-theme="light"] .raum-reiter[data-active] { color: var(--primary-text); }
/* Der :hover in der @media-Regel (Z. ~1328) setzt wieder --primary-light und
   hebelte den Light-Fix darueber aus: gemessen 1,63:1 auf dem Glow-Grund
   (hover_kontrast_pruefen.py, 30.08.2026 — die Zeigerposition deckte es vorher
   nie auf, weil das Gate die Maus parkt). #92400e traegt dort 5,26:1. */
[data-theme="light"] .raum-reiter[data-active]:hover { color: var(--primary-text); }
/* Die zurueckgenommenen Karten-Marken (Vorbereitet/Abgeschlossen) fallen beim
   Karten-Hover auf 4,29:1 — der Grund wird surface3, die Schrift bleibt
   --text-faint. Nur der Hover-Fall braucht die dunklere Stufe (4,83:1);
   der Ruhezustand liegt ueber der Grenze und behaelt die Zuruecknahme. */
[data-theme="light"] .projekt-karte:hover .marke--vorbereitet,
[data-theme="light"] .projekt-karte:hover .marke--abgeschlossen { color: var(--text-muted); }
[data-theme="light"] .feed-datum,
/* Das inaktive Zaehlerchen bekommt im dunklen Modus ein festes #b4b4b4 — hell
   genug dort, auf weissem Grund aber nur 2.07:1. Feste Farben im Basisteil
   wirken immer in BEIDEN Modi; hier braucht es die helle Entsprechung. */
/* Im Hellmodus fehlte die Fläche: 7 % WEISS auf weissem Grund ist nichts, die
   Zahl stand nackt neben dem Wort und las sich als Teil davon („Dokumente 4",
   UX-Durchsicht 12.08.). Schwarz mit 6 % ist das helle Gegenstueck. */
[data-theme="light"] .tab:not(.active) .tab-badge {
  color: var(--text-muted); background: var(--hover);
}

/* ─── Filterleisten-Chips (.pill) ────────────────────────────────────────────
   `.pill` war in KEINER Stylesheet-Datei definiert, nur im Markup verwendet.
   Ohne Regel greift die Standard-Linkfarbe des Browsers (#0000EE) — auf dunklem
   Grund 2.04:1. Betraf die Filterzeile auf „Meine Mängel" und vier weitere
   Seiten und war auf dem Screenshot der Nutzerin deutlich zu sehen. */
.pill {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 12px; font-size: 14px; font-weight: 600; line-height: 1.6;
  color: var(--text-muted); background: var(--surface3);
  /* Als <button> ohne eigene Angabe zeichnet der Browser 2px outset schwarz.
     Genau die Rahmen, die Stufe 1 ueberall entfernt hat — dieser stand aber in
     keiner Datei und war fuer eine Textsuche nach `border:` unsichtbar. Gemessen
     am 10.08.2026 an 29 Schaltflaechen (19x .pill, 5x .pill.active, 5x
     .kreis-chip); gefunden im Bild, nicht im Code. Dieselbe Klasse Fehler wie
     die fehlende Farbe oben — `.pill` wird als <a> UND als <button> benutzt. */
  border: none;
  /* 8px wie .chip in der Projektliste (12.08.2026): Filterleisten sind
     dieselbe Sache und sahen als Kapseln aus wie eine zweite Bauart. */
  border-radius: 8px;
  min-height: 44px;   /* Apple HIG — Filter werden auf der Baustelle getippt */
  /* Und mindestens so breit (18.10.2026, Geraetetest je Sprache): englisch
     „All" mass 41x44, das deutsche „Alle" war nur zufaellig breit genug. */
  min-width: 44px; justify-content: center;
  text-decoration: none;
  transition: background-color var(--tempo) var(--kurve), color var(--tempo) var(--kurve);
}
.pill:hover { color: var(--text); }
.pill.active {
  color: var(--primary-light); background: var(--primary-glow);
}
[data-theme="light"] .pill.active { color: var(--primary-text); }

/* ─── Projektübergreifende Sichten (/maengel, /bautagebuecher) ───────────────
   Lagen zuvor als <style>-Block in alle_maengel.html. Beim Bau der zweiten
   Sicht haetten sie kopiert werden muessen — zwei Kopien driften auseinander,
   und genau so entstand der Kontrastfehler, den Bea gefunden hat (die eine
   Kopie kannte --card-bg, die Variable gab es nie). Eine Stelle fuer beide. */
.ueb-filterbar { display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-bottom:1rem; }
.ueb-filterbar label { font-size: 14px; color:var(--text-muted); }
.ueb-filterbar select { max-width:320px; }
/* `margin-right:auto` haelt den Untertitel am Titel: der Kopf ist ein
   space-between-Flex, und sobald eine Primaeraktion dazukommt (01.08., Befund 14)
   landete „projektuebergreifend" sonst allein in der Mitte zwischen beiden. Ein
   Untertitel gehoert zur Ueberschrift, nicht an den gegenueberliegenden Rand. */
.page-subtitle { font-size: 14px; color:var(--text-muted); align-self:center; margin-left:.6rem; margin-right:auto; }
.ueb-liste { display:flex; flex-direction:column; gap:12px; }
.ueb-row { background:var(--surface); border-radius:12px; padding:12px 16px; }
.ueb-row-main { display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
.ueb-row-titel { font-weight:600; color:var(--text); text-decoration:none; }
.ueb-row-titel:hover { text-decoration:underline; }
.ueb-row-meta { margin-top:8px; font-size: 14px; color:var(--text-muted); display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.ueb-projekt-chip { color:var(--text-muted); text-decoration:none; background:var(--surface3); padding:2px 8px; border-radius:999px; }
.ueb-projekt-chip:hover { text-decoration:underline; color:var(--text); }
.ueb-row-text { margin-top:8px; font-size: 16px; color:var(--text); line-height:1.45; }
.filter-pills { display:flex; gap:8px; flex-wrap:wrap; }

/* ─── HERO-Belege im Dokumente-Reiter, 18.09.2026 ────────────────────────────
   Nach Beas Klickdummy vom 18.09. Alle Klassen sind neu und mit `hero-` bzw.
   `tag-hero`/`tag-storniert`/`dokument-item--vorgaenger` benannt — keine
   bestehende Zeile aendert sich dadurch. */
.hero-sync {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  background:var(--surface); border:1px solid var(--border);
  border-radius:12px; padding:12px 16px; margin-bottom:1.1rem;
}
.hero-sync-ico {
  display:inline-flex; align-items:center; justify-content:center;
  width:36px; height:36px; border-radius:12px;
  background:var(--surface3); color:var(--text-muted); flex:none;
}
.hero-sync-text { display:flex; flex-direction:column; gap:2px; margin-right:auto; }
.hero-sync-text .text-muted { font-size:14px; }
.hero-sync form { margin:0; }
.hero-sync .btn { min-height:40px; }
/* Der Herkunftsstempel. Bewusst zurueckhaltend: er soll die Zeile einordnen,
   nicht mit dem Dokumentnamen um Aufmerksamkeit ringen. */
.tag-hero { background:var(--surface3); color:var(--text-muted); letter-spacing:.02em; }
/* Storniert ist kein Schmuck, sondern eine Warnung: wer eine stornierte
   Rechnung fuer die geltende haelt, zahlt den falschen Betrag. Deshalb die
   einzige farbige Kennzeichnung in dieser Liste. */
.tag-storniert { background:var(--bad-bg); color:var(--danger-text); }
.tag-intern { background:var(--orange-bg); color:var(--warning); }
@media (max-width: 560px) {
  .hero-sync-text { margin-right:0; }
  .hero-sync .btn { width:100%; }
}

/* Der Umschalter „Ansicht als Bauherr" (F5, 19.09.2026) ist am 25.09. samt
   Stilen entfallen — Bea 22.09.: „ich brauche dort keine ansicht als bauherr". */

/* ─── Import aus Fremdsoftware (HERO/pds), 18.09.2026 ────────────────────────
   Die Seite sucht, statt den ganzen Bestand zu zeigen. Das Suchfeld ist
   deshalb kein Beiwerk, sondern der Einstieg — es steht ganz oben und nimmt
   die volle Breite ein.
   Alle Klassen hier sind NEU und mit `ansch-` praefixiert: die Regeln greifen
   ausschliesslich auf der Importseite, keine bestehende Seite aendert sich. */
.ansch-suche { display:flex; gap:8px; margin-bottom:1rem; }
.ansch-suche input[type="search"] {
  flex:1; min-width:0; padding:12px 16px; font-size:16px;
  border:1px solid var(--border); border-radius:12px;
  background:var(--surface); color:var(--text);
}
.ansch-suche input[type="search"]::placeholder { color:var(--text-muted); }
/* 44 px Mindesthoehe: der Knopf wird auf der Baustelle mit dem Daumen getroffen
   (Apple HIG, R24). */
.ansch-suche .btn { min-height:44px; white-space:nowrap; }
.ansch-hinweis { margin-bottom:1rem; }
/* Die Belegnummer des Anbieters ist das, wonach der Betrieb sucht — sie steht
   vor dem Namen und ist als Nummer erkennbar (Tabellenziffern, damit
   „TES-393" und „TES-39" untereinander gleich breit beginnen). */
.ansch-nr {
  font-variant-numeric:tabular-nums; font-size:14px; font-weight:600;
  color:var(--text-muted); background:var(--surface3);
  padding:2px 8px; border-radius:999px;
}
.ansch-wert { margin-left:auto; font-variant-numeric:tabular-nums; font-weight:600; }
.ansch-blaettern {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-top:1rem;
}
.ansch-blaettern .form-hint { margin:0; }
@media (max-width: 560px) {
  /* Nebeneinander waere das Feld auf dem Telefon zu schmal zum Lesen des
     Getippten; der Knopf rutscht darunter statt zu schrumpfen. */
  .ansch-suche { flex-direction:column; }
  .ansch-wert { margin-left:0; }
}

/* ─── Bauzeitenplan ──────────────────────────────────────────────────────────
   Die Balkenlage kommt fertig in Prozent aus utils/bauzeit.py — hier wird nur
   dargestellt. Bewusst kein Raster-Framework und keine Gantt-Bibliothek: die
   CSP laesst keine fremden Skripte zu, und gerechnet wird ohnehin serverseitig,
   damit Tests die Position eines Vorgangs pruefen koennen. */
.bzp { display:flex; flex-direction:column; gap:2px; margin-bottom:1.5rem; }
.bzp-kopf, .bzp-zeile { display:flex; align-items:center; gap:12px; }
.bzp-kopf { padding-bottom:8px; border-bottom:1px solid var(--border); margin-bottom:8px; }
.bzp-spalte-titel { flex:0 0 220px; min-width:0; }
.bzp-vorgang-titel { font-weight:600; color:var(--text); font-size: 16px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bzp-vorgang-meta { display:flex; gap:8px; align-items:center; flex-wrap:wrap;
  font-size: 12px; color:var(--text-muted); margin-top:2px; }
/* Kurze Hervorhebung des Sprungziels (Bea 17.08.2026): wer aus „Meine Mängel"
   auf einen Mangel klickt, landet sonst in einer Liste aus 30 gleich
   aussehenden Karten. Reiner Rahmen, keine Bewegung — bei `prefers-reduced-
   motion` bleibt er dadurch ohnehin richtig. */
.ziel-hervorgehoben {
  box-shadow: 0 0 0 2px var(--primary);
  border-radius: var(--radius);
  transition: box-shadow var(--t3) var(--kurve);
}

/* Zeitraum direkt unter dem Titel (Bea 17.08.2026). Etwas kraeftiger als die
   uebrige Meta-Zeile: er beantwortet die haeufigste Frage am Plan („wann?") und
   war vorher nur im Tooltip — auf dem Telefon also gar nicht. */
.bzp-vorgang-zeitraum { font-size: 12px; color:var(--text); opacity:.85;
  margin-top:2px; font-variant-numeric: tabular-nums; }
.bzp-achse { position:relative; flex:1; height:20px; }
.bzp-marke { position:absolute; top:0; transform:translateX(-50%); font-size: 12px;
  color:var(--text-muted); white-space:nowrap; }
/* Die Heute-Marke faellt oft mit einer Monatsmarke zusammen. Ohne eigenen Grund
   und z-index lesen sich beide ineinander ("heAlutg 26"). */
.bzp-heute-kopf { position:absolute; top:0; transform:translateX(-50%); font-size: 12px;
  font-weight:600; color:var(--primary-text); white-space:nowrap; z-index:2;
  background:var(--bg); padding:0 4px; border-radius:4px; }
/* Randmarken nicht zentrieren, sonst haengt die halbe Beschriftung ausserhalb
   des Bildschirms (auf dem iPhone gemessen: 392 px bei 390 px Fenster). */
.bzp-marke--links { transform:none; }
.bzp-marke--rechts { transform:translateX(-100%); }
.bzp-spur { position:relative; flex:1; height:34px; background:var(--surface2);
  border-radius:6px; overflow:hidden; }
/* Der Balken ist die geplante Dauer (gedaempft), die Fuellung der Fortschritt
   (kraeftig). Andersherum — kraeftiger Balken mit dunkler Fuellung — wirkt ein
   fertiger Vorgang dunkler als ein unbegonnener, also genau verkehrt. */
.bzp-balken { position:absolute; top:6px; height:22px; border-radius:6px;
  /* Der 1px-Rand bleibt bewusst: er ist Datentinte (geplante Dauer), kein Dekor. */
  background:var(--primary-glow); border:1px solid var(--primary);
  min-width:6px; }
.bzp-balken--spaet { border-color:var(--danger); background:var(--bad-bg); }
.bzp-fortschritt { position:absolute; inset:0 auto 0 0; border-radius:4px;
  background:var(--primary); }
.bzp-balken--spaet .bzp-fortschritt { background:var(--danger); }
.bzp-meilenstein { position:absolute; top:9px; width:16px; height:16px; margin-left:-8px;
  background:var(--primary-light); transform:rotate(45deg); border-radius:3px; }
/* Wochenenden liegen GANZ HINTEN (z-index 0) — sie sind Orientierung, kein
   Inhalt. Der Balken darueber bleibt voll lesbar; nur die freie Spur zeigt,
   wo Samstag und Sonntag liegen. Bewusst sehr zurueckhaltend: waere der
   Streifen kraeftig, konkurrierte er mit den Balken um die Aufmerksamkeit. */
.bzp-wochenende { position:absolute; top:0; bottom:0; z-index:0;
  background:var(--hover); pointer-events:none;
  /* Ein am Planende angeschnittener Samstag hat rechnerisch Breite 0 — die
     Mindestbreite haelt ihn sichtbar, ohne die Geometrie zu verfaelschen. */
  min-width:3px; }
/* Feiertage (Bea 05.08.): gleiche Zurueckhaltung wie Wochenenden, aber warm
   getoent und minimal kraeftiger — ein einzelner Tag muss neben einem
   2-Tage-Wochenende erkennbar bleiben. Name steht im title-Attribut. */
.bzp-feiertag { position:absolute; top:0; bottom:0; z-index:0;
  background:var(--orange-bg); pointer-events:auto;
  min-width:3px; }
.bzp-balken, .bzp-meilenstein, .bzp-heute-linie { z-index:1; }
.bzp-heute-linie { position:absolute; top:0; bottom:0; width:2px;
  background:var(--primary-text); opacity:.55; }
.bzp-aktionen { flex:0 0 auto; display:flex; gap:4px; align-items:center; }
.bzp-aktionen form { margin:0; }
/* Icon-only-Knoepfe: 44x44 Apple-HIG-Tippziel. Vorbestehender Befund (43x44,
   Slack-Ruecklauf 11.08.), nach dem Icon-Tausch 39-41 px — jetzt zentral fix. */
.bzp-aktionen .btn { min-width: 44px; min-height: 44px; }
.bzp-bearbeiten { padding:8px 0 12px 232px; }
/* UX 31.07. #4: Felder tragen sichtbare Labels — Ausrichtung an der Unterkante,
   damit Knopf und Inputs trotz Label-Zeile auf einer Linie stehen. */
.bzp-formzeile { display:flex; gap:8px 12px; flex-wrap:wrap; align-items:flex-end; }
.bzp-feld { display:flex; flex-direction:column; gap:4px; flex:1 1 140px; min-width:120px; }
.bzp-feld--breit { flex:2 1 180px; }
.bzp-feld--prozent { flex:0 0 100px; min-width:90px; }
.bzp-feld--knopf { flex:0 0 auto; min-width:0; }
/* B8: das „Sonstiges"-Beschriftungsfeld — zu, bis das Dropdown es aufklappt.
   Umschalten NUR per classList (R4: nie zwei display-Angaben inline). */
.bzp-freitext-feld { display:none; }
.bzp-freitext-feld.offen { display:flex; }
.bzp-label { font-size: 12px; font-weight:600; color:var(--text-muted);
  text-transform:uppercase; letter-spacing:.4px; }
.bzp-label-hinweis { font-weight:400; text-transform:none; letter-spacing:0; }
.bzp-formzeile .form-input { width:100%; }
.bzp-prozent { flex:0 0 auto; }
@media (max-width: 640px) {
  .bzp-feld, .bzp-feld--breit { flex:1 1 100%; }
  .bzp-feld--prozent { flex:1 1 45%; }
  .bzp-feld--knopf { flex:1 1 100%; }
  .bzp-feld--knopf .btn { width:100%; }
}
.bzp-neu { margin-top:1.5rem; }
.bzp-hinweis { margin-top:8px; font-size: 14px; color:var(--text-muted); }
.bzp-legende { font-size: 14px; color:var(--text-muted); }
/* Wartende Verschiebung (Etappe 6b). Gestrichelt wie der Terminvorschlag —
   dieselbe Aussage („noch nicht beschlossen") soll im ganzen Programm gleich
   aussehen, sonst muss man sie an jeder Stelle neu lernen. Auf dem Telefon
   stapeln sich Text und Knoepfe (column), ab 640px stehen sie nebeneinander. */
.bzp-vorschlag {
  display: flex; flex-direction: column; gap: 12px;
  margin: 0 0 12px; padding: 12px 12px;
  border: 1px dashed var(--warning); border-radius: var(--radius);
  background: color-mix(in srgb, var(--warning) 7%, var(--surface));
  font-size: 14px;
}
.bzp-vorschlag-text { color: var(--text); line-height: 1.5; }
.bzp-vorschlag-alt { color: var(--text-muted); }
.bzp-vorschlag-grund { color: var(--text-muted); font-style: italic; }
.bzp-vorschlag-aktionen { display: flex; gap: 8px; flex-wrap: wrap; }
.bzp-vorschlag-wartet { color: var(--text-muted); }
@media (min-width: 640px) {
  .bzp-vorschlag { flex-direction: row; align-items: center; justify-content: space-between; }
  .bzp-vorschlag-aktionen { flex-shrink: 0; }
}
/* Der Hinweis auf Vorgaenge ausserhalb des Fensters stand als knallblauer
   Standard-Link im Bild — im Dunkelmodus der einzige blaue Fleck der Seite. */
.bzp-legende a { color:var(--primary-text); text-decoration:underline; }
/* Zoom-Umschalter (Bea 22.07.). Die Knoepfe sind Tippziele und muessen deshalb
   44x44 px erreichen (Apple HIG, R24) — genau daran waren am 29.07. 41 Stellen
   in dieser App gescheitert. min-height plus Polsterung statt fester Hoehe,
   damit der Text bei groesserer Systemschrift nicht abgeschnitten wird. */
.bzp-zoom { display:flex; flex-wrap:wrap; gap:12px 16px; align-items:center;
  justify-content:space-between; margin-bottom:16px; }
.bzp-zoom-stufen, .bzp-zoom-blaettern { display:flex; gap:8px; align-items:center;
  flex-wrap:wrap; }
.bzp-zoom-knopf { display:inline-flex; align-items:center; justify-content:center;
  min-height:44px; min-width:44px; padding:0 16px;
  border-radius:8px; background:var(--surface3); color:var(--text);
  font-size: 14px; font-weight:600; text-decoration:none; white-space:nowrap; }
.bzp-zoom-knopf:hover { color:var(--primary-text); }
/* #fff auf Orange war 3,19:1 — Beas Token (R: --on-primary) statt Weiss. */
.bzp-zoom-knopf.is-aktiv { background:var(--primary); color:var(--on-primary); }
.bzp-zoom-zeitraum { font-size: 14px; color:var(--text-muted); white-space:nowrap;
  padding:0 4px; }
@media (max-width: 760px) {
  .bzp-kopf, .bzp-zeile { flex-wrap:wrap; }
  .bzp-spalte-titel { flex:1 1 100%; }
  .bzp-achse, .bzp-spur { flex:1 1 100%; }
  .bzp-bearbeiten { padding-left:0; }
  /* Umgebrochen stand die Knopfreihe naeher am NAECHSTEN Vorgang als am
     eigenen — bei einem Loeschen-Knopf gefaehrlich (UX-Durchsicht 12.08.).
     Die Zeile bekommt ihre eigene Flaeche mit Abstand nach unten, die Knoepfe
     ruecken eng an den Balken darueber. */
  .bzp-zeile {
    background: var(--surface); border-radius: var(--radius);
    padding: 12px; margin-bottom: 16px; row-gap: 4px;
  }
  .bzp-aktionen { margin-top: 2px; }
}
/* Auf dem Telefon wird aus dem Wort „heute" ein Dreieck. Das Wort ist 45 px
   breit und stand quer über der Nachbarmarke (iPhone, Wochen-Zoom); die
   durchgehende Linie in den Spuren trägt die Information ohnehin. */
@media (max-width: 560px) {
  .bzp-marke { font-size: 12px; }
  .bzp-heute-wort { position:absolute; width:1px; height:1px; overflow:hidden;
    clip-path:inset(50%); white-space:nowrap; }
  .bzp-heute-kopf { padding:0; background:none; }
  .bzp-heute-kopf::after { content:'▼'; font-size: 12px; line-height:1;
    color:var(--primary-text); }
}

/* ─── Background Blobs ───────────────────────────────────────────────────── */
/* Blobs + Filmkorn entfernt (Design-Umstellung nach Prototyp, 12.08.2026):
   die drei animierten Blur-Farbkreise gaben der Seite an jeder Ecke eine andere
   Hintergrundfarbe (#1f1811 warm / #1a161e violett / #111111) — gemessen mit
   referenz_messer.py. Die Flaeche ist jetzt ueberall exakt var(--bg). */

/* ─── Base ──────────────────────────────────────────────────────────────── */
body {
  font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-weight: 400;
  background: var(--bg);
  color: var(--text);
  /* Flex-Spalte, damit der Footer bei kurzen Seiten am unteren Rand sitzt statt
     direkt unter dem Inhalt in der Leere zu schweben (UX-Durchgang 31.07.,
     Befund 18: Einstellungen und Firma sind schmale Formularkarten in einem
     1280-px-Fenster, darunter standen ~600 px Nichts). Die schmale Spalte selbst
     bleibt — ein Formular ueber die volle Breite waere schlechter lesbar, nicht
     besser. Es ging um den heimatlosen Footer, nicht um die Kartenbreite. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  line-height: 1.55;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Ziffern gleicher Breite: Zahlen fluchten in Listen und Kennzahlen (Prototyp) */
  font-variant-numeric: tabular-nums;
}

/* Der Schein liegt HINTER allem und bleibt beim Scrollen stehen (fixed), damit
   lange Seiten nicht nach unten hin ausbleichen. z-index:-1 malt ihn ueber den
   body-Hintergrund, aber unter jeden Inhalt. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--schimmer);
}
h1, h2, h3, h4, h5, h6 {
  font-family: 'Archivo', 'IBM Plex Sans', sans-serif;
  letter-spacing: -0.3px;
  color: var(--text);
}
p { color: var(--text-muted); }
strong { color: var(--text); font-weight: 600; }
.text-muted { color: var(--text-muted) !important; }
hr { border-color: var(--border); }

/* ─── Ladebalken ────────────────────────────────────────────────────────── */
#ladebalken {
  position: fixed; top: 0; left: 0; width: 0%; height: 2px;
  background: linear-gradient(90deg, var(--primary), var(--primary-light), var(--primary));
  background-size: 200% 100%;
  animation: lade-anim 1.4s ease infinite;
  z-index: 9999; transition: width 0.4s ease;
  box-shadow: 0 0 8px rgba(217,119,6,0.5);
}
@keyframes lade-anim { 0% { background-position: 0%; } 100% { background-position: 200%; } }

/* ─── Navbar ────────────────────────────────────────────────────────────── */
.navbar {
  background: var(--navbar-bg);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--border);
  padding: 12px 24px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky; top: 0; z-index: 200;
}
.navbar-brand {
  display: flex; align-items: center; gap: 12px;
  text-decoration: none;
  font-family: 'Archivo', sans-serif;
  font-size: 20px; font-weight: 800;
  letter-spacing: -0.6px; color: white;
}
.brand-icon { font-size: 20px; }
.brand-name { color: white; }
.brand-name span { color: var(--primary); }
.brand-sub {
  font-size: 12px; font-weight: 500;
  font-family: 'IBM Plex Sans', sans-serif;
  color: rgba(255,255,255,0.65);
  background: var(--hover);
  padding: 2px 8px; border-radius: 20px;
}
.navbar-right { display: flex; align-items: center; gap: 4px; }
.nav-link {
  color: rgba(255,255,255,0.55);
  border-radius: 8px; font-size: 14px; padding: 4px 12px;
  transition: var(--t2) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
  background: transparent;
  text-decoration: none; font-weight: 500;
  display: inline-flex; align-items: center; gap: 4px;
}
.nav-link:hover {
  background: var(--hover);
  color: rgba(255,255,255,0.9);
}
.nav-link-muted { color: rgba(255,255,255,0.35); }

/* ─── Beas Glocke (18.09.2026, 21:19) ────────────────────────────────────────
   Ein Symbol in der Kopfleiste, links von „Projekte", mit orangem Punkt bei
   Neuem. 34x34 am Rechner; am Telefon 44x44 (unten, @media 640) — Apple-HIG-
   Tippziel, R24. Der Punkt sitzt ueber der Ecke des Symbols, ohne Ring: die
   Leiste ist halbtransparent, ein Ring in Flaechenfarbe saehe auf dem
   Hintergrund wie ein Loch aus. */
.nav-glocke { position: relative; width: 34px; height: 34px; padding: 0;
              justify-content: center; font-size: 16px; }
.nav-glocke-punkt {
  position: absolute; top: 6px; right: 7px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--primary-light);
}
[data-theme="light"] .nav-glocke-punkt { background: var(--primary); }

/* Die Liste hinter dem Punkt (templates/glocke/liste.html). Ein Eintrag ist
   EIN Link ueber die ganze Zeile — kein kleiner Knopf daneben. Neue Eintraege
   tragen denselben Punkt wie die Kopfleiste, damit Bea ihn wiedererkennt. */
.glocke-liste { list-style: none; margin: 0; padding: 0; }
.glocke-liste li + li { border-top: 1px solid var(--border); }
.glocke-eintrag {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 12px; margin: 0 -10px; border-radius: 12px;
  color: var(--text); text-decoration: none; min-height: 44px;
  transition: background var(--t2) var(--kurve);
}
.glocke-eintrag:hover { background: var(--hover); color: var(--text); }
[data-theme="light"] .glocke-eintrag:hover { background: var(--hover); }
.glocke-eintrag-punkt { flex: 0 0 8px; width: 8px; height: 8px; margin-top: 8px;
                        border-radius: 50%; background: transparent; }
.glocke-eintrag-neu .glocke-eintrag-punkt { background: var(--primary-light); }
[data-theme="light"] .glocke-eintrag-neu .glocke-eintrag-punkt { background: var(--primary); }
.glocke-eintrag-inhalt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.glocke-eintrag-titel { font-size: 12px; font-weight: 700; letter-spacing: 0.04em;
                        text-transform: uppercase; color: var(--text-muted); }
.glocke-eintrag-neu .glocke-eintrag-titel { color: var(--primary-light); }
/* Orange als Schrift auf hellem Grund: dieselbe Stufe wie .tab.active (5,26:1). */
[data-theme="light"] .glocke-eintrag-neu .glocke-eintrag-titel { color: var(--primary-text); }
.glocke-eintrag-text { font-size: 14px; line-height: 1.45; overflow-wrap: anywhere; }
.glocke-eintrag-neu .glocke-eintrag-text { font-weight: 600; }
.glocke-eintrag-meta { font-size: 12px; color: var(--text-muted); }
.glocke-leer { padding: 8px 0 4px; }
.glocke-fuss { margin-top: 1.25rem; font-size: 12px; }
/* Nur fuer Vorleser — es gab bis hier keine solche Klasse im Stylesheet. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px;
                   padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ─── Main ──────────────────────────────────────────────────────────────── */
/* Oben 32px -> 22px (Bea 07.08.2026: "da wird viel flaeche vergeudet die unten
   fehlt … es muss nicht gequetscht werden aber da geht locker noch mehr").
   Bewusst nicht auf null: der Titel soll nicht an der Kopfleiste kleben. */
/* Breite 980 -> 1240 (Stufe 3, Beas Freigabe „alle 3" vom 07.08.2026): 980 px
   stammen aus der Zeit, als hier nur ein Chat stand. Projektlisten, Maengel- und
   Dokumenttabellen liessen daneben auf jedem Laptop Rand liegen; die Projekt-
   kacheln (auto-fill, min 290) passen ab hier zu viert statt zu dritt.
   Der Wert ist gemessen, nicht gewaehlt: `box-sizing: border-box` zieht die
   seitlichen 20 px Innenabstand von der max-width ab. Bei 1240 blieben 1200 px
   Inhalt — 1200/(290+14) = 3,9, also weiterhin DREI Spalten, nur breitere
   Kacheln. Das ist Flaeche verteilen statt nutzen, das Gegenteil von Beas
   Anliegen ("da wird viel Flaeche vergeudet"). 1280 laesst 1240 px Inhalt und
   damit die vierte Spalte zu; es ist zugleich das obere Ende der freigegebenen
   Spanne 1200-1280. Was BEI dieser Breite nicht mitwachsen darf, ist einzeln
   begrenzt (Chatspalte unten, .page-mittel, Rechtstexte inline). */
.main-content { max-width: 1280px; margin: 0 auto; padding: 24px 24px 80px; width: 100%; flex: 1 0 auto; }

/* ─── Flash ─────────────────────────────────────────────────────────────── */
.flash-container { margin-bottom: 24px; }
.flash {
  padding: 12px 16px; border-radius: var(--radius);
  margin-bottom: 8px; font-size: 14px; font-weight: 500;
}
.flash-success, .flash-bestaetigung { background: var(--orange-bg); color: var(--warning); }
.flash-error  { background: var(--bad-bg);  color: var(--danger-text); }
.flash-info    { background: var(--info-bg); color: var(--info-text); }

/* ─── Zahlungshinweis (Mahnkette, 07.08.2026) ────────────────────────────── */
/* Bleibt sichtbar, solange die Frist läuft — anders als eine Flash-Meldung, die
   beim nächsten Klick weg ist. Schriftfarben aus --primary-text/--danger-text,
   nicht aus --warning/--danger: die sind als Flächenfarben gedacht und
   erreichen als Text auf hellem Grund keine 4.5:1 (siehe Kommentar dort). */
.zahlungshinweis {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 12px 16px; border-radius: var(--radius);
  margin-bottom: 24px; font-size: 14px; line-height: 1.5;
}
.zahlungshinweis a {
  margin-left: auto; font-weight: 600; text-decoration: underline;
  color: inherit; white-space: nowrap;
  /* Tippziel nach Apple HIG (R24) — der Link ist auf dem Telefon der einzige
     Weg zurück ins Bezahlen. */
  min-height: 44px; display: inline-flex; align-items: center;
}
.zahlungshinweis-mahnung {
  background: var(--orange-bg); color: var(--primary-text);
}
.zahlungshinweis-pausiert {
  background: var(--bad-bg); color: var(--danger-text);
}
/* Testphase Tag 31–60 (AGB 3(2), 18.10.2026): derselbe Ton wie die Mahnung —
   ein Zustand mit Frist, kein Fehler. */
.zahlungshinweis-testphase {
  background: var(--orange-bg); color: var(--primary-text);
}
.zahlungshinweis strong { color: inherit; }

/* ─── Hinweiskasten (23.08.2026) ─────────────────────────────────────────── */
/* Ein bleibender Hinweis, der KEINE Flash-Meldung ist: der AGB-Platzhalter und
   die gesperrte Bestellung stehen dauerhaft auf der Seite, nicht bis zum
   naechsten Klick. Generisch, weil es die dritte Stelle mit demselben Bedarf
   ist (Zahlungshinweis, Abnahme-Stand, jetzt Recht/Bestellung) — eine vierte
   Sonderklasse waere dieselbe Regel an vier Orten.
   Farbwahl wie bei den Geschwistern: --primary-text/--danger-text, nicht
   --warning/--danger (Flaechenfarben, als Text unter 4.5:1). */
.hinweis-kasten {
  padding: 12px 16px; border-radius: var(--radius);
  margin-bottom: 1rem; font-size: 14px; line-height: 1.55;
  background: var(--orange-bg); color: var(--primary-text);
}
.hinweis-kasten--stopp { background: var(--bad-bg); color: var(--danger-text); }
/* Ein .btn-outline im Kasten („Ausblenden" im App-Hinweis der Projektliste):
   der allgemeine Hover macht die Schrift orange und legt 6 % Weiss auf die
   Orange-Toenung — im Dunkelmodus 4.27:1 (gemessen 14.10.2026,
   test_hover_kontrast_bfsg). Hier bleibt die Schrift in Textfarbe; der
   orange Rahmen zeigt den Hover weiterhin an. */
.hinweis-kasten .btn-outline:hover { color: var(--text); }
.hinweis-kasten strong { color: inherit; }
.hinweis-kasten a {
  color: inherit; text-decoration: underline; font-weight: 600;
  min-height: 44px; display: inline-flex; align-items: center;
}

/* ─── Rechtstexte: Impressum · Datenschutz · Barrierefreiheit ────────────── */
/* Die Zwischenueberschriften trugen `class="mt-4 h5"` — zwei Bootstrap-Klassen,
   die es hier nie gab (25 Stellen, gefunden mit tools/css_klassen_pruefer.py
   am 17.08.2026). Wirkung: kein Abstand ueber der Ueberschrift, und die
   gewollte Abstufung „semantisch h2, optisch kleiner" gab es nicht. Kaputt war
   nichts — es sah nur nach etwas anderem aus, als jemand gemeint hatte.
   Pflichtseiten nach BFSG: sie werden gelesen, gerade von Bea. */
.rechtstext-h {
  margin-top: 1.75rem; margin-bottom: .5rem;
  font-size: 16px; font-weight: 700; color: var(--text);
}
/* Der Rahmen der drei Seiten stand als `class="container py-5"` im HTML —
   beides Bootstrap, beides hier nicht vorhanden. Der Text klebte dadurch oben
   und unten am Rand, und zentriert war er nur, weil im style-Attribut zufaellig
   `max-width` stand (ohne `margin:auto`). Jetzt traegt die eigene Klasse den
   Rahmen. */
.rechtstext {
  max-width: 800px; margin-left: auto; margin-right: auto;
  padding-top: 2.5rem; padding-bottom: 3rem; line-height: 1.65;
}

/* ─── Abnahme-Stand (Bea 17.08.2026) ─────────────────────────────────────── */
/* „Für was sind die Unterschriften gedacht? sollte dort nicht das
   abnahmeprotokoll erscheinen und dann die Unterschriften?" — der Kasten sagt
   VOR dem Unterschreiben, was man abnimmt. Wichtigster Fall: offene Mängel.

   ⚠️ Eigene Klasse, weil der erste Entwurf `alert alert-warning` benutzte —
   die es im Baubegleiter nicht gibt. Ergebnis: unformatierter Fliesstext an der
   Stelle, an der die Warnung stehen sollte. Derselbe Fehler wie `btn-secondary`
   auf der Fehlerseite am selben Tag; im Bild sofort zu sehen, im Test nie.
   Schriftfarben aus --primary-text/--danger-text wie beim Zahlungshinweis:
   --warning/--danger sind Flaechenfarben und erreichen als Text auf hellem
   Grund keine 4.5:1. */
.abnahme-stand {
  padding: 12px 16px; border-radius: var(--radius);
  margin-bottom: 1rem; font-size: 16px; line-height: 1.5;
}
.abnahme-stand--offen { background: var(--bad-bg); color: var(--danger-text); }
.abnahme-stand--frei  { background: var(--orange-bg); color: var(--primary-text); }
.abnahme-stand strong { color: inherit; }
.abnahme-stand ul { margin: .5rem 0 0; padding-left: 1.2rem; }
.abnahme-stand li { margin-bottom: .2rem; }
/* Der Link stand in Browser-Blau mitten im roten Kasten (Bildbefund). */
.abnahme-stand a {
  color: inherit; text-decoration: underline; font-weight: 600;
  min-height: 44px; display: inline-flex; align-items: center;
}

/* ─── Card / Karte ───────────────────────────────────────────────────────── */
/* Karten seit 10.08.2026 (Beas Freigabe, Stufe 1): EIN Trennmittel — die Flaeche.
   Kein Rand, kein Ruheschatten mehr; die Treppe bg->surface (oben) traegt allein.
   Kanten gibt es nur noch, wo sie arbeiten: Eingabefelder, Fokusringe,
   Trennlinien in Listen, Statusbalken, die Upload-Zone. */
.card, .karte {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 32px;
  position: relative; overflow: hidden;
}
/* Glanz-Verlauf entfernt (12.08.2026, Prototyp): die Flaeche ist ueberall
   exakt gleich — kein Schimmer, keine Textur, keine Blobs. */
.card-title { font-size: 20px; font-weight: 700; margin-bottom: 24px; color: var(--text); }

/* ─── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 8px 16px; border-radius: 8px;
  font-size: 14px; font-weight: 600;
  cursor: pointer; border: none;
  text-decoration: none; transition: var(--t2) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
  gap: 8px; white-space: nowrap;
  font-family: 'IBM Plex Sans', sans-serif;
  letter-spacing: -0.1px;
}
.btn-primary {
  background: var(--primary); color: var(--on-primary);
  box-shadow: 0 2px 8px var(--orange-bg), 0 0 0 0 var(--orange-bg);
}
.btn-primary:hover {
  background: var(--primary-light);
  box-shadow: 0 4px 16px rgba(217,119,6,0.4);
  transform: translateY(-1px);
}
.btn-outline {
  background: transparent; color: var(--text);
  border: 1px solid var(--border-strong);
}
/* Ein <select> mit .btn-Klassen erbt sonst das NATIVE Steuerlement-Weiss
   (mobil aufgefallen: weisser Kasten, heller Text — unlesbar). Explizit
   dunkel, Pfeil bleibt dem Browser ueberlassen. */
select.btn { background: var(--surface2); color: var(--text); }
[data-theme="light"] select.btn { background: var(--surface); }
.btn-outline:hover {
  background: var(--hover);
  border-color: var(--primary);
  /* --primary-text, nicht --primary: Orange als SCHRIFT steht auf hellem Grund
     bei 3.19:1 (gemessen 30.08.2026, axe traf den Hover-Zustand per Zufalls-
     Mausposition). Im Dunkelmodus ist der Wert identisch (#d97706), im hellen
     das lesbare #9c4708 — dieselbe Regel wie bei jeder anderen Orange-Schrift
     seit dem 16.08. Rahmen darf --primary bleiben (UI-Grenze: 3:1 reicht). */
  color: var(--primary-text);
}
.btn-success { background: var(--primary); color: var(--on-primary); box-shadow: 0 2px 8px var(--orange-bg); }
.btn-success:hover { background: var(--primary-light); transform: translateY(-1px); }
.btn-danger { background: var(--bad-bg); color: var(--danger-text); }
.btn-danger:hover { background: var(--bad-bg); }
.btn-full { width: 100%; }
.btn-sm { padding: 8px 12px; font-size: 14px; }
.btn-xs { padding: 4px 8px; font-size: 12px; border-radius: 6px; }

/* ─── Forms ──────────────────────────────────────────────────────────────── */
.form-group { margin-bottom: 16px; }
.form-label {
  display: block; font-size: 12px; font-weight: 600;
  color: var(--text-muted); margin-bottom: 8px;
  text-transform: uppercase; letter-spacing: 0.5px;
}
.form-input {
  width: 100%; padding: 12px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px; color: var(--text);
  background: var(--surface2);
  transition: border-color var(--t2) var(--kurve), box-shadow var(--t2) var(--kurve);
  font-family: 'IBM Plex Sans', sans-serif;
}
.form-input:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--orange-bg);
}
.form-input::placeholder { color: var(--text-faint); }
/* Ausgefuellte Felder blieben weiss (Bea 11.08.2026: „das weiss ist furchbar")
   — das ist der Autofill-Anstrich von Chrome/Safari, der `background` schlicht
   ueberschreibt. Farbe laesst sich dort nur ueber einen riesigen Inset-Schatten
   setzen; `background-color` wird ignoriert. Die Übergangsdauer haelt den
   eigenen Ton fest, sonst blitzt beim Ausfuellen kurz das Weiss durch. */
.form-input:-webkit-autofill,
.form-input:-webkit-autofill:hover,
.form-input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px var(--surface2) inset;
  box-shadow: 0 0 0 1000px var(--surface2) inset;
  caret-color: var(--text);
  transition: background-color 5000s ease-in-out 0s;
}
.form-input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px var(--surface2) inset,
                      0 0 0 3px var(--orange-bg);
  box-shadow: 0 0 0 1000px var(--surface2) inset,
              0 0 0 3px var(--orange-bg);
}
.form-textarea { min-height: 88px; resize: vertical; }
/* `select.form-input` muss mit: ohne `appearance: none` zeichnet Safari das
   Auswahlfeld nativ und ignoriert dabei die gesetzten Farben — auf dem iPhone
   stand die Projektauswahl unter „Meine Mängel" weiß im Dunkelmodus, während
   die berechneten CSS-Werte korrekt dunkel meldeten. Nur im Bild zu sehen,
   nicht in der Messung. (29.07.2026) */
.form-select,
select.form-input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23737373' d='M6 8L0 0h12z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
  padding-right: 36px; cursor: pointer;
  background-color: var(--surface2);
}
/* Kompaktes Auswahlfeld im Seitenkopf — schmaler als ein Formularfeld, aber
   mit dem vollen Pfeil-Freiraum rechts. */
.status-select {
  width: auto; display: inline-block;
  padding: 4px 32px 4px 12px;
  font-size: 14px; font-weight: 600;
}
.form-actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 24px; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.form-hint { font-size: 12px; color: var(--text-muted); margin-top: 8px; }

/* ─── Page layouts ───────────────────────────────────────────────────────── */
.page-narrow { max-width: 480px; margin: 0 auto; }
/* 480 px sind eine Formularspalte (Registrieren, Profil) — fuer eine Liste mit drei
   Aktionen je Zeile zu eng: gemessen blieben dem Vorlagennamen 112 px, „Abnahme-
   protokoll" braucht 129 px und brach um. Nicht geschaetzt, im Browser gemessen. */
.page-mittel { max-width: 760px; margin: 0 auto; }
/* Ruhige Spalte fuer zeilenweise gelesene Reiter (Termine, Dokumente, Maengel,
   Einstellungen). Sitzt auf dem PANEL, nicht auf der Liste: sonst stuenden
   Filterchips, Uploadfeld und "+ Termin vorschlagen" auf 1240 px, waehrend die
   Liste darunter bei 940 endet — der Versatz saehe nach Fehler aus statt nach
   Absicht. Was im selben Reiter voll bleiben soll, hebt die Begrenzung mit
   `.volle-breite` wieder auf. */
.lesespalte { max-width: var(--lesespalte); margin-inline: auto; }
/* Profil: Felder ab ~700 px zu zweit, Adresse ueber die ganze Breite (Bea 06.11.2026). */
.profil-raster { display: grid; grid-template-columns: 1fr; column-gap: 20px; }
@media (min-width: 700px) { .profil-raster { grid-template-columns: 1fr 1fr; } .profil-raster .profil-voll { grid-column: 1 / -1; } }
.volle-breite { max-width: none; }
/* Sitzt die Lesespalte auf dem Seitencontainer selbst, muss dessen seitlicher
   Innenabstand oben drauf — sonst blieben 900 px Inhalt statt 940, und die
   Kartenzeilen dieser Seiten waeren schmaler als dieselben Karten in den
   Projektreitern. Derselbe box-sizing-Fallstrick wie bei Stufe 3 (1280 -> 1240). */
.main-content.lesespalte { max-width: calc(var(--lesespalte) + 40px); }

/* ── Einstellungen: Schalter und Rechte-Karten nebeneinander ──────────────
   Bea 17.08.2026 zur Benachrichtigungsseite: „passe das auch an die
   bildschirmbreite an wie das andere." Vier Schalter untereinander in einer
   480-px-Spalte liessen auf ihrem Bildschirm links und rechts je ~900 px leer.
   `auto-fit` statt fester Spaltenzahl: auf dem Telefon bleibt es EINE Spalte,
   ohne Media-Query und ohne zweiten Satz Regeln, der auseinanderlaufen kann. */
.einst-raster {
  display: grid; gap: 1rem; margin-bottom: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
.einst-schalter {
  display: flex; align-items: flex-start; gap: 12px; cursor: pointer;
  padding: .75rem; background: var(--surface2); border-radius: 8px;
  border: 1px solid transparent;
  transition: border-color var(--tempo) var(--kurve),
              background-color var(--tempo) var(--kurve);
}
.einst-schalter:hover { border-color: var(--border-strong); }
/* Als <a> (Kontowahl der Spielwiese) faerbt der Browser sonst seine eigene
   Linkfarbe darueber — im Dunkelmodus ein kraeftiges Blau mitten im Orange. */
a.einst-schalter { color: inherit; text-decoration: none; }
/* Beas „c" (09.09.2026): je Ereignis-Typ die Wahl sofort / taeglich
   gebuendelt / aus — eine Radiogruppe als Segmentleiste statt eines Hakens.
   Die Karte ist ein <div>, kein <label>: ein Label um drei Radios wuerde
   jeden Klick auf den Text dem ersten Radio zuschreiben. Tippziele 44 px
   (R24, Apple HIG), auch in der kompakten Fassung des Firmen-Blocks.
   Aktive Option: --on-primary statt Weiss (#fff auf Orange waere 3,19:1). */
.einst-schalter--modus { cursor: default; flex-direction: column; gap: .55rem; }
.einst-schalter--modus:hover { border-color: transparent; }
.modus-wahl {
  display: inline-flex; max-width: 100%; border: 1px solid var(--border-strong);
  border-radius: 999px; overflow: hidden; background: var(--surface);
}
.modus-wahl__option { position: relative; flex: 1 1 auto; }
.modus-wahl__option input { position: absolute; opacity: 0; width: 0; height: 0; }
.modus-wahl__option span {
  display: flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 .9rem; white-space: nowrap;
  font-size: 14px; font-weight: 600; color: var(--text-muted); cursor: pointer;
  transition: background-color var(--tempo) var(--kurve), color var(--tempo) var(--kurve);
}
.modus-wahl__option + .modus-wahl__option span { border-left: 1px solid var(--border-strong); }
.modus-wahl__option input:checked + span { background: var(--primary); color: var(--on-primary); }
.modus-wahl__option input:focus-visible + span { outline: 2px solid var(--primary); outline-offset: -3px; }
.modus-wahl--kompakt { margin-left: .4rem; vertical-align: middle; }
.modus-wahl--kompakt span { padding: 0 .7rem; font-size: 12px; }
.modus-zeile {
  display: inline-flex; align-items: center; flex-wrap: wrap; gap: .3rem .4rem;
  min-height: 44px; font-size: 16px;
}
.einst-rechtekarte {
  background: var(--surface2); border-radius: 8px; padding: .8rem;
}

/* Angebot fuer eingeladene Gewerke, unter der Projektliste. Ruhig gehalten:
   eine Zeile Text und ein Umriss-Knopf, keine Werbeflaeche. Wer eingeladen
   mitarbeitet, soll seine Projekte sehen, nicht ein Banner. */
.gewerk-angebot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  margin: 2rem 0 .5rem; padding: 1rem 1.25rem;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--surface2); color: var(--text-muted); font-size: 14px;
}
.gewerk-angebot strong { color: var(--text); font-weight: 600; }
.gewerk-angebot .btn { flex-shrink: 0; min-height: 44px; }
.page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
.page-title { font-size: 20px; font-weight: 800; letter-spacing: -0.5px; color: var(--text); }

/* ─── Startseite Split-Screen ────────────────────────────────────────────── */
.login-split {
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: calc(100vh - 60px);
  margin: -32px -20px -80px;
}
.login-brand-side {
  background: linear-gradient(150deg, #78350f 0%, #92400e 40%, #b45309 80%, var(--primary) 100%);
  padding: 60px 48px;
  display: flex; flex-direction: column; justify-content: center;
  position: relative; overflow: hidden;
}
.login-brand-side::before {
  content: ''; position: absolute; top: -80px; right: -80px;
  width: 320px; height: 320px; border-radius: 50%;
  background: rgba(255,255,255,0.05);
}
.login-brand-side::after {
  content: ''; position: absolute; bottom: -120px; left: -60px;
  width: 400px; height: 400px; border-radius: 50%;
  background: rgba(255,255,255,0.04);
}
.login-brand-inner { position: relative; z-index: 1; max-width: 380px; }
.login-brand-badge {
  display: inline-block; font-size: 12px; font-weight: 600;
  color: rgba(255,255,255,0.8); background: var(--hover);
  padding: 4px 12px; border-radius: 20px; margin-bottom: 32px;
}
.login-brand-title {
  font-size: 34px; font-weight: 800; color: white;
  letter-spacing: -1px; line-height: 1.15; margin-bottom: 16px;
  font-family: 'Archivo', sans-serif;
}
.login-brand-sub { font-size: 16px; color: rgba(255,255,255,0.78); line-height: 1.6; margin-bottom: 40px; }
.login-brand-features { display: flex; flex-direction: column; gap: 16px; }
.login-brand-feature {
  display: flex; align-items: center; gap: 12px;
  color: rgba(255,255,255,0.88); font-size: 16px; font-weight: 500;
}
.login-brand-feature-icon {
  width: 34px; height: 34px; border-radius: 8px;
  background: rgba(255,255,255,0.15);
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; flex-shrink: 0;
}
.login-form-side {
  background: var(--bg); padding: 60px 48px;
  display: flex; flex-direction: column; justify-content: center;
}
.login-form-inner { max-width: 360px; width: 100%; }
.login-form-title {
  font-size: 27px; font-weight: 800; letter-spacing: -0.5px;
  margin-bottom: 8px; color: var(--text);
  font-family: 'Archivo', sans-serif;
}
.login-form-sub { font-size: 14px; color: var(--text-muted); margin-bottom: 32px; }
.login-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 24px 0; color: var(--text-faint); font-size: 12px;
}
.login-divider::before, .login-divider::after {
  content: ''; flex: 1; height: 1px; background: var(--border);
}
.login-hint { font-size: 12px; color: var(--text-muted); margin-top: 24px; line-height: 1.6; text-align: center; }

/* ─── Doku-Vorlagen-Editor: Split-Layout mit Live-Vorschau (Nico N12) ────── */
.vorlage-view-switch {
  display: none; gap: 8px; margin-bottom: 16px;
  background: var(--surface); padding: 4px;
  border-radius: var(--radius-lg);
}
.vorlage-view-btn {
  flex: 1; min-height: 44px; padding: 8px 16px; border: none; border-radius: var(--radius);
  background: transparent; color: var(--text-muted);
  font-size: 14px; font-weight: 600; font-family: 'IBM Plex Sans', sans-serif;
  cursor: pointer;
  transition: background-color var(--t2) var(--kurve), color var(--t2) var(--kurve), transform var(--t1) var(--kurve);
}
.vorlage-view-btn:active { transform: scale(0.97); }
.vorlage-view-btn.active {
  /* --primary-text statt --primary: auf der Orange-Toenung ueber hellem Grund
     stand die Schrift bei <4.5:1 (axe, webkit/iPhone-Profil 30.08.2026).
     Dunkelmodus unveraendert (#d97706). */
  background: rgba(217,119,6,0.15); color: var(--primary-text);
}
.vorlage-split { display: grid; grid-template-columns: minmax(300px, 420px) 1fr; gap: 32px; align-items: start; }
.vorlage-pane-vorschau { position: sticky; top: 20px; }
.vorlage-vorschau-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.vorlage-vorschau-label {
  font-size: 12px; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.6px;
}
.vorlage-vorschau-popout {
  background: none; border: none; cursor: pointer; padding: 4px 2px;
  /* --primary-text statt --primary: als Schrift auf --bg erreichte die
     Flaechenfarbe nur 3.0:1, die Textvariante 5.49:1. Gleiche Stelle wie
     .upload-zone-link — die Geschwister sind einzeln zu suchen. */
  font-size: 14px; font-weight: 600; color: var(--primary-text);
  transition: color var(--t2) var(--kurve), transform var(--t1) var(--kurve);
}
.vorlage-vorschau-popout:hover { text-decoration: underline; }
.vorlage-vorschau-popout:active { transform: scale(0.97); }
.vorlage-papier {
  background: #fff; border-radius: var(--radius-lg);
  /* Schwebendes „Papier" — der grosse Schatten ist hier Tiefe, kein Kartendekor. */
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
/* Nico 18.09.2026: „Die Dokumente im Dokumenten Editor sollten Immer das Format
   DIN A4 haben." Das ERZEUGTE PDF war immer A4 (@page size: A4 in
   utils/vorlage_pdf.py) — falsch war nur die Vorschau: volle Breite mal
   Fensterhoehe, das Seitenverhaeltnis ergab sich zufaellig aus der Fenstergroesse.
   Gemessen an seinem Bildschirmfoto rund 1:1,9 statt 1:1,41. Wer dort einen
   Umbruch beurteilt, beurteilt eine Seite, die es nicht gibt.
   Die Breite ist aus der zulaessigen Hoehe zurueckgerechnet, damit der Rahmen
   nie hoeher wird als vorher — sonst schoebe das A4-Verhaeltnis das Formular
   daneben aus dem Bild. */
.vorlage-papier-frame {
  display: block; border: 0;
  aspect-ratio: 210 / 297;
  width: min(100%, calc(min(75vh, 800px) * 210 / 297));
  margin-inline: auto;
}

/* Nico 01.11.2026 (Schalter dok_editor_format): Vorschau in ECHTER A4-Groesse.
   Der Rahmen ist 210 x 297 mm gross und wird als Ganzes auf die Papierbreite
   verkleinert (--a4-skala setzt editor.html). Vorher lief die Vorschau-Seite im
   ~420 px schmalen Rahmen mit 12-px-Schrift und ohne Seitenraender — relativ
   fast doppelt so grosse Schrift, anderer Umbruch als im PDF. */
/* Feste Spaltenbreite: der skalierte Rahmen hat keine Eigenbreite mehr, sonst
   schrumpfte die Spalte auf die Kopfzeile „Live-Vorschau … In neuem Tab". */
.vorlage-split-a4 { grid-template-columns: clamp(300px, 34%, 420px) minmax(0, 1fr); }
.vorlage-papier.a4-skaliert {
  position: relative;
  width: min(100%, calc(min(75vh, 800px) * 210 / 297));
  aspect-ratio: 210 / 297;
  margin-inline: auto;
}
.vorlage-papier.a4-skaliert .vorlage-papier-frame {
  position: absolute; top: 0; left: 0;
  width: 210mm; height: 297mm; max-width: none; aspect-ratio: auto; margin: 0;
  transform: scale(var(--a4-skala, 0.5)); transform-origin: 0 0;
}

/* Textblock auf DIN-A4-Flaeche: Blatt 210 mm breit, 20 mm Rand links/rechts wie im
   PDF; Schrift und Abstaende kommen aus blatt_css (utils/vorlage_pdf.py). */
.dok-textblock { padding-left: 32px; }
.dok-textblock-hinweis { font-size: 12px; margin: 8px 0 0; }
.dok-blatt-huelle {
  overflow-x: auto; overflow-y: hidden;
  background: #e9e9ec; border-radius: var(--radius);
  padding: 8px 0;
}
.dok-blatt-seite {
  width: 210mm; box-sizing: border-box; margin: 0 auto;
  padding: 10mm 20mm; background: var(--papier);
  box-shadow: 0 1px 4px var(--schatten);
}
.dok-blatt-original .dok-blatt-seite { margin: 0; }
/* Alles im Blatt auf die Browser-Vorgabe zuruecksetzen — so wie WeasyPrint es
   sieht. Ohne das erbten Ueberschriften und Fettes Farbe und Schrift der App
   (im Dunkelmodus: hellgrau auf weissem Papier). Die Regeln aus blatt_css sind
   spezifischer (.dok-blatt h2 …) und gelten danach wie im PDF. */
.dok-blatt * { all: revert; }
.dok-blatt {
  min-height: 30mm; outline: none; cursor: text;
  /* Ueberschreibt nichts an der Schrift — die kommt aus blatt_css. */
  margin: 0 !important;
  text-align: left; letter-spacing: normal; text-transform: none;
}
.dok-blatt:focus-visible, .dok-blatt:focus { box-shadow: 0 0 0 2px rgba(217,119,6,.45); border-radius: 2px; }
.dok-leiste {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  padding: 8px; margin-bottom: 8px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  position: sticky; top: 64px; z-index: 5;
}
.dok-leiste[hidden] { display: none; }
.dok-knopf {
  min-width: 36px; min-height: 36px; padding: 4px 8px;
  border: 1px solid transparent; border-radius: var(--radius);
  background: transparent; color: var(--text); cursor: pointer;
  font-size: 16px; line-height: 1; font-family: Arial, Helvetica, sans-serif;
  display: inline-flex; align-items: center; justify-content: center;
}
.dok-knopf svg { width: 16px; height: 16px; stroke: currentColor; stroke-width: 1.6; fill: currentColor; }
.dok-knopf svg path { fill: none; }
.dok-knopf svg text { stroke: none; font-family: Arial, sans-serif; }
.dok-knopf:hover { background: var(--bg); border-color: var(--border); }
.dok-knopf[aria-pressed="true"] { background: var(--orange-bg); color: var(--primary-text); border-color: var(--primary); }
.dok-knopf-text { font-size: 14px; font-family: inherit; }
.dok-wahl {
  min-height: 36px; padding: 4px 8px; font-size: 14px;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); color: var(--text);
}
.dok-textblock-anzeige {
  padding: 12px 12px; border-left: 3px solid var(--border); background: var(--surface2);
  border-radius: var(--radius); font-size: 14px; line-height: 1.5;
}
.dok-textblock-anzeige p, .dok-textblock-anzeige ul, .dok-textblock-anzeige ol { margin: 0 0 8px; }
.dok-textblock-anzeige ul, .dok-textblock-anzeige ol { padding-left: 24px; }
.dok-textblock-anzeige h2 { font-size: 16px; margin: 8px 0; }
.dok-textblock-anzeige h3 { font-size: 16px; margin: 8px 0; }
.dok-textblock-anzeige .gr-klein { font-size: 12px; }
.dok-textblock-anzeige .gr-gross { font-size: 16px; }
.dok-textblock-anzeige .gr-sehr-gross { font-size: 20px; }
.dok-trenner { width: 1px; align-self: stretch; background: var(--border); margin: 2px 2px; }
/* Schriftfarbe (Schalter dok_editor_format, Bea 02.11.2026): fester Text beim
   Ausfuellen auf Papier, sonst waere Schwarz im Dunkelmodus unlesbar. */
.dok-textblock-anzeige.dok-textblock-papier { background: var(--papier); color: var(--papier-tx); }
.dok-farbe-wrap { position: relative; display: inline-flex; }
.dok-farbe-knopf { flex-direction: column; gap: 2px; }
.dok-farbe-strich { width: 16px; height: 4px; border-radius: 2px; background: var(--dok-farbe, var(--papier-tx)); box-shadow: 0 0 0 1px var(--border); }
.dok-farbe-feld {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 6;
  display: flex; flex-direction: column; gap: 8px; padding: 8px; width: 216px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.dok-farbe-feld[hidden] { display: none; }
.dok-farbe-palette { display: flex; flex-wrap: wrap; gap: 4px; }
.dok-farbe-wahl {
  width: 28px; height: 28px; padding: 0; cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--dok-farbe, var(--papier-tx));
}
.dok-farbe-wahl:focus-visible, .dok-farbe-wahl[aria-pressed="true"] { outline: 2px solid var(--primary); outline-offset: 1px; }
.dok-farbe-hex { display: flex; gap: 4px; align-items: center; }
.dok-farbe-hex .form-input { flex: 1; min-width: 0; font-size: 14px; padding: 4px 8px; }
.dok-farbe-fehler { margin: 0; font-size: 12px; color: var(--danger-text); }
/* Finger statt Maus: Leistenknoepfe und Farbpunkte auf 44 px (Apple HIG),
   gemessen 02.11.2026 auf der Spielwiese: Farbpunkte 28 px, Knoepfe 36 px.
   Das Farbfeld bleibt innerhalb der Bildschirmbreite. */
@media (max-width: 768px), (pointer: coarse) {
  .dok-knopf, .dok-wahl { min-width: 44px; min-height: 44px; }
  .dok-farbe-wahl { width: 44px; height: 44px; }
  .dok-farbe-feld { width: min(308px, calc(100vw - 32px)); }
}

/* ─── Hero (für Magic-Link-Seite etc.) ─────────────────────────────────── */
.hero {
  background: linear-gradient(135deg, #78350f 0%, #b45309 60%, var(--primary) 100%);
  color: white; border-radius: var(--radius-lg);
  padding: 44px 32px; margin-bottom: 24px;
  position: relative; overflow: hidden;
}
.hero::before {
  content: ''; position: absolute; top: -60px; right: -60px;
  width: 240px; height: 240px; border-radius: 50%;
  background: rgba(255,255,255,0.06);
}
.hero-inner { max-width: 500px; position: relative; z-index: 1; }
.hero-badge {
  font-size: 12px; font-weight: 600; background: rgba(255,255,255,0.15);
  display: inline-block; padding: 4px 12px; border-radius: 20px; margin-bottom: 16px;
}
.hero-title { font-size: 34px; font-weight: 800; margin-bottom: 12px; letter-spacing: -0.7px; font-family: 'Archivo', sans-serif; }
.hero-subtitle { font-size: 16px; opacity: 0.88; margin-bottom: 24px; }
.hero-features { display: grid; gap: 8px; }
.hero-feature { font-size: 14px; opacity: 0.88; font-weight: 500; }

/* ─── Auth (Fallback) ────────────────────────────────────────────────────── */
.auth-section { max-width: 400px; margin: 0 auto; }
.auth-divider { text-align: center; color: var(--text-muted); font-size: 14px; margin: 16px 0; }
.auth-hint { font-size: 12px; color: var(--text-muted); text-align: center; margin-top: 16px; }
.success-icon { font-size: 52px; margin-bottom: 16px; }
.email-highlight {
  font-size: 16px; font-weight: 600; color: var(--primary);
  background: var(--orange-bg);
  padding: 8px 16px; border-radius: var(--radius);
  display: inline-block; margin: 8px 0;
}
.hint-box {
  background: var(--surface2);
  border-radius: var(--radius); padding: 16px 16px;
  font-size: 14px; color: var(--text-muted); margin-top: 24px;
}
/* Links im Hinweiskasten hatten keinen Stil und fielen auf das Browser-Blau
   (#0000EE) zurueck — auf dem dunklen Grund praktisch unlesbar. Aufgefallen erst
   im Screenshot der Anmelde-Bestaetigung (09.08.), nicht im Test. */
.hint-box a { color: var(--primary-text); font-weight: 600; }
.hint-box a:hover { color: var(--primary-light); }
.text-center { text-align: center; }

/* ─── Listenzeile: Text links, Aktionen rechts ───────────────────────────── */
/* `min-width: 0` ist der eigentliche Punkt: ohne ihn schrumpft der Textblock nicht
   unter seine Inhaltsbreite, die Zeile wird breiter als der Container und die
   Aktionsgruppe startet je nach Textlaenge an einer anderen Stelle. Genau so war
   es in den Dokument-Vorlagen (UX-Durchgang 31.07., Befund 11) — die
   Textbaustein-Liste daneben hatte den Wert laengst und stand still. */
.listenzeile {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 1rem; padding: .7rem 0; border-bottom: 1px solid var(--border);
}
.listenzeile--oben { align-items: flex-start; }
.listenzeile > :first-child { min-width: 0; }
/* `margin-left:auto` statt space-between: so enden die Aktionen IMMER am rechten
   Rand — auch wenn sie bei schmalem Platz in die naechste Zeile rutschen. Der
   erste Versuch presste sie mit dem Text in eine Zeile; dann brach „Abnahme-
   protokoll" mitten im Wort um. Ein zerhackter Name ist schlimmer als ein
   Umbruch der Knopfgruppe. */
.listenzeile-aktionen { display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: auto; }
/* Abstand vor der zerstoerenden Aktion — „Loeschen" klebte rot an „Bearbeiten",
   und ein Fehlklick kostet hier eine ganze Vorlage. */
.listenzeile-aktionen .aktion-gefahr { margin-left: 12px; }

/* ─── Projekt-Grid ───────────────────────────────────────────────────────── */
/* grid-auto-rows: 1fr — sonst bestimmt jede Zeile ihre Hoehe selbst und das Raster
   franst aus: Kacheln mit Mangel-Zaehler sind hoeher als ohne, Kacheln ohne Adresse
   niedriger. Mit dem Datum auf margin-top:auto sitzt die Fusszeile ueberall gleich.
   UX-Durchgang 31.07., Befund 12. */
.projekt-grid { display: grid; gap: 16px; grid-auto-rows: 1fr; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); }
/* .projekt-card entfernt (12.08.2026): die Projektliste traegt jetzt
   .projekt-karte nach dem Prototyp (Zeitstrahl + Kennzahlen), siehe unten. */

/* ─── Badges ─────────────────────────────────────────────────────────────── */
/* .projekt-status entfernt (12.08.2026): in keinem Template mehr benutzt,
   die Projektkarten tragen .marke. */
.status-aktiv { background: var(--orange-bg); color: var(--primary); }
.status-abgeschlossen { background: var(--hover); color: var(--text-muted); }
/* EINE Pillenform in der ganzen App (12.08.2026): dieselbe Form wie .marke auf
   den Projektkarten — eckig statt rund, Archivo, Versalien. Vorher standen
   runde .badge und eckige .marke nebeneinander auf derselben Seite; genau die
   „vielen Formen", die Bea am 11.08. an der Beteiligtenliste bemaengelt hat. */
.badge {
  display: inline-flex; align-items: center;
  font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 6px;
}
.badge-success  { background: var(--orange-bg);  color: var(--warning); }
.badge-warning  { background: var(--orange-bg);  color: var(--warning); }
.badge-danger   { background: var(--bad-bg);   color: var(--danger-text); }
.badge-info     { background: var(--info-bg);  color: var(--info-text); }
/* --text-muted (#909090) erreicht auf dem aufgehellten Grund nur 4.49:1. */
.badge-secondary{ background: var(--hover); color: var(--text-muted); }
/* Zwei Stufen aus dem Prototyp: die Marke traegt die LAUFENDE Arbeit,
   Erledigtes wird zurueckgenommen statt hervorgehoben. */
.badge-aktiv    { background: var(--orange-bg);  color: var(--primary-light); }
.badge-ruhe     { background: var(--hover); color: var(--text-faint); }
[data-theme="light"] .badge-aktiv { background: var(--orange-bg); color: var(--primary-text); }
[data-theme="light"] .badge-ruhe  { background: var(--hover); color: var(--text-faint); }
/* Rollen-Pillen seit 12.08.2026 EINE ruhige Form statt vier Farben (Beas
   Befund "durchbar mit den vielen farben und formen"): die Rolle traegt der
   TEXT. Nur die eigene Marke (Handwerker = Projektfuehrer) bleibt orange. */
.badge-rolle-handwerker { background: var(--orange-bg); color: var(--primary-light); }
[data-theme="light"] .badge-rolle-handwerker { color: var(--primary-text); }
.badge-rolle-partner    { background: var(--hover); color: var(--text-muted); }
.badge-rolle-kunde      { background: var(--hover); color: var(--text-muted); }
.badge-rolle-architekt  { background: var(--hover); color: var(--text-muted); }
[data-theme="light"] .badge-rolle-partner,
[data-theme="light"] .badge-rolle-kunde,
[data-theme="light"] .badge-rolle-architekt { background: var(--hover); }

/* ─── Projekt-Detail ─────────────────────────────────────────────────────── */
.projekt-header {
  display: flex; justify-content: space-between; align-items: flex-start;
  /* 28/22 -> 18/14: zusammen mit dem kleineren Seitenrand oben kommt die
     Reiterzeile rund 30 px hoeher, ohne dass etwas zusammenrueckt. */
  gap: 16px; margin-bottom: 16px; padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
/* Kopf der Projekt-UNTERSEITEN (Stefan 23.08.2026): derselbe Aufbau wie
   .projekt-header, aber ohne die rechte Spalte (Statuswahl gibt es nur auf der
   Projektseite selbst). Die Trennlinie faellt hier weg — direkt darunter folgt
   die Reiterleiste, zwei waagerechte Kanten uebereinander wirken wie ein
   Fehler. */
.projekt-unterseite-kopf { margin-bottom: 16px; }
.back-link {
  font-size: 14px; color: var(--text-muted); text-decoration: none;
  display: inline-flex; align-items: center; gap: 4px;
  margin-bottom: 8px; font-weight: 500; transition: color var(--t2) var(--kurve);
}
.back-link:hover { color: var(--primary-text); } /* wie .btn-outline:hover — Orange-Schrift auf hell: 3.19:1 */
.projekt-titel { font-size: 27px; font-weight: 800; letter-spacing: -0.6px; color: var(--text); font-family: 'Archivo', sans-serif; }
.projekt-adresse { font-size: 14px; color: var(--text-muted); margin-top: 4px; }
.projekt-beschreibung { font-size: 14px; color: var(--text-muted); margin-top: 8px; line-height: 1.6; }
.projekt-header-right { display: flex; flex-direction: column; gap: 8px; align-items: flex-end; flex-shrink: 0; }

/* Deeplink auf einen Reiter (…/projekt/5#termine) schob den Seitenanfang unter die
   sticky Navbar (60 px hoch) — betrifft geteilte Links und Lesezeichen, beim Klick
   im Reiter passiert es nicht, weil dort gar nicht gesprungen wird.
   UX-Durchgang 31.07., Befund 13. `:target` deckt auch kuenftige Anker ab. */
.tab-content, :target { scroll-margin-top: 76px; }

/* ─── Tabs ───────────────────────────────────────────────────────────────── */
/* Auf breiten Fenstern UMBRECHEN statt scrollen: neun Reiter brauchen mehr als
   die 1160 px Inhaltsbreite, die Leiste endete mitten in „⚠ Be…" und nichts
   zeigte an, dass da noch etwas kommt (UX-Durchgang 31.07., Befund 8). Ein
   verstecktes Element auf einem 1280-px-Bildschirm ist schlicht unauffindbar.
   Schmale Geraete scrollen weiter — dort waeren vier Reiterzeilen ueber dem
   Inhalt schlimmer als ein Wischen; den Hinweis darauf gibt der Verlauf unten. */
.tabs {
  display: flex; flex-wrap: wrap; gap: 2px; margin-bottom: 24px;
  background: var(--surface); padding: 4px;
  border-radius: var(--radius-lg);
  /* Stefan 18.09.2026 (Chat-Klickdummy): beim Scrollen bleibt die Reiterleiste
     mit kleinem Abstand oben stehen. `top` = Hoehe der Navbar (60 px, selbst
     sticky) + 8 px Luft. z-index unter der Navbar (200) und unter den Modals
     (900), ueber dem Inhalt. `scroll-margin-top: 76px` der Anker passt weiter:
     der Anker landet knapp unter der Leiste statt darunter versteckt. */
  position: sticky; top: 68px; z-index: 150;
}
.tab {
  padding: 8px 16px; border-radius: var(--radius);
  font-size: 14px; font-weight: 600;
  text-decoration: none; color: var(--text-muted);
  cursor: pointer; display: flex; align-items: center; gap: 8px;
  white-space: nowrap; transition: var(--t2) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
}
.tab:hover { background: var(--surface3); color: var(--text); }
.tab.active {
  background: var(--orange-bg);
  /* --primary auf dem eigenen 15%-Grund ergibt 4.47:1 — knapp unter AA.
     --primary-light ist derselbe Farbton, nur hell genug. */
  color: var(--primary-light);
}
.tab-badge { border-radius: 12px; padding: 1px 8px; font-size: 12px; font-weight: 600; }
.tab.active .tab-badge { background: var(--orange-bg); }
.tab:not(.active) .tab-badge { background: var(--hover); color: var(--text-muted); }
.tab-content { display: none; }
.tab-content.active { display: block; }

/* ─── Feed ───────────────────────────────────────────────────────────────── */
/* Chatfenster so breit wie die Reiterleiste darueber (Bea 26.08.2026):
   „es ging darum dass das chatfenster kleiner ist als die reiter oben, das
   meinte ich mit reihe dass es durchgehend ist."

   Damit ist ihr Auftrag vom 18.08. richtiggestellt — gemeint war die BREITE des
   Fensters, nicht die Flucht der Blasen. Gemessen am 27.08. bei 1280 px:
   `.tabs` 1240 breit ab x=20, `.feed` 1000 ab x=140. Die Kante sprang also um
   120 px je Seite. Auf dem Telefon waren beide schon gleich (362) — der Befund
   ist reine Desktop-Sache.

   Die Blasen wachsen dabei NICHT mit — Bea am 18.08.: „der chat an sich kann
   kleiner bleiben, so wie er jetzt ist". Ihre bisherige Groesse steckt als
   fester Deckel in .feed-item (720 = 72 % der alten 1000er Spalte); ohne den
   waere aus der breiteren Flaeche automatisch eine breitere Blase geworden. */
.feed, .feed-form { max-width: none; margin-left: 0; margin-right: 0; }
/* Separates Chatfenster (Stefan 23.08.2026, ts 1787488480): der Verlauf scrollt
   in einem eigenen Kasten, Titel/Reiter/Composer bleiben stehen. Vorher wuchs
   die ganze Seite mit jeder Nachricht (gemessen 25.08.: 3335 px bei 28
   Nachrichten). JS setzt den Kasten beim Laden und Raumwechsel ans Ende. */
.feed { display: flex; flex-direction: column; gap: 16px; margin-bottom: 24px; min-height: 80px;
        max-height: min(58vh, 640px); overflow-y: auto; overscroll-behavior: contain;
        padding-right: 8px; }
/* Chat als Vollbild (Stefan 18.09.2026, Klickdummy chat-klickdummy.zip):
   „beim Scrollen soll die Reiterleiste oben stehen bleiben, der Chat dann die
   ganze Seite fuellen; Nachrichtenfenster weiter scrollbar, mit Rahmen."
   Der Feed-Reiter wird eine Spalte, die den Platz unter der (sticky) Leiste
   bis zum Fensterende einnimmt; Raumleiste und Composer bleiben fest, das
   Nachrichtenfenster dazwischen waechst und scrollt. Die Hoehe rechnet:
   Fenster − Navbar 60 − Leiste ~48 + Abstand 24 − Fussluft 16.
   `min-height` statt `height`: waechst der Composer (Direkt-Panel offen),
   schiebt er nach unten statt das Nachrichtenfenster auf null zu quetschen. */
#feed.tab-content.active {
  display: flex; flex-direction: column;
  min-height: calc(100vh - 60px - 48px - 24px - 16px);
}
#feed .feed {
  flex: 1 1 auto; min-height: 220px; max-height: none;
  border: 1px solid var(--border); border-radius: var(--radius-lg);
  padding: 16px 16px 16px 16px; background: var(--surface2);
}
#feed .feed-form { flex: 0 0 auto; }
/* Gerätetest 19.09.2026 (4 Befunde, iPhone SE/15, beide Engines): als Kind
   der neuen Flex-Spalte verliert die Raumleiste das Stretchen — ihre
   `margin: auto` (Zentrierung auf die Lesespalte) hebt `align-items: stretch`
   auf, die Breite wird max-content, alle Chips in EINER Zeile: 878 px bei 390.
   `width: 100%` gibt die Zeilenbreite zurueck, `max-width` zentriert weiter. */
#feed .raum-leiste { width: 100%; min-width: 0; }
/* Auf dem Telefon ist die Adressleiste im vh enthalten — 100vh ist dort
   hoeher als der sichtbare Bereich. Deshalb weniger abziehen wollen wir nicht;
   stattdessen gilt die Untergrenze, und die Seite darf scrollen. */
@media (max-width: 767px) {
  #feed.tab-content.active { min-height: 0; }
  #feed .feed { min-height: 260px; max-height: min(58vh, 560px); }
}
/* Eigener Fokusring (25.08.2026): der Feed ist seit heute mit `tabindex="0"`
   anwaehlbar (sonst kam man mit der Tastatur nicht an aeltere Nachrichten —
   axe: scrollable-region-focusable). Der Browser-Standardring ist hier
   `auto 1px rgb(16,16,16)` — gemessen; auf dunklem Grund ist Schwarz praktisch
   unsichtbar, und WCAG 2.4.11 verlangt 3:1 fuer den Indikator selbst. Gleiches
   Muster wie .projekt-karte:focus-visible, damit Fokus im Produkt einheitlich
   aussieht. `outline-offset` haelt den Ring aus dem Text heraus. */
.feed:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.feed-item {
  background: var(--surface);
  border-radius: var(--radius-lg); padding: 12px 16px;
  /* Fester Deckel seit 27.08.2026: die Feed-Spalte begrenzt nicht mehr (sie ist
     jetzt so breit wie die Reiterleiste, Bea 26.08.). 720 px = 72 % der alten
     1000er Spalte — die Blase behaelt damit exakt ihre bisherige Groesse. Ohne
     diese Zeile waere aus dem breiteren Fenster eine breitere Blase geworden,
     und genau das wollte Bea nicht („der chat an sich kann kleiner bleiben"). */
  max-width: min(72%, 720px);
  /* Ohne das dehnt der Flex-Standard `stretch` FREMDE Blasen auf die vollen
     72 %, waehrend eigene ueber `align-self: flex-end` inhaltsbreit bleiben:
     ein „Hallo" von Familie Schulz stand als 720 px breiter Kasten neben einem
     handtellergrossen eigenen. Gefunden im Hellmodus-Bild am 10.08.2026 —
     im Dunkeln faellt es kaum auf, weil die Blase dort wenig vom Grund absticht. */
  align-self: flex-start;
}
/* Beas Auftrag vom 18.08.2026, mit Bild: „die chats bitte auch in eine reihe
   so wie oben die punkte … sonst muss man den kopf immer zu weit links und
   rechts drehen beim lesen."

   Bis dahin standen eigene Blasen rechts, fremde links. Bei ihrer Fensterbreite
   lagen zwischen dem Anfang einer fremden und dem Ende einer eigenen Nachricht
   ueber 1000 px — das Auge springt bei jeder Zeile ueber die halbe Seite. Der
   Absender geht dabei nicht verloren: der Name steht ohnehin ueber jeder Blase,
   und die eigene bleibt orange hinterlegt.

   Die Blasenbreite bleibt unveraendert (Bea: „der chat an sich kann kleiner
   bleiben, so wie er jetzt ist") — geaendert wird nur die Flucht. */
.feed-item-own {
  /* Zurueck nach rechts (Bea 26.08.2026): „aber die nachrichten vom versender
     sollen immer rechts stehen." Ihr Auftrag vom 18.08. betraf die Fensterbreite
     (siehe .feed), nicht die Flucht — die Umstellung auf flex-start war meine
     Fehldeutung. Damit traegt wieder die POSITION die Zuordnung, so wie es
     jeder aus anderen Messengern kennt. */
  align-self: flex-end;
  background: var(--orange-bg);
  /* Der Streifen ist die FOLGE der Umstellung oben, nicht Zierde.
     Nachgemessen am Bild vom 18.08.: die Fuellung allein traegt die
     Unterscheidung nicht. Eigene Blase gegen fremde ergibt 1.17:1 Helligkeit —
     und zwar vorher genauso (1.16:1 auf dem alten Grau). Solange eigene
     Nachrichten rechts standen, machte das nichts: die POSITION war das
     Signal, die Farbe nur Beigabe. Mit der Flucht faellt das Signal weg, und
     seit dem warmen Grund sind beide Blasen zusaetzlich derselbe Farbklang
     statt Grau gegen Braun — der Helligkeitswert misst das nicht mit.
     Deshalb eine Kante: sie funktioniert unabhaengig von Ton und Helligkeit,
     kostet keine Breite (Bea: „der chat an sich kann kleiner bleiben") und
     bleibt auch fuer Farbenblinde lesbar. */
  /* Die Kante wandert mit der Blase auf die AUSSENseite. Sie bleibt, obwohl die
     Position die Zuordnung wieder allein tragen wuerde: gemessen ergibt eigene
     gegen fremde Blase nur 1.17:1 Helligkeit, und wer den Verlauf schmal oder
     stark gezoomt liest, sieht von der Flucht wenig. Fuer Farbenblinde ist sie
     ohnehin das einzige Merkmal, das nicht am Farbton haengt. */
  border-right: 3px solid var(--primary);
  border-top-right-radius: 4px;
  border-bottom-right-radius: 4px;
}
.feed-meta { display: flex; gap: 8px; margin-bottom: 4px; align-items: center; }
.feed-meta strong { font-size: 14px; font-weight: 600; color: var(--text); }
.feed-datum { font-size: 12px; color: var(--text-faint); }
.feed-text { font-size: 14px; line-height: 1.5; color: var(--text); }
/* Sendebereich als Composer-Karte (UX 31.07. #1+#2). Vorher war .feed-form eine
   Flex-ZEILE (Relikt aus Textarea+Knopf-Zeiten): Chips, Sichtbarkeits-Zeile und
   Aktionsleiste wurden Spalten derselben Zeile — Textarea auf ~30px gequetscht,
   Platzhalter brach senkrecht, Senden-Knopf ragte auf 375px aus der Seite. */
/* Stufe 2 (Design, 10.08.2026): EIN Feld statt Kasten-im-Kasten. Vorher trugen
   .feed-form und die Textarea beide --surface2 — im Dunkelmodus lag damit ein
   gerahmtes Rechteck auf einer gleichfarbigen Flaeche, was wie ein Zeichenfehler
   aussah. Jetzt ist der Composer selbst das Eingabefeld: er traegt die einzige
   Kante und den Fokusring (Stufe-1-Positivliste: Eingaben behalten ihre Kante,
   aber nur EINE), die Textarea darin ist randlos und durchsichtig. */
.feed-form { display: flex; flex-direction: column; gap: 8px; margin-top: 12px;
  background: var(--surface2);
  border: 1px solid var(--border);
  border-radius: 12px; padding: 12px 12px;
  transition: border-color var(--t2) var(--kurve), box-shadow var(--t2) var(--kurve); }
/* Derselbe Fokusring wie .form-input:focus — das Feld verhaelt sich fuer den
   Nutzer wie ein Eingabefeld, also muss es auch so leuchten. Greift auch beim
   Tabben auf Chips und Emoji-Knopf: die gehoeren sichtbar zum selben Feld. */
.feed-form:focus-within {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--orange-bg);
}
.feed-form > * { min-width: 0; }
.feed-input { width: 100%; min-height: 64px; resize: vertical;
  background: transparent; border: none; padding: 4px 2px; }
/* Der Fokus sitzt am Feld, nicht am Textbereich — sonst leuchteten zwei Ringe
   ineinander. Sichtbar bleibt er trotzdem (Container-Ring oben). */
.feed-input:focus { outline: none; box-shadow: none; border-color: transparent; }
/* #bbb (globale Platzhalterfarbe hell) steht auf dem leicht grauen Feldgrund bei
   1.7:1. Der Platzhalter ist hier die einzige Beschriftung des Textfelds. */
.feed-input::placeholder { color: var(--text-faint); }
.feed-actions { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.feed-senden { min-height: 44px; min-width: 96px; }

/* Raum-Leiste über dem Verlauf (Bea 11.08.2026). Loest die Chip-Zeile „An:"
   unter dem Textfeld ab: die war reines Sendeziel, waehrend der Verlauf
   darueber immer alles zeigte — „chat sehe ich ueberall das gleiche". Jetzt
   waehlt EIN Bedienelement den Raum, den man liest und in den man schreibt. */
.raum-leiste { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;
  max-width: var(--lesespalte); margin-left: auto; margin-right: auto; }
.raum-reiter {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 12px; font-size: 14px; font-weight: 600; line-height: 1;
  color: var(--text-muted); background: var(--surface3);
  border: none;   /* nativer 2px-outset-Rahmen des <button> — siehe .pill */
  border-radius: 999px; cursor: pointer;
  transition: transform var(--t1) var(--kurve),
              background-color var(--t2) var(--kurve), color var(--t2) var(--kurve);
}
.raum-reiter[data-active] { color: var(--primary-light); background: var(--primary-glow); }
/* Die gestrichelte Linie ist Information („nur ich"), kein Dekor — sie bleibt
   als einzige Reiter-Kante erhalten. */
.raum-reiter--privat { border: 1px dashed var(--border-strong); padding: 4px 12px; }
.raum-reiter:active { transform: scale(.97); }
/* Raeume, die es nicht mehr gibt (Kollege ausgeschieden): lesbar, nicht
   beschreibbar — deshalb zurueckgenommen statt gleichwertig neben den aktiven. */
.raum-reiter[data-nur-ansicht] { opacity: .72; font-style: italic; }
.raum-zahl { font-size: 12px; font-weight: 600; color: var(--text-faint); }
.raum-reiter[data-active] .raum-zahl { color: inherit; }

/* Ungelesen-Punkte (Bea 18.09.2026, 19:03): „oranger Punkt am Feed und am
   betroffenen Chat". Ein Punkt und keine Zahl — neben der Raum-Zahl (wie viele
   Nachrichten der Raum insgesamt hat) waere eine zweite Zahl nicht zu
   unterscheiden. Die Farbe ist die vorhandene Akzentfarbe, damit der Punkt in
   beiden Themen (hell/dunkel) sitzt und nicht als Fremdkoerper wirkt. */
.raum-punkt,
.feed-punkt {
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: .35rem;
  border-radius: 50%;
  background: var(--primary, var(--primary));
  vertical-align: middle;
  flex: none;
}
.raum-punkt[hidden],
.feed-punkt[hidden] { display: none; }
@media (hover: hover) and (pointer: fine) {
  .raum-reiter:hover { color: var(--text); }
  .raum-reiter[data-active]:hover { color: var(--primary-light); }
}
.kreis-teilnehmer-zeile { font-size: 12px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Handy: Reiter scrollen seitlich statt sich zu einer halben Bildschirmhöhe zu
   stapeln (UX 31.07. #1 — sechszeilige Chip-Spalte vor dem ersten Tippen). */
@media (max-width: 640px) {
  .raum-leiste { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; padding-bottom: 2px; }
  .raum-leiste::-webkit-scrollbar { display: none; }
  /* 40 px kamen bisher nur mit dem nativen 2px-Rahmen oben und unten auf die
     44 px der Apple-Vorgabe. Ohne den Rahmen (siehe .pill) waeren es 40 —
     deshalb hier der echte Wert statt der zufaellig passenden Summe. */
  .raum-reiter { flex: 0 0 auto; min-height: var(--touch-min); }
}
@media (prefers-reduced-motion: reduce) {
  .kreis-chip { transition: background-color var(--t2) var(--kurve), border-color var(--t2) var(--kurve), color var(--t2) var(--kurve); }
  .kreis-chip:active { transform: none; }
}
.empty-state-small { color: var(--text-muted); font-size: 14px; padding: 24px 0; text-align: center; }
/* --primary-text statt --primary (10.09.2026): der Link „Ersten Termin
   vorschlagen" stand mit #d97706 auf #eceff3 bei 2.84:1 — axe/BFSG verlangt
   4.5:1. Vierter Fall derselben Trennung (siehe --primary-text oben);
   gefunden erst, als der a11y-Test wieder eine echte Projekt-ID traf. */
.empty-state-small a { color: var(--primary-text); font-weight: 500; }

/* ─── Termine ────────────────────────────────────────────────────────────── */
.section-action { margin-bottom: 16px; }
.termin-liste { display: flex; flex-direction: column; gap: 12px; }
.termin-card {
  background: var(--surface);
  border-radius: var(--radius-lg); padding: 16px 16px;
  transition: var(--t3) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
}
.termin-card:hover { background: var(--surface3); }
/* Die farbigen Statusbalken links sind Daten (bestaetigt/vorgeschlagen/…) und
   bleiben — sie waren nie Teil des Rahmen-Problems. */
.termin-bestaetigt  { border-left: 3px solid var(--primary); }
.termin-vorgeschlagen{ border-left: 3px solid var(--warning); }
.termin-abgesagt    { border-left: 3px solid var(--text-faint); opacity: 0.55; }
/* Bea 20.08.2026: „ich sehe die auswahl, aber sie ist fast durchsichtig" —
   die 0.55-Opazitaet oben galt bisher der GESAMTEN Karte, also auch dem
   Aktionen-Knopf mit der neuen Reaktivieren-Option. Der Inhalt bleibt gedaempft,
   die Bedienelemente nicht. */
.termin-abgesagt .termin-actions { opacity: 1; }
.termin-verschoben  { border-left: 3px solid var(--info); }
/* Terminvorschlag (Stefan 23.08.2026): „gestrichelt umrandet" — der Rahmen ist
   hier die ganze Botschaft. Er sagt „noch nicht beschlossen", und zwar ohne
   Text, auch bei einem Blick aus zwei Metern auf ein Telefon.
   Der Rahmen liegt INNEN (inset box-shadow statt border), damit die Karte
   dieselbe Breite und Höhe behält wie ihr bestätigtes Gegenstück — ein 2px
   border würde sie um 4px verschieben und die Liste unruhig machen. */
.termin-vorschlag {
  border-left: 3px dashed var(--warning);
  outline: 1px dashed var(--warning);
  outline-offset: -4px;
  background: color-mix(in srgb, var(--warning) 6%, var(--surface));
}
.termin-vorschlag:hover { background: color-mix(in srgb, var(--warning) 10%, var(--surface3)); }
.termin-vorschlag-aktionen { display: flex; gap: 8px; margin-top: 12px; }
.termin-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 8px; }
.termin-titel { font-weight: 700; font-size: 16px; color: var(--text); }
.termin-gewerk {
  font-size: 12px; color: var(--text-muted);
  background: var(--surface3); padding: 2px 8px;
  border-radius: 20px; margin-left: 8px;
}

/* ─── Empfänger-Auswahl (Termin anlegen) ──────────────────────────────────
   Bea 20.08.2026: "durch anklicken in einem dropdown von allen beteiligten
   kann man alle oder einzelne leute einladen" — EIN Auswahlfeld statt Select
   + Mehrfachauswahl. Als Pillen statt natives <select multiple> (auf dem
   Handy kaum bedienbar, Tippziele viel zu klein — R24). Reine Checkboxen
   dahinter, damit es auch ohne JS funktioniert; die :has()-Regel spiegelt nur
   den Checked-Zustand optisch. */
.empfaenger-auswahl { display: flex; flex-wrap: wrap; gap: 8px; }
.empfaenger-pill {
  position: relative; display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 16px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface2);
  font-size: 14px; color: var(--text-muted); cursor: pointer;
  transition: background-color var(--t2) var(--kurve), border-color var(--t2) var(--kurve), color var(--t2) var(--kurve);
}
.empfaenger-pill input { position: absolute; opacity: 0; pointer-events: none; }
.empfaenger-pill:has(input:checked) {
  background: var(--primary-glow); border-color: var(--primary);
  color: var(--primary-light);
}
[data-theme="light"] .empfaenger-pill:has(input:checked) { color: var(--primary-text); }
/* Keine `opacity` auf Text (25.08.2026): sie zieht den Kontrast mit herunter,
   ohne dass man es im Quelltext sieht — gemessen wurde #81818e statt #676774
   (7 Elemente auf der Termin-Seite). Gedaempft heisst zurueckhaltend, nicht
   unlesbar. Dritter Fall desselben Musters an diesem Tag. */
.empfaenger-pill small { color: var(--text-faint); font-weight: 400; }
.empfaenger-pill.empfaenger-alle { font-weight: 600; }

/* ─── Termin-Popup (Modal) ─────────────────────────────────────────────────
   Bea 20.08.2026: "nicht wie gerade eine neue seite, ein pop up soll aufgehen".
   Gleiches Muster wie .dropdown-menu (opacity/visibility/pointer-events statt
   display:none/flex — R4/Modal-CSS-Bug) + eigene Klasse "offen", damit ein
   Klick ausserhalb (Backdrop) und Escape sauber schliessen koennen. */
.modal-backdrop {
  position: fixed; inset: 0; background: var(--scrim);
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity var(--t3) var(--kurve); z-index: 900;
}
.modal-backdrop.offen { opacity: 1; pointer-events: all; visibility: visible; }
.modal {
  position: fixed; top: 50%; left: 50%;
  transform: translate(-50%, -48%) scale(0.97);
  background: var(--surface); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); width: min(440px, calc(100vw - 32px));
  max-height: calc(100vh - 48px); overflow-y: auto;
  opacity: 0; pointer-events: none; visibility: hidden; z-index: 901;
  transition: opacity var(--t3) var(--kurve),
              transform var(--t3) var(--kurve);
}
.modal.offen { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: all; visibility: visible; }
.modal-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 16px 24px 0;
}
.modal-header h3 { font-size: 16px; font-weight: 700; color: var(--text); margin: 0; }
.modal-close {
  background: none; border: none; font-size: 24px; line-height: 1;
  color: var(--text-muted); cursor: pointer; padding: 4px 12px;
  min-width: 44px; min-height: 44px;
}
.modal-body { padding: 12px 24px 24px; }
.modal-body .form-group:last-of-type { margin-bottom: 16px; }

/* ─── Dokumentvorschau (Domi 23.08.2026) ───────────────────────────────────
   „nein ist kein komfort. gleich bauen." Das Produkt verspricht „alles an
   einem Ort" — beim Oeffnen eines Dokuments verliess der Nutzer genau diesen
   Ort: die Datei ging in einen eigenen Browser-Tab, mit dessen Aussehen, ohne
   Projektbezug und ohne Weg zurueck. Beas Darkmode-Meldung dazu war das
   Symptom, der Bruch im Versprechen die Ursache.

   Breiter als das Termin-Modal: eine A4-Seite bei 440 px ist unlesbar. Und
   `--modal-breit` statt einer Zahl im Markup, damit die Vorschau auf dem
   Telefon dieselbe Regel benutzt wie am Schreibtisch. */
.modal--breit { width: min(960px, calc(100vw - 24px)); }
/* Bestaetigungsfenster (Stefan 18.09.2026): schmal, Text, zwei Knoepfe rechts.
   Liegt ueber allen anderen Modals — es fragt nach, waehrend eines offen sein
   kann (z.B. Loeschen aus der Dokumentvorschau). */
.modal--confirm { width: min(420px, calc(100vw - 32px)); z-index: 951; }
#bb-confirm-backdrop { z-index: 950; }
.bb-confirm-text { font-size: 14px; line-height: 1.5; color: var(--text); margin: 0 0 16px; white-space: pre-line; }
.bb-confirm-aktionen { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
.bb-confirm-aktionen .btn { min-height: 44px; min-width: 96px; }
/* Der Cookie-Hinweis liegt auf Ebene 99999 und damit ueber JEDEM Fenster —
   absichtlich, er ist selbst ein Dialog. Gemessen am 23.08.2026: der Fuss der
   Vorschau („Herunterladen") lag dahinter, und `is_visible()` meldete
   trotzdem „sichtbar", weil Playwright Ueberdeckung nicht prueft. Erst im Bild
   zu sehen. Statt an den Ebenen zu drehen, weicht das Fenster aus — dasselbe
   Mittel, mit dem die Seite schon den Seitenfuss freihaelt
   (`body.bb-cookie-open .main-content`). Gilt nur, solange der Hinweis offen
   ist, also beim Erstbesuch. */
body.bb-cookie-open .modal--breit { max-height: calc(100vh - 160px); }
.dokvorschau {
  /* Hoehe fest, nicht nach Inhalt: ein iframe ohne Hoehe ist 150 px hoch
     (HTML-Vorgabe) — die Seite waere da, aber nicht zu lesen. */
  width: 100%; height: min(72vh, 800px); border: 0; border-radius: 8px;
  background: var(--surface2);
}
.dokvorschau-bild {
  display: block; max-width: 100%; max-height: min(72vh, 800px);
  margin: 0 auto; border-radius: 8px;
}
.dokvorschau-fuss {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 12px;
}
.dokvorschau-fuss .text-muted { margin-right: auto; font-size: 14px; }
@media (max-width: 640px) {
  /* Auf dem Telefon ist ein zentriertes Fenster mit Rand verschenkter Platz:
     die Vorschau nimmt den Bildschirm.

     Spaltenfluss statt gerechneter Hoehe: der erste Entwurf gab dem Bild
     `calc(100vh - 190px)`. Im Bild vom 23.08. war zu sehen, dass der Fuss mit
     „Herunterladen" dabei unter den Rand rutschte — und genau der ist auf dem
     Telefon der Notausgang, wenn Safari ein PDF nicht einbettet. Jede solche
     Rechnung raet, was ausser dem Bild noch Platz braucht (Kopfzeile,
     Cookie-Hinweis, Browserleiste); der Fluss muss es nicht raten.
     `dvh` statt `vh`, weil `vh` auf dem Telefon die eingeklappte Adressleiste
     mitzaehlt und die Seite dann um deren Hoehe zu hoch ist.
     Kein `display`-Wechsel fuer die Sichtbarkeit — die bleibt bei
     opacity/visibility (R4). */
  .modal--breit {
    width: 100vw; height: 100dvh; max-height: 100dvh; top: 0; left: 0;
    transform: none; border-radius: 0;
    display: flex; flex-direction: column;
  }
  .modal--breit.offen { transform: none; }
  body.bb-cookie-open .modal--breit {
    height: calc(100dvh - 160px); max-height: calc(100dvh - 160px);
  }
  .modal--breit .modal-body {
    flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
  }
  .modal--breit .modal-body > div:first-child {
    flex: 1 1 auto; min-height: 0; overflow: auto;
    /* Ein Bild im Hochformat liesse sonst die ganze Restflaeche unter sich leer
       und klebte oben am Kopf. Zentriert steht es da, wo man hinsieht. */
    display: flex; align-items: center; justify-content: center;
  }
  .modal--breit .dokvorschau-fuss { flex: 0 0 auto; }
  .dokvorschau { height: 100%; max-height: none; }
  .dokvorschau-bild { max-height: 100%; }
}
.termin-datum { font-size: 14px; color: var(--text-muted); margin-bottom: 4px; font-weight: 500; }
.termin-notiz {
  font-size: 14px; color: var(--text-muted);
  background: var(--surface2); padding: 8px 12px;
  border-radius: var(--radius); margin: 8px 0;
}
.termin-by { font-size: 12px; color: var(--text-faint); }
.termin-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.termin-info-box {
  background: var(--surface2);
  border-radius: var(--radius); padding: 16px 16px;
  margin-bottom: 24px; font-size: 14px; color: var(--text);
}

/* ─── Upload Zone ────────────────────────────────────────────────────────── */
.upload-zone {
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface2);
  padding: 32px 24px;
  text-align: center;
  cursor: pointer;
  transition: var(--t3) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
  margin-bottom: 12px;
  position: relative;
}
.upload-zone:hover, .upload-zone.dragover {
  border-color: var(--primary);
  background: var(--orange-bg);
  box-shadow: 0 0 0 4px var(--orange-bg);
}
.upload-zone.hat-dateien { border-style: solid; border-color: var(--primary); }
.upload-zone-inner { pointer-events: none; }
.upload-zone-icon { font-size: 34px; margin-bottom: 12px; opacity: 0.7; }
.upload-zone-text { font-size: 16px; color: var(--text-muted); margin-bottom: 8px; }
/* --primary-text statt --primary (25.08.2026): als Schrift auf --surface2
   erreichte die Flaechenfarbe nur 2.97:1. Die Textvariante steht seit dem
   16.08. im System — sie war an dieser Stelle nur nicht benutzt. */
.upload-zone-link { color: var(--primary-text); font-weight: 600; }
.upload-zone-hint { font-size: 12px; color: var(--text-faint); }
.upload-preview {
  display: flex; flex-wrap: wrap; gap: 12px;
  justify-content: center; margin-top: 16px;
}
.upload-preview-item {
  position: relative;
  width: 80px;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.upload-preview-img {
  width: 72px; height: 72px; object-fit: cover;
  border-radius: 8px;
}
.upload-preview-icon {
  width: 72px; height: 72px;
  border-radius: 8px;
  background: var(--surface3);
  display: flex; align-items: center; justify-content: center;
  font-size: 27px;
}
.upload-preview-name {
  font-size: 12px; color: var(--text-muted);
  text-align: center; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; width: 72px;
}
.upload-preview-remove {
  position: absolute; top: -6px; right: -6px;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--danger); color: white;
  border: none; cursor: pointer;
  font-size: 12px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
  line-height: 1;
}
.upload-buttons {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 12px; flex-wrap: wrap;
}
.upload-oder { font-size: 12px; color: var(--text-faint); }
.upload-optionen {
  background: var(--orange-bg);
  border-radius: var(--radius-lg); padding: 16px;
  margin-bottom: 24px; animation: fadeIn var(--t3) var(--kurve);
}
.upload-optionen-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.upload-optionen-row .form-group { flex: 1; min-width: 140px; margin-bottom: 0; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: translateY(0); } }

/* ─── Dokumente ──────────────────────────────────────────────────────────── */
.upload-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.upload-submit { flex-shrink: 0; }
.dokument-liste { display: flex; flex-direction: column; gap: 8px; }
.dokument-item {
  background: var(--surface);
  border-radius: var(--radius-lg); padding: 16px 16px;
  display: flex; justify-content: space-between; align-items: center;
  /* `wrap`, damit der Aufklappblock der Versionen als dritte, volle Zeile IN
     der Karte liegt — und mit ihr gefiltert wird, statt als Nachbar zu
     verwaisen, wenn die Karte ausgeblendet ist. */
  flex-wrap: wrap;
  gap: 16px; transition: background-color var(--t3) var(--kurve);
}
.dokument-item:hover { background: var(--surface3); }
.dokument-info { display: flex; align-items: center; gap: 16px; flex: 1; min-width: 0; }
/* Die Kachel traegt die Art (Block F, 19.09.2026): 36 px wie das Symbol der
   HERO-Leiste, Farbe aus `--kind-*`. Ohne `data-kind` bleibt sie neutral. */
.dokument-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 12px; flex-shrink: 0;
  font-size: 20px; background: var(--surface3); color: var(--text-muted);
}
.dokument-icon[data-kind="angebot"]              { background: var(--kind-angebot-bg);              color: var(--kind-angebot); }
.dokument-icon[data-kind="auftragsbestaetigung"] { background: var(--kind-auftragsbestaetigung-bg); color: var(--kind-auftragsbestaetigung); }
.dokument-icon[data-kind="rechnung"]             { background: var(--kind-rechnung-bg);             color: var(--kind-rechnung); }
.dokument-icon[data-kind="aufmass"]              { background: var(--kind-aufmass-bg);              color: var(--kind-aufmass); }
.dokument-icon[data-kind="bericht"]              { background: var(--kind-bericht-bg);              color: var(--kind-bericht); }
.dokument-icon[data-kind="plan"]                 { background: var(--kind-plan-bg);                 color: var(--kind-plan); }
.dokument-icon[data-kind="gewaehrleistung"]      { background: var(--kind-gewaehrleistung-bg);      color: var(--kind-gewaehrleistung); }
.dokument-icon[data-kind="foto"]                 { background: var(--kind-foto-bg);                 color: var(--kind-foto); }
.dokument-icon[data-kind="bedienungsanleitung"]  { background: var(--kind-bedienungsanleitung-bg);  color: var(--kind-bedienungsanleitung); }
.dokument-icon[data-kind="sonstige"]             { background: var(--kind-sonstige-bg);             color: var(--kind-sonstige); }
/* Versionen aufklappen (Block F). Der Knopf sieht aus wie ein Link in der
   Metazeile; der Block liegt als volle Zeile unter Info und Aktionen. */
.dok-versionen-toggle {
  background: none; border: 0; padding: 0; font: inherit; font-size: 14px;
  color: var(--primary-text, var(--primary)); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
  /* Trefferflaeche 44 px (Apple HIG, Geraetetest 10.10.2026: 69x24), die
     Metazeile bleibt optisch gleich hoch — der negative Rand nimmt die
     zusaetzliche Hoehe wieder aus dem Zeilenfluss. Ober- und unterhalb liegt
     nichts Klickbares, die Flaeche ueberlappt also keinen anderen Knopf. */
  display: inline-flex; align-items: center;
  min-height: 44px; margin-block: -10px;
}
.dok-versionen-toggle:hover, .dok-versionen-toggle:focus-visible { color: var(--text); }
.dokument-versionen {
  flex-basis: 100%; margin: 0 -4px -4px;
  background: var(--surface2); border-radius: 8px; padding: 4px 8px;
  display: flex; flex-direction: column; gap: 2px;
}
/* Die Autorenregel oben setzt `display:flex` und wuerde die Browserregel fuer
   `hidden` ueberstimmen — der Block staende dann immer offen (Zweitmeinung). */
.dokument-versionen[hidden] { display: none; }
.dokument-versionen:not([hidden]) { animation: dokVersionenEin var(--t2) var(--kurve); }
@keyframes dokVersionenEin { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .dokument-versionen:not([hidden]) { animation: none; } }
.dokument-version {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 8px 8px 44px; font-size: 14px; color: var(--text-muted);
}
.dokument-version-name { flex: 1; min-width: 0; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dokument-version-betrag { font-variant-numeric: tabular-nums; white-space: nowrap; }
.dokument-version .btn { min-height: 28px; }
/* Schmal: der Name bekommt die ganze Breite und darf umbrechen — sonst wird
   „Rechnung Abschlag 1" zu „Rechnun…", waehrend Nummer und Betrag Platz haben
   (Bildbefund iPhone 15, 19.09.2026). */
@media (max-width: 560px) {
  .dokument-version { padding-left: 8px; }
  .dokument-version-name { flex-basis: 100%; white-space: normal; order: -1; }
}
.dokument-name { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.dokument-meta { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; align-items: center;
                 font-size: 14px; }
/* Groesse, Datum und Hochlader standen nach dem Emoji-Ausbau als drei
   gleichrangige Textbrocken nebeneinander ("14.1 MB 14.06.2026 von Holger").
   Ein Mittelpunkt zwischen den TEXT-Angaben trennt sie wieder — die Pillen
   davor tragen ihre Grenze selbst und bekommen keinen. */
.dokument-meta .text-muted + .text-muted::before {
  content: '·'; color: var(--text-faint); margin-right: 8px;
}
.dokument-actions { display: flex; gap: 8px; flex-shrink: 0; }
/* Dokument-Kategorien: gleiche eckige Form wie .badge/.marke. Die Kategorie
   traegt der TEXT — drei Sonderfarben (blau/gelb/violett) neben dem
   Marken-Orange waren drei zusaetzliche Bedeutungstraeger ohne Bedeutung. */
.tag {
  font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em;
  padding: 2px 8px; border-radius: 6px;
  background: var(--surface3); color: var(--text-muted);
}

/* ─── Beteiligte ─────────────────────────────────────────────────────────── */
.beteiligte-liste { display: flex; flex-direction: column; gap: 8px; margin-bottom: 32px; }
.beteiligter-item {
  background: var(--surface);
  border-radius: var(--radius-lg); padding: 16px 16px;
  display: flex; align-items: center; gap: 16px;
}
.beteiligter-avatar {
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary); display: flex; align-items: center; justify-content: center;
  font-family: 'Archivo', sans-serif;
  font-weight: 700; font-size: 16px; flex-shrink: 0;
}
.beteiligter-info { flex: 1; min-width: 0; }
/* Mail und Telefon im Design statt im Browser-Blau (Beas Befund 11.08.) */
.beteiligter-meta a { color: var(--text-muted); text-decoration: none; }
.beteiligter-meta a:hover { color: var(--text); text-decoration: underline; }
/* Badges + Aktionsknöpfe rechts in der Beteiligten-Zeile. flex-wrap, weil die
   Leiste seit dem Gewerk-Haken (Bea 06.08.) bis zu vier Elemente trägt — als
   starre Zeile schob sie die Seite auf dem Handy auf 858px Breite. */
.beteiligter-aktionen {
  display: flex; align-items: center; gap: 8px;
  flex-wrap: wrap; justify-content: flex-end;
}
/* Setzt die nicht umkehrbare Aktion sichtbar von den harmlosen ab. */
.aktionen-trenner {
  width: 1px; align-self: stretch; margin: 0 2px;
  background: var(--border-strong);
}
.btn-entfernen:hover { border-color: var(--alarm); color: var(--danger-text); }
@media (max-width: 720px) {
  /* Auf dem Handy unter die Info-Spalte rutschen statt daneben quetschen:
     die Karte wird zur Spalte, die Aktionsleiste bricht linksbündig um. */
  .beteiligter-item { flex-wrap: wrap; }
  .beteiligter-aktionen { flex-basis: 100%; justify-content: flex-start; }
}
.beteiligter-name { font-weight: 600; font-size: 16px; color: var(--text); }
/* Kontaktangaben als Tippziele (24.08.2026, R24).
   Gemessen: die E-Mail-Links im Reiter Beteiligte waren 15 px hoch — mit dem
   Daumen nicht zuverlaessig zu treffen, und Bea testet auf dem iPhone. Der
   Pruefer hatte diesen Reiter vorher nie angesehen (display:none).

   Nur auf Geraeten, die mit dem Finger bedient werden: mit der Maus ist ein
   15 px hoher Textlink kein Problem, und auf dem Desktop soll die Zeile eine
   Zeile bleiben. Aus der Aufzaehlung wird darunter eine Liste — deshalb
   verschwinden die Trennpunkte.

   ⚠️ Die Grenze war zuerst `max-width: 767px` — das iPad ist genau 768 px breit
   und fiel damit heraus; der Geraetepruefer meldete die drei Links dort weiter
   (in beiden Engines). Ein iPad wird mit dem Finger bedient, gehoert also
   dazu. `pointer: coarse` waere die inhaltlich richtige Frage, ist im Pruefer
   aber nicht verlaesslich emuliert — deshalb die Breite, mit dem iPad drin.

   29.10.2026 (Domi: „Funktionen, die nicht Tablet oder iPad erkennen"): die
   Breite allein reichte nicht. Heutige iPads sind 820–1024 px breit, ein
   Android-Tablet 1280 — dort blieben die Links 15 px hoch (gemessen, beide
   Engines). Und das „nicht verlaesslich emuliert" war ein Messfehler:
   Chromium verliert die Touch-Emulation nach einem Ganzseitenbild, vorher
   meldet es `pointer: coarse` korrekt. Deshalb jetzt beides. */
@media (max-width: 768px), (pointer: coarse) {
  .beteiligter-kontakt { display: flex; flex-direction: column; align-items: flex-start; }
  .beteiligter-kontakt .meta-trenner { display: none; }
  .beteiligter-kontakt a {
    display: inline-flex; align-items: center;
    min-height: 44px; min-width: 44px;
  }
}
.beteiligter-meta { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }
/* ─── Kommentare am Mangel (Stefan 18.09.2026) ───────────────────────────
   Gleiche Form wie die Aufgaben-Rueckmeldung: es ist dieselbe Sache an einem
   anderen Objekt, und zwei Gestaltungen dafuer waeren nur Laerm. */
.mangel-kommentare { border-top: 1px solid var(--border); padding-top: .4rem; }
.mangel-kommentar {
  border-left: 2px solid var(--border-strong);
  padding: .3rem 0 .3rem .75rem; margin: .4rem 0;
}
.mangel-kommentar-kopf { font-size: 12px; color: var(--text-muted); }
.mangel-kommentar-text { font-size: 14px; white-space: pre-wrap; margin-top: 2px; }
.mangel-kommentar-form {
  display: flex; gap: .5rem; align-items: center;
  flex-wrap: wrap; margin-top: .5rem;
}
.mangel-kommentar-form input[type="text"] { flex: 1 1 200px; min-width: 0; }
@media (max-width: 720px) {
  /* flex-basis wirkt in der Spalte auf die HOEHE — dieselbe Falle wie bei der
     Aufgaben-Rueckmeldung, dort am 19.09.2026 mit 200 px gemessen. */
  .mangel-kommentar-form { flex-direction: column; align-items: stretch; }
  .mangel-kommentar-form input[type="text"] { flex: 0 0 auto; }
}

/* ─── Rueckmeldungen an einer Aufgabe (Nico 18.09.2026) ──────────────────
   Eingerueckt und mit linker Kante: der Block gehoert sichtbar ZU der Karte
   darueber und ist keine zweite Liste. */
.aufgabe-rueckmeldungen { border-top: 1px solid var(--border); padding-top: .5rem; }
.aufgabe-notiz {
  border-left: 2px solid var(--border-strong);
  padding: .4rem 0 .4rem .75rem; margin: .5rem 0;
}
.aufgabe-notiz-kopf { font-size: 12px; color: var(--text-muted); }
.aufgabe-notiz-text { font-size: 14px; white-space: pre-wrap; margin-top: 2px; }
.aufgabe-notiz-bild {
  max-width: 180px; max-height: 180px; border-radius: 8px;
  margin-top: .4rem; display: block; object-fit: cover;
}
.aufgabe-notiz-form { margin-top: .6rem; }
/* Auf dem Telefon untereinander: nebeneinander quetschte der Dateiknopf den
   Absenden-Knopf unter 44 px Breite (Apple HIG, R24). */
.aufgabe-notiz-zeile {
  display: flex; gap: .5rem; align-items: center;
  flex-wrap: wrap; margin-top: .4rem;
}
.aufgabe-notiz-zeile input[type="file"] { flex: 1 1 200px; min-width: 0; }
@media (max-width: 720px) {
  .aufgabe-notiz-zeile { flex-direction: column; align-items: stretch; }
  /* ⚠️ `flex-basis` wirkt auf die HAUPTACHSE — in der Spalte ist das die
     Hoehe. Mit dem geerbten `flex: 1 1 200px` war der Dateiknopf auf dem
     iPhone 200 px hoch (gemessen 19.09.2026: 252 px Zeile gegen 40 px am
     Desktop). Im Bild sah es aus wie ein leerer Kasten; die Zahl hat gesagt,
     woher er kam. */
  .aufgabe-notiz-zeile input[type="file"] { flex: 0 0 auto; }
}

/* ─── Kontakte aus dem angebundenen System (19.09.2026) ──────────────────
   Bewusst ANDERS als `.beteiligter-item`: gestrichelter Rahmen statt gefuellter
   Karte, kein Avatar. Der Unterschied „Konto / kein Konto" darf nicht nur im
   Hinweistext stehen — wer die Seite ueberfliegt, liest Form, nicht Prosa. */
.fremdkontakte { margin-bottom: 32px; }
.fremdkontakte-titel { font-size: 16px; font-weight: 700; margin-bottom: .35rem; }
.fremdkontakte-hinweis {
  font-size: 14px; color: var(--text-muted); margin-bottom: .9rem;
  max-width: 60ch;
}
.fremdkontakte-gruppe { margin-bottom: 16px; }
.fremdkontakte-art {
  font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 8px;
}
.fremdkontakt-item {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg); padding: 12px 16px;
  display: flex; align-items: center; gap: 16px;
  margin-bottom: 8px;
}
@media (max-width: 720px) {
  .fremdkontakt-item { flex-wrap: wrap; }
}
/* Einladbarer Kontakt (Bea 07.10.2026): Hover leuchtet orange, Klick laedt ein. */
.fremdkontakt-item--einladbar { cursor: pointer; transition: border-color var(--t2) var(--kurve), box-shadow var(--t2) var(--kurve), background var(--t2) var(--kurve); }
.fremdkontakt-item--einladbar:hover,
.fremdkontakt-item--einladbar:focus-within {
  border-color: var(--primary); border-style: solid;
  box-shadow: 0 0 0 1px var(--primary), 0 0 14px rgba(217,119,6,0.35);
  background: var(--orange-bg);
}
.fremdkontakt-einladen { border: 0; cursor: pointer; font: inherit; font-size: 12px; white-space: nowrap; }
.fremdkontakt-item--einladbar:hover .fremdkontakt-einladen,
.fremdkontakt-einladen:focus-visible { background: var(--primary); color: var(--on-primary); }
.fremd-dialog {
  border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  background: var(--surface); color: var(--text); padding: 24px;
  width: min(480px, calc(100vw - 32px)); margin: auto;
}
.fremd-dialog::backdrop { background: var(--scrim); }
.fremd-dialog h3 { margin-bottom: 8px; }
.fremd-dialog-bekannt { font-size: 14px; color: var(--text-muted); margin-bottom: 16px; }
.fremd-dialog-bekannt:empty { display: none; }
.fremd-dialog .form-group { margin-bottom: 12px; }
.fremd-luecke { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(217,119,6,0.35); }
.fremd-fehlt { color: var(--primary-text, var(--primary)); }
.fremd-dialog-knoepfe { display: flex; gap: 12px; justify-content: flex-end; margin-top: 16px; }
.einladen-form {
  background: var(--orange-bg);
  border-radius: var(--radius-lg); padding: 24px;
}
.einladen-form h3 { font-size: 16px; font-weight: 700; margin-bottom: 16px; color: var(--text); }
.einladen-row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
/* Nico 18.09.2026: „die felder sind gross genug, der inhalt kann nicht gesehen
   werden." In der Zeile standen acht Felder; die zwei Auswahlfelder bekamen mit
   `flex:1` halb so viel Platz wie die Textfelder und zeigten „Part ▾" statt
   „Partner-Gewerk" (im Vorher-Bild belegt). Ein Auswahlfeld, dessen Inhalt man
   nicht lesen kann, ist eine Rateaufgabe.
   `min-width` statt eines groesseren `flex`: die Breite haengt damit am Inhalt
   und nicht daran, wie viele Felder gerade danebenstehen — das gilt auch nach
   Beas geplantem Ausduennen der Zeile weiter. Der Umbruch (`flex-wrap`) faengt
   schmale Fenster ab, statt die Felder wieder zu quetschen. */
.einladen-row select.form-select { min-width: 11.5rem; }
.einladen-submit { flex-shrink: 0; }

/* ─── Empty State ─────────────────────────────────────────────────────────────
   Bea 11.08.2026: „für alle seiten bitte auch dieses fette ‚noch kein xyz'
   viiiiel kleiner machen. es soll selbst mit meiner bildschirmgröße alles auf
   eine seite passen wenn möglich." Vorher: 72 px Polster oben UND unten, ein
   52-px-Zeichen und eine 19-px-Zeile — zusammen rund 240 px fuer die Aussage
   „hier ist noch nichts". Auf ihrem Bild schob das die eigentliche Eingabe
   unter die Bildschirmkante. Jetzt rund 130 px; die Schriftgroessen bleiben
   Stufen der 7er-Skala (15 statt 19), das Zeichen ist Dekor und faellt frei. */
.empty-state { text-align: center; padding: 36px 24px; }
.empty-icon { font-size: 32px; margin-bottom: 12px; opacity: 0.5; }
.empty-state h2 { font-size: 16px; font-weight: 700; margin-bottom: 8px; color: var(--text); }
.empty-state p { color: var(--text-muted); font-size: 14px; margin-bottom: 16px; max-width: 340px; margin-left: auto; margin-right: auto; }

/* ─── Mobile ─────────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
  .login-split { grid-template-columns: 1fr; min-height: auto; margin: -32px -20px 0; }
  .login-brand-side { padding: 40px 24px; }
  .login-brand-title { font-size: 27px; }
  .login-form-side { padding: 36px 24px; }
  .login-form-inner { max-width: 100%; }

  /* Doku-Vorlagen-Editor (Nico N12): Split weicht einem Bearbeiten/Vorschau-Umschalter. */
  .vorlage-view-switch { display: flex; }
  .vorlage-split { display: block; }
  .vorlage-pane-vorschau { position: static; margin-bottom: 16px; }
  .vorlage-pane { display: none; }
  .vorlage-pane.active { display: block; }
  /* Auf dem Telefon bleibt A4, nur die Hoehenschranke ist kleiner. */
  .vorlage-papier-frame { width: min(100%, calc(65dvh * 210 / 297)); }
  .vorlage-papier.a4-skaliert { width: min(100%, calc(65dvh * 210 / 297)); }
  .vorlage-papier.a4-skaliert .vorlage-papier-frame { width: 210mm; }
  .dok-textblock { padding-left: 0; }
  /* Farbfeld an der ganzen Leiste (sticky = Bezug) statt am Knopf — sonst ragt
     es auf dem Handy rechts aus dem Bild. */
  .dok-farbe-wrap { position: static; }
  .dok-farbe-feld { left: 8px; right: 8px; width: auto; }
}
@media (max-width: 640px) {
  .navbar { padding: 0 16px; }
  /* "by Bibertron"-Pille raus: Brand + rechte Buttons sprengen sonst die navbar
     auf schmalen Handys (<390px) → horizontaler Overflow bis 26px (task_fe8ae104) */
  .brand-sub { display: none; }
  /* Bottom-Padding großzügiger als Desktop (80px): das fixierte Cookie-Banner
     umbricht auf schmalen Screens auf ~190px Höhe (Text + Button untereinander)
     und blockte sonst auf kurzen Seiten den letzten Button per Klick (N12-Fund 22.07.,
     Doku-Editor „Vorlage speichern" hinter dem Banner). */
  .main-content { padding: 24px 16px 200px; }
  .projekt-header { flex-direction: column; }
  .projekt-header-right { align-items: flex-start; flex-direction: row; flex-wrap: wrap; }
  .form-row { grid-template-columns: 1fr; }
  .upload-row, .einladen-row { flex-direction: column; }
  .upload-row .form-group, .einladen-row .form-group { flex: unset !important; width: 100%; }
  .dokument-item { flex-direction: column; align-items: flex-start; }
  /* Schmal: doch scrollen — und sichtbar machen, DASS man scrollen kann.
     Zwei Ebenen: die Abdeckung in Flaechenfarbe ist an den INHALT geheftet
     (local) und wandert mit ihm, der Schatten klebt am sichtbaren Rand
     (scroll). Ist man ganz rechts, schiebt sich die Abdeckung ueber den
     Schatten und er verschwindet von selbst — ohne JS und ohne dauerhaft
     sichtbare Scrollleiste (auf Touch-Geraeten gibt es die ohnehin nicht). */
  .tabs {
    flex-wrap: nowrap; overflow-x: auto; gap: 2px;
    background-image:
      linear-gradient(to left, var(--surface), var(--surface)),
      linear-gradient(to left, rgba(0,0,0,.38), transparent);
    background-position: right center, right center;
    background-size: 20px 100%, 34px 100%;
    background-repeat: no-repeat;
    background-attachment: local, scroll;
  }
  .tab { padding: 8px 12px; font-size: 14px; }
  .feed-item { max-width: 92%; }
  .card, .karte { padding: 24px; }
  .hero { padding: 32px 24px; }
  .hero-title { font-size: 27px; }
}

/* ─── Dropdowns ──────────────────────────────────────────────────────────── */
.dropdown { position: relative; display: inline-block; }
.dropdown-toggle { display: inline-flex; align-items: center; gap: 4px; }
/* Schwebende Menues trennen sich per Erhebung (shadow-lg) und einer eine Spur
   helleren Flaeche — noetig, weil sie oft ueber gleichfarbigen Karten stehen. */
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); left: 0;
  background: var(--overlay);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  min-width: 180px; z-index: 500;
  overflow: hidden;
  opacity: 0; transform: translateY(-6px) scale(0.97);
  pointer-events: none;
  /* `visibility: hidden` zusaetzlich zu opacity (15.08.2026): opacity und
     pointer-events nehmen ein Element NICHT aus der Tab-Reihenfolge. Ohne die
     Zeile wandert man mit TAB durch ein geschlossenes Menue, das man nicht
     sieht, und Screenreader lesen es vor. Gemessen mit
     ~/.claude/tools/fokusfallen_pruefer.py: 10 unsichtbar erreichbare
     Bedienelemente je Seite, darunter „Abmelden".
     Die Ausblende-Animation bleibt: `visibility` steht mit Verzoegerung (--t2)
     in der Liste und springt erst am Ende um, das Menue verschwindet also nicht
     schlagartig; `.offen` setzt die Verzoegerung auf 0 (sofort sichtbar). */
  visibility: hidden;
  transition: opacity var(--t2) var(--kurve), transform var(--t2) var(--kurve),
              visibility 0s linear var(--t2);
}
.dropdown-menu.offen {
  opacity: 1; transform: translateY(0) scale(1);
  transition-delay: 0s;
  pointer-events: all;
  visibility: visible;
}
.dropdown-left .dropdown-menu { left: auto; right: 0; }
.dropdown-item {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 16px; font-size: 14px; font-weight: 500;
  color: var(--text-muted); text-decoration: none;
  background: none; border: none; width: 100%;
  cursor: pointer; font-family: 'IBM Plex Sans', sans-serif;
  transition: var(--t1) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
}
.dropdown-item:hover { background: var(--hover); color: var(--text); }
.dropdown-item-success { color: var(--primary); }
.dropdown-item-success:hover { background: var(--orange-bg); color: var(--primary-light); }
.dropdown-item-danger { color: var(--danger-text); }
.dropdown-item-danger:hover { background: var(--bad-bg); color: var(--danger-text); }
.dropdown-divider { height: 1px; background: var(--border); margin: 4px 0; }

/* ─── Navbar User Dropdown ───────────────────────────────────────────────── */
.nav-dropdown { position: relative; }
.nav-dropdown-btn {
  display: flex; align-items: center; gap: 8px;
  background: var(--hover);
  border: none;
  border-radius: 8px; padding: 8px 12px;
  color: rgba(255,255,255,0.7); cursor: pointer;
  transition: var(--t2) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity; font-family: 'IBM Plex Sans', sans-serif;
}
.nav-dropdown-btn:hover { background: var(--hover); color: white; }
[data-theme="light"] .nav-dropdown-btn { background: var(--hover); color: rgba(0,0,0,0.6); }
[data-theme="light"] .nav-dropdown-btn:hover { background: rgba(0,0,0,0.09); color: var(--text); }
.nav-user-avatar {
  width: 24px; height: 24px; border-radius: 50%;
  background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
  color: #0a0a0a; display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600; flex-shrink: 0;
}
.nav-dropdown-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  background: var(--overlay);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  min-width: 220px; z-index: 500; overflow: hidden;
  opacity: 0; transform: translateY(-6px) scale(0.97);
  pointer-events: none;
  visibility: hidden;                  /* siehe .dropdown-menu — Tab-Falle */
  transition: opacity var(--t2) var(--kurve), transform var(--t2) var(--kurve),
              visibility 0s linear var(--t2);
}
.nav-dropdown-menu.offen { opacity: 1; transform: translateY(0) scale(1);
                           pointer-events: all; visibility: visible; transition-delay: 0s; }
.nav-dropdown-header { padding: 16px 16px; }
.nav-dropdown-name { font-size: 14px; font-weight: 600; color: var(--text); }
.nav-dropdown-email { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.nav-dropdown-divider { height: 1px; background: var(--border); }

/* ─── Toast Benachrichtigungen ───────────────────────────────────────────── */
/* z-index ueber dem Cookie-Hinweis (99999): beim ersten Besuch lag der Toast
   sonst dahinter (gemessen 11.10.2026); den Abstand nach unten setzt
   zeigeToast(), solange der Hinweis offen ist. */
#toast-container {
  position: fixed; bottom: 24px; right: 24px;
  display: flex; flex-direction: column; gap: 12px;
  z-index: 100000; pointer-events: none;
}
.toast-nachricht {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 8px 12px 16px; border-radius: var(--radius-lg);
  font-size: 14px; font-weight: 500;
  background: var(--overlay);
  box-shadow: var(--shadow-lg);
  opacity: 0; transform: translateY(10px) scale(0.97);
  /* Ausgang schneller als Eingang; nur opacity/transform, nie `all`. */
  transition: opacity var(--t2) var(--kurve), transform var(--t2) var(--kurve);
  pointer-events: all; max-width: 360px;
  color: var(--text);
}
.toast-nachricht.sichtbar {
  opacity: 1; transform: translateY(0) scale(1);
  transition: opacity var(--t3) var(--kurve), transform var(--t3) var(--kurve);
}
.toast-symbol { font-weight: 600; }
.toast-text { flex: 1; }
/* Tippziel 44x44 (Apple HIG, R24) — sichtbar bleibt nur das kleine Kreuz. */
.toast-zu {
  flex: none; width: 44px; height: 44px; margin: -10px -4px -10px 0;
  border: 0; background: none; color: inherit; opacity: .65;
  font-size: 20px; line-height: 1; cursor: pointer; border-radius: var(--radius-md, 8px);
}
.toast-zu:hover, .toast-zu:focus-visible { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .toast-nachricht, .toast-nachricht.sichtbar { transform: none; }
}
/* Getoente Toasts: die Toenung liegt UEBER der Overlay-Flaeche (zwei
   Hintergruende), damit sie auch im Hellmodus deckend bleibt. */
.toast-success { background: linear-gradient(var(--orange-bg), var(--orange-bg)) var(--overlay); color: var(--primary-light); }
.toast-error   { background: linear-gradient(var(--bad-bg), var(--bad-bg)) var(--overlay);  color: var(--danger-text); }
.toast-warning { background: linear-gradient(var(--orange-bg), var(--orange-bg)) var(--overlay); color: var(--warning); }
.toast-info    { background: linear-gradient(var(--info-bg), var(--info-bg)) var(--overlay); color: var(--info-text); }

/* ─── Tooltips ───────────────────────────────────────────────────────────── */
.tooltip-box {
  position: absolute; z-index: 9999;
  background: var(--overlay); color: var(--text);
  border-radius: 6px;
  padding: 4px 12px; font-size: 12px; font-weight: 500;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity var(--t2) var(--kurve);
  box-shadow: var(--shadow);
}
.tooltip-box.sichtbar { opacity: 1; }

/* ─── Dark-Mode Button ───────────────────────────────────────────────────── */
#darkmode-btn {
  background: var(--hover);
  border: none;
  color: rgba(255,255,255,0.6);
  border-radius: 8px; padding: 8px 12px;
  cursor: pointer; transition: var(--t2) var(--kurve); transition-property: background-color, border-color, color, box-shadow, transform, opacity;
  display: flex; align-items: center;
  font-size: 14px;
}
#darkmode-btn:hover {
  background: var(--hover);
  color: rgba(255,255,255,0.9);
}
[data-theme="light"] #darkmode-btn {
  background: var(--hover);
  color: rgba(0,0,0,0.6);
}
[data-theme="light"] #darkmode-btn:hover { background: rgba(0,0,0,0.1); color: rgba(0,0,0,0.9); }

/* ─── Formular Fehlerstatus ──────────────────────────────────────────────── */
.feld-fehler { border-color: var(--danger) !important; box-shadow: 0 0 0 3px var(--bad-bg) !important; }

/* ─── Preisseite: Karten stapeln auf schmalen Screens (Baukasten ① 24.07.) ─── */
.bb-preise-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
@media (max-width: 640px) { .bb-preise-grid { grid-template-columns: 1fr; } }

/* ─── Preisseite: EIN Monats-Abo + 5-€-Zusatz-Hinweis + 1-€-Trial (Beas Modell 24.07.) ─── */
/* overflow-x nachgetragen 29.07.2026: Der Lichtschein unten ist fest 460px breit
   und mittig gesetzt. Bei 390px Fensterbreite ragte er 49px ueber jeden Rand, und
   die Preisseite liess sich auf dem iPhone seitlich schieben (425px statt 390).
   Sichtbar war davon nichts — der Verlauf ist am Rand laengst durchsichtig; kaputt
   war nur das Wischverhalten. Genau deshalb faellt so etwas beim Ansehen nie auf.

   `clip` statt `hidden`: `hidden` wuerde auch senkrecht beschneiden und damit die
   bb-reveal-Einblendungen der Kinder anschneiden. In Safari vor 16 kennt niemand
   `clip`; dort bleibt es beim heutigen Verhalten, wird also nicht schlechter. */
/* Drei Karten brauchen Breite. Alles, was KEINE Karte ist (Kopf, Statusband,
   Leistungen, Hinweise, Testphase), bleibt auf Lesespaltenbreite — sonst zieht
   sich ein Fliesstext ueber 1080 px und wird unlesbar. */
.bb-preise { position: relative; max-width: 1080px; margin: 0 auto; padding: 2.25rem 1rem 4rem;
  overflow-x: clip; }
.bb-status, .bb-unterkarten, .bb-trial, .bb-preise__trust {
  max-width: 620px; margin-inline: auto; }
.bb-preise::before {                    /* orange Atmosphäre hinter dem Abo */
  content: ""; position: absolute; top: 130px; left: 50%; width: 460px; height: 460px;
  transform: translateX(-50%);
  background: radial-gradient(circle, var(--primary-glow), transparent 68%);
  pointer-events: none; z-index: 0;
}
.bb-preise > * { position: relative; z-index: 1; }

.bb-preise__head { text-align: center; margin-bottom: 1.6rem; }
.bb-preise__title { font-size: clamp(1.7rem, 4.5vw, 2.3rem); font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.6rem; }
/* Ungebunden an die 620px-Kopfbreite (anders als frueher): Beas Mockup zeigt
   den Titel einzeilig ueber die volle Breite, nur die Unterzeile ist schmaler
   gefasst. Bei 620px brach der Titel in zwei Zeilen um — Vergleich mit dem
   Mockup am 17.09.2026 gemessen (81px Titelhoehe statt 53px). */
.bb-preise__sub { color: var(--text-muted); font-size: 16px; max-width: 480px;
  margin: 0 auto; }
.bb-preise__demo { margin-top: .75rem; background: var(--primary-glow); color: var(--text);
  border-radius: var(--radius); padding: .5rem .9rem; font-size: 14px; }

.bb-abo {
  background: var(--surface); border-radius: var(--radius-xl);
  padding: 2.4rem 2rem 2rem; text-align: center; position: relative; overflow: hidden;
  box-shadow: 0 24px 60px -24px rgba(0,0,0,0.7);
}
.bb-abo::before {                       /* feiner oranger Akzent oben */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, transparent, var(--primary), transparent);
}
.bb-abo__label { display: inline-block; font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--primary-text); margin-bottom: 1rem; }
/* Betrag und Währungszeichen wachsen GEMEINSAM (12.08.2026): das € stand fest
   auf 27px, während der Betrag per clamp auf bis zu 74px ging — es klebte
   unten am Betrag und las sich zusammen mit dem grauen „/ Monat" als
   „80 e / Monat". Jetzt 0.42 der Betragsgröße, also derselbe clamp mal 0.42.
   Der schmale Abstand bleibt: im Deutschen steht zwischen Zahl und € eines. */
.bb-abo__price { display: flex; align-items: baseline; justify-content: center; gap: 0.12em; line-height: 1; }
.bb-abo__amount { font-size: clamp(3.4rem, 12vw, 4.6rem); font-weight: 900; color: var(--primary); letter-spacing: -0.03em; }
.bb-abo__cur { font-size: clamp(2.1rem, 7.4vw, 2.85rem); font-weight: 600; color: var(--primary); }
.bb-abo__per { font-size: 16px; font-weight: 600; color: var(--text-muted); margin-left: 0.3em; }
.bb-abo__quota { color: var(--text); font-size: 16px; margin: 0.5rem 0 1.6rem; }
.bb-abo__features { list-style: none; text-align: left; display: flex; flex-direction: column; gap: 0.7rem; margin: 0 auto 1.8rem; max-width: 340px; padding: 0; }
.bb-abo__features li { position: relative; padding-left: 1.7rem; color: var(--text); font-size: 16px; }
.bb-abo__features li::before { content: "✓"; position: absolute; left: 0; top: -1px; color: var(--primary); font-weight: 600; }
.bb-abo__cta { width: 100%; max-width: 340px; font-size: 16px; padding: 12px 24px; }

/* ── Preiskarten (Beas Mockup, 01.09.2026) ─────────────────────────────────
   Nur Marken-Token, keine Farbe aus dem Mockup: das ist dunkel-only und braechte
   ein zweites Orange mit. `--primary-text` ist bereits themenabhaengig (hell
   #9c4708), deshalb tragen die Preiszahlen es und nicht `--primary` — auf
   hellem Grund kaeme das Marken-Orange sonst auf 3,1:1. */
.bb-karten {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem;
  align-items: stretch; margin-bottom: 1.5rem;
}
.bb-karte {
  position: relative; display: flex; flex-direction: column; text-align: center;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 1.9rem 1.4rem 1.5rem;
  /* Der Rahmen wechselt bei der hervorgehobenen Karte die Farbe. Ohne
     `transition` springt er beim Themenwechsel hart um. Unter 300 ms und mit
     eigener Kurve — ein Standard-ease wirkt hier traege. */
  transition: border-color var(--t2) var(--kurve), transform var(--t2) var(--kurve);
}
.bb-karte--hervor { border-color: var(--primary); background: var(--primary-glow); }
/* Weg B (18.09.2026): `--hervor` ist der STATUS „gebuchter Tarif", `--gewaehlt`
   die AUSWAHL des Kunden. Vorher trug eine Optik beide Bedeutungen, und die
   Empfehlung („Meistgewählt") las sich als getroffene Wahl. */
.bb-karten[role="radiogroup"] .bb-karte { cursor: pointer; }
.bb-karten[role="radiogroup"] .bb-karte:hover { border-color: var(--primary); transform: translateY(-2px); }
.bb-karte--gewaehlt {
  border-color: var(--primary);
  background: var(--primary-glow);
  box-shadow: 0 0 0 2px var(--primary);
}
/* Das Haekchen sagt „diese ist gewaehlt" auch dort, wo der Rahmen allein zu
   leise waere — kleine Bildschirme, wenig Kontrast, Farbsehschwaeche. */
.bb-karte--gewaehlt::after {
  content: "\2713";
  position: absolute; top: .75rem; right: .9rem;
  width: 1.5rem; height: 1.5rem; line-height: 1.5rem; text-align: center;
  border-radius: 50%; background: var(--primary); color: #fff;
  font-size: 14px; font-weight: 600;
}
.bb-karte:focus-visible { outline: 3px solid var(--primary); outline-offset: 3px; }
.bb-karten-fuss { display: flex; justify-content: center; margin-top: 1.5rem; }
.bb-weiter { text-align: center; }
.bb-weiter__cta { min-width: 16rem; }
.bb-weiter__fein { margin-top: .6rem; font-size: 14px; color: var(--text-muted); }
/* Die Marke sitzt AUF dem Rahmen, nicht darueber: `top:-0.72rem` plus eigener
   Grund, damit die Linie darunter nicht durchscheint. */
.bb-karte__marke {
  position: absolute; top: -0.72rem; left: 50%; transform: translateX(-50%);
  background: var(--primary); color: var(--on-primary);
  font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 12px; border-radius: 999px; white-space: nowrap;
}
.bb-karte__name {
  color: var(--text-muted); font-size: 12px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; margin-bottom: .8rem;
}
.bb-karte__preis { display: flex; align-items: baseline; justify-content: center; line-height: 1; }
.bb-karte__zahl { font-size: clamp(2.4rem, 5vw, 3rem); font-weight: 900;
  color: var(--primary-text); letter-spacing: -.03em; }
.bb-karte__cur { font-size: 20px; font-weight: 600; color: var(--primary-text);
  margin-left: .12em; align-self: flex-start; margin-top: .35em; }
.bb-karte__einheit { color: var(--text-muted); font-size: 14px; margin: .55rem 0 1.1rem; }
.bb-karte__linie { border-top: 1px solid var(--border); margin-bottom: 1.1rem; }
.bb-karte__limit { font-size: 14px; color: var(--text); margin-bottom: 1.3rem; }
/* `margin-top:auto` schiebt den Knopf ans Kartenende — sonst stehen die drei
   Knoepfe auf verschiedenen Hoehen, sobald ein Limittext umbricht. */
.bb-karte__form { margin-top: auto; }
.bb-karte__cta { width: 100%; font-size: 14px; padding: 12px 16px; min-height: 44px; }
.bb-karte__cta[disabled] { opacity: .55; cursor: default; }

.bb-karten__hinweis { text-align: center; color: var(--text-muted); font-size: 14px;
  line-height: 1.6; margin: 0 0 1.6rem; }
.bb-leistungen { background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 1.2rem 1.4rem; margin-bottom: 1rem; }
.bb-leistungen__titel { font-size: 12px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: .9rem; }
.bb-leistungen .bb-abo__features { margin-bottom: 0; max-width: none; }
/* `.bb-addon` ist auf 340 px gebaut (es sass frueher IN der schmalen Abo-Karte).
   Unter den Karten steht es neben dem 620 px breiten Leistungskasten und sah
   damit ausgefranst aus — im Bild sofort zu sehen, im Code nicht. */
.bb-unterkarten .bb-addon { max-width: none; }

@media (max-width: 860px) {
  .bb-karten { grid-template-columns: 1fr; gap: 1.6rem; }
  /* Einspaltig sitzt die Marke der zweiten und dritten Karte sonst auf dem
     Rand der Karte darueber. */
  .bb-karte { padding-top: 2rem; }
}

.bb-addon {
  display: flex; align-items: flex-start; gap: 0.6rem; text-align: left;
  margin: 1.4rem auto 0; max-width: 340px; padding: 0.8rem 0.9rem;
  background: var(--surface2); border-radius: var(--radius);
  color: var(--text-muted); font-size: 14px; line-height: 1.45;
}
.bb-addon strong { color: var(--text); }
.bb-addon__plus { color: var(--primary); font-weight: 600; font-size: 16px; line-height: 1.3; }

.bb-trial {
  display: flex; align-items: center; justify-content: space-between; gap: 1.2rem; flex-wrap: wrap;
  margin-top: 1.4rem; padding: 1.3rem 1.5rem;
  background: linear-gradient(180deg, var(--surface2), var(--surface));
  border: 1px solid var(--primary); border-radius: var(--radius-lg);
}
.bb-trial__eyebrow { font-weight: 600; color: var(--text); font-size: 16px; margin-bottom: 0.15rem; }
.bb-trial__line { color: var(--text-muted); font-size: 16px; line-height: 1.45; }
.bb-trial__line strong { color: var(--primary-text); }
.bb-trial__fine { display: block; color: var(--text-faint); font-size: 14px; margin-top: 0.15rem; }
.bb-trial__cta { white-space: nowrap; border-color: var(--primary); color: var(--primary-text); }
.bb-trial__cta:hover { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }

.bb-preise__trust { text-align: center; color: var(--text-muted); font-size: 14px; margin-top: 1.8rem; }

@media (max-width: 560px) {
  .bb-trial { flex-direction: column; align-items: stretch; text-align: center; }
  .bb-trial__cta { width: 100%; }
}

/* Eingangs-Animation beim Laden — ease-out, kurz, gestaffelt; respektiert reduced-motion */
@keyframes bbRevealUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
.bb-reveal-up { animation: bbRevealUp var(--t3) var(--kurve) both; }
@media (prefers-reduced-motion: reduce) { .bb-reveal-up { animation: none; } }

/* Cookie-Banner (fixed) verdeckt sonst den Seitenfuß — Platz schaffen solange er offen ist */
body.bb-cookie-open .main-content { padding-bottom: 160px; }


/* ─── Dunkelmodus-Schutz: heller Container braucht dunklen Text ──────────────
   Gemeldet von Bea (26.07.2026): „Container/Karten rendern weiß im Darkmode,
   Text unlesbar." Ursache gemessen: Container mit fest hellem Hintergrund erben
   die globale Textfarbe --text, die im dunklen Standard #f0f0f0 ist.
   Ergebnis weiß auf weiß — Kontrast 1,14 (lesbar wären >= 4,5).

   Diese Regel greift auch bei Inline-Styles in Templates, die kein CSS-Token
   nutzen — also auch bei künftigen. Sauberer wäre, jede Stelle auf Tokens
   umzustellen; das ist Teil von Beas Design-Baukasten und kommt dort. */
.vorlage-papier,
[style*="background:#fff"],  [style*="background: #fff"],
[style*="background:white"], [style*="background: white"],
[style*="background:#f8f9fa"], [style*="background: #f8f9fa"] {
  color: #111111;
}

/* ─── Navigations-Dropdown: Einträge waren ungestylt ────────────────────────
   Gemessen 26.07.2026 (Beas Meldung „Text unlesbar"): .nav-dropdown-item wird in
   base.html für „Alle Projekte", „Alle Mängel", „Vorlagen", „Profil", „Abmelden"
   verwendet, war im CSS aber NIE definiert. Ohne Textfarbe rendert der Browser
   sein Standard-Linkblau #0000EE — auf dem dunklen Menü Kontrast 1,85 (nötig 4,5).
   Betraf jede Seite, weil die Navigation global ist. */
.nav-dropdown-item {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  transition: background var(--t2) var(--kurve), color var(--t2) var(--kurve);
}
.nav-dropdown-item:hover,
.nav-dropdown-item:focus-visible {
  background: var(--hover);
  color: var(--primary-light);
}
/* Abmelden ist seit dem 08.08. ein POST-Formular (CSRF-Schutz) — der Knopf darin
   muss aussehen wie die <a>-Menuepunkte daneben, sonst faellt er optisch heraus. */
.nav-dropdown-form { margin: 0; }
.nav-dropdown-form button.nav-dropdown-item {
  width: 100%;
  background: none;
  border: none;
  /* NUR die Schriftfamilie erben. Ein `font: inherit` wuerde auch die Groesse
     setzen und damit die 14px von .nav-dropdown-item ueberschreiben — gemessen
     08.08.: der Knopf kam auf 14,5px und stand sichtbar aus der Liste heraus. */
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.nav-dropdown-item.nav-dropdown-item-danger { color: var(--danger-text); }
.nav-dropdown-item.nav-dropdown-item-danger:hover { background: var(--bad-bg); color: var(--danger-text); }
[data-theme="light"] .nav-dropdown-item:hover,
[data-theme="light"] .nav-dropdown-item:focus-visible { background: var(--hover); color: var(--primary-dark); }

/* ─── Tippziele auf dem Telefon (Apple HIG 44×44pt) ───────────────────────
   Gemessen 29.07.2026 mit ~/.claude/tools/geraete_pruefer.py: 43 Bedienelemente
   der Weboberfläche lagen bei 21–36px Höhe (.btn hat 9px Polsterung und keine
   Mindesthöhe, .btn-sm 6px, .btn-xs 3px). Bea arbeitet am iPhone — dort trifft
   der Daumen das nicht zuverlässig.

   Die Mobil-App unter app_frontend/ macht es längst richtig und kennt dafür
   --touch-min: 44px. Diese Datei hatte die Konvention nie übernommen; hier wird
   sie nachgezogen, mit demselben Namen, damit es eine Wahrheit bleibt.

   Nur klickbare .pill: dieselbe Klasse dient auch als Status-Kennzeichen
   („Offen", „Erledigt"), und ein Etikett braucht keine Tippfläche.
   Am großen Bildschirm mit Maus ändert sich nichts.                          */
:root { --touch-min: 44px; }
/* Bea 27.10.2026 (Schalter knopf_rolle, Klasse am <body> aus
   utils/ansicht.knopf_groesse): Knopfgroesse nach Rolle, in App und Web
   gleich. Alle Rollen ausser Monteur 40 px wie die PL-App, Monteur
   Handschuh-Groesse 48 px — und das auch am Desktop (Regel nach dem
   Media-Block). Ohne Schalter keine Klasse: alles wie oben. */
body.knopf-normal { --touch-min: 40px; }
body.knopf-monteur { --touch-min: 48px; }
body.knopf-monteur :is(.btn, .btn-sm, .btn-xs, a.pill, button.pill, .tab, .nav-dropdown-btn,
  .form-input, .form-select, select, button, [role=button],
  input:not([type=checkbox], [type=radio], [type=hidden], [type=file], [type=range])) {
  min-height: var(--touch-min);
}
body.knopf-monteur :is(.btn, .btn-sm, .btn-xs, .nav-dropdown-btn, button, [role=button]) {
  min-width: var(--touch-min);
}
@media (max-width: 768px), (pointer: coarse) {
  .btn, .btn-sm, .btn-xs,
  a.pill, button.pill,
  .nav-dropdown-item, .nav-dropdown-btn,
  /* Diese beiden hängen ihre Maße inline im Basis-Template und tragen keine
     Klasse — über die ID erwischt man sie trotzdem. */
  #darkmode-btn, #bbCookieAccept {
    min-height: var(--touch-min);
  }
  #darkmode-btn, .nav-dropdown-btn { min-width: var(--touch-min); }
  /* Nachtrag 25.08.2026 (BB-Fehlerdurchgang): Icon-Knoepfe ohne Text (✕ am
     Bautagebuch-Foto, ⋯-Menues, +/-Zeile) waren 31–32px breit — die
     min-height-Regel oben machte sie hoch genug, aber nicht breit genug.
     min-width trifft nur sie: Textknoepfe sind laengst breiter als 44px. */
  .btn, .btn-sm, .btn-xs { min-width: var(--touch-min); }

  /* Nachtrag 29.07.2026, zweiter Geraetelauf. Die Regel oben deckte Knoepfe und
     Chips ab — drei Gruppen fehlten, und ausgerechnet die meistbenutzten:

     .tab (37px) ist die Projekt-Navigation. Zwoelf Reiter, jeder Weg im Projekt
     fuehrt darueber; das war das groesste verbliebene Loch.
     .form-input/.form-select (39px) betrifft jedes Formular der Weboberflaeche,
     auch das Einladen-Formular, das ich am selben Tag erweitert habe.
     .ueb-row-titel/.ueb-projekt-chip (23-24px) sind reine Textlinks in den
     Uebersichtslisten. Die Zeile ringsum ist NICHT klickbar (.ueb-row ist ein
     Kasten, kein Link) — der Titel ist also die einzige Trefferflaeche.

     inline-flex statt bloss min-height: an einem inline-Element bleibt eine
     Mindesthoehe wirkungslos. */
  .tab,
  .form-input, .form-select, select.form-input {
    min-height: var(--touch-min);
  }
  .ueb-row-titel, .ueb-projekt-chip {
    display: inline-flex; align-items: center; min-height: var(--touch-min);
  }
  /* Dritter Lauf: Kopfzeile, Zurueck-Link und die Kreis-Auswahl im Feed. Die
     nav-dropdown-Eintraege lagen bei 43px — die Regel oben griff, das Ergebnis
     blieb ein Pixel darunter (Polsterung + Zeilenhoehe runden ab). Eine
     Mindesthoehe, die um einen Pixel verfehlt wird, ist keine Mindesthoehe. */
  .nav-link, .navbar-brand, .back-link, .kreis-chip {
    min-height: var(--touch-min);
    display: inline-flex; align-items: center;
  }
  /* Glocke (29.10.2026): ihre feste Breite von 34 px wurde nur in der
     Telefon-Regel (max-width 760px) auf 44 gesetzt. iPad und Android-Tablet
     sind breiter und blieben bei 34x44 — gemessen, beide Engines. */
  .nav-glocke { width: var(--touch-min); height: var(--touch-min); }
  .nav-glocke-punkt { top: 10px; right: 11px; }

  /* Fuenfter Lauf, 14.08.2026: die Chatraum-Reiter. Sie bekamen ihre 44 px
     bisher NUR aus der 640-px-Regel weiter oben (Zeile ~1068) — ein iPad hat
     768 px und ist trotzdem ein Tippgeraet. Gemessen: 44 px bis 600 px Breite,
     danach 25 px, und zwar auf iPad in Chromium UND WebKit.
     Dieselbe Luecke wie beim Nachtrag vom 29.07.: die Raeume kamen am 12.08.
     dazu, die Liste hier wurde nicht mitgezogen. Neue Bedienelemente gehoeren
     in BEIDE Regeln — die Breitenregel allein deckt Tablets nicht ab. */
  .raum-reiter { min-height: var(--touch-min); }
  .nav-dropdown-item { min-height: calc(var(--touch-min) + 2px); }

  /* Fusszeile: eigenstaendiger Verweis, kein Satzbestandteil — hier gilt die
     Tippflaeche. */
  footer a[href] { display: inline-flex; align-items: center; min-height: var(--touch-min); }

  /* Links MITTEN IM FLIESSTEXT (01.08.2026, vierter Geraetelauf: „Meine Firma"
     in den Einstellungen, 77x16 px in WebKit).

     Hier stand frueher, solche Links muessten klein bleiben, weil eine
     Mindesthoehe die Zeile auseinanderreisst. Das stimmt fuer `min-height` —
     aber nicht fuer vertikales Padding: an einem `display:inline`-Element
     vergroessert Padding die Trefferflaeche, OHNE die Zeilenbox zu veraendern.
     Derselbe Irrtum stand am 01.08. im Webseitenbau-Werkzeug und wurde dort
     widerlegt (Learning #153: „geht nicht" war eine Aussage ueber die Technik,
     keine ueber die Sache).

     14 px oben und unten machen aus 16 px Texthoehe 44 px Trefferhoehe. Bewusst
     nur auf `.fliesstext-link` und nicht auf jedes a im Absatz: bei mehreren
     Links direkt untereinander wuerden sich die Flaechen ueberlappen, und dann
     trifft der Daumen den falschen. */
  a.fliesstext-link { padding: 16px 0; }

  /* Rechtstext-Links (Impressum/Datenschutz/Barrierefreiheit): gleiche Technik.
     Geraetelauf 10.08.: 17px-Trefferhoehe auf allen schmalen Breiten — die
     einzigen verbliebenen Tippziel-Befunde der Weboberflaeche. */
  .rechtstext a { padding: 16px 0; }
}

/* Anerkannte Behinderung am Balken (Beas „Verzug in den Bauzeitenplan", 29.07.2026).
   Nur ein Zeichen im Balken — der Klartext samt Grund und Zeitraum steht in der
   Titelspalte, wo Platz dafuer ist. Im Balken selbst waere ein Text bei kurzen
   Vorgaengen sofort abgeschnitten. */
.bzp-behindert { position:absolute; right:4px; top:50%; transform:translateY(-50%);
  z-index:2; width:16px; height:16px; border-radius:50%;
  background:var(--danger); color:#fff; font-size: 12px; font-weight:600;
  line-height:16px; text-align:center; }

/* ── Preis-Staffel (30.07.2026) ──────────────────────────────────────────────
   Beas Modell ist eine Staffel, nicht ein Preis. Die Tabelle steht bewusst
   unter dem grossen Preis und nicht daneben: auf dem Telefon (390 px) waeren
   vier Karten nebeneinander entweder unlesbar klein oder wuerden seitlich
   wegrutschen — der Fehler, der am 29.07. auf der WSB-Preisseite auftrat. */
/* ── Statusband des Bestandskunden (Bea 11.08.2026) ─────────────────────────
   Die Preisseite war reine Akquise: derselbe Anblick fuer den Besucher wie fuer
   den, der seit Monaten zahlt. Das Band steht deshalb VOR der Verkaufskarte und
   beantwortet zuerst seine zwei Fragen — was habe ich, und wie viel ist weg.
   Flaechentoene ueber Variablen, damit der Hellmodus nicht nachgezogen werden
   muss (die Landing hatte genau daran zwei Wochen lang 1.02:1). */
.bb-status { text-align: left; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 1.1rem 1.25rem; margin-bottom: 1.25rem; }
.bb-status__zeile { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.bb-status__label { font-size: 14px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: .2rem; }
.bb-status__tarif { font-size: 24px; font-weight: 600; letter-spacing: -.01em;
  display: flex; align-items: center; gap: .5rem; }
.bb-status__preis { font-size: 24px; font-weight: 600; color: var(--primary-text); white-space: nowrap; }
.bb-status__per { font-size: 14px; font-weight: 600; color: var(--text-muted); margin-left: .3em; }
.bb-status__quota { margin-top: .9rem; }
.bb-status__quota-text { font-size: 16px; color: var(--text); line-height: 1.45; }
/* Pro-Code einloesen (Gutscheine Typ B, 06.10.2026) — wie das Feld auf der
   Bestellseite: Eingabe dehnt sich, Knopf behaelt 44 px (R24). */
.bb-status__gutschein label { display: block; font-weight: 600; margin-bottom: .4rem; }
.bb-status__gutschein-zeile { display: flex; gap: 12px; }
.bb-status__gutschein-zeile .form-input { flex: 1; min-width: 0; text-transform: uppercase; letter-spacing: .04em; }
.bb-status__gutschein-zeile .btn { flex-shrink: 0; min-height: 44px; }
/* Projekte dazubuchen (Bea 15.10.2026). Tippziele 44 px (R24); Zahlenfeld ohne
   Pfeile, weil Plus/Minus daneben stehen. */
.bb-zusatz__form { margin-top: .7rem; }
.bb-zusatz__zeile { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.bb-zusatz__stepper { display: flex; align-items: center; gap: 8px; }
.bb-zusatz__stepper .btn { min-width: 44px; min-height: 44px; padding: 0; }
.bb-zusatz__stepper .form-input { width: 4.2rem; min-height: 44px; text-align: center; font-weight: 600; -moz-appearance: textfield; appearance: textfield; }
.bb-zusatz__stepper .form-input::-webkit-outer-spin-button,
.bb-zusatz__stepper .form-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.bb-zusatz__summe { text-align: right; font-size: 16px; line-height: 1.35; }
.bb-zusatz__knopf { width: 100%; min-height: 44px; margin-top: .8rem; }
.bb-zusatz__stand { margin-top: .8rem; font-size: 14px; }
.bb-zusatz__dialog { position: fixed; inset: 0; margin: auto; height: fit-content; max-width: 26rem; width: calc(100% - 2rem); border: 0.5px solid var(--border, #ccc); border-radius: 12px; padding: 1.2rem; background: var(--surface, #fff); color: inherit; }
.bb-zusatz__dialog::backdrop { background: var(--scrim); }
.bb-zusatz__titel { margin: 0 0 .6rem; font-size: 20px; }
.bb-zusatz__rechnung { margin: 0 0 .6rem; line-height: 1.5; }
.bb-zusatz__hinweis { margin: 0 0 1rem; font-size: 14px; opacity: .85; }
.bb-zusatz__aktionen { display: flex; justify-content: space-between; gap: 12px; }
.bb-zusatz__aktionen .btn { min-height: 44px; }
/* Links im Abo-Kasten (Kuendigungsweg, 21.08.2026): style.css hat KEINE globale
   `a`-Regel — jeder Link braucht seine Farbe selbst. Ohne diese Zeile zeichnete
   der Browser den Kuendigungslink im Standard-Blauviolett, mitten im dunklen
   Orange-Thema. Farbe ist --primary-text, nicht --primary: das Markenorange
   traegt als Text nur 3,8:1 (16.08.2026). Nur im Bild aufgefallen. */
.bb-status__quota-text a,
.bb-addon a,
.bb-status__warn a { color: var(--primary-text); text-decoration: underline; }
/* Tippziel nach Apple HIG (R24), gemessen 23.08.2026 mit tools/geraete_pruefer.py:
   diese drei Links auf der Preisseite waren 17-38 px hoch — auf iPhone SE, 15,
   iPad, in Chromium UND WebKit. Es sind die Wege zum Dazubuchen, zum
   Kuendigen und zur Enterprise-Anfrage: also genau die drei, auf die es
   ankommt. `inline-flex` statt `padding`, weil ein senkrechtes Padding auf
   einem Inline-Link die Trefferflaeche zwar vergroessert, die gemessene
   Elementhoehe aber nicht — der Pruefer haette weiter gemeldet, und er hat
   recht: der Browser vergroessert die Zeilenhoehe dadurch nicht. */
.bb-status__quota-text a,
.bb-addon a,
.bb-status__warn a {
  /* `inline-block` mit senkrechtem Polster, NICHT inline-flex: flex macht aus
     `<strong>7 €</strong> dazubuchen` zwei Flex-Elemente und schluckt dabei das
     Leerzeichen dazwischen — im Bild stand „Zusatzprojekt 7 €dazubuchen", und
     die Enterprise-Zeile brach an falscher Stelle um. Beides erst im
     Vorher/Nachher-Vergleich zu sehen (R26), im Geraetetest war es „sauber".
     Dieselbe Loesung wie `.rechtstext a` weiter unten: 14 px Polster bringen
     die 17 px Textzeile ueber die 44 px des Apple-HIG. */
  display: inline-block; padding: 16px 0;
}
/* Der Balken ist Beiwerk zur Zahl. 8 px hoch statt duenner Linie, damit er auf
   dem Telefon ueberhaupt ablesbar ist. */
.bb-status__bar { margin-top: .55rem; height: 8px; border-radius: 50px; overflow: hidden;
  background: var(--border); }
.bb-status__bar span { display: block; height: 100%; border-radius: 50px; background: var(--primary);
  transition: width var(--t3) var(--kurve); }
.bb-status__bar span.is-voll { background: var(--danger, var(--danger-text)); }
.bb-status__warn { margin-top: .8rem; font-size: 16px; line-height: 1.45; color: var(--text);
  background: var(--primary-glow); border-radius: var(--radius); padding: .6rem .8rem; }
@media (max-width: 480px) {
  .bb-status__zeile { flex-direction: column; gap: .4rem; }
}

.bb-staffel { margin: 1.25rem 0 1rem; text-align: left; }
.bb-staffel__titel { font-size: 16px; font-weight: 600; margin-bottom: .5rem; color: var(--text-muted); }
.bb-staffel__tabelle { width: 100%; border-collapse: collapse; font-size: 16px; }
.bb-staffel__tabelle th { text-align: left; font-weight: 600; color: var(--text-muted);
  font-size: 14px; text-transform: uppercase; letter-spacing: .03em; padding: .35rem .5rem; }
.bb-staffel__tabelle td { padding: .5rem; border-top: 1px solid var(--border); }
.bb-staffel__tabelle tr.bb-staffel__aktiv td { background: var(--orange-bg); font-weight: 600; }
.bb-staffel__tabelle tr.bb-staffel__aktiv td:first-child { border-left: 3px solid var(--primary); }
.bb-staffel__hinweis { font-size: 14px; color: var(--text-muted); margin-top: .5rem; }

/* Auf schmalen Geraeten wird aus der Staffel-Tabelle eine Liste.
   Gefunden am 30.07.2026 im Bild, nicht in der Messung: bei 375 px passten drei
   Spalten nicht nebeneinander, "Projekte / Monat" brach um und die PREIS-Spalte
   lag ausserhalb des sichtbaren Bereichs — ausgerechnet die Zahl, wegen der die
   Seite existiert. Der Ueberlauf-Test blieb gruen, weil das Dokument nicht
   breiter wurde; gequetscht wurde innerhalb der Karte. */
@media (max-width: 480px) {
  .bb-staffel__tabelle thead { display: none; }
  .bb-staffel__tabelle tr { display: block; border-top: 1px solid var(--border); padding: .35rem 0; }
  .bb-staffel__tabelle td { display: inline-block; border: 0; padding: .15rem .5rem .15rem 0; }
  .bb-staffel__tabelle td:first-child { display: block; padding-right: 0; }
  .bb-staffel__tabelle td:nth-child(2)::before { content: 'Projekte: '; color: var(--text-muted); }
  /* Zeichen direkt, kein CSS-Escape: 'U+00B7' wurde vom Browser als NUL + "b7"
     gelesen und erschien als Ersatzzeichen im Bild. */
  .bb-staffel__tabelle td:nth-child(3)::before { content: '· '; color: var(--text-muted); }
  /* Die Desktop-Kante sitzt auf td:first-child und galt mobil weiter — neben
     der Zeilen-Kante stand dadurch ein ZWEITER oranger Strich direkt am
     Radio-Knopf. Mobil traegt nur noch die Zeile die Kante. */
  .bb-staffel__tabelle tr.bb-staffel__aktiv td { background: none; }
  .bb-staffel__tabelle tr.bb-staffel__aktiv td:first-child { border-left: 0; }
  /* .5rem reichte nicht: der Radio-Knopf der Pro-Zeile stand direkt an der
     orangenen Kante und wurde von ihr angeschnitten, waehrend Starter und
     Premium volle Kreise zeigten (UX-Durchsicht 12.08.). Alle drei Zeilen
     bekommen jetzt denselben linken Einzug — die aktive traegt dort ihre
     Kante, die anderen einen unsichtbaren Platzhalter, damit nichts springt. */
  .bb-staffel__tabelle tr { border-left: 3px solid transparent; padding-left: .9rem; }
  .bb-staffel__tabelle tr.bb-staffel__aktiv { background: var(--orange-bg);
    border-left-color: var(--primary); }
}

/* ─── Rechtstext-Seiten (Impressum · Datenschutz · Barrierefreiheit) ────────
   Links standen hier in der Browser-Standardfarbe: dunkles Blau auf #0f0f0f.
   Im Dunkelmodus war die Kontakt-E-Mail des Impressums dadurch praktisch
   unlesbar — auf einer Seite, die es rechtlich gerade nicht sein darf
   (§ 5 DDG verlangt „leicht erkennbar"). Gefunden am 01.08.2026 im Screenshot,
   nicht im Test: die Route antwortete die ganze Zeit sauber mit 200.
   --primary-text ist die fuer Schrift gepruefte Orange-Variante und hat je
   Modus einen eigenen Ton (dunkel #d97706, hell #b45309). */
.rechtstext a { color: var(--primary-text); text-decoration: underline; }
.rechtstext a:hover { color: var(--primary-light); }
/* Kontaktseite (Bea 19.10.2026): der Link zur Datenschutzerklaerung war im
   Browser-Standard (lila nach dem Besuch). Gleiche Farbe wie die Rechtstexte. */
.kontakt-intro a, .kontakt-intro a:visited { color: var(--primary-text); text-decoration: underline; }
.kontakt-intro a:hover { color: var(--primary-light); }

/* ═══ Projektliste nach Prototyp "Daten fuellen die Flaeche" (12.08.2026) ═══
   Freigegeben von Domi + Bea als Standard-Design. Quelle:
   ~/Documents/CraftFox-Dokumente/bb-prototyp-projektliste/. Der Sprung kommt
   aus Struktur und Datendichte, nicht aus Kontrast: Text bleibt #f0f0f0 auf
   #0f0f0f (Beas Auflage 07.08. — kein hartes Weiss auf Schwarz). */

/* Die Tageslage: was der Bauleiter morgens wissen muss — steht VOR den
   Karten, nicht in ihnen. */
.lagezeile {
  display: flex; gap: 32px; flex-wrap: wrap;
  padding: 16px 0 24px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--border);
}
.lagezeile__punkt { display: flex; align-items: baseline; gap: 8px; }
.lagezeile__zahl {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 27px;
  letter-spacing: -0.02em; line-height: 1; color: var(--text);
}
.lagezeile__punkt--alarm .lagezeile__zahl { color: var(--alarm); }
.lagezeile__punkt--warn  .lagezeile__zahl { color: var(--primary-light); }
[data-theme="light"] .lagezeile__punkt--warn .lagezeile__zahl { color: var(--primary-text); }
.lagezeile__label { font-size: 14px; color: var(--text-muted); }

/* Werkzeugzeile: Filter-Chips + Primaeraktion. flex-wrap, weil bei 375 px der
   Knopf sonst neben drei Chips steht und die Seite aufschiebt (Geraetetest). */
/* Suchfeld und Primäraktion auf EINER Linie (Bea 24.08.2026, 14:11).
   `flex-wrap` ist hier die eigentliche Arbeit: auf dem Telefon soll das Suchfeld
   die volle Breite behalten und der Knopf darunter rutschen, statt sich beide
   auf 390 px zu teilen. */
.projekt-suchzeile { display: flex; gap: 12px; align-items: center;
  flex-wrap: wrap; margin-bottom: 1rem; }
.projekt-suchzeile #projekt-suche { flex: 1 1 240px; max-width: 380px; }
.projekt-suchzeile .btn { margin-left: 0; }
.projekt-suchzeile .btn-primary { margin-left: auto; }
@media (max-width: 640px) {
  /* Umgebrochen ist „margin-left:auto" sinnlos und schoebe den Knopf nach rechts
     an den Rand, statt ihn wie die Karten links beginnen zu lassen. */
  .projekt-suchzeile #projekt-suche { flex: 1 1 100%; max-width: none; }
  .projekt-suchzeile .btn-primary { margin-left: 0; }
}
.werkzeuge { display: flex; gap: 12px; align-items: center; margin-bottom: 24px;
             flex-wrap: wrap; }
.projekt-aktionen { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 1rem; }
.sortierung { display: inline-flex; align-items: center; gap: 8px; margin-left: auto;
              font-size: 14px; color: var(--text-muted); }
.sortierung span { white-space: nowrap; }
.sortierung select { width: auto; min-height: 44px; border-radius: 999px; padding-left: 16px; padding-right: 36px; }
@media (max-width: 640px) { .sortierung { margin-left: 0; flex: 1 1 100%; } .sortierung select { flex: 1; } }
.chip {
  font-family: 'Archivo', sans-serif; font-size: 14px; font-weight: 500;
  color: var(--text-muted); background: none; border: 0;
  padding: 8px 16px; border-radius: 8px; cursor: pointer;
  min-height: 44px;              /* Apple HIG Tippziel */
  transition: background var(--tempo) var(--kurve), color var(--tempo) var(--kurve);
}
.chip:hover { background: var(--surface); color: var(--text); }
.chip--an, .chip.active { background: var(--surface3); color: var(--text); }

/* Drei Spalten, nicht vier: die Karte traegt einen Zeitstrahl, der Breite
   braucht. align-items:start — Karten ohne Plan duerfen kuerzer sein. */
.projekt-gitter {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;
  align-items: start;
}
@media (max-width: 1100px) { .projekt-gitter { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px)  { .projekt-gitter { grid-template-columns: 1fr; } }

.projekt-karte {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 24px 24px 16px;
  display: flex; flex-direction: column;
  outline: none; text-decoration: none; color: var(--text);
  transition: background var(--tempo) var(--kurve),
              transform var(--tempo) var(--kurve);
}
.projekt-karte:hover     { background: var(--surface3); transform: translateY(-2px); }
.projekt-karte:focus-visible { box-shadow: 0 0 0 2px var(--primary-light); }

/* Verzug schreit nicht mit einer Farbflaeche, sondern markiert mit einer
   Kante links — sie liest sich als Registerreiter, nicht als Fehlermeldung. */
.projekt-karte--alarm { box-shadow: inset 3px 0 0 var(--alarm); }
.projekt-karte--alarm:focus-visible { box-shadow: inset 3px 0 0 var(--alarm), 0 0 0 2px var(--primary-light); }

.projekt-karte__kopf { margin-bottom: 16px; }
.marke {
  display: inline-block; font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 6px; margin-bottom: 12px;
}
.marke--in_arbeit, .marke--aktiv { background: var(--hover); color: var(--text-muted); }
.marke--vorbereitet   { background: var(--hover); color: var(--text-faint); }
.marke--mangelbehebung{ background: var(--orange-bg);   color: var(--primary-light); }
.marke--abgeschlossen { background: var(--hover); color: var(--text-faint); }
[data-theme="light"] .marke--in_arbeit, [data-theme="light"] .marke--aktiv { background: var(--hover); color: var(--text-muted); }
[data-theme="light"] .marke--vorbereitet, [data-theme="light"] .marke--abgeschlossen { background: var(--hover); color: var(--text-faint); }
[data-theme="light"] .marke--mangelbehebung { background: var(--orange-bg); color: var(--primary-text); }

.projekt-karte__titel {
  font-family: 'Archivo', sans-serif;
  font-size: 20px; font-weight: 700; letter-spacing: -0.018em; line-height: 1.25;
  color: var(--text);
}
.projekt-karte__ort { font-size: 14px; color: var(--text-faint); margin-top: 4px; }

/* ── Zeitstrahl: jeder Vorgang ein Segment auf der echten Zeitachse, die
   Heute-Linie schneidet hindurch. ── */
.strahl { margin-bottom: 16px; }
.strahl__spur {
  position: relative; height: 26px;
  background: var(--hover); border-radius: 6px;
  /* KEIN overflow:hidden — der Meilenstein am Bauende sitzt auf 100 % und
     wuerde sonst halbiert; das las sich als "kleiner als". */
}
[data-theme="light"] .strahl__spur { background: var(--hover); }
/* Verstrichene Bauzeit als ruhige Unterlegung — traegt die Aussage "wie weit
   sind wir zeitlich" auch, wenn einzelne Vorgaenge zu schmal sind. */
.gewesen {
  position: absolute; inset: 0 auto 0 0;
  background: var(--hover);
  border-radius: 5px 0 0 5px;
}
[data-theme="light"] .gewesen { background: var(--hover); }
.seg {
  position: absolute; top: 5px; height: 16px; border-radius: 3px;
  background: var(--fertig);
}
.seg--fertig      { background: var(--fertig); }
/* Die Zukunft bleibt bewusst leise: was zaehlt, ist wo wir HEUTE stehen. */
.seg--offen       { background: var(--hover); }
[data-theme="light"] .seg--offen { background: rgba(0,0,0,0.08); }
.seg--aktiv       { background: var(--orange-bg); }
.seg--aktiv .seg__fuell {
  position: absolute; inset: 0 auto 0 0; display: block;
  background: var(--primary-light); border-radius: 3px;
}
.seg--ueberfaellig { background: var(--alarm); }

.raute {
  position: absolute; top: 7px; width: 12px; height: 12px;
  margin-left: -6px; transform: rotate(45deg); border-radius: 2px;
  background: var(--surface); box-shadow: 0 0 0 2px var(--text-faint);
}
.raute--fertig { background: var(--text-faint); }

.heute-linie {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: var(--text);
}
.heute-linie::after {      /* Kopf auf der Linie: das Auge findet sie sofort */
  content: ''; position: absolute; top: 0; left: -2px;
  width: 6px; height: 3px; background: var(--text); border-radius: 0 0 2px 2px;
}

.strahl__skala {
  position: relative; display: flex; justify-content: space-between;
  font-size: 12px; color: var(--text-faint); margin-top: 8px;
  letter-spacing: 0.02em; white-space: nowrap;
}
.strahl__heute-marke {
  position: absolute; transform: translateX(-50%);
  color: var(--text-muted); font-weight: 500;
}
/* Im Prototyp stand hier 22 % Weiss — 2,03:1, vom eigenen Kontrast-Gate
   gerissen. "noch 212 T" ist Information, kein Dekor. */
.strahl__rest { color: var(--text-faint); }

/* ── Lagezeile in der Karte ── */
.lage {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 14px; color: var(--text-muted);
  padding: 12px 0 12px; margin-bottom: 2px;
  border-bottom: 1px solid var(--border);
}
.lage__marke {
  flex: none; font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--text-faint);
}
.lage--alarm .lage__marke { color: var(--alarm); }
.lage__text { min-width: 0; overflow-wrap: anywhere; }   /* lange Sprachen, s. .kzs */
.lage__text b { color: var(--text); font-weight: 600; }
.lage__wert { color: var(--primary-light); font-weight: 600; margin-left: 4px; }
[data-theme="light"] .lage__wert { color: var(--primary-text); }

/* ── Kennzahlen: drei Zahlen, aus zwei Metern lesbar — der Bauleiter haelt
   das Telefon nicht auf Lesedistanz. Farbe NUR wo sie etwas heisst. ── */
/* minmax(0, 1fr) statt 1fr (18.10.2026, Mehrsprachigkeit): `1fr` heisst
   „mindestens so breit wie das laengste Wort" — „TERMIN PRZEKROCZONY" machte
   die Karte auf dem Telefon 453 px breit, die Seite liess sich schieben. */
.kzs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
       padding: 16px 0 4px; }
.kz { display: flex; flex-direction: column; gap: 1px; }
.kz__zahl {
  font-family: 'Archivo', sans-serif;
  font-size: 27px; font-weight: 700; letter-spacing: -0.03em; line-height: 1.05;
  color: var(--text);
}
.kz--alarm   .kz__zahl { color: var(--alarm); }
.kz--warn    .kz__zahl { color: var(--primary-light); }
[data-theme="light"] .kz--warn .kz__zahl { color: var(--primary-text); }
.kz--gut     .kz__zahl { color: var(--gut); }
.kz__label {
  font-family: 'Archivo', sans-serif;
  font-size: 12px; font-weight: 500; letter-spacing: 0.045em;
  text-transform: uppercase; color: var(--text-faint);
  /* Darf umbrechen statt die Karte zu sprengen (bei 390 px auch Deutsch
     „WARTEN AUF MICH"); alle Karten tragen dieselben Labels, die Hoehen
     bleiben gleich. */
  overflow-wrap: anywhere;
}

/* ── Leerfall: ein Projekt ohne Bauzeitenplan ist der Normalfall, kein
   Fehler. Eine Zeile genuegt, kein leerer Kasten. ── */
.leer {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  font-size: 14px; padding: 4px 0 4px;
  border-bottom: 1px solid var(--border);
}
.leer__text { color: var(--text-faint); }
.leer__tat  {
  color: var(--primary-light); font-weight: 600; text-decoration: none;
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px;
  margin-left: -8px; border-radius: 8px;
}
[data-theme="light"] .leer__tat { color: var(--primary-text); }
.leer__tat:hover { background: var(--orange-bg); }

/* ── Kartenfuss ── */
.projekt-karte__fuss {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: auto; padding-top: 12px;
  font-size: 12px; color: var(--text-faint);
}
.fuss__fort { color: var(--text-muted); }
.fuss__fort--leer { color: var(--text-faint); }

/* ── Bewegung: einmal beim Laden, gestaffelt. Danach Ruhe. ── */
@media (prefers-reduced-motion: no-preference) {
  .projekt-karte { animation: karteAuf var(--t3) var(--kurve) backwards; }
  .projekt-karte:nth-child(1) { animation-delay: 0ms; }
  .projekt-karte:nth-child(2) { animation-delay: 45ms; }
  .projekt-karte:nth-child(3) { animation-delay: 90ms; }
  .projekt-karte:nth-child(4) { animation-delay: 135ms; }
  .projekt-karte:nth-child(5) { animation-delay: 180ms; }
  .projekt-karte:nth-child(6) { animation-delay: 225ms; }
  @keyframes karteAuf {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
}

/* Zaehler neben der Seitenueberschrift ("6 laufend") */
.zaehler {
  font-family: 'Archivo', sans-serif; font-size: 14px; font-weight: 500;
  color: var(--text-faint); letter-spacing: 0.04em; margin-left: 12px;
}
.lage--still .lage__text { color: var(--text-faint); }

/* Hinweiszeile im Anmelde-Fenster. Lag bis zum 27.08.2026 im <style>-Block von
   index.html und galt damit nur auf der Startseite — das Fenster steht aber auf
   allen drei Marketing-Seiten. */
.bl-login-hint { text-align: center; font-size: 14px; color: var(--text-muted);
                 margin: 16px 0 0; line-height: 1.5; }

/* ═══ Marketing-Navigation (Bea 26.08.2026) ═══════════════════════════════
   Ihre Spec, Punkt für Punkt: Logo links (steht schon in .navbar-brand),
   rechts Start / Für Ihr Gewerk / Preise, Trennlinie, Login umrandet,
   „Kostenlos starten" gefüllt orange. Aktive Seite hervorgehoben.
   Hamburger unter 980 px (bis 29.10.2026: 760, siehe die Medienabfrage unten).

   Sticky + Blur bringt `.navbar` bereits mit — Punkt 1 war erfüllt, bevor die
   Spec kam. Nachgesehen statt nachgebaut. */
.marketing-nav { display: flex; align-items: center; gap: 4px; }

/* „Aktive Seite wird farblich hervorgehoben (z.B. heller/weiß), andere Links
   bleiben gedimmt" — `.nav-link` ist bereits gedimmt, hier also nur die
   Aufhellung. Kein eigener Hintergrund: der gehört dem Hover. */
.nav-link-aktiv { color: #fff; font-weight: 600; }

.nav-trenner {
  width: 1px; height: 22px; background: var(--border);
  margin: 0 8px; flex: none;
}

/* Login: sekundär, umrandet, KEIN Vollfarb-Fill (ihre Worte). */
.nav-link-login {
  border: 1px solid var(--border);
  color: rgba(255,255,255,0.85);
  /* R24: 44 px, nicht 40. Der Gerätetest hat es am iPad gefunden: Beas
     Mobil-Grenze liegt bei 760 px, das iPad ist 768 breit — dort gilt also
     diese Regel, und getippt wird trotzdem. Die Leiste ist 60 px hoch, 44 plus
     Rand passt hinein. */
  min-height: 44px; padding: 0 16px;
  /* Ein <button> erbt die Schrift nicht: in Safari stand „Login" in der
     Systemschrift neben den Archivo-Links (Geraetebild 29.10.2026). */
  font-family: inherit; cursor: pointer;
}
.nav-link-login:hover { border-color: var(--primary); color: #fff; }

/* „bleibt visuell der wichtigste CTA in der Nav" */
.nav-cta {
  background: var(--primary); color: var(--on-primary);
  font-size: 14px; font-weight: 600;
  border-radius: 8px; border: none; cursor: pointer;
  text-decoration: none; white-space: nowrap;
  margin-left: 8px; min-height: 44px; padding: 0 16px;
  display: inline-flex; align-items: center;
  transition: filter var(--t2) var(--kurve);
}
.nav-cta:hover { filter: brightness(1.08); }

.nav-hamburger {
  display: none; flex-direction: column; gap: 4px;
  background: none; border: none; cursor: pointer;
  /* 44x44 (R24) — der Knopf, den auf dem Telefon jeder als Erstes sucht. */
  min-width: 44px; min-height: 44px; align-items: center; justify-content: center;
}
.nav-hamburger span {
  width: 20px; height: 2px; background: #fff; border-radius: 2px;
  transition: transform var(--t2) var(--kurve), opacity var(--t2) var(--kurve);
}
/* Hellmodus: die Leiste ist dort weiss — weisse Striche waren unsichtbar
   (Durchklick 04.11.2026, Handy-Startseite/Preise/Rechtstexte). */
[data-theme="light"] .nav-hamburger span { background: var(--text); }
.nav-hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Beas Grenze war „Ab ~760px". Seit 29.10.2026 979 px: mit Funktionen,
   Wissen UND dem Login-Knopf (jetzt auch im Vormerk-Modus) ragte die Leiste
   zwischen 761 und 880 px bis zu 67 px rechts heraus — das iPad hochkant
   scrollte seitlich — und brach bis ~970 px in zwei Zeilen um. Gemessen mit
   `tools/bb_login_knopf_pruefen.py`: 980 px ist die erste saubere Breite. */
@media (max-width: 979px) {
  .nav-hamburger { display: flex; }
  .marketing-nav {
    display: none;
    position: absolute; top: 60px; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 2px;
    /* DECKEND, nicht durchscheinend (gemessen am iPhone-Bild 27.08.2026):
       `--navbar-bg` ist halbtransparent und für eine 60-px-Leiste über einer
       ruhigen Kante gedacht. Als aufgeklapptes Menü lag der Hero-Text mitten
       zwischen den Menüpunkten — „Für Ihr Gewerk" stand auf „HANDWERKSBETRIEBE".
       Ein Menü, das man nicht lesen kann, ist keins. Der Blur bleibt für die
       Kante darunter. */
    background: var(--surface);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    border-bottom: 1px solid var(--border);
    box-shadow: 0 18px 40px var(--schatten);
    padding: 12px 16px 16px;
  }
  /* „Login und Kostenlos starten bleiben auch mobil leicht erreichbar (z.B.
     oben im aufgeklappten Menü)" — hier stehen sie am Ende der Liste, aber in
     voller Breite und als die zwei auffälligsten Elemente. */
  .marketing-nav.offen { display: flex; }
  .marketing-nav .nav-link { min-height: 44px; padding: 0 12px; }
  /* Beas Glocke: am Telefon 44x44 (R24), der Punkt rueckt mit. */
  .nav-glocke { width: 44px; height: 44px; }
  .nav-glocke-punkt { top: 10px; right: 11px; }
  .nav-trenner { width: auto; height: 1px; margin: 8px 0; }
  /* 44 px auch hier (R24): auf dem Desktop reicht 40, weil dort eine Maus
     zeigt — im aufgeklappten Menü wird getippt. Gemessen: der CTA blieb bei
     40 px, weil er kein `.nav-link` ist und die Regel darüber ihn nicht traf. */
  .nav-cta, .nav-link-login {
    justify-content: center; margin-left: 0; min-height: 44px;
  }
}

/* ── Preisseite: Weg-Wahl, Laufzeit-Umschalter, Enterprise-Karte ────────────
   Beas Mockup `bibertron_pricing_mockup-2` (27.08.2026), gebaut am 02.09.2026.

   ⚠️ Wie bei den Preiskarten: KEINE Farben aus dem Mockup. Das Mockup ist
   dunkel-only und bringt ein eigenes Orange mit; hier gelten die Marken-Token
   (--primary, --on-primary = Beas Kontrast-Entscheidung vom 31.08.), sonst
   haetten wir zwei verschiedene Oranges und einen Hellmodus, den niemand
   entworfen hat.

   Tippziele durchgehend min-height 44px (Apple HIG, R24) — die erste
   Geraetemessung am 29.07. fand 43 zu kleine. */

.bb-wegwahl { text-align: center; margin-bottom: 1.1rem; }
.bb-wegwahl__knoepfe {
  display: inline-flex; gap: 4px; padding: 4px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 999px;
}
.bb-wegwahl__knopf {
  border: 0; background: transparent; color: var(--text-muted);
  font: inherit; font-size: 14px; font-weight: 600;
  padding: 12px 16px; min-height: 44px; border-radius: 999px; cursor: pointer;
  transition: background var(--t2) var(--kurve), color var(--t2) var(--kurve);
}
.bb-wegwahl__knopf.is-aktiv { background: var(--primary); color: var(--on-primary); }
.bb-wegwahl__fein { color: var(--text-muted); font-size: 14px; margin: .5rem 0 0; }

/* Umschalter nach Beas Mockup (`term-row`, 27.08.2026): rechtsbuendig direkt
   ueber den Karten, echter Schalter statt zweier Text-Knoepfe mit Unterstrich.
   Reine Darstellung — Verhalten (Sperre waehrend der Testphase, Formularfeld)
   bleibt unveraendert, siehe laufzeit-umschalter.js. Am 17.09.2026 gemessen:
   die alten mittigen Unterstrich-Knoepfe waren der auffaelligste Unterschied
   zum Mockup neben der zweizeiligen Ueberschrift. */
.bb-laufzeit { margin: 0 0 1.4rem; }
.bb-laufzeit__zeile {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  justify-content: flex-end;
}
.bb-laufzeit__label {
  border: 0; background: transparent; color: var(--text-muted);
  font: inherit; font-size: 14px; font-weight: 600; padding: 12px 2px;
  min-height: 44px; display: inline-flex; align-items: center; gap: .4rem;
  cursor: pointer;
  transition: color var(--t2) var(--kurve);
}
.bb-laufzeit__label.is-aktiv { color: var(--text); font-weight: 600; }
/* Gesperrt heisst waehrend der Testphase: sichtbar, aber nicht waehlbar. Kein
   Ausblenden — der Hinweis darunter erklaert warum. */
.bb-laufzeit__label.is-gesperrt,
.bb-laufzeit__label[disabled] { opacity: .4; cursor: not-allowed; }
/* Der Schalter selbst ist ein zweiter Klickbereich fuer denselben Zustand
   (laufzeit-umschalter.js bindet ihn zusaetzlich zu den beiden Labels). */
.bb-laufzeit__schalter {
  position: relative; width: 34px; height: 19px; flex-shrink: 0;
  background: var(--surface2); border: 1px solid var(--border); border-radius: 999px;
  cursor: pointer; display: inline-block;
}
.bb-laufzeit__punkt {
  position: absolute; top: 1px; left: 1px; width: 15px; height: 15px;
  background: var(--primary); border-radius: 50%;
  transition: transform var(--t2) var(--kurve);
}
.bb-laufzeit__schalter.is-an .bb-laufzeit__punkt { transform: translateX(15px); }
.bb-laufzeit__schalter.is-gesperrt { opacity: .4; cursor: not-allowed; }
.bb-laufzeit__marke {
  background: var(--primary-glow); color: var(--primary-text);
  font-size: 12px; font-weight: 600; letter-spacing: .04em;
  padding: 4px 8px; border-radius: 999px; white-space: nowrap;
}
.bb-laufzeit__hinweis { text-align: right; color: var(--text-muted); font-size: 12px; margin: .35rem 0 0; }

/* Die Feinzeile unter dem Kartenknopf ("100 % unverbindlich & ohne Zahlungsdaten").
   Steht ausserhalb des Formulars, damit `margin-top:auto` am Formular weiter
   alle drei Knoepfe auf eine Hoehe zieht. */
.bb-karte__fein {
  color: var(--text-muted); font-size: 12px; margin: .5rem 0 0; line-height: 1.4;
}

.bb-enterprise {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.2rem; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
}
.bb-enterprise__name {
  color: var(--text-muted); font-size: 12px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; margin-bottom: .35rem;
}
.bb-enterprise__zeile { margin: 0; color: var(--text); font-size: 14px; line-height: 1.55; }
.bb-enterprise__cta { min-height: 44px; white-space: nowrap; }
/* Seit Bea 01.10.2026 direkt unter den Preiskarten, der Zusatzprojekt-Hinweis
   haengt eng darunter (gleiche Breite), erst dann folgt der Knopf. */
.bb-enterprise--oben { margin-top: 1.5rem; margin-bottom: 0; }
.bb-addon--unter-enterprise { max-width: none; margin-top: .6rem; }

@media (max-width: 640px) {
  /* Auf dem Telefon untereinander: nebeneinander waeren beide Knoepfe zu
     schmal fuer 44 px Tippflaeche, und die Marke bricht sonst mitten im Wort. */
  .bb-wegwahl__knoepfe { display: flex; flex-direction: column; border-radius: var(--radius-lg); }
  .bb-wegwahl__knopf { border-radius: var(--radius); }
  .bb-enterprise { flex-direction: column; align-items: stretch; text-align: left; }
  .bb-enterprise__cta { width: 100%; }
}

/* ── Vorregistrierung (30.09.2026) ─────────────────────────────────────────
   Haekchen + Text als EIN Tippziel (44 px, R24) — dieselbe Form wie die
   Bestaetigungen in der Bestellung (.bs-bestaetigung), hier global, weil sie
   in Registrierung UND Vorregistrierung steht. */
.haken-zeile {
  display: flex; gap: 12px; align-items: flex-start; padding: 12px;
  background: var(--surface2); border-radius: 12px; margin: 12px 0;
  cursor: pointer; font-size: 14px; line-height: 1.5; min-height: 44px;
}
.haken-zeile input { margin-top: 4px; width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--primary); }
/* Verweise im Haekchentext (AGB/Datenschutz, 16.10.2026) wie in der Bestellung —
   ohne die Regel standen sie in Browser-Blau auf dunklem Grund. */
.haken-zeile a { color: var(--primary-text); text-decoration: underline; }

/* Zustimmung Eingeladener (16.10.2026): der Wortlaut steht in einem eigenen
   Rollbereich, damit Haekchen und Knopf ohne langes Scrollen erreichbar bleiben. */
.nb-wortlaut {
  /* Einzug fuer die Absatznummern „(1)": sonst nur am Rahmen `.rd` gesetzt —
     ohne ihn lag die Nummer ueber dem Text (Bild 16.10.). */
  --rd-einzug: 34px;
  max-height: 46vh; overflow-y: auto; margin: 16px 0 8px; padding: 4px 16px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface2);
  font-size: 14px; line-height: 1.55;
}
.nb-wortlaut:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.nb-stand { font-size: 14px; margin: 0 0 4px; }
.nb-stand a { color: var(--primary-text); text-decoration: underline; }
.nb-abmelden { margin-top: 12px; }
.vr-zaehler { display: flex; flex-wrap: wrap; gap: 8px 24px; font-size: 14px; color: var(--text-muted); }
.vr-zaehler strong { color: var(--text); font-size: 16px; }

/* ─── Rechtsdokumente: AGB · Datenschutz · AVV (02.10.2026) ──────────────────
   Gestaltung „Plankopf": das Schriftfeld oben ist dem Feld einer Bauzeichnung
   nachgebaut — eckig, Haarlinien, kleine Versalien-Beschriftung. Es sagt, WELCHE
   Fassung man liest; das ist bei Vertragstexten die erste Frage.
   Nur vorhandene Schriften (Archivo/IBM Plex, lokal) und Farbvariablen — keine
   nachgeladenen Inhalte Dritter (das verspricht die Datenschutzerklaerung B3).
   Rahmen: templates/rechtliches/_dokument.html. */
/* EIN Einzug fuer Ueberschrift-Nummer, (1)-Nummer und Folgetext — in px, nicht
   em: die Ueberschrift hat eine andere Schriftgroesse als der Text, mit em
   standen Nummer und Titel nicht in einer Flucht (gemessen im Bild 02.10.). */
.rd { --rd-einzug: 42px; max-width: 1120px; margin: 0 auto; padding: 24px 0 56px; }

.rd-reiter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 32px; }
.rd-reiter-link {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px;
  border: 1px solid var(--border-strong); border-radius: 999px;
  color: var(--text-muted); font-size: 14px; font-weight: 600; text-decoration: none;
  transition: background var(--tempo) var(--kurve), color var(--tempo) var(--kurve),
              border-color var(--tempo) var(--kurve);
}
.rd-reiter-link:hover { color: var(--text); background: var(--hover); }
.rd-reiter-link[aria-current="page"] {
  color: var(--on-primary); background: var(--primary); border-color: var(--primary);
}

.rd-kopf { display: grid; grid-template-columns: 72px 1fr; gap: 24px; align-items: center; }
.rd-wappen {
  width: 72px; height: 72px; border-radius: 16px; display: block;
  box-shadow: 0 0 0 1px var(--border-strong), var(--shadow-sm);
}
.rd-dachzeile {
  margin: 0 0 4px; font-family: 'Archivo', sans-serif; font-size: 12px;
  font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--primary-text);
}
.rd-titel {
  margin: 0; font-family: 'Archivo', sans-serif; font-weight: 800;
  font-size: clamp(27px, 3.6vw, 40px); line-height: 1.12; letter-spacing: -0.8px; color: var(--text);
  /* „Geschäftsbedingungen" ist breiter als ein iPhone SE: ohne Trennung schob es
     die Seite 10 px seitlich (gemessen 09.10.2026, 375 px → 385 px). */
  overflow-wrap: break-word; -webkit-hyphens: auto; hyphens: auto;
}
/* Grid-Spalte darf schmaler werden als ihr laengstes Wort (sonst greift die Trennung nie). */
.rd-kopf > * { min-width: 0; }
.rd-unter { margin: 8px 0 0; color: var(--text-muted); font-size: 16px; line-height: 1.5; }

/* Das Schriftfeld: zwei Felder, getrennt durch Haarlinien */
.rd-plankopf {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 24px 0 16px; border: 1.5px solid var(--border-strong); border-radius: 3px;
  background: var(--surface);
}
.rd-plankopf > div { padding: 12px 16px 12px; min-width: 0; }
/* Plankopf + Download-Symbol rechts daneben (Bea 06.10.2026). Die Zeile traegt
   den Aussenabstand, damit der Plankopf ohne Symbol genauso steht wie vorher. */
.rd-plankopf-zeile { display: flex; gap: 12px; align-items: stretch; margin: 24px 0 16px; }
.rd-plankopf-zeile > .rd-plankopf { flex: 1; min-width: 0; margin: 0; }
.rd-download {
  flex: none; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; min-width: 60px; padding: 8px 12px;
  border: 1.5px solid var(--border-strong); border-radius: 3px; background: var(--surface);
  color: var(--primary-text); font-size: 12px; font-weight: 600; letter-spacing: .1em;
  text-decoration: none;
  transition: background-color var(--tempo) var(--kurve), color var(--tempo) var(--kurve);
}
.rd-download i { font-size: 20px; line-height: 1; }
.rd-download:hover { background: var(--hover); color: var(--text); }
.rd-download-lang { display: none; }
.rd-download:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.rd-plankopf > div + div { border-left: 1px solid var(--border-strong); }
.rd-plankopf dt {
  font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 4px;
}
/* Android-UX 08.11.2026, E2/B14: „anywhere“ brach „(haftungsbeschränkt)“ an beliebiger
   Stelle („haftungsbeschränk-t“, „…schränkt / )“). Silbentrennung nach Sprache und
   Umbruch im Wort nur, wenn das Wort allein nicht passt. */
.rd-plankopf dd { margin: 0; font-size: 14px; font-weight: 600; color: var(--text);
  overflow-wrap: break-word; -webkit-hyphens: auto; hyphens: auto; }
.rd-in-kraft { color: var(--text-muted); font-size: 14px; }
.rd-aktion { margin: 0 0 8px; }

.rd-raster { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 52px; margin-top: 32px; }

/* Inhaltsverzeichnis: am Desktop mitlaufend, am Telefon aufklappbar */
.rd-toc-klapp { display: none; }
.rd-toc-fest {
  position: sticky; top: 84px; max-height: calc(100vh - 110px); overflow-y: auto;
  padding-right: 8px; scrollbar-width: thin;
}
.rd-toc-titel {
  margin: 0 0 12px; font-size: 12px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-faint);
}
.rd-toc-liste { list-style: none; margin: 0; padding: 0; border-left: 1px solid var(--border-strong); }
.rd-toc-liste a {
  display: grid; grid-template-columns: 3.1em 1fr; gap: 4px; padding: 8px 12px 8px 12px;
  margin-left: -1px; border-left: 2px solid transparent;
  color: var(--text-muted); font-size: 14px; line-height: 1.35; text-decoration: none;
  transition: color var(--tempo) var(--kurve), border-color var(--tempo) var(--kurve);
}
.rd-toc-liste a:hover { color: var(--text); }
.rd-toc-liste a[aria-current="true"] { color: var(--text); border-left-color: var(--primary); }
.rd-toc-nr { color: var(--primary-text); font-variant-numeric: tabular-nums; font-weight: 600; }
/* Feste Inhaltsspalte auf Tablets (29.10.2026): sie steht ab 961 px — also auch
   auf dem Android-Tablet und dem iPad quer, die mit dem Finger bedient werden.
   Die 44 px gab es bisher nur in der eingeklappten Liste darunter (max 960px);
   hier waren die Eintraege 30 px hoch (gemessen). */
@media (pointer: coarse) {
  .rd-toc-fest .rd-toc-liste a { min-height: var(--touch-min, 44px); align-items: center; }
}
.rd-toc-teil a { font-weight: 600; color: var(--text); margin-top: 8px; }

/* Der Text */
.rd-text { max-width: 720px; font-size: 16px; line-height: 1.72; color: var(--text); }
.rd-text p { margin: 0 0 .85em; }
.rd-text a { color: var(--primary-text); text-decoration: underline; text-underline-offset: 2px; overflow-wrap: anywhere; }
.rd-abschnitt { scroll-margin-top: 84px; margin-top: 38px; padding-top: 24px; border-top: 1px solid var(--border); }
.rd-abschnitt:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.rd-h {
  /* minmax: „§ 10" und „Anlage 1" sind breiter als der Einzug — mit fester
     Spalte ragten sie in den Titel. */
  display: grid; grid-template-columns: minmax(var(--rd-einzug), max-content) 1fr;
  column-gap: .45em; align-items: baseline; margin: 0 0 16px;
  font-family: 'Archivo', sans-serif; font-size: 20px; font-weight: 700; line-height: 1.3; color: var(--text);
}
.rd-nr { color: var(--primary-text); font-variant-numeric: tabular-nums; }
/* Dokumente ohne Paragraphennummern (Impressum): keine leere Nummernspalte. */
.rd-ohne-nr .rd-h, .rd-ohne-nr .rd-toc-liste a { grid-template-columns: 1fr; }
.rd-ohne-nr .rd-nr, .rd-ohne-nr .rd-toc-nr { display: none; }
.rd-teil {
  scroll-margin-top: 84px; margin: 64px 0 16px; padding: 12px 0 0;
  border-top: 3px solid var(--primary);
  font-family: 'Archivo', sans-serif; font-size: 24px; font-weight: 800; letter-spacing: -0.3px; color: var(--text);
}
.rd-teil .rd-nr { display: block; min-width: 0; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; margin-bottom: 2px; }
.rd-h3 {
  margin: 24px 0 12px; font-size: 12px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-muted);
}

/* (1), (2) … haengend: die Nummer steht links frei, der Text in einer Flucht */
.rd-absatz { position: relative; padding-left: var(--rd-einzug); }
.rd-anr { position: absolute; left: 0; color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* Alle Folgeabsaetze nach einem (n)-Absatz gehoeren zu ihm — mit `+` war nur
   der erste eingerueckt (Bild 02.10., AGB 2 Abs. 4). */
.rd-absatz ~ p:not(.rd-absatz) { padding-left: var(--rd-einzug); }
.rd-buchst { list-style: none; margin: -.2em 0 .9em; padding: 0 0 0 var(--rd-einzug); }
/* Listen erben sonst Farbe/Gewicht globaler li-Regeln und standen heller und
   fetter als der Fliesstext daneben. */
.rd-text li, .rd-text td { color: inherit; font-weight: 400; }
.rd-text p, .rd-text li { color: var(--text-muted); }
.rd-text strong { color: var(--text); font-weight: 600; }
.rd-buchst li { position: relative; padding-left: 1.9em; margin-bottom: .35em; }
.rd-bnr { position: absolute; left: 0; color: var(--primary-text); font-weight: 600; }

/* Aufzaehlungen: kleine Raute wie eine Markierung im Plan */
.rd-punkte { list-style: none; margin: .2em 0 1em; padding: 0; }
.rd-punkte li { position: relative; padding-left: 1.4em; margin-bottom: .45em; }
.rd-punkte li::before {
  content: ""; position: absolute; left: 0; top: .72em; width: 6px; height: 6px;
  background: var(--primary); transform: rotate(45deg);
}

.rd-tabelle { overflow-x: auto; margin: .4em 0 1.2em; border: 1px solid var(--border-strong); border-radius: 3px; }
.rd-tabelle table { width: 100%; border-collapse: collapse; font-size: 14px; line-height: 1.5; }
.rd-tabelle th {
  text-align: left; padding: 8px 12px; background: var(--surface);
  font-size: 12px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint);
  border-bottom: 1px solid var(--border-strong);
}
.rd-tabelle td { padding: 12px 12px; vertical-align: top; border-top: 1px solid var(--border); }
.rd-tabelle td:first-child { font-weight: 600; min-width: 11em; }

.rd-ende {
  margin-top: 56px !important; padding-top: 16px; border-top: 1px solid var(--border);
  font-size: 14px; color: var(--text-muted);
}

@media (max-width: 960px) {
  .rd-raster { grid-template-columns: minmax(0, 1fr); gap: 16px; margin-top: 16px; }
  .rd-toc-fest { display: none; }
  .rd-toc-klapp {
    display: block; border: 1px solid var(--border-strong); border-radius: var(--radius);
    background: var(--surface);
  }
  .rd-toc-klapp summary {
    min-height: 48px; display: flex; align-items: center; padding: 0 16px;
    font-weight: 600; font-size: 14px; cursor: pointer;
  }
  .rd-toc-klapp summary::-webkit-details-marker { display: none; }
  .rd-toc-klapp summary::after {
    content: ""; margin-left: auto; width: 8px; height: 8px;
    border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted);
    transform: rotate(45deg) translateY(-2px); transition: transform var(--tempo) var(--kurve);
  }
  .rd-toc-klapp[open] summary::after { transform: rotate(225deg) translateY(-2px); }
  .rd-toc-klapp[open] summary { border-bottom: 1px solid var(--border); }
  .rd-toc-klapp .rd-toc-liste { border-left: 0; padding: 8px 4px 12px; max-height: 60vh; overflow-y: auto; }
  .rd-toc-klapp .rd-toc-liste a { min-height: 44px; align-items: center; }
}
@media (max-width: 640px) {
  .rd { padding-top: 8px; }
  .rd-kopf { grid-template-columns: 56px 1fr; gap: 16px; }
  .rd-wappen { width: 56px; height: 56px; border-radius: 12px; }
  /* Download als eigene Zeile unter dem Plankopf: daneben nahm er dem Kopf so
     viel Breite, dass „haftungsbeschränkt" mitten im Wort umbrach (390 px, 09.10.). */
  .rd-plankopf-zeile { flex-direction: column; gap: 8px; }
  .rd-download { flex-direction: row; gap: 8px; min-height: 44px; }
  .rd-download i { font-size: 16px; }
  .rd-download-lang { display: inline; }
  .rd-text { font-size: 16px; }
  .rd { --rd-einzug: 34px; }
  /* Tabelle der Dienstleister: jede Zeile als Karte statt seitlich abgeschnitten */
  .rd-tabelle { border: 0; overflow: visible; }
  .rd-tabelle thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .rd-tabelle tr { display: block; border: 1px solid var(--border-strong); border-radius: 3px; margin-bottom: 12px; }
  .rd-tabelle td { display: block; border-top: 0; padding: 8px 12px; }
  .rd-tabelle td + td { border-top: 1px solid var(--border); }
  .rd-tabelle td::before {
    content: attr(data-label); display: block; font-size: 12px; font-weight: 600;
    letter-spacing: .1em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 2px;
  }
}
@media print {
  .navbar, footer, .rd-reiter, .rd-toc, #bbCookieBanner { display: none !important; }
  .rd-raster { display: block; }
  .rd-text { max-width: none; color: #000; }
}

/* Marke in der Kopfleiste: das Bibertron-Wappen vor „by Bibertron" (02.10.2026) */
@media (min-width: 641px) { .brand-sub { display: inline-flex; align-items: center; gap: 8px; } }
.brand-wappen { width: 18px; height: 18px; border-radius: 4px; display: block; }

/* Kontaktschutz (Bea 07.10.2026): der Knopf sieht aus wie ein Link. */
.kontakt-zeigen {
  background: none; border: 0; padding: 0; font: inherit; cursor: pointer;
  color: var(--primary-text, var(--primary)); text-decoration: underline;
  text-underline-offset: 2px;
  /* Tippflaeche 44 px hoch (Apple HIG; gemessen vorher 21–26 px), ohne den Text
     zu verschieben: das Polster nach oben/unten gleicht der negative Rand aus. */
  padding: 12px 0; margin: -12px 0;
}
.kontakt-zeigen:hover, .kontakt-zeigen:focus-visible { text-decoration-thickness: 2px; }
.kontakt-zeigen:disabled { cursor: progress; opacity: .7; }

/* ── Spracheingabe (Domi 07.10.2026, Schalter `spracheingabe`) ─────────────
   Nur im DOM, wenn der Schalter an ist (templates/_sprachknopf.html). Der Knopf
   ist gestrichelt wie in der App (.voice-btn), damit er als Hilfe neben dem
   Formular liest und nicht als dessen Absenden-Knopf. */
.sprach-box { margin: 0 0 .75rem; }
.sprach-zeile { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.sprach-knopf {
  border: 1.5px dashed var(--primary); color: var(--primary-text, var(--primary));
  min-height: 44px; gap: .4rem;
  transition: transform var(--t2) var(--kurve), background-color var(--t2) var(--kurve);
}
.sprach-knopf:active { transform: scale(.97); }
.sprach-knopf.sprach-aktiv {
  border-style: solid; border-color: var(--danger); color: var(--danger-text, var(--danger));
}
.sprach-knopf.sprach-aktiv .ph { animation: sprachPuls 1.1s ease-in-out infinite; }
@keyframes sprachPuls { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
  .sprach-knopf.sprach-aktiv .ph { animation: none; }
  .sprach-knopf { transition: none; }
}
.sprach-sprache .form-select { min-height: 44px; width: auto; padding-top: .35rem; padding-bottom: .35rem; }
.sprach-hinweis { font-size: 12px; color: var(--text-muted); margin: .35rem 0 0; line-height: 1.4; }
.sprach-einverstaendnis { display: flex; gap: .5rem; align-items: flex-start; font-size: 14px; margin-top: .5rem; }
.sprach-einverstaendnis input { margin-top: 4px; width: 18px; height: 18px; flex: 0 0 auto; }
.sprach-rundgang-kopf { font-size: 14px; margin: .75rem 0 .35rem; }
.sprach-rundgang-liste { margin: 0 0 .5rem; padding-left: 1.25rem; }
.sprach-rundgang-eintrag { margin-bottom: .6rem; }
.sprach-rundgang-meta { color: var(--text-muted); font-size: 14px; }
.sprach-rundgang-text { font-size: 14px; margin-top: 2px; }
.sprach-rundgang-knoepfe { display: flex; gap: .4rem; margin-top: .35rem; }
.sprach-rundgang-knoepfe .btn, .sprach-rundgang .btn-xs { min-height: 36px; }

/* ─── Rueckmeldung / Kaefer (Bea 09.10.2026) ─────────────────────────────── */
.rm-knopf {
  position: fixed; right: 16px; bottom: calc(16px + env(safe-area-inset-bottom));
  width: 48px; height: 48px; border-radius: 50%; z-index: 800;
  background: var(--overlay); color: var(--primary-text);
  border: 1px solid var(--border-strong); box-shadow: var(--shadow);
  font-size: 24px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.rm-knopf:hover { border-color: var(--primary); }
.rm-knopf:disabled { opacity: .6; cursor: progress; }
/* --ck-hoehe = echte Hoehe der Cookie-Leiste (cookie_einwilligung.js, Bea 05.11.2026, Punkt 3:
   auf dem iPhone lag der Kaefer ueber „Nur notwendige“). 72px = alter Wert, falls das Skript fehlt. */
body.bb-cookie-open .rm-knopf { bottom: calc(var(--ck-hoehe, 72px) + 16px + env(safe-area-inset-bottom)); }
.rm-fenster { width: min(480px, calc(100vw - 32px)); }
.rm-fenster .modal-header h3 .ph { color: var(--primary-text); margin-right: 8px; }
.rm-wahl { border: 0; margin: 0 0 16px; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.rm-karte {
  display: flex; flex-direction: column; gap: 2px; cursor: pointer; position: relative;
  border: 1px solid var(--border-strong); border-radius: var(--radius); padding: 12px 12px;
  min-height: 44px; font-size: 14px;
}
.rm-karte input { position: absolute; opacity: 0; inset: 0; cursor: pointer; }
.rm-karte-titel { font-weight: 600; color: var(--text); }
.rm-karte-text { font-size: 12px; color: var(--text-muted); }
.rm-karte:has(input:checked) { border: 1.5px solid var(--primary); background: var(--primary-glow); }
.rm-karte:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--orange-bg); }
.rm-zaehler, .rm-hinweis { font-size: 12px; color: var(--text-faint); }
.rm-zaehler { text-align: right; margin-top: 4px; }
.rm-bild {
  display: flex; align-items: center; gap: 12px; cursor: pointer; margin-bottom: 16px;
  background: var(--surface2); border-radius: var(--radius); padding: 12px 12px; font-size: 14px;
}
.rm-bild[hidden] { display: none; }
.rm-bild img { width: 84px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border-strong); }
.rm-bild input { width: 18px; height: 18px; accent-color: var(--primary); flex: none; }
.rm-anhang {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; cursor: pointer; font-size: 14px;
  border: 1px dashed var(--border-strong); border-radius: var(--radius); padding: 12px 12px; color: var(--text-muted);
}
.rm-anhang input { font-size: 12px; max-width: 100%; }
.rm-fehler { color: var(--danger-text); font-size: 14px; margin-bottom: 12px; }
.rm-fuss { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rm-fuss .rm-hinweis { flex: 1 1 180px; line-height: 1.4; }
.rm-danke-text { margin: 4px 0 16px; font-size: 14px; color: var(--text); }

/* ─── Rueckmeldungen, Betreiberseite (Bea 09.10.2026) ────────────────────── */
.rma-filter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.rma-abstand { flex: 1 1 0; }
.rma-chip { border: 1px solid var(--border-strong); border-radius: 99px; padding: 8px 16px; font-size: 14px;
  color: var(--text-muted); text-decoration: none; min-height: 32px; display: inline-flex; align-items: center; gap: 4px; }
.rma-chip.aktiv { background: var(--primary); border-color: var(--primary); color: var(--on-primary); font-weight: 600; }
.rma-raster { display: grid; grid-template-columns: minmax(0, 280px) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 760px) { .rma-raster { grid-template-columns: minmax(0, 1fr); } }
.rma-liste { display: flex; flex-direction: column; gap: 8px; }
.rma-eintrag { display: flex; flex-direction: column; gap: 4px; background: var(--surface); padding: 12px 12px;
  font-size: 14px; text-decoration: none; color: var(--text); border-left: 3px solid transparent; }
.rma-eintrag.neu { border-left-color: var(--primary); }
.rma-eintrag.gewaehlt { background: var(--overlay); outline: 1px solid var(--border-strong); }
.rma-eintrag-kopf { display: flex; align-items: center; gap: 8px; }
.rma-eintrag-kopf .ph { color: var(--primary-text); }
.rma-zeit { margin-left: auto; font-size: 12px; color: var(--text-faint); }
.rma-vorschau { color: var(--text-muted); }
.rma-detail-kopf { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.rma-meta { font-size: 14px; color: var(--text-muted); line-height: 1.6; margin-bottom: 12px; overflow-wrap: anywhere; }
.rma-text { font-size: 16px; line-height: 1.55; white-space: pre-wrap; margin: 0 0 12px; }
.rma-bild { max-width: 100%; border: 1px solid var(--border-strong); border-radius: 8px; display: block; margin-bottom: 8px; }
.rma-dateien { font-size: 12px; color: var(--text-muted); display: flex; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.rma-status { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.rma-antwort { border-top: 1px solid var(--border); padding-top: 12px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.rma-antwort .form-input { width: 100%; }
.rma-vorlagen { display: flex; gap: 8px; flex-wrap: wrap; }

/* ─── Besuche, Betreiberseite (Bea 09.10.2026) ───────────────────────────── */
.bs-kacheln { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 16px; }
.bs-kachel { padding: 16px 16px; }
.bs-gross { font-size: 28px; font-weight: 600; color: var(--text); line-height: 1.1; }
.bs-klein { font-size: 12px; color: var(--text-muted); margin-top: 4px; font-weight: 400; }
.bs-block { padding: 16px 16px; margin-bottom: 16px; }
.bs-titel { font-size: 14px; font-weight: 700; margin: 0 0 12px; color: var(--text); }
.bs-spalten { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; }
.bs-zeile { display: grid; grid-template-columns: minmax(90px, 160px) minmax(0, 1fr) auto; gap: 12px; align-items: center; font-size: 14px; padding: 4px 0; }
.bs-name { color: var(--text-muted); overflow-wrap: anywhere; }
.bs-spur { background: var(--surface2); border-radius: 99px; height: 10px; overflow: hidden; }
.bs-fuell { display: block; height: 100%; background: var(--primary); border-radius: 99px; min-width: 2px; }
.bs-zahl { text-align: right; white-space: nowrap; color: var(--text); }
.bs-quote { color: var(--text-muted); font-size: 12px; }
.bs-fussnote { font-size: 12px; color: var(--text-faint); line-height: 1.5; margin: 12px 0 0; }
.bs-saeulen { display: flex; align-items: flex-end; gap: 4px; height: 110px; }
.bs-saeule { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.bs-saeule span { display: block; width: 100%; background: var(--primary); border-radius: 3px 3px 0 0; min-height: 2px; }
.bs-achse { display: flex; justify-content: space-between; font-size: 12px; color: var(--text-faint); margin-top: 4px; }

/* ─── Nutzung, Betreiberseite (Bea 09.10.2026) ───────────────────────────── */
.au-tabelle { width: 100%; border-collapse: collapse; font-size: 14px; }
.au-tabelle td { padding: 8px 8px 8px 0; border-top: 1px solid var(--border); vertical-align: top; }
.au-tabelle tr:first-child td { border-top: 0; }
.au-kopf td { font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .4px; border-top: 0; }
.au-grau { color: var(--text-muted); }
.au-zahl { text-align: right; font-weight: 600; white-space: nowrap; }
.au-breit { table-layout: auto; }
.au-ampel { display: inline-block; border-radius: 99px; padding: 2px 8px; font-size: 12px; font-weight: 600; }
.au-aktiv { background: var(--ok-bg); color: #4ec98a; }
.au-ruhig { background: rgba(224,169,74,.18); color: #e0a94a; }
.au-schlaeft { background: var(--bad-bg); color: var(--danger-text); }
.au-neu { background: rgba(168,146,245,.18); color: #a892f5; }
/* Heller Modus (24.10.2026, Zahlarten-Seite): die Schriftfarben oben sind fuer
   dunklen Grund gewaehlt und kamen auf dem hellen Pillengrund auf 1,8–2,3:1.
   Gemessen mit tools/farbkontrast_rechnen.py gegen den gemischten Grund
   (18 % Farbe auf Weiss): jetzt 5,3–6,0:1. */
[data-theme="light"] .au-aktiv { color: #1f6b45; }
[data-theme="light"] .au-ruhig { color: #7d5714; }
[data-theme="light"] .au-schlaeft { color: #b40d0d; }
[data-theme="light"] .au-neu { color: #5b36d9; }
.au-mini { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 12px; color: var(--text-muted); }
.au-mini > div { background: var(--surface2); border-radius: 8px; padding: 8px 12px; }
.au-mini strong { display: block; font-size: 20px; color: var(--text); margin-bottom: 2px; }

/* ─── Kunden, Betreiberseite (Domi 11.10.2026) ───────────────────────────── */
/* Breite Tabellen scrollen in ihrem Kasten, nicht die ganze Seite (R24). */
.ak-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ak-scroll .au-tabelle td { white-space: nowrap; }
.ak-felder { display: grid; grid-template-columns: minmax(120px, 190px) minmax(0, 1fr); gap: 4px 12px; font-size: 14px; margin: 0; }
.ak-felder dt { color: var(--text-muted); }
.ak-felder dd { margin: 0; overflow-wrap: anywhere; color: var(--text); }
.ak-suche { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.ak-suche .form-input { flex: 1; min-width: 180px; }

/* ─── Nutzerfuehrung v6c (Nachtbau 16./17.10.2026, Schalter `ui_v6c`) ──────
   Alles hier greift nur, wenn die Projektseite die v6c-Bausteine rendert.
   Farbregel des Entwurfs: Orange heisst „du bist dran" (Hauptknopf, Marker),
   Rot heisst ueberfaellig, Blau „jemand anderes arbeitet", Grau „niemand hat
   angefangen". Alle Werte aus den bestehenden Variablen — kein neuer Ton. */
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
           clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Kopfzeile mit den Stammdaten statt eigener Karte */
.v6c-meta { color: var(--text-muted); font-size: 14px; margin: -6px 0 16px; display: flex;
            gap: 4px 16px; flex-wrap: wrap; align-items: center; }
/* Hero „Jetzt dran" — der eine Mittelpunkt */
.hero-dran { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
             padding: 16px 24px 16px; margin-bottom: 16px; }
.hero-dran__kopf { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.hero-dran__kopf h2 { font-size: 20px; font-weight: 600; margin: 0; color: var(--text); }
.hero-dran__satz { color: var(--text-muted); font-size: 14px; }
.dran-zeile { display: flex; align-items: center; justify-content: space-between; gap: 16px;
              padding: 12px 0; border-top: 1px solid var(--border); }
.dran-zeile__text { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.dran-zeile__text strong { font-size: 16px; font-weight: 600; color: var(--text); }
.dran-zeile__sub { display: flex; gap: 8px 12px; flex-wrap: wrap; align-items: center;
                   font-size: 14px; color: var(--text-muted); }
/* 44 px auch am Rechner: der Geraetetest (R24) mass 66x40 bei 375–768 px. */
.dran-knopf { flex-shrink: 0; min-height: 44px; min-width: 44px; text-decoration: none; }
.dran-leer { color: var(--text-muted); font-size: 14px; margin: 12px 0 4px; }
.dran-mehr summary { cursor: pointer; list-style: none; padding: 12px 0 4px; border-top: 1px solid var(--border);
                    color: var(--primary-text); font-size: 14px; font-weight: 500; min-height: 44px;
                    display: flex; align-items: center; gap: 8px; }
.dran-mehr summary::-webkit-details-marker { display: none; }
.dran-mehr summary::after { content: "\25BE"; font-size: 12px; }
.dran-mehr[open] summary::after { content: "\25B4"; }
/* Dringlichkeit an fester Stelle */
.frist { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.frist--ueberfaellig { color: var(--danger-text); font-weight: 600; }
.frist--ueberfaellig::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--danger); }
.frist--heute { color: var(--primary-text); font-weight: 600; }
/* Textlink statt Rahmenknopf fuer „mehr" */
.lnk { background: none; border: 0; color: var(--primary-text); font-weight: 500; font-size: 14px;
       padding: 8px 0; text-decoration: underline; text-underline-offset: 3px; display: inline-block;
       min-height: 44px; line-height: 32px; }
/* Kennzahlen als klickbare Pillen mit Pfeil */
.lage2 { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.lg { display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px 0 16px;
      border: 1px solid var(--border); border-radius: 999px; background: var(--surface);
      text-decoration: none; color: inherit; font-size: 14px;
      transition: border-color var(--tempo) var(--kurve); }
.lg:hover { border-color: var(--border-strong); }
.lg__label { color: var(--text-muted); }
.lg b { font-weight: 600; }
.lg__wert--ok { color: var(--gut); }
.lg__wert--bad { color: var(--danger-text); }
.lg__chev { color: var(--text-muted); transition: transform var(--t2) var(--kurve); }
.lg:hover .lg__chev { transform: translateX(2px); }
/* Zwei Spalten: Aktivitaet links, Termine + Baustelle rechts */
.v6c-cols { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 16px; align-items: start; }
.v6c-stapel { display: grid; gap: 16px; align-content: start; }
.v6c-karte { margin: 0; padding: 16px 16px; }
.v6c-karte__titel { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
                    color: var(--text-muted); margin: 0 0 12px; }
.v6c-karte__text { margin: 0 0 12px; font-size: 14px; line-height: 1.55; }
.v6c-status { max-width: 320px; margin-bottom: 8px; }
.aktivitaet { list-style: none; margin: 0; padding: 0; }
.aktivitaet__zeile { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; gap: 12px; align-items: start;
                     padding: 8px 0; border-top: 1px solid var(--border); font-size: 14px; }
.aktivitaet__zeile:first-child { border-top: 0; padding-top: 2px; }
.aktivitaet__typ { width: 8px; height: 8px; border-radius: 50%; margin-top: 8px; background: var(--text-faint); }
.aktivitaet__typ--mangel { background: var(--warning); }
.aktivitaet__typ--termin { background: var(--info); }
.aktivitaet__typ--nachricht { background: var(--text-faint); }
.aktivitaet__typ--bautagebuch { background: var(--gut); }
.aktivitaet__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.aktivitaet__text strong { font-weight: 600; }
.aktivitaet__detail { color: var(--text-muted); font-size: 14px; overflow-wrap: anywhere; }
.aktivitaet__zeit { color: var(--text-muted); font-size: 12px; white-space: nowrap; margin-top: 2px; }
/* EIN Marker fuer „du bist dran", ueberall gleich */
.dran { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600;
        padding: 2px 8px; border-radius: 999px; background: var(--primary-glow);
        color: var(--primary-light); white-space: nowrap; vertical-align: middle; }
/* Dunkel: --primary-text auf dem Orange-Hauch ergab 4,44:1 (gemessen 17.10.2026),
   --primary-light liegt darueber. Hell bleibt --primary-text (dort ohne Befund). */
[data-theme="light"] .dran { color: var(--primary-text); }
.dran::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--primary); }
/* Chat: feste Farbe je Person (7 Toene, ohne Orange/Rot/Gruen), Hell dunkler */
.pc-0 { --pc: #7fa9ff; } .pc-1 { --pc: #9fb3c8; } .pc-2 { --pc: #b9a8e6; } .pc-3 { --pc: #c79bff; }
.pc-4 { --pc: #f08cc0; } .pc-5 { --pc: #4fc9d9; } .pc-6 { --pc: #b5d67e; }
[data-theme="light"] .pc-0 { --pc: #2152b8; } [data-theme="light"] .pc-1 { --pc: #475569; }
[data-theme="light"] .pc-2 { --pc: #5b4a9e; } [data-theme="light"] .pc-3 { --pc: #6a35c2; }
[data-theme="light"] .pc-4 { --pc: #a42a68; } [data-theme="light"] .pc-5 { --pc: #095f6b; }
[data-theme="light"] .pc-6 { --pc: #435f12; }  /* pc-5/pc-6 wie app.css (23.10.): vorher 4,29 / 4,40:1 im Kuerzel-Kreis */
.feed--v6c { gap: 2px; }
.feed-trenner { display: flex; align-items: center; gap: 12px; color: var(--text-muted); font-size: 12px;
                margin: 16px 0 4px; align-self: stretch; }
.feed-trenner::before, .feed-trenner::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.feed-item.cmw { display: flex; gap: 12px; align-items: flex-start; background: none; padding: 0;
                 max-width: min(88%, 640px); margin: 2px 0 0; }
.feed-item.cmw--first { margin-top: 12px; }
.cmw:not(.cmw--first) .cm-av { visibility: hidden; }
.cm-av { flex: 0 0 32px; width: 32px; height: 32px; border-radius: 50%; display: inline-flex; align-items: center;
         justify-content: center; font-size: 12px; font-weight: 600; color: var(--pc);
         background: color-mix(in srgb, var(--pc) 20%, var(--surface));
         border: 1px solid color-mix(in srgb, var(--pc) 60%, transparent); }
.cmw .cm { background: var(--surface); border-radius: 4px 10px 10px 10px; padding: 12px 16px 8px;
           border-left: 3px solid var(--pc); min-width: 0; }
.cmw:not(.cmw--own):not(.cmw--first) .cm { border-radius: 4px 10px 10px 4px; }
.cmw--own { flex-direction: row-reverse; align-self: flex-end; }
.cmw--own .cm { border: 0; border-radius: 10px 4px 10px 10px; background: color-mix(in srgb, var(--text) 9%, var(--surface)); }
.cmw--own:not(.cmw--first) .cm { border-radius: 12px; }
.cm-k { display: flex; gap: 4px 8px; align-items: baseline; flex-wrap: wrap; font-size: 14px; margin-bottom: 2px; color: var(--text-muted); }
.cm-k strong { color: var(--pc); font-weight: 600; font-size: 14px; }
.cmw--own .cm-k strong { color: var(--text); }
.cm-rolle { font-size: 12px; border: 1px solid color-mix(in srgb, var(--pc) 55%, transparent); color: var(--pc);
            border-radius: 999px; padding: 0 8px; }
.cm-betrieb { font-size: 12px; }
.cm-zeit { font-size: 12px; color: var(--text-muted); margin-top: 4px; text-align: right; }
.cmw .feed-text { font-size: 16px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
/* Projektliste: „wartet auf dich" auf der Karte */
.kz--dran .kz__zahl { color: var(--primary-text); }
@media (max-width: 760px) {
  .v6c-cols { grid-template-columns: minmax(0, 1fr); }
  .lage2 { display: grid; grid-template-columns: 1fr; }
  .lg { justify-content: space-between; }
  .hero-dran { padding: 16px 16px 12px; }
  .dran-zeile { flex-wrap: wrap; }
  .dran-knopf { margin-left: auto; }
  .feed-item.cmw { max-width: 100%; }
  .mangel-card .dran, .btb-card .dran { display: flex; width: fit-content; margin-bottom: 4px; }
}

/* ─── v6c Reiter (17.10.2026 abends): „Listen als Zeilen in EINEM Block,
   Seiten mit Knopf unten" — dieselbe Form wie die App (app.css `.zeilen`).
   Die Eintraege behalten ihre alten Klassen (termin-card, mangel-card …):
   Skripte, Filter und die Klick-Tests haengen daran. `.zeile` nimmt ihnen
   nur die Kartenoptik; `!important`, weil manche Karten Abstaende inline
   tragen. Ohne Schalter rendert keine Vorlage diese Klassen. */
.zeilen-block { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
                overflow: hidden; margin: 0 0 16px; display: block; }
.zeilen-block > .zeile { background: none !important; border: 0 !important; border-top: 1px solid var(--border) !important;
                         border-radius: 0 !important; box-shadow: none !important; margin: 0 !important;
                         padding: 16px 16px !important; opacity: 1; }
.zeilen-block > .zeile:first-child { border-top: 0 !important; }
.zeilen-block > .zeile.zeile--archiv { opacity: .6; }
/* Der Vorschlag zu einem Termin haengt an seiner Zeile: eingerueckt, gestrichelt links */
.zeilen-block > .zeile.termin-vorschlag { border-top-style: dashed !important; padding-left: 32px !important; }
.abschnitt-label { font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
                   color: var(--text-muted); margin: 24px 2px 8px; }
.abschnitt-label:first-child { margin-top: 0; }
/* Seitenfuss: die eine Hauptaktion der Seite steht am Ende */
.seiten-fuss { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin: 16px 0 4px; }
.seiten-fuss .btn { min-height: 44px; }
/* Ein Formular als Hauptaktion am Fuss (Mangel erfassen, Aufgabe hinzufuegen) */
.fuss-formular { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
                 padding: 16px 16px; margin: 16px 0 4px; }
.fuss-formular.card { box-shadow: none; }
.zeile-kopf { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* Stand je Partei (Abnahme): Punkt · Text · Marker */
.zeilen-block > .stand-zeile { display: flex; align-items: center; gap: 12px; }
.stand-zeile__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.stand-zeile__text strong { font-weight: 600; }
.stand-zeile__text small { color: var(--text-muted); font-size: 14px; }
.sz-punkt { width: 9px; height: 9px; border-radius: 50%; background: var(--text-faint); flex: none; }
.sz-punkt--ok { background: var(--gut); }
.sz-punkt--wartet { background: var(--primary); }
/* v6c-Farbregel „Gruen nur als Status": im Bestand ist .badge-success Orange
   (Marke), damit sah „Erledigt" aus wie „du bist dran". Mit Schalter traegt
   jede Erfolgs-Marke Gruen (--gut, gemessen >= 4,5:1 auf beiden Gruenden);
   Knoepfe bleiben unberuehrt. `body.ui-v6c` setzt base.html.
   Werte GEMESSEN (kontrast_messung.py, 17.10.2026): --gut selbst als Schrift
   erreichte nur 4,29 (dunkel) / 4,07 (hell) — darum eigene, kraeftigere
   Schriftfarbe, ~5,7:1 auf beiden Gruenden. */
.ui-v6c .badge-success { background: color-mix(in srgb, var(--gut) 14%, transparent); color: #5fb383; }
[data-theme="light"] .ui-v6c .badge-success { background: color-mix(in srgb, var(--gut) 12%, transparent); color: #23683f; }
/* Alle uebrigen Listen mit `ueb-liste`/`ueb-row` (Firma-Mitglieder, Wetter-Logbuch,
   Anschluesse, Admin) als Zeilenblock — EINE Regel statt je Vorlage (17./18.10.2026).
   Seiten, die schon `zeilen-block` tragen, sehen damit gleich aus. */
.ui-v6c .ueb-liste { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
                     overflow: hidden; display: block; gap: 0; }
.ui-v6c .ueb-liste > .ueb-row { background: none; border-radius: 0; border-top: 1px solid var(--border);
                                padding: 16px 16px; margin: 0; }
.ui-v6c .ueb-liste > .ueb-row:first-child { border-top: 0; }
/* Projektuebergreifende Listen: die eine Handlung je Zeile steht rechts */
.ueb-row-knopf { margin-left: auto; min-height: 44px; display: inline-flex; align-items: center; }
/* Glocke als Zeilen: der Link IST die Zeile (ganze Flaeche tippbar) */
.zeilen-block > li.zeile { padding: 0 !important; }
.glocke-eintrag--v6c { margin: 0; border-radius: 0; padding: 12px 16px; align-items: center; }
.glocke-eintrag--v6c .glocke-eintrag-inhalt { flex: 1 1 auto; }
.glocke-eintrag--v6c .glocke-eintrag-punkt { margin-top: 0; }
.glocke-eintrag-symbol { flex: 0 0 auto; color: var(--text-muted); font-size: 16px; display: flex; }
.glocke-eintrag-neu .glocke-eintrag-symbol { color: var(--primary-text); }
@media (max-width: 760px) {
  .zeilen-block > .zeile { padding: 12px 16px !important; }
  .zeilen-block > .zeile.termin-vorschlag { padding-left: 24px !important; }
  .seiten-fuss .btn { flex: 1 1 auto; }
}

/* Logo in EINER Zeile auf dem Telefon (Staging-Runde 18.10.2026). Seit die Glocke
   (44 px) in der Kopfzeile steht, fehlte bei 390 px genau ein Pixel: rechts
   brauchen Glocke + Projekte + Konto + Hell/Dunkel 228 px, das Logo 124 px —
   „Bau-" und „Begleiter" brachen in zwei Zeilen. Gemessen (bb_staging_css_probe):
   17 px Schrift, 12 px Rand und 2 px Abstand ergeben 109 px Logo und passen bei
   360/375/390 ohne seitliches Wegrutschen. Unter 360 reicht der Platz auch so
   nicht — dort bleibt der Umbruch das kleinere Uebel (nowrap waere 29 px breiter). */
@media (min-width: 360px) and (max-width: 400px) {
  .navbar { padding: 0 12px; }
  .navbar-brand { font-size: 16px; letter-spacing: -0.7px; }
  .brand-name { white-space: nowrap; }
  .navbar-right { gap: 2px; }
}

/* Sprachwahl im Fuss (Bea 19.10.2026, Variante A): ein Knopf mit der aktuellen
   Sprache; die Liste klappt nach OBEN auf, weil der Fuss unten sitzt. Nativ per
   <details> (templates/base.html), Tippziele 44 px wie in den App-Zeilen. */
.sprachwahl { position: relative; }
.sprachwahl-knopf { list-style: none; display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 12px; border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--text-muted); font-size: 14px; cursor: pointer; user-select: none; }
.sprachwahl-knopf::-webkit-details-marker { display: none; }
.sprachwahl-knopf:hover { color: var(--text); }
.sprachwahl-knopf:focus-visible, .sprachwahl .sprachwahl-liste a:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.sprachwahl-pfeil { font-size: 12px; transition: transform var(--t2) var(--kurve); }
.sprachwahl[open] .sprachwahl-pfeil { transform: rotate(180deg); }
.sprachwahl-liste { position: absolute; left: 0; bottom: calc(100% + 6px); z-index: 50; min-width: 180px;
  margin: 0; padding: 4px; list-style: none; background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow); }
.sprachwahl .sprachwahl-liste a { display: flex; align-items: center; justify-content: space-between; min-height: 44px;
  padding: 0 12px; border-radius: 6px; color: var(--text-muted); font-size: 14px; text-decoration: none; }
.sprachwahl .sprachwahl-liste a:hover { background: var(--bg); color: var(--text); }
.sprachwahl .sprachwahl-liste a[aria-current="true"] { color: var(--text); font-weight: 600; }
.sprachwahl .sprachwahl-liste a[aria-current="true"]::after { content: "\2713"; color: var(--primary); }
@media (prefers-reduced-motion: reduce) { .sprachwahl-pfeil { transition: none; } }

/* ═══ Cookie-Leiste und Cookie-Einstellungen (Bea 19.10.2026) ═════════════════
   Die beiden Hauptknoepfe sind gleichrangig: `.ck-knopf` legt Groesse, Schrift
   und Abstand fest, die Varianten unterscheiden sich NUR in der Farbe (ein Test
   in tests/test_cookie_einwilligung.py achtet darauf). „Alle akzeptieren" in
   Bibertron-Orange, „Nur notwendige" mit gleich starkem Rand. Tippziele 44 px. */
.ck-leiste { position: fixed; left: 0; right: 0; bottom: 0; z-index: 99999; background: var(--overlay);
  color: var(--text); border-top: 1px solid var(--edge); box-shadow: 0 -8px 28px var(--schatten);
  padding: 0.6rem 1.25rem calc(0.6rem + env(safe-area-inset-bottom)); font-family: inherit;
  font-size: 14px; line-height: 1.45; }
.ck-leiste[hidden] { display: none; }
.ck-innen { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; max-width: 1100px; margin: 0 auto; }
.ck-text { flex: 1 1 280px; margin: 0; color: var(--text-muted); }
.ck-text strong { color: var(--text); font-weight: 600; }
.ck-aktionen { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; flex-shrink: 0; }
.ck-link { font-size: 14px; color: var(--text-muted); text-decoration: underline; display: inline-flex;
  align-items: center; justify-content: center; min-height: 44px; min-width: 44px; padding: 0 12px; }
.ck-knopf { min-height: 44px; padding: 0 1.4rem; border-radius: 8px; font-size: 14px; font-weight: 600;
  font-family: inherit; cursor: pointer; border: 2px solid transparent; }
.ck-knopf--primaer { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
.ck-knopf--rand { background: var(--surface); color: var(--text); border-color: var(--text-muted); }
.ck-knopf:focus-visible, .ck-link:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
@media (max-width: 520px) {
  .ck-aktionen { width: 100%; }
  .ck-aktionen .ck-knopf { flex: 1 1 140px; }
}

.ck-seite { max-width: 820px; margin: 0 auto; padding: 32px 24px 96px; }
.ck-seite h1 { margin: 0 0 12px; }
.ck-lead { color: var(--text-muted); line-height: 1.6; margin: 0 0 24px; }
.ck-lead a, .ck-stand a { color: inherit; text-decoration: underline; }
.ck-gruppe { border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface);
  padding: 16px 16px; margin: 0 0 16px; }
.ck-kopf { display: flex; gap: 16px; align-items: center; justify-content: space-between; }
.ck-kopf h2 { margin: 0 0 4px; font-size: 16px; }
.ck-kopf p { margin: 0; color: var(--text-muted); font-size: 14px; line-height: 1.5; }
.ck-status { flex-shrink: 0; font-size: 14px; color: var(--text-muted); text-align: right; max-width: 150px; }
.ck-schalter { position: relative; flex-shrink: 0; display: inline-block; width: 52px; height: 44px; cursor: pointer; }
.ck-schalter input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.ck-schieber { position: absolute; left: 0; top: 8px; width: 52px; height: 28px; border-radius: 12px;
  background: var(--border-strong); transition: background var(--t2) var(--kurve); }
.ck-schieber::after { content: ""; position: absolute; left: 3px; top: 3px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--surface); transition: transform var(--t2) var(--kurve); }
.ck-schalter input:checked + .ck-schieber { background: var(--primary); }
.ck-schalter input:checked + .ck-schieber::after { transform: translateX(24px); }
.ck-schalter input:focus-visible + .ck-schieber { outline: 2px solid var(--primary); outline-offset: 2px; }
.ck-dienst { border-top: 1px solid var(--border); margin-top: 12px; padding-top: 4px; }
.ck-dienst summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; font-weight: 600;
  font-size: 14px; }
.ck-dienst dl { margin: 0 0 8px; display: grid; grid-template-columns: minmax(110px, 170px) 1fr; gap: 8px 16px;
  font-size: 14px; line-height: 1.5; }
.ck-dienst dt { color: var(--text-muted); }
.ck-dienst dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 560px) { .ck-dienst dl { grid-template-columns: 1fr; gap: 2px; } .ck-dienst dd { margin-bottom: 8px; } }
.ck-knopfreihe { display: flex; gap: 12px; flex-wrap: wrap; margin: 24px 0 8px; }
.ck-meldung { min-height: 1.4em; margin: 4px 0 16px; color: var(--text-muted); font-size: 14px; }
.ck-stand { color: var(--text-muted); font-size: 14px; margin-top: 24px; }
@media (prefers-reduced-motion: reduce) { .ck-schieber, .ck-schieber::after { transition: none; } }

/* Meine ToDos auf- und zuklappbar (Bea 28.10.2026, Schalter projektliste_kompakt) */
.todo-auf > summary { cursor: pointer; list-style: none; min-height: 44px; display: flex; align-items: center; gap: 12px; }
.todo-auf > summary::-webkit-details-marker { display: none; }
.todo-auf > summary::before { content: "\25BE"; order: -1; flex: none; width: 24px; text-align: center; font-size: 20px; line-height: 1; color: var(--text-muted, #888); }
.todo-auf:not([open]) > summary::before { content: "\25B8"; }

/* Reiter in zwei Ebenen (Bea 29.10.2026, Schalter projektliste_kompakt): Bereiche oben, Reiter des Bereichs darunter */
.tabs-bk { position: sticky; top: 68px; z-index: 150; margin-bottom: 24px; padding: 0 12px 4px; background: var(--surface); border-radius: var(--radius-lg); }
.tabs-bk .tabs { position: static; margin: 0; padding: 4px 0 0; background: transparent; }
.tabs-gruppen { display: flex; gap: 2px; overflow-x: auto; scrollbar-width: none; border-bottom: 1px solid var(--border, var(--border)); }
.tabs-gruppen::-webkit-scrollbar { display: none; }
.tabs-gruppen .gruppe { display: flex; align-items: center; min-height: 44px; padding: 0 16px; font-size: 14px; font-weight: 600; color: var(--text-muted); text-decoration: none; white-space: nowrap; border-bottom: 3px solid transparent; margin-bottom: -1px; }
.tabs-gruppen .gruppe:hover { color: var(--text); }
.tabs-gruppen .gruppe.active { color: var(--text); border-bottom-color: var(--primary); }
.tabs--bk .tab { background: none; border-radius: 0; border-bottom: 3px solid transparent; padding: 8px 16px; font-weight: 500; }
.tabs--bk .tab:hover { background: none; color: var(--text); }
.tabs--bk .tab.active { background: none; color: var(--text); border-bottom-color: var(--primary); }
.tabs--bk .tab.bk-aus { display: none; }
.tabs--bk.tabs--einzeln { display: none; }
.tabs--bk .tab[data-gruppe="planung"][href*="bauzeitenplan"] { order: -1; }

/* Kaesten heller (Bea 02.11.2026, Variante A), wie in wd.css */
:root{--ctl:#80776e;--s3:#2c2621;--kasten:#241f1b;--kante:inset 0 1px 0 rgba(255,232,204,.06)}
[data-theme="light"]{--ctl:#767b86;--s3:#e6e8ec;--kasten:#f6f7f9;--kante:inset 0 1px 0 #fff}
.card, .karte, [data-theme="light"] .card, [data-theme="light"] .karte {
  background: var(--kasten); border-color: var(--border-strong); box-shadow: var(--kante), var(--shadow-sm);
}

/* Bausteine (Bea 02.11.2026): was Inhalt traegt oder schwebt, ist ein Kasten; was man bedient, bleibt flach und zeigt Orange nur fuer an/aktiv. docs/styleguide.md */
/* Tabs: Unterstreichung wie .subtabs im neuen Web (aktiv --text, 500, 3 px Orange darunter) */
[data-theme="light"] .tabs, .tabs { background: var(--bg); padding: 0; border-radius: 0; gap: 2px; border-bottom: 1px solid var(--border-strong); }
.tab { border-radius: 0; border-bottom: 3px solid transparent; margin-bottom: -1px; min-height: 44px; padding: 0 16px; font-weight: 400; color: var(--text-muted); }
.tab:hover, [data-theme="light"] .tab:hover { background: none; color: var(--text); }
.tab.active, [data-theme="light"] .tab.active { background: none; color: var(--text); font-weight: 500; border-bottom-color: var(--primary); }
.tabs-bk .tabs { background: transparent; border-bottom: 0; }
/* Menue */
.dropdown-menu { background: var(--kasten); border: 1px solid var(--border-strong); box-shadow: var(--kante), 0 8px 24px var(--schatten); padding: 4px; }
.dropdown-item { padding: 8px 12px; border-radius: 8px; color: var(--text); }
.dropdown-item > i:first-child, .dropdown-item > .ph:first-child { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 28px; height: 28px; border-radius: 8px; background: var(--s3); color: var(--text-muted); font-size: 16px; }
.dropdown-item:hover { background: var(--s3); }
.dropdown-item:hover > i:first-child, .dropdown-item:hover > .ph:first-child { background: var(--surface); }
.dropdown-item-danger, .dropdown-item-danger:hover { color: var(--danger-text); }
.dropdown-item-danger > i:first-child, .dropdown-item-danger > .ph:first-child { background: var(--bad-bg); color: var(--danger-text); }
/* Toast */
.toast-nachricht, .toast-success, .toast-error, .toast-warning, .toast-info { background: var(--kasten); color: var(--text); border: 1px solid var(--border-strong); box-shadow: var(--kante), 0 8px 24px var(--schatten); max-width: 380px; }
.toast-symbol { display: inline-flex; align-items: center; justify-content: center; flex: none; width: 24px; height: 24px; border-radius: 50%; font-size: 14px; background: var(--info-bg); color: var(--info-text); }
.toast-success .toast-symbol { background: var(--ok-bg); color: var(--gut); }
.toast-error .toast-symbol { background: var(--bad-bg); color: var(--danger-text); }
.toast-warning .toast-symbol { background: var(--orange-bg); color: var(--primary-text); }
/* Banner: Kasten mit Kreis links, keine Seitenlinie, keine Vollfarbe */
.flash, .hinweis-kasten, .zahlungshinweis { position: relative; padding: 12px 16px 12px 52px; background: var(--kasten); color: var(--text); border: 1px solid var(--bd); box-shadow: var(--kante); border-radius: 12px; }
.flash::before, .hinweis-kasten::before, .zahlungshinweis::before { content: "i"; position: absolute; left: 16px; top: 12px; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; background: var(--info-bg); color: var(--info-text); font-size: 12px; font-weight: 600; }
.flash-success::before, .flash-bestaetigung::before { content: "\2713"; background: var(--ok-bg); color: var(--gut); }
.flash-error::before, .hinweis-kasten--stopp::before, .zahlungshinweis-pausiert::before { content: "!"; background: var(--bad-bg); color: var(--danger-text); }
.hinweis-kasten::before, .zahlungshinweis-mahnung::before, .zahlungshinweis-testphase::before { content: "!"; background: var(--orange-bg); color: var(--primary-text); }
.hinweis-kasten--stopp::before, .zahlungshinweis-pausiert::before { background: var(--bad-bg); color: var(--danger-text); }
.flash-success, .flash-bestaetigung, .flash-error, .flash-info, .hinweis-kasten--stopp, .zahlungshinweis-mahnung, .zahlungshinweis-pausiert, .zahlungshinweis-testphase { background: var(--kasten); color: var(--text); }
/* Leerer Zustand: Kasten, grosser Kreis, Titel in Archivo 20 */
.empty-state { background: var(--kasten); border: 1px solid var(--border-strong); box-shadow: var(--kante); border-radius: 12px; padding: 32px 24px; }
.empty-icon { display: flex; align-items: center; justify-content: center; width: 64px; height: 64px; margin: 0 auto 16px; border-radius: 50%; background: var(--orange-bg); color: var(--primary-text); font-size: 24px; opacity: 1; }
.empty-state h2 { font-family: var(--font-titel, 'Archivo', 'IBM Plex Sans', sans-serif); font-size: 20px; font-weight: 600; margin-bottom: 8px; }
.empty-state p { color: var(--text-muted); font-size: 14px; }
/* Upload: flach, gestrichelt, Orange erst bei Ziehen oder gewaehlter Datei */
.upload-zone { background: transparent; border: 1px dashed var(--ctl); }
.upload-zone:hover, .upload-zone.dragover { background: var(--orange-bg); border-color: var(--primary-text); box-shadow: none; }
.upload-zone.hat-dateien { border-style: solid; border-color: var(--primary-text); }
/* Schalter (Cookie-Einstellungen): aus = Rand, an = Rand und Toenung orange */
.ck-schieber { background: transparent; border: 1px solid var(--ctl); box-sizing: border-box; }
.ck-schieber::after { left: 2px; top: 2px; width: 22px; height: 22px; background: var(--ctl); }
.ck-schalter input:checked + .ck-schieber { background: var(--orange-bg); border-color: var(--primary-text); }
.ck-schalter input:checked + .ck-schieber::after { background: var(--primary-text); transform: translateX(22px); }

/* ── Bewegung: reduzierte Bewegung (Bea 02.11.2026, docs/bewegung_uebergabe.md) ──
   Eine zentrale Regel je Datei: jede Animation und jeder Uebergang schrumpft auf 1 ms,
   Schleifen laufen nur einmal. Ladekreis und Schimmer bleiben als stehendes Bild sichtbar. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}
