/* ==========================================================================
   DIE SCHRIFT — der Grund, warum die App vorher nach niemandem aussah
   ==========================================================================
   Hier stand: system-ui. Also der Systemzeichensatz. Eine Oberflaeche ohne
   eigene Schrift hat typografisch KEINE Identitaet, und das ist der groesste
   Einzelposten am Eindruck „das sieht zwanzig Jahre alt aus". Alles andere —
   Farbe, Radien, Schatten — wirkt erst danach.

   Es ist DIESELBE Schrift wie auf der oeffentlichen Seite: Archivo, aus der
   Tradition amerikanischer Industrie- und Beschilderungsschriften, schmal,
   kraeftig, werkstattnah. Wer von elektro-os.de in die App wechselt, soll nicht
   das Gefuehl haben, das Produkt gewechselt zu haben.

   EINE Kopie der Dateien, unter /web/schrift/. Ein zweiter Satz unter /app/
   waere 58 KB doppelt und wuerde beim naechsten Schriftwechsel auseinander
   laufen. Der Service Worker legt sie mit in die Schale (sw.js), damit die App
   auch ohne Netz ihre Schrift hat.

   Selbst gehostet und nicht ueber die Google-CDN: Wer Schriften von
   fonts.gstatic.com laedt, uebermittelt die IP-Adresse jedes Nutzers an Google.
   Deutsche Gerichte haben das mehrfach als DSGVO-Verstoss gewertet. */
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/web/schrift/archivo-400.woff2") format("woff2");
}
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("/web/schrift/archivo-500.woff2") format("woff2");
}
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 600;
  font-display: swap; src: url("/web/schrift/archivo-600.woff2") format("woff2");
}
@font-face {
  font-family: "Archivo"; font-style: normal; font-weight: 800;
  font-display: swap; src: url("/web/schrift/archivo-800.woff2") format("woff2");
}

/* ==========================================================================
   DIE FARBEN
   ==========================================================================
   VORHER: --hintergrund #f2f5f9, --primaer #14507a. Ein kaltes Blaugrau und ein
   dunkles Marineblau — die Standardfarben jeder Verwaltungssoftware seit etwa
   2003. Dazu Ueberschriften IN der Markenfarbe (h2 { color: --primaer }), was
   dasselbe Jahrzehnt noch einmal unterstreicht.

   JETZT: derselbe Satz wie auf der oeffentlichen Seite. Warmer Papiergrund,
   braeunliches Schwarz, und die Flamme als einzige kraeftige Farbe.

   DIE REGEL DAHINTER, und sie ist der eigentliche Unterschied: Die Flamme
   markiert HANDLUNG und AUSWAHL — den Knopf, den man drueckt, die Zeile, auf der
   man steht, das Feld, in dem man tippt. Sonst nichts. Eine Oberflaeche, in der
   auch Ueberschriften, Rahmen und Symbole die Markenfarbe tragen, hat keine
   Betonung mehr, weil alles betont ist. Genau daran erkennt man alte
   Verwaltungsmasken.

   Die Variablennamen bleiben (--primaer, --rahmen, …): Sie stehen an 62 Stellen
   in dieser Datei. Ein Umbenennen waere eine zweite Baustelle ohne Gewinn. */
:root {
  /* Nicht #FDFCFB wie auf der Webseite: Dort steht Text auf dem Grund, hier
     liegen weisse Karten darauf. Zwischen #FDFCFB und #FFFFFF liegen zwei
     Helligkeitsstufen — die Karte waere unsichtbar, und die Oberflaeche eine
     einzige weisse Flaeche ohne Gliederung. */
  --hintergrund: #F6F4F1;
  --flaeche: #FFFFFF;
  --sand: #F4F2EF;          /* zweite Ebene: Tabellenkopf, ruhende Felder */
  --sand-2: #EAE6E1;
  --text: #1F1D1B;          /* braeunliches Schwarz, kein Marineschwarz */
  --text-weich: #423D38;
  --gedaempft: #6F6862;
  --primaer: #E04A0C;       /* DIE FLAMME. Nur Handlung und Auswahl. */
  --primaer-tief: #B93A06;  /* gedrueckt, Hover */
  --primaer-hell: #FDEEE4;
  --ok: #2E6047;
  --ok-blass: #E7F0EA;
  --warn: #9A5B00;
  --warn-blass: #FBEEDB;
  --gefahr: #B3261E;
  --gefahr-blass: #FBE4E0;
  --rahmen: #E9E5E0;
  --rahmen-stark: #D5CFC8;

  /* Die Seitenspalte ist NICHT die Markenfarbe. Ein Block in Signalorange ueber
     die volle Bildschirmhoehe waere acht Stunden lang eine Zumutung — die
     Flamme wirkt nur, solange sie selten ist. Tiefe Tinte, und die Flamme
     markiert darin den Eintrag, auf dem man steht. */
  --spalte: #1F1D1B;
  --spalte-text: #EDE9E4;
  --spalte-linie: rgba(255, 252, 248, 0.10);

  /* SCHATTEN STATT RAHMEN. Vorher trug jede Karte eine 1px-Linie ringsum; bei
     dreissig Karten untereinander ergibt das ein Gitter, und das Auge findet
     keine Ordnung mehr. Ein Schatten sagt „liegt oben", ohne eine Linie zu
     ziehen. Warm getoent, nicht grau: Ein grauer Schatten auf warmem Grund
     sieht schmutzig aus. */
  --schatten-s: 0 1px 2px rgba(90, 55, 25, 0.06), 0 1px 1px rgba(90, 55, 25, 0.04);
  --schatten-m: 0 4px 12px -4px rgba(90, 55, 25, 0.12), 0 2px 4px rgba(90, 55, 25, 0.05);
  --schatten-l: 0 24px 48px -20px rgba(90, 55, 25, 0.28), 0 4px 12px rgba(90, 55, 25, 0.06);

  --rund: 12px;
  --rund-s: 9px;

  --schrift: "Archivo", ui-sans-serif, "Segoe UI", system-ui,
             -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Segoe UI Mono",
          "Roboto Mono", Menlo, Consolas, monospace;

  /* Gesprächs-Einschub und Aufnahme-Bahn rechnen alle auf denselben Boden.
     --chat-boden = 84px: Der mittige Sprach-Knopf ist 64 px hoch und sitzt
     12 px über dem Rand, seine Oberkante liegt also bei 76 px + Safe-Area;
     8 px Luft darüber. Wer diese Zahl ändert, verdeckt den Knopf, den der
     Daumen gerade hält. */
  --chat-boden: 84px;
  /* 76 % der Breite, nicht 88: Von 88 % blieb links ein Streifen, der die
     Zusage „das Formular verschwindet nicht" nur behauptet. Auf 390 px sind das
     296 px Panel und 94 px Formular — plus die obere Bildschirmhälfte, die der
     Einschub gar nicht anfasst. */
  --chat-breite: min(76vw, 400px);
  /* vh hier, dvh in der Feature-Query weiter unten: Auf iOS unter 15.4 gibt es
     dvh nicht, und eine unbekannte Einheit in einem calc() lässt die ganze
     Deckelung ausfallen. */
  --chat-hoehe: 56vh;
  /* Wird zur Laufzeit aus visualViewport gesetzt: Ohne diesen Wert liegt der
     Einschub unter der Bildschirmtastatur, sobald jemand in einem Formular
     getippt hat. */
  --tastatur-h: 0px;
  --ptt-pegel: 0;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--hintergrund);
  color: var(--text);
  min-height: 100vh;
}

.versteckt { display: none !important; }
.fehler { color: var(--gefahr); }
.hinweis { color: var(--gedaempft); font-size: 0.9rem; }

/* Das Lagebild wird als Text gezeigt und nicht als Tabelle: Es IST Text — genau
   der, den das Modell liest. Wer ihn hübsch aufbereitet, sieht etwas anderes als
   die KI, und dann ist die Ansicht wertlos. */
.lage-text {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-left: 4px solid var(--primaer);
  border-radius: 0 8px 8px 0;
  padding: 12px 14px;
  margin: 10px 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.82rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
}

/* --- Was aus einem Diktat kommt ---
   Die Fahne steht ÜBER dem Formular und nennt die Felder, die das Diktat
   geändert hat. Der Rest des Formulars stammt aus der Kartei; ohne diese
   Unterscheidung sieht ein geändertes Feld aus wie jedes andere — und der
   Meister sucht es. Genau das ist passiert: Die Straße lag in einer
   zugeklappten Gruppe, und das Formular wirkte leer. */
.sprach-fahne {
  margin: 0 0 12px;
  padding: 8px 12px;
  border-left: 4px solid var(--primaer);
  background: color-mix(in srgb, var(--primaer) 8%, transparent);
  border-radius: 0 8px 8px 0;
  font-size: 0.9rem;
}
/* Der kurze Blitz auf dem getroffenen Feld: Er sagt „hier", ohne dass man
   lesen muss. Nach zweieinhalb Sekunden ist er weg — ein Feld, das dauerhaft
   leuchtet, sieht nach einem Fehler aus. */
.sprach-treffer {
  outline: 3px solid var(--primaer);
  outline-offset: 2px;
  transition: outline-color 0.6s ease-out;
}

/* Nur für Vorlesesoftware: sichtbar für den Screenreader, unsichtbar auf dem
   Bildschirm. display:none wäre falsch — daraus liest niemand vor. */
.nur-vorlesen {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Login --- */
#login-view {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.login-karte {
  background: var(--flaeche);
  border-radius: 14px;
  box-shadow: 0 2px 12px rgba(20, 40, 60, .12);
  padding: 32px;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.login-karte h1 { margin: 0; color: var(--primaer); }
.untertitel { margin: 0; color: var(--gedaempft); }

label { display: flex; flex-direction: column; gap: 6px; font-size: 0.9rem; font-weight: 600; }

input, select {
  padding: 10px 12px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  font-size: 1rem;
  background: #fff;
  color: var(--text);
}

button { cursor: pointer; border: none; border-radius: 8px; font-weight: 600; font-size: 0.95rem; }

.primaer { background: var(--primaer); color: #fff; padding: 12px 18px; }
.sekundaer { background: var(--primaer-hell); color: var(--primaer); padding: 10px 16px; }

/* --- Layout --- */
#app-view { display: flex; min-height: 100vh; }

#hauptbereich {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

#sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--primaer);
  color: #fff;
  display: flex;
  flex-direction: column;
  padding: 20px 12px;
  gap: 4px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.nav-ikon { width: 20px; text-align: center; opacity: 0.85; flex-shrink: 0; }

.logo { font-size: 1.3rem; font-weight: 700; padding: 0 10px; }
.tenant-name { font-size: 0.8rem; opacity: 0.75; padding: 0 10px 16px; }

.nav-btn {
  background: transparent;
  color: #fff;
  text-align: left;
  padding: 10px 12px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.nav-btn:hover { background: rgba(255, 255, 255, .12); }
.nav-btn.aktiv { background: rgba(255, 255, 255, .22); }
.nav-btn.logout { margin-top: auto; opacity: 0.8; }

.pill {
  background: var(--warn);
  color: #fff;
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 0.75rem;
}

#content { flex: 1; padding: 28px 32px 60px; max-width: 1100px; width: 100%; }

h2 { margin-top: 0; color: var(--primaer); }
h3 { color: var(--gedaempft); }

/* --- Kennzahlen-Karten --- */
.karten {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}

.karte {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  padding: 16px 18px;
}

.karte .zahl { font-size: 1.8rem; font-weight: 700; color: var(--primaer); }
.karte .beschriftung { color: var(--gedaempft); font-size: 0.9rem; }

/* Einstellungen: eine Karte je Regel, gestapelt statt Tabelle. Ein Stundensatz
   braucht Platz fuer seinen Hinweis — in einer Tabellenzelle liest den niemand. */
.einst-karte { margin-bottom: 10px; }
.einst-karte .zeile-aktionen { margin-top: 8px; align-items: center; }
.einst-karte input, .einst-karte select { min-width: 180px; }
.einst-karte textarea { min-width: 260px; flex: 1 1 100%; font-family: inherit; }

/* --- Listen / Tabellen --- */
.tabelle { width: 100%; border-collapse: collapse; background: var(--flaeche); border-radius: 12px; overflow: hidden; }
.tabelle th, .tabelle td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--rahmen); font-size: 0.93rem; vertical-align: top; }
.tabelle th { background: var(--primaer-hell); color: var(--primaer); }

.zeile-aktionen { display: flex; gap: 8px; flex-wrap: wrap; }
.btn-ok { background: var(--ok); color: #fff; padding: 8px 14px; }
.btn-nein { background: var(--gefahr); color: #fff; padding: 8px 14px; }
.btn-klein { background: var(--primaer-hell); color: var(--primaer); padding: 8px 14px; }

.status {
  display: inline-block;
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 0.8rem;
  font-weight: 600;
  background: var(--rahmen);
}
.status.entwurf, .status.pending, .status.angefordert, .status.geplant { background: var(--warn-blass); color: var(--warn); }
.status.freigegeben, .status.approved, .status.bestellt, .status.in_arbeit { background: var(--primaer-hell); color: var(--primaer); }
.status.unterschrieben, .status.geliefert, .status.fertig { background: var(--ok-blass); color: var(--ok); }
.status.storniert, .status.rejected { background: var(--gefahr-blass); color: var(--gefahr); }
.status.versendet { background: var(--sand-2); color: var(--text-weich); }
.status.angenommen, .status.bezahlt { background: var(--ok-blass); color: var(--ok); }
.status.abgelehnt { background: var(--gefahr-blass); color: var(--gefahr); }

/* --- Rechnungen (M2) --- */
.warn-karte { border-color: var(--warn); }
.warn-balken {
  background: var(--warn-blass);
  color: var(--warn);
  padding: 8px 12px;
  border-radius: 8px;
  margin: 8px 0;
  font-size: 0.9rem;
}
.ueberfaellig { color: var(--gefahr); font-weight: 700; }

/* --- Mahnwesen (M3) --- */
.tab-zeile { display: flex; gap: 8px; margin: 18px 0 14px; }
.tab-btn { background: var(--rahmen); color: var(--gedaempft); padding: 8px 16px; }
.tab-btn.aktiv { background: var(--primaer); color: #fff; }
.check-zeile { flex-direction: row !important; align-items: center; gap: 6px; font-weight: 500; }
.check-zeile input { width: auto; }
.ampel { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 6px; }
.ampel.gruen { background: var(--ok); }
.ampel.gelb { background: var(--warn); }
.ampel.rot { background: var(--gefahr); }

/* --- Angebote: Speak-to-Form (M1) --- */
.diktat-zeile { display: flex; gap: 10px; flex: 1 1 100%; }
.diktat-zeile input { flex: 1; }
/* (Die Regel für .recording ist entfallen: Die eigene Aufnahme-Maschine der
   Formulare gab es zuletzt im August 2026. Beide Mikrofone tragen jetzt
   data-ptt und bekommen ihre Zustände aus den Regeln weiter unten.) */

/* Ein Feld, das der Entwurf leer gelassen hat. Rot umrandet, nicht rot gefüllt:
   Es ist keine Fehleingabe, es fehlt nur noch etwas — und die Nachfrage im
   Einschub nennt genau diese Felder. */
.feld-fehlt {
  border-color: var(--warn);
  background: var(--sand);
}

/* --- Verkaufsseite eines Artikels --- */
.artikel-bild-zeile { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.artikel-bild {
  width: 120px;
  height: 120px;
  object-fit: contain;
  border: 1px solid var(--rahmen);
  border-radius: 10px;
  background: var(--hintergrund);
}

/* --- Gewerke-Bausteine am Angebot ---
   Angekreuzt wird selten, gelesen wird immer: Die Felder erscheinen erst nach
   dem Haken, damit ein Angebot über zwanzig Meter Kabel nicht nach der
   Anlagengröße einer Photovoltaik-Anlage fragt. */
.gewerke-block { flex: 1 1 100%; display: flex; flex-direction: column; gap: 8px; }
.gewerk-karte {
  border: 1px solid var(--rahmen);
  border-radius: 10px;
  padding: 10px 12px;
  background: var(--flaeche);
}
.gewerk-felder { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.gewerk-felder label { flex: 1 1 200px; }

.pos-zeile { display: flex; gap: 8px; flex: 1 1 100%; align-items: center; }
.pos-zeile select { flex: 2 1 240px; }
.pos-zeile input { flex: 0 0 90px; }
.pos-zeile .pos-preis { flex: 0 0 120px; text-align: right; color: var(--gedaempft); font-size: 0.9rem; }
.pos-zeile select.pos-geltung { flex: 0 0 160px; }

/* Anruf-Link in der Auftrags-Akte. Auf dem Handy wählt ein Tipp die Nummer; auf
   dem Computer muss trotzdem erkennbar sein, dass es eine Nummer ist und kein
   Text. Deshalb Farbe UND Unterstreichung — Farbe allein reicht nicht, wenn
   jemand sie nicht unterscheiden kann. */
.tel-link { color: var(--primaer); text-decoration: underline; font-weight: 600; white-space: nowrap; }
/* Wahlweise Positionen zählen nicht in die Angebotssumme. Ohne sichtbaren
   Unterschied sucht der Meister den Fehler in der Summe statt in seiner Auswahl. */
.pos-zeile.pos-wahlweise { border-left: 3px solid var(--gedaempft); padding-left: 6px; }
.pos-zeile.pos-wahlweise .pos-preis { text-decoration: line-through; }

/* Herkunfts-Badge (UX-Vertrag): KI-vorbefüllt vs. manuell geändert */
.herkunft { font-size: 0.72rem; border-radius: 999px; padding: 1px 8px; margin-left: 6px; vertical-align: middle; }
.herkunft.ki { background: var(--primaer-hell); color: var(--primaer); }
.herkunft.manuell { background: var(--rahmen); color: var(--gedaempft); }

/* --- Formulare --- */
.formular { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 20px; }
.formular input, .formular select { flex: 1 1 180px; }
.formular button { flex: 0 0 auto; }

.filter-zeile { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }

/* --- Nachtrag-Details --- */
.detail-box { background: var(--flaeche); border: 1px solid var(--rahmen); border-radius: 12px; padding: 16px; margin-top: 12px; }
.detail-box img.signatur { max-width: 320px; width: 100%; border: 1px solid var(--rahmen); border-radius: 8px; background: #fff; }
.sign-link { word-break: break-all; font-size: 0.85rem; }

/* --- Termine: Wochenansicht (M4) --- */
.wochen-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}

.tag-spalte {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  padding: 10px;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tag-kopf { border-bottom: 1px solid var(--rahmen); padding-bottom: 6px; }

/* --- Die Plantafel: Zeilen sind Monteure, Spalten sind Tage ---
   Das Raster kippt von sieben gleichen Spalten auf „Name + sieben Tage". Der
   Name steht links und bleibt schmal: Er ist die Zeilenbeschriftung, nicht der
   Inhalt. */
.wochen-grid.plantafel {
  grid-template-columns: 1fr;
  gap: 6px;
}
.plantafel-zeile {
  display: grid;
  grid-template-columns: 150px repeat(7, minmax(0, 1fr));
  gap: 6px;
  align-items: stretch;
}
.plantafel-kopf { position: sticky; top: 0; background: var(--hintergrund); z-index: 1; }
.plantafel-kopf-tag {
  padding: 6px 8px;
  border-bottom: 1px solid var(--rahmen);
}
.plantafel-name {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px;
  font-weight: 600;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 10px;
  font-size: 0.9rem;
}
.plantafel-zelle {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 10px;
  padding: 6px;
  min-height: 62px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.plantafel-karte { font-size: 0.8rem; padding: 6px 8px; gap: 2px; }
/* Die Stundensumme steht unten in der Zelle — sie ist die Antwort auf „geht da
   noch was rein?", und die liest man am Fuß, nicht am Kopf. */
.plantafel-stunden { margin-top: auto; font-size: 0.78rem; color: var(--gedaempft); }
.plantafel-stunden.warnung { color: var(--warn); font-weight: 600; }
.tag-fuss { margin-top: auto; font-size: 0.8rem; }

.einsatz-karte {
  border: 1px solid var(--rahmen);
  border-left: 4px solid var(--primaer);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 0.88rem;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.einsatz-karte.status-storniert { opacity: 0.55; }
.einsatz-karte.status-storniert strong { text-decoration: line-through; }
.einsatz-karte.status-verschoben { border-left-color: var(--warn); }
.einsatz-karte.status-bestaetigt { border-left-color: var(--ok); }

.einsatz-zeile { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.erinnerung-icon { font-size: 0.9rem; }

.ma-punkt {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.ma-auswahl {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  flex: 1 1 100%;
  align-items: center;
}

@media (max-width: 1100px) {
  .wochen-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .wochen-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Toast ---
   z-index 32 und damit über allem: Der Toast trägt jetzt die Quittung jeder
   sprachgesteuerten Navigation („Berger geöffnet.") — bei einer reinen Handlung
   ist er die EINZIGE sichtbare Rückmeldung. Vorher lag er auf 10 und damit
   unter dem 76 Pixel großen Sprach-Knopf (z 16), der ihm auf dem Computer
   mittig die Mitte verdeckte. */
#toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--text);
  color: #fff;
  padding: 12px 22px;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .25);
  z-index: 32;
}

body.ansicht-desktop #toast { bottom: 116px; }
/* Während einer Aufnahme ist die Bahn die Meldung. Zwei Kanäle übereinander
   sind Krach — und der Toast läge genau darauf. */
body.ptt-aktiv #toast { display: none; }

/* --- Tablet (nur erzwungene Computer-Ansicht auf kleinem Bildschirm) --- */
@media (max-width: 820px) {
  body.ansicht-desktop #app-view { flex-direction: column; }
  body.ansicht-desktop #sidebar {
    width: 100%;
    height: auto;
    position: static;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }
  body.ansicht-desktop .tenant-name { padding: 0 10px; }
  body.ansicht-desktop #content { padding: 20px 16px 48px; }
}

/* Leads (M5): Score-Badges + Timeline */
.score-badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 0.82rem; font-weight: 700; }
.score-heiss { background: var(--gefahr-blass); color: var(--gefahr); border: 1px solid var(--gefahr); }
.score-warm { background: var(--warn-blass); color: var(--warn); border: 1px solid var(--warn); }
.score-kalt { background: var(--primaer-hell); color: var(--primaer); border: 1px solid var(--primaer); }
.timeline-eintrag { padding: 6px 0; border-bottom: 1px solid var(--rahmen); font-size: 0.92rem; }
.timeline-typ { display: inline-block; min-width: 96px; font-weight: 700; color: var(--primaer); }

/* Prüfprotokolle (M6): Bewertungs-Badges + Status-Ampel */
.bewertung-badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 0.82rem; font-weight: 700; }
.bewertung-ok { background: var(--ok-blass); color: var(--ok); border: 1px solid var(--ok); }
.bewertung-warnung { background: var(--warn-blass); color: var(--warn); border: 1px solid var(--warn); }
.bewertung-nicht_ok { background: var(--gefahr-blass); color: var(--gefahr); border: 1px solid var(--gefahr); }
.bewertung-nicht_geprueft { background: var(--sand-2); color: var(--gedaempft); border: 1px solid var(--gedaempft); }
.status.in_pruefung { background: var(--primaer-hell); color: var(--primaer); }
.status.bestanden { background: var(--ok-blass); color: var(--ok); }
.status.bestanden_mit_maengeln { background: var(--warn-blass); color: var(--warn); }
.status.nicht_bestanden { background: var(--gefahr-blass); color: var(--gefahr); }
.messwert-ersetzt { opacity: 0.55; }
.warn-text { color: var(--gefahr); font-weight: 600; font-size: 0.92rem; }

/* =====================================================================
   App-Shell (Login, Topbar, Mobile-Ansicht, Sprach-Knopf, Overlay)
   ===================================================================== */

/* --- Login --- */
.login-logo {
  width: 64px;
  height: 64px;
  border-radius: 16px;
  background: var(--primaer);
  color: #fff;
  font-size: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto;
}

.login-karte h1, .login-karte .untertitel { text-align: center; }

.login-button {
  padding: 14px 18px;
  font-size: 1.05rem;
  min-height: 48px;
}

#login-fehler {
  background: var(--gefahr-blass);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 0;
  font-size: 0.92rem;
}

/* --- Topbar (Desktop) --- */
#topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--flaeche);
  border-bottom: 1px solid var(--rahmen);
  padding: 10px 24px;
  position: sticky;
  top: 0;
  z-index: 5;
}

.topbar-info { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.topbar-info strong { color: var(--primaer); }

.topbar-aktionen { position: relative; }

.menue-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  box-shadow: 0 6px 24px rgba(20, 40, 60, .18);
  padding: 10px;
  min-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  z-index: 20;
}

.menue-titel { font-size: 0.78rem; font-weight: 700; color: var(--gedaempft); padding: 6px 10px 2px; text-transform: uppercase; letter-spacing: .04em; }

.menue-zeile {
  display: flex;
  flex-direction: row !important;
  align-items: center;
  gap: 8px;
  padding: 10px;
  border-radius: 8px;
  font-weight: 500;
  font-size: 0.95rem;
  background: transparent;
  color: var(--text);
  text-align: left;
  width: 100%;
  min-height: 44px;
}

.menue-zeile:hover { background: var(--primaer-hell); }
.menue-zeile input { width: auto; }
.menue-trennlinie { border-top: 1px solid var(--rahmen); margin: 6px 0; }
.menue-logout { color: var(--gefahr); font-weight: 600; }

/* --- Ansichts-Umschaltung --- */
body.ansicht-mobil #sidebar, body.ansicht-mobil #topbar { display: none; }
body.ansicht-desktop #tabbar { display: none; }
body.ansicht-mobil #ptt-bereich { display: none; } /* mobil sitzt der Knopf in der Tab-Bar */

body.ansicht-mobil #content {
  padding: 16px 14px 130px; /* Platz für Tab-Bar inkl. überstehendem Sprach-Knopf */
  max-width: 640px;
  margin: 0 auto;
}

/* --- Mobile: Bottom-Tab-Bar --- */
#tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  background: var(--flaeche);
  border-top: 1px solid var(--rahmen);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  z-index: 15;
}

.tab-eintrag {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: transparent;
  color: var(--gedaempft);
  font-size: 0.72rem;
  font-weight: 600;
  min-height: 56px;
  border-radius: 0;
  padding: 6px 2px;
}

.tab-eintrag .tab-ikon { font-size: 1.25rem; }
.tab-eintrag.aktiv { color: var(--primaer); }

/* Sprach-Knopf als fester Mittelpunkt der Tab-Bar (Center-Action-Button) */
.tab-mitte { flex: 0 0 84px; position: relative; }

#ptt-mobil {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--primaer);
  color: #fff;
  border: 4px solid var(--flaeche);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(20, 80, 122, .45);
  user-select: none;
  -webkit-user-select: none;
}

#ptt-mobil .ptt-ikon { font-size: 1.5rem; line-height: 1; }

/* Die Zustände des Sprach-Knopfes stehen gesammelt im Abschnitt
   „Sprachbedienung" weiter unten — vier Knöpfe, dieselben Klassen. */

/* --- Mobile: Mein Tag --- */
.schnellaktionen {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin: 14px 0 20px;
}

.aktion-karte {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 14px;
  padding: 14px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-height: 96px;
  color: var(--text);
}

.aktion-karte:active { background: var(--primaer-hell); }
.aktion-ikon { font-size: 1.5rem; color: var(--primaer); }
.aktion-titel { font-weight: 700; font-size: 0.9rem; }
.aktion-sub { font-size: 0.72rem; color: var(--gedaempft); text-align: center; }

.termin-karte {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-left: 5px solid var(--primaer);
  border-radius: 12px;
  padding: 14px 16px;
  margin-bottom: 10px;
}

.termin-karte .termin-zeit { font-weight: 700; color: var(--primaer); font-size: 1.05rem; }
.termin-karte .termin-meta { color: var(--gedaempft); font-size: 0.88rem; margin-top: 4px; }

.leer-zustand {
  background: var(--flaeche);
  border: 1px dashed var(--rahmen);
  border-radius: 12px;
  padding: 22px 18px;
  text-align: center;
  color: var(--gedaempft);
}

/* --- Mobile: Modul-Kacheln --- */
.modul-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.modul-kachel {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 14px;
  min-height: 88px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 10px 4px;
  text-align: center;
}

.modul-kachel:active { background: var(--primaer-hell); }
.modul-ikon { font-size: 1.4rem; color: var(--primaer); }

/* --- Mobile: Menü --- */
.menue-logout-mobil {
  width: 100%;
  min-height: 52px;
  font-size: 1.05rem;
  margin-top: 14px;
}

#view-menue .karte { margin-bottom: 12px; }

/* --- Sprach-Knopf, Desktop (mobil sitzt er in der Tab-Bar) --- */
#ptt-bereich {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 24px;
  display: flex;
  justify-content: center;
  z-index: 16;
  pointer-events: none;
}

#ptt-bereich > * { pointer-events: auto; }

#ptt {
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background: var(--primaer);
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  box-shadow: 0 4px 18px rgba(20, 80, 122, .45);
  user-select: none;
  -webkit-user-select: none;
}

#ptt .ptt-ikon { font-size: 1.6rem; line-height: 1; }
#ptt .ptt-label { font-size: 0.6rem; font-weight: 700; text-align: center; padding: 0 6px; }

/* Der Puls fasst „transform" NICHT an: #ptt-mobil steht über
   transform: translateX(-50%) in der Mitte der Tab-Bar, und ein
   transform: scale() in den Keyframes hätte diese Verschiebung überschrieben —
   der Knopf wäre beim Drücken 32 Pixel nach rechts unter dem Daumen
   weggesprungen. „scale" als eigene Eigenschaft lässt translateX in Ruhe. */
@keyframes ptt-puls {
  0%, 100% { scale: 1; }
  50% { scale: 1.08; }
}

/* --- Offline-Queue-Balken (schwebt über Tab-Bar bzw. Sprach-Knopf) --- */
#queue-bar {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 116px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--text);
  color: #fff;
  border-radius: 999px;
  padding: 8px 16px;
  font-size: 0.85rem;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .25);
  z-index: 16;
}

body.ansicht-mobil #queue-bar {
  bottom: calc(76px + env(safe-area-inset-bottom, 0px) + 14px);
}

/* Während einer Aufnahme steht die Bahn an dieser Stelle — der Wartezähler
   kann die fünf Sekunden warten. */
body.ptt-aktiv #queue-bar { visibility: hidden; }
/* Bei offenem Einschub wandert der Offline-Hinweis nach oben, wo Platz ist. */
body.chat-offen.ansicht-mobil #queue-bar { top: 8px; bottom: auto; }

#queue-bar button {
  background: var(--warn);
  color: #fff;
  border-radius: 999px;
  padding: 4px 12px;
  font-size: 0.8rem;
}

/* =====================================================================
   Sprachbedienung: Aufnahme-Bahn und Gesprächs-Einschub
   =====================================================================
   Hier stand bis August 2026 ein modales Overlay mit Backdrop. Es war der
   Grund für die häufigste Beschwerde am ganzen System: Knopf drücken, Popup
   kommt, sprechen, Popup schließen, Knopf erneut drücken. Ein Modal über dem
   Formular nimmt dem Nutzer außerdem genau das weg, worüber er spricht.

   Ersatz sind zwei Dinge, die nichts verdecken, was man bedienen muss:
   eine Bahn am unteren Rand (läuft die Aufnahme?) und ein Einschub von
   rechts (hat die KI etwas gesagt?). */

/* --- Die Aufnahme-Bahn --- */
#ptt-leiste {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--chat-boden) + env(safe-area-inset-bottom, 0px) + var(--tastatur-h));
  z-index: 17;
  min-height: 64px;
  display: none;
  align-items: center;
  /* Umbruch ist Pflicht: Pegel, Uhr, zwei 48-Pixel-Knöpfe UND ein Satz gehen auf
     einem 360-Pixel-Gerät nicht in eine Zeile. Ohne ihn wurde genau die
     Anweisung abgeschnitten, die dem Nutzer sagt, was zu tun ist. */
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 12px;
  background: var(--gefahr);
  color: #fff;
  font-weight: 600;
}

body.ptt-aktiv #ptt-leiste,
body.ptt-meldet #ptt-leiste,
body.ptt-sendet #ptt-leiste { display: flex; }
/* Nach dem Ende bleibt die Bahn kurz stehen, um eine Meldung zu tragen
   („Zu kurz — halten, sprechen, loslassen") — dann aber neutral, nicht rot:
   Rot heißt in dieser App „es läuft". */
body:not(.ptt-aktiv) #ptt-leiste { background: var(--text); }
body.ansicht-desktop #ptt-leiste { bottom: 112px; }
/* Läuft die Aufnahme über den Antwort-Knopf IM Einschub, ist dieser selbst die
   Rückmeldung — dann wäre die Bahn eine zweite Meldung an einer Stelle, an der
   sie das Panel überdeckt. Die Regel hängt am BESITZER der Aufnahme, nicht am
   Panelzustand: Wer bei offenem Einschub den Knopf in der Tab-Bar hält, braucht
   die Bahn weiterhin — sonst hätte er auf dem iPhone (kein vibrate) keinen
   einzigen Kanal. */
/* Zwei Einschränkungen, jede aus einem eigenen Fall:
   `.chat-offen`, weil eine gerastete Aufnahme sonst unsichtbar weiterläuft,
   sobald man den Einschub wegschiebt — offenes Mikrofon ohne jede Anzeige.
   `:not(.gerastet)`, weil die Ansage „Senden drücken" sagt und der Senden-Knopf
   in der Bahn sitzt: Wer ihn ausblendet, kündigt einen Knopf an, den es nicht
   gibt. */
body.ptt-in-chat.chat-offen #ptt-leiste:not(.gerastet) { display: none; }
/* Umgekehrt: Wer bei offenem Einschub den Knopf in der Tab-Bar hält, muss die
   Bahn sehen — der Einschub liegt sonst darüber (z 28) und verdeckt sie. Für die
   Dauer der Aufnahme gewinnt die Bahn und verdeckt dafür den Fuß des Einschubs,
   den in diesem Moment niemand braucht. */
body.chat-offen #ptt-leiste { z-index: 29; }
#ptt-leiste.warnung { background: var(--warn); }
#ptt-leiste.gerastet { background: var(--gefahr); }

/* Der Satz bekommt eine eigene, volle Zeile UNTER Pegel, Uhr und Knöpfen
   (order: 1) und darf zwei bis drei Zeilen hoch werden. Die Bahn wächst dabei
   nach oben; sie ist fixiert und transient, es verschiebt sich nichts. */
#ptt-hinweis {
  order: 1;
  flex: 1 0 100%;
  white-space: normal;
  font-size: 0.9rem;
  font-weight: 500;
}

#ptt-uhr {
  font-variant-numeric: tabular-nums;
  min-width: 44px;
  font-size: 0.95rem;
}

/* Sieben fette Balken: die Bewegung, die aus zwei Metern Entfernung sagt
   „es hört zu". Unter 360 Pixeln Breite entfällt sie — dort tragen rote Fläche
   und Uhr die Aussage allein, und der Abbrechen-Knopf braucht den Platz. */
.pegel { display: flex; align-items: flex-end; gap: 3px; height: 26px; flex: 0 0 auto; }
.pegel-balken {
  width: 5px;
  height: 6px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .35);
  transition: height .08s linear;
}
.pegel-balken.an { background: #fff; }

@media (max-width: 359px) {
  .pegel { display: none; }
  .ptt-wort { display: none; }
}

#ptt-freihand, #ptt-senden, #ptt-abbrechen, #chat-abbrechen {
  flex: 0 0 auto;
  min-height: 48px;
  min-width: 48px;
  padding: 0 12px;
  border-radius: 10px;
  background: rgba(0, 0, 0, .28);
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
}

#ptt-senden { background: var(--ok); }

/* Der Ring um den Knopf wächst mit dem Pegel — dieselbe Aussage wie die Bahn,
   nur dort, wo der Daumen ohnehin liegt. */
.ptt-ring {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow: 0 0 0 calc(2px + var(--ptt-pegel, 0) * 10px) rgba(192, 57, 43, .35);
  opacity: 0;
}

.aufnahme .ptt-ring, .gerastet .ptt-ring { opacity: 1; }

/* Zustände auf ALLEN Sprach-Knöpfen gleich — ein Knopf, sechs Orte.
   Über [data-ptt] und nicht über eine Namensliste: Die beiden Mikrofone an
   den Formularen (#angebot-mikro, #einsatz-mikro) hingen seit ihrer
   Umstellung an derselben Zustandsmaschine, fehlten aber in jeder dieser
   Regeln — sie zeigten beim Aufnehmen nichts an. Wer den nächsten Knopf
   baut, gibt ihm data-ptt und ist fertig. */
[data-ptt] { position: relative; }
[data-ptt].aufnahme:not(#heute-mikro),
[data-ptt].gerastet:not(#heute-mikro) {
  background: var(--gefahr);
  color: #fff;
}
[data-ptt].aufnahme:not(#heute-mikro) {
  animation: ptt-puls 1s ease-in-out infinite;
}
#heute-mikro.aufnahme, #heute-mikro.gerastet {
  border-color: var(--gefahr);
  background: var(--gefahr-blass);
}
[data-ptt].ruestet:not(#heute-mikro) { background: var(--gedaempft); }

/* Halten heißt halten: kein Scrollen, keine Textauswahl, kein Kontextmenü und
   kein Doppeltipp-Zoom unter dem Daumen. Die drei kleinen Knöpfe liegen fest
   außerhalb des Scrollflusses, dort ist „none" gefahrlos. */
[data-ptt]:not(#heute-mikro) {
  touch-action: none;
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}
/* Der große Start-Knopf liegt IM scrollenden Bereich. „none" würde dort das
   Scrollen der Startansicht töten — deshalb bleibt die vertikale Achse dem
   Browser, und die Aufnahme wird erst nach einer kurzen Verzögerung scharf. */
#heute-mikro {
  touch-action: pan-y;
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
}

/* --- Der Gesprächs-Einschub --- */
/* Sichtbarkeit läuft NICHT über .versteckt (display:none !important): Das ist
   nicht animierbar, und die Bewegung von rechts nach links IST die Aussage
   „das kam von der Seite und kann dorthin zurück". visibility:hidden nimmt den
   geschlossenen Einschub zugleich aus Trefferprüfung und Vorlesebaum — kein
   inert, kein aria-hidden-Umschalten. Kein Nachfahre darf visibility:visible
   setzen, sonst wird er trotz geschlossenem Panel bedienbar und vorgelesen. */
#chat-faden {
  position: fixed;
  z-index: 28;
  display: flex;
  flex-direction: column;
  background: var(--flaeche);
  transform: translateX(105%);
  visibility: hidden;
  transition: transform .22s ease-out, visibility 0s linear .22s;
}

body.chat-offen #chat-faden {
  transform: translateX(0);
  visibility: visible;
  transition: transform .22s ease-out, visibility 0s;
}

/* Mobil: rechts angeschlagen, unten über dem Sprach-Knopf, nie über der
   Tab-Bar. 76 % Breite statt 92 %: Bei 92 % bliebe vom Formular ein Streifen,
   der die Zusage „das Formular verschwindet nicht" nur behauptet. */
body.ansicht-mobil #chat-faden {
  right: 0;
  bottom: calc(var(--chat-boden) + env(safe-area-inset-bottom, 0px) + var(--tastatur-h));
  width: var(--chat-breite);
  height: auto;
  /* Die alten Einheiten stehen hier, die neuen in der Feature-Query darunter.
     Eine zweite Deklaration mit dvh an DIESER Stelle wäre kein Rückfall gewesen:
     Ein Browser ohne dvh verwirft die ganze Regel, die vorherige gilt weiter —
     aber sobald calc() eine unbekannte Einheit enthält, fällt die Deckelung
     komplett aus und das Panel wächst über den Bildschirm. */
  max-height: 56vh;
  min-height: min(
    240px,
    calc(100vh - var(--chat-boden) - env(safe-area-inset-bottom, 0px) - var(--tastatur-h) - 16px)
  );
  border: 1px solid var(--rahmen);
  border-right: none;
  border-radius: 16px 0 0 16px;
  box-shadow: -6px 0 24px rgba(0, 0, 0, .25);
  padding-right: env(safe-area-inset-right, 0px);
}

/* dvh nur, wo es existiert (iOS ab 15.4, alle aktuellen Browser). Dort ist die
   Höhe zusätzlich gegen den wirklich verfügbaren Raum gedeckelt, damit im
   Querformat der Fuß mit dem Antwort-Knopf sichtbar bleibt. */
@supports (height: 1dvh) {
  :root { --chat-hoehe: 56dvh; }
  body.ansicht-mobil #chat-faden {
    max-height: min(
      var(--chat-hoehe),
      calc(100dvh - var(--chat-boden) - env(safe-area-inset-bottom, 0px) - var(--tastatur-h) - 16px)
    );
    min-height: min(
      240px,
      calc(100dvh - var(--chat-boden) - env(safe-area-inset-bottom, 0px) - var(--tastatur-h) - 16px)
    );
  }
}

@media (orientation: landscape) and (max-height: 500px) {
  :root { --chat-hoehe: 82vh; }
}

@supports (height: 1dvh) {
  @media (orientation: landscape) and (max-height: 500px) {
    :root { --chat-hoehe: 82dvh; }
  }
}

/* Computer: die rechte Ebene, wie die Detail-Ansicht — derselbe Schatten von
   links, derselbe Rand. #content wird NICHT verengt: Die Tabellen dort sind
   sechs- und siebenspaltig und haben keinen eigenen Scroll-Container, jede
   Verengung schöbe sie ins Body-Overflow. Der Einschub liegt darüber und wird
   weggeschoben. */
body.ansicht-desktop #chat-faden {
  top: 0;
  bottom: 0;
  right: 0;
  width: min(38vw, 400px);
  max-height: none;
  border-radius: 0;
  border-left: 1px solid var(--rahmen);
  box-shadow: -6px 0 24px rgba(0, 0, 0, .18);
}

body.ansicht-desktop.chat-offen #ptt-bereich { right: min(38vw, 400px); }

#chat-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid var(--rahmen);
  color: var(--primaer);
}

#chat-zu {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--rahmen);
  color: var(--text);
}

/* overscroll-behavior ist Pflicht: Ohne sie scrollt iOS am Ende des Verlaufs
   das Formular dahinter weg. Kein Body-Scroll-Lock — hinten soll man
   weiterarbeiten können, das ist der ganze Zweck. */
#chat-verlauf {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
}

.chat-eintrag {
  max-width: 92%;
  padding: 10px 12px;
  border-radius: 12px;
  font-size: 0.95rem;
  line-height: 1.35;
}

.chat-eintrag.nutzer {
  align-self: flex-end;
  background: var(--primaer-hell);
  color: var(--text);
  font-style: italic;
}

.chat-eintrag.ai {
  align-self: flex-start;
  background: var(--hintergrund);
  border: 1px solid var(--rahmen);
}

.chat-eintrag.frage { border-left: 4px solid var(--primaer); font-weight: 600; }
.chat-eintrag.karte { align-self: stretch; max-width: 100%; background: var(--flaeche); }
.chat-eintrag.quittung { align-self: stretch; background: var(--ok-blass); border: 1px solid var(--ok); }
.chat-eintrag.quittung.nein { background: var(--gefahr-blass); border-color: var(--gefahr); }
.chat-eintrag.navigation { align-self: flex-start; color: var(--gedaempft); font-size: 0.85rem; }
.chat-eintrag.system { align-self: stretch; background: var(--warn-blass); border: 1px solid var(--warn); }
.chat-eintrag ul { margin: 6px 0 0; padding-left: 18px; }
.chat-tagestrenner {
  align-self: center;
  color: var(--gedaempft);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: .04em;
}

/* Die Bestätigungskarte im Verlauf: dieselben Regeln wie vorher im Overlay,
   nur unter neuem Dach — voiceKarte() bleibt dadurch unverändert. */
#chat-verlauf .felder { width: 100%; border-collapse: collapse; }
#chat-verlauf .felder th, #chat-verlauf .felder td {
  text-align: left;
  padding: 6px 8px;
  border-bottom: 1px solid var(--rahmen);
  font-size: 0.92rem;
  vertical-align: top;
}
#chat-verlauf .felder th { color: var(--gedaempft); font-weight: 600; width: 40%; }
#chat-verlauf .aktionen { display: flex; gap: 10px; margin-top: 14px; }
/* Gegenvorschlaege: abgesetzt von den Warnungen darueber und von der Freigabe
   darunter. Sie sind weder das eine noch das andere — sie sind der Ausweg. Der
   linke Balken sagt: Das gehoert zusammen und ist nicht Teil der Karte selbst. */
.vorschlaege {
  margin-top: 10px;
  padding: 8px 10px;
  border-left: 3px solid var(--primaer);
  background: rgba(127, 127, 127, 0.07);
  border-radius: 0 8px 8px 0;
}
/* DIE MORGENLAGE. Oben, ruhig, lesbar mit einer Hand.
   Der linke Balken ist kein Schmuck: Er trennt „was heute zu tun ist" von allem
   darunter, das ein Bericht ist. Ein ruhiger Tag verliert die Farbe — sonst sieht
   „nichts Dringendes" aus wie ein Alarm. */
.morgenlage {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-left: 4px solid var(--warn);
  background: rgba(127, 127, 127, 0.08);
  border-radius: 0 10px 10px 0;
}

/* STARTKLAR — die Karte der ersten Tage. Sie sieht aus wie die Morgenlage und
   nicht wie eine Werbeeinblendung: Was aussieht wie Werbung, wird weggeklickt.
   Der Balken ist die einzige Zierde und trägt eine Aussage: Wie weit bin ich. */
.startklar {
  margin: 0 0 16px;
  padding: 12px 14px;
  border-left: 4px solid var(--ok);
  background: rgba(127, 127, 127, 0.08);
  border-radius: 0 10px 10px 0;
}
.startklar-kopf { margin: 0 0 8px; font-weight: 600; }
.startklar-balken {
  height: 6px;
  border-radius: 3px;
  background: var(--rahmen);
  overflow: hidden;
  margin-bottom: 12px;
}
.startklar-fuellung { height: 100%; background: var(--ok); }
.startklar-liste { display: flex; flex-direction: column; gap: 12px; }
.startklar-zeile { border-left: 2px solid var(--rahmen); padding-left: 10px; }
.startklar-zeile.pflicht { border-left-color: var(--warn); }
/* Der Titel IST der Weg dorthin: „Einstellungen → Firmendaten" zu lesen und
   dann selbst zu finden, sind zwei Handlungen. */
.startklar-titel {
  background: none;
  border: 0;
  padding: 0;
  min-height: 32px;
  font: inherit;
  font-weight: 600;
  color: var(--primaer);
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}
.startklar-marke {
  margin-left: 8px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--warn);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.startklar-zeile .hinweis { margin: 2px 0 0; }
.startklar-wo { margin: 2px 0 0; font-size: 0.8rem; color: var(--gedaempft); }
.morgenlage.ruhig { border-left-color: var(--rahmen); }
.morgenlage-kopf { margin: 0 0 8px; font-weight: 600; }
.morgenlage-liste { margin: 0; padding-left: 18px; }
.morgenlage-liste li { margin-bottom: 6px; line-height: 1.45; }
/* Eine anklickbare Zeile sieht wie Text aus und verhaelt sich wie ein Knopf:
   Ein Kasten um jede Zeile waere eine Knopfleiste, und die liest man nicht. */
.morgenlage-zeile {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: var(--primaer);
  text-align: left;
  font: inherit;
  text-decoration: underline;
  text-decoration-style: dotted;
  cursor: pointer;
  min-height: 32px;
}
.morgenlage .hinweis { margin: 8px 0 0; font-size: 0.8rem; }

/* Die Frage nach dem Grund einer Ablehnung. Abgesetzt und leise: Sie ist eine
   Bitte und keine Aufgabe — wer sie uebergeht, hat nichts falsch gemacht. */
.grundfrage { margin-top: 10px; }
.grundfrage .hinweis { margin: 0 0 6px; }
.grundfrage .aktionen { margin-top: 0; flex-wrap: wrap; gap: 8px; display: flex; }
.grundfrage button { min-height: 40px; font-size: 0.9rem; }

/* „die KI liest sie mit" — der Zusatz am Etikett eines Notizfelds. Leise, aber
   da: Wer eine Notiz schreibt, soll wissen, dass sie mehr als ein Merkzettel
   ist. Ohne diesen Hinweis waere die Wirkung unsichtbar, und unsichtbare
   Wirkung ist genau das, was Software unheimlich macht. */
.ki-liest {
  font-weight: 400;
  font-size: 0.82rem;
  color: var(--primaer);
  margin-left: 6px;
  white-space: nowrap;
}

/* Was die KI weiss: Der Satz zuerst, das Drumherum leise. Wer die Liste
   ueberfliegt, soll das WISSEN lesen und nicht die Herkunft. */
.wissen-zeile { margin-bottom: 10px; }
.wissen-zeile strong { display: block; margin-bottom: 4px; }
.wissen-zeile .hinweis { margin: 0 0 6px; }
.wissen-buero { color: var(--warn); }

/* Der Wochenblick: woran der Befund haengt, in Farbe.
   Ein Kalkulationsproblem und ein Haftungsrisiko brauchen verschiedene
   Antworten. Wer eine Liste von zwoelf Punkten ohne Unterschied vor sich hat,
   liest sie von oben nach unten und nicht nach Wichtigkeit — und faengt beim
   harmlosesten an. Die Farben sind dieselben wie bei .status, damit „rot"
   ueberall im System dasselbe heisst. */
.wb-risiko { background: var(--gefahr-blass); color: var(--gefahr); }
.wb-geld { background: var(--warn-blass); color: var(--warn); }
.wb-zeit { background: var(--primaer-hell); color: var(--primaer); }
.wb-chance { background: var(--ok-blass); color: var(--ok); }
/* „Ablauf" bleibt grau: Es ist die Sammelsorte, und eine Sammelsorte, die
   auffaellt, zieht die Aufmerksamkeit von den vier Sorten weg, die etwas
   bedeuten. */
.wochenblick-marke { margin-bottom: 6px; }

/* Der Berater: ein Gespraech, kein Formular.
   Die zwei Seiten muessen sich auf einen Blick unterscheiden — wer beim
   Ueberfliegen nicht sieht, wer gerade geredet hat, liest den Verlauf falsch.
   Deshalb Rand LINKS beim Berater und rechts eingerueckt beim Menschen: derselbe
   Griff wie in jeder Nachrichten-App, und er funktioniert ohne Farbe. */
.berater-verlauf {
  max-height: 58vh;
  overflow-y: auto;
  margin-bottom: 16px;
  padding-right: 4px;
}
.berater-zug { margin-bottom: 14px; }
.berater-text { margin: 0; white-space: pre-wrap; }
.berater-berater {
  border-left: 3px solid var(--primaer);
  padding-left: 12px;
}
.berater-mensch {
  margin-left: 15%;
  padding: 8px 12px;
  border-radius: 10px;
  background: var(--rahmen);
}
/* Wie oft nachgeschlagen wurde — leise, aber immer da. */
.berater-fuss { margin: 4px 0 0; font-size: 0.8rem; }
.berater-eingabe textarea { width: 100%; resize: vertical; }

/* Der Sprechen-Knopf waehrend der Aufnahme. Rot und pulsierend, weil „laeuft
   gerade" der einzige Zustand ist, den man beim Sprechen nicht selbst sieht —
   man schaut nicht auf den Bildschirm, waehrend man redet. */
#berater-sprechen.laeuft {
  background: var(--gefahr); color: #fff;
  box-shadow: inset 0 0 0 1.5px var(--gefahr);
  animation: beraterpuls 1.6s ease-in-out infinite;
}
@keyframes beraterpuls { 0%,100% { opacity: 1 } 50% { opacity: 0.72 } }
@media (prefers-reduced-motion: reduce) { #berater-sprechen.laeuft { animation: none } }


#chat-verlauf .vorschlaege {
  margin-top: 14px;
  padding: 10px 12px;
  border-left: 3px solid var(--primaer);
  background: rgba(127, 127, 127, 0.07);
  border-radius: 0 8px 8px 0;
}
#chat-verlauf .vorschlaege .hinweis { margin: 0 0 8px; }
/* Umbrechen statt quetschen: „Martina Meister am 19.08.2026" ist laenger als
   ein halber Handy-Bildschirm. */
#chat-verlauf .vorschlaege .aktionen { margin-top: 0; flex-wrap: wrap; }
#chat-verlauf .vorschlaege button { min-height: 44px; }
#chat-verlauf .freigeben, #chat-verlauf .ablehnen {
  flex: 1;
  min-height: 52px;
  font-size: 1.05rem;
  color: #fff;
}
#chat-verlauf .freigeben { background: var(--ok); }
#chat-verlauf .ablehnen { background: var(--gefahr); }
#chat-verlauf .warn-balken { color: var(--warn); font-weight: 600; }

#chat-neu-chip {
  position: absolute;
  right: 14px;
  bottom: 96px;
  min-height: 44px;
  padding: 0 14px;
  border-radius: 999px;
  background: var(--primaer);
  color: #fff;
  font-size: 0.85rem;
  z-index: 1;
}

#chat-fuss {
  border-top: 1px solid var(--rahmen);
  padding: 10px 12px max(env(safe-area-inset-bottom, 0px), 10px);
}

#chat-status { margin: 0 0 6px; min-height: 1.1em; }
.chat-fuss-zeile { display: flex; gap: 8px; align-items: stretch; }

/* Ein Druck pro Antwort, dort wo die Augen sind: Der Antwort-Knopf sitzt im
   Fuß des Einschubs, direkt unter der Frage. */
#chat-antwort {
  flex: 1 1 auto;
  min-height: 64px;
  border-radius: 12px;
  background: var(--rahmen);
  color: var(--text);
  font-weight: 700;
}

#chat-antwort.erwartet { background: var(--primaer); color: #fff; }
#chat-abbrechen { background: var(--gedaempft); }

/* --- Der Griff --- */
/* Sichtbar ist ein 28 Pixel schmaler Streifen — und genau dieser Streifen ist
   auch die Trefferfläche. Ein unsichtbarer Überhang darüber hinaus wäre
   bequemer zu treffen und würde jeden Knopf schlucken, der darunter endet.
   28 × 112 erfüllt die Mindestgröße (WCAG 2.2, 2.5.8: 24 × 24) mit Abstand;
   44 Pixel Breite wären die dicke Karte am Rand, die ausdrücklich nicht
   gewollt ist. Bedient wird er per TIPPEN, nicht per Ziehen — damit kollidiert
   er nicht mit der Zurück-Wischzone, die Android an beiden Bildschirmrändern
   für sich beansprucht. */
#chat-griff {
  position: fixed;
  z-index: 27;
  right: env(safe-area-inset-right, 0px);
  top: 50%;
  transform: translateY(-50%);
  width: 28px;
  padding: 0;
  background: transparent;
  border: none;
  display: none;
}

/* Die Einblende-Bedingung trägt beide Ausschlüsse selbst. Eine spätere Regel
   „body.detail-offen #chat-griff { display: none }" allein genügte NICHT: Sie
   hat dieselbe Spezifität wie diese hier und stand nur zufällig danach — beim
   nächsten Umsortieren wäre der Griff über der Akte wieder da. */
body.chat-hat-verlauf:not(.chat-offen):not(.detail-offen) #chat-griff { display: block; }
/* Über einer offenen Akte hat der Griff nichts zu suchen: Er lag dort über dem
   rechten Rand des Detail-Panels und schluckte dessen Bedienelemente. Sprechen
   geht weiter über den Knopf in der Tab-Bar. */
body.detail-offen #chat-griff { display: none; }

.chat-griff-strich {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 112px;
  border-radius: 12px 0 0 12px;
  background: var(--primaer);
  color: #fff;
  box-shadow: -2px 0 8px rgba(0, 0, 0, .2);
}

.chat-griff-schrift {
  writing-mode: vertical-rl;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: .04em;
}

.chat-griff-zaehler {
  position: absolute;
  top: -8px;
  left: -10px;
  min-width: 20px;
  height: 20px;
  border-radius: 999px;
  background: var(--gefahr);
  color: #fff;
  font-size: 0.72rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Mobil in der Daumenzone statt in der Bildschirmmitte. */
body.ansicht-mobil #chat-griff {
  top: auto;
  bottom: calc(var(--chat-boden) + env(safe-area-inset-bottom, 0px) + var(--tastatur-h) + 12px);
  transform: none;
}

/* Bewegung ist abschaltbar — der erste Block dieser Art im Projekt. Er nimmt
   endlich auch den Puls des Sprach-Knopfes mit, der bisher nicht abschaltbar
   war. */
@media (prefers-reduced-motion: reduce) {
  #chat-faden { transition: none; }
  #ptt.aufnahme, #ptt-mobil.aufnahme, #chat-antwort.aufnahme,
  #heute-mikro.aufnahme, .pegel-balken { animation: none; transition: none; }
}

/* --- Mobile: Karten-Listen statt Tabellen --- */
.karte-liste { display: flex; flex-direction: column; gap: 10px; }

.daten-karte {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.daten-karte.tappbar { cursor: pointer; }
.daten-karte.tappbar:active { background: var(--primaer-hell); }

.daten-karte-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.daten-karte-kopf strong { min-width: 0; overflow-wrap: anywhere; }

.daten-feld { display: flex; gap: 8px; font-size: 0.92rem; }
.daten-feld .daten-label {
  flex: 0 0 40%;
  max-width: 40%;
  color: var(--gedaempft);
  font-weight: 600;
}
.daten-feld .daten-wert { min-width: 0; overflow-wrap: anywhere; }

.daten-aktionen { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
.daten-aktionen button { flex: 1 1 auto; min-height: 44px; }
.daten-aktionen > select, .daten-aktionen > input { flex: 1 1 100%; }
.daten-aktionen > label { flex: 1 1 100%; display: flex; align-items: center; gap: 8px; font-weight: 500; }
.daten-aktionen input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; }

.tag-liste-kopf {
  margin: 18px 0 4px;
  color: var(--gedaempft);
  font-weight: 700;
}

/* --- Mobile: Tabellen & Formulare fingerfreundlich --- */
body.ansicht-mobil button { min-height: 48px; }
body.ansicht-mobil input, body.ansicht-mobil select, body.ansicht-mobil textarea {
  min-height: 48px;
  font-size: 1rem; /* verhindert Auto-Zoom auf iOS */
}
body.ansicht-mobil .formular input, body.ansicht-mobil .formular select { flex: 1 1 100%; }
body.ansicht-mobil .formular button { flex: 1 1 100%; }
body.ansicht-mobil .diktat-zeile { flex-wrap: wrap; }
body.ansicht-mobil .diktat-zeile input, body.ansicht-mobil .diktat-zeile button { flex: 1 1 100%; }
body.ansicht-mobil .zeile-aktionen input, body.ansicht-mobil .zeile-aktionen select { flex: 1 1 100%; }
body.ansicht-mobil .zeile-aktionen input[type="checkbox"] { flex: 0 0 auto; width: 22px; height: 22px; min-height: 0; }
body.ansicht-mobil .tab-btn { flex: 1; padding: 12px 8px; }
body.ansicht-mobil .tab-zeile { flex-wrap: wrap; }
body.ansicht-mobil .wochen-grid { grid-template-columns: 1fr; }
body.ansicht-mobil .karten { grid-template-columns: repeat(2, 1fr); }
/* 76 Pixel über dem Boden des Einschubs: Damit steht der Toast auf jedem Gerät
   knapp über der Aufnahme-Bahn (64 px hoch) und rechnet auf derselben Größe wie
   Bahn, Einschub und Griff — eine feste Zahl hätte die Safe-Area unterschlagen. */
body.ansicht-mobil #toast {
  bottom: calc(var(--chat-boden) + env(safe-area-inset-bottom, 0px) + var(--tastatur-h) + 76px);
}
body.ansicht-mobil .pos-zeile { flex-wrap: wrap; }
body.ansicht-mobil .pos-zeile select { flex: 1 1 100%; }
body.ansicht-mobil .pos-zeile input { flex: 1 1 100px; }
body.ansicht-mobil .pos-zeile .pos-preis { flex: 1 1 auto; }
body.ansicht-mobil .detail-box .tabelle,
body.ansicht-mobil .karte .tabelle { display: block; overflow-x: auto; }

/* Karten-Listen ohne Renderer (Belege, Nachbetreuung): Abstand zwischen Karten */
#beleg-list .karte, #nb-eskalation-list .karte, #nb-vorschlag-list .karte,
#nb-historie-list .karte, #nb-consent-list .karte, #tagesbericht-list .karte,
#pruefung-faellig .karte { margin-bottom: 10px; }

/* Desktop: Content braucht unten Platz für den schwebenden Sprach-Knopf */
body.ansicht-desktop #content { padding-bottom: 140px; }

/* =====================================================================
   Detail-Ansicht (generisch): Klick auf Karte/Zeile öffnet das Detail
   als eigene Ansicht über der Liste — mobil Fullscreen, Desktop Panel
   rechts. Die Liste darunter behält ihre Scroll-Position.
   ===================================================================== */

#detail-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 25, 35, .45);
  display: flex;
  justify-content: flex-end;
  z-index: 25; /* unter dem Sprach-Overlay (30) */
}

.detail-panel {
  background: var(--hintergrund);
  width: 100%;
  max-width: 720px;
  height: 100%;
  overflow-y: auto;
  padding: 16px 20px 80px;
  box-shadow: -6px 0 24px rgba(0, 0, 0, .25);
}

@media (max-width: 820px) {
  .detail-panel { max-width: none; box-shadow: none; }
}

.detail-kopf {
  display: flex;
  align-items: center;
  gap: 12px;
  position: sticky;
  top: -16px; /* gleicht das Panel-Padding aus, bleibt beim Scrollen sichtbar */
  background: var(--hintergrund);
  padding: 16px 0 10px;
  margin: -16px 0 12px;
  z-index: 1;
}

#detail-zurueck {
  background: var(--primaer-hell);
  color: var(--primaer);
  padding: 10px 16px;
  flex-shrink: 0;
}

#detail-titel { color: var(--primaer); font-size: 1.05rem; }

/* --- Akten (Auftrag/Kunde): Kopf, Summen, Nächste Schritte, Sektionen --- */

.akte-kopf {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.akte-titel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 1.1rem;
}

.akte-summen { margin-top: 12px; }
/* Soll gegen Ist: ein eigener Block, weil er eine Frage beantwortet und keine
   Liste ist. Die Ampel traegt Farbe, damit man sie im Vorbeigehen sieht. */
.akte-nachkalkulation { margin-top: 14px; padding: 10px 12px; border-radius: 8px;
  background: var(--flaeche-2, var(--sand)); }
.akte-nachkalkulation strong { display: block; margin-bottom: 4px; }
.nk-ampel { font-weight: 600; margin-bottom: 6px; }
.nk-ampel.rot { color: var(--gefahr); }
.nk-ampel.gelb { color: var(--warn); }
.nk-ampel.gruen { color: var(--ok); }
.akte-summen .karte .zahl { font-size: 1.3rem; }
.akte-summen .karte.offen .zahl { color: var(--gefahr); }

.naechste-schritte {
  background: var(--primaer-hell);
  border-radius: 12px;
  padding: 14px 16px;
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.naechste-schritte > strong { color: var(--primaer); }

.schritt-btn {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
  width: 100%;
}

.schritt-btn .schritt-details { font-weight: 400; font-size: 0.85rem; opacity: .92; }

.akte-aktionen { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.akte-aktionen button { flex: 1 1 150px; }

.akte-sektion { margin-top: 22px; }
.akte-sektion > h3 { margin: 0 0 10px; }

/* Der Verlauf: zugeklappt, weil die Akte von den Belegen handelt und nicht von der
   Buchfuehrung ueber sie. Die Zeile traegt links einen Strich — was zusammengehoert,
   soll man sehen, ohne es zu lesen. */
.verlauf > summary {
  cursor: pointer;
  font-weight: 600;
  padding: 8px 0;
  min-height: 44px;          /* Fingerbreite: aufgeklappt wird mit dem Daumen */
  display: flex;
  align-items: center;
}
.verlauf-zeile {
  padding: 8px 0 8px 12px;
  border-left: 2px solid var(--rahmen);
  margin-bottom: 4px;
}
.verlauf-kopf { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.verlauf-detail {
  font-size: 0.9rem;
  color: var(--gedaempft);
  margin-top: 3px;
  /* Ein alter und ein neuer Wert koennen lang sein; umbrechen ist besser als
     abschneiden, denn abgeschnitten ist genau die Haelfte weg, die man sucht. */
  overflow-wrap: anywhere;
}

.summen-zeile {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding: 10px 14px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 10px;
  font-size: 0.92rem;
}

.summen-zeile strong { color: var(--primaer); }
.summen-zeile .offen-wert { color: var(--gefahr); font-weight: 700; }

.abschlag-vorschau { flex: 1 1 100%; margin: 0; font-weight: 600; }

/* tappbare Tabellen-Zeilen (Desktop) — wie bei Leads/Prüfungen */
tr.tappbar { cursor: pointer; }
tr.tappbar:hover td { background: var(--primaer-hell); }

/* --- Foto-Dokumentation (M12) --- */
.foto-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.foto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
  margin-top: 8px;
}
.foto-zelle {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.foto-thumb {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--rahmen);
  background: var(--sand);
}
.foto-knopf {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* --- Heute: Mikrofon als Hauptbedienung -------------------------------------
   Das Mikrofon war ein 76-px-Kreis unten in der Ecke und sah damit aus wie
   eine Zusatzfunktion. Auf dem Startbildschirm ist es das erste und groesste
   Element — Sprache ist die Hauptbedienung, nicht eine Taste am Rand.
   Der schwebende Knopf bleibt auf allen anderen Ansichten bestehen. */
.mikro-gross {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  width: 100%;
  margin: 4px 0 22px;
  padding: 22px 18px;
  border: none;
  border-radius: 16px;
  background: var(--primaer);
  color: #fff;
  cursor: pointer;
  text-align: center;
}
.mikro-gross:active { transform: scale(0.995); }
.mikro-gross-ikon { font-size: 2.4rem; line-height: 1; }
.mikro-gross-text { font-size: 1.1rem; font-weight: 600; }
.mikro-gross-beispiel { font-size: 0.92rem; opacity: 0.85; }

/* Eine Zeile Arbeit: ein Satz, ein Knopf. Kein Status, keine Ampel, keine
   Prozentzahl — die Zeile sagt, was ist, und der Knopf, was zu tun ist. */
.aufgabe-zeile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  margin-bottom: 8px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
}
.aufgabe-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.aufgabe-satz { font-size: 1rem; }
.aufgabe-herkunft { font-size: 0.85rem; color: var(--gedaempft); }
.aufgabe-knopf { flex: 0 0 auto; white-space: nowrap; }

body.ansicht-mobil .aufgabe-zeile { flex-direction: column; align-items: stretch; }
body.ansicht-mobil .aufgabe-knopf { width: 100%; }

/* Der Text einer Nachricht bleibt Text — kein HTML, keine Fernladung. */
.mail-text { white-space: pre-wrap; word-break: break-word; }

/* ===== Der Tagesplan: Streifen und Liste =====================================

   Zwei Gesten, mehr gibt es nicht: einen Tag antippen und einen Knopf drücken.
   Keine Filter, keine Sortierung, keine Prioritätszahl — der Tag IST die
   Priorität. Alles ist auf Handschuhe ausgelegt: kein Ziel unter 44 Pixeln.
*/

/* Nur auf dem Handy — am Computer steht links die Navigation. */
body.ansicht-desktop .nur-mobil { display: none; }

.tagesstreifen {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 4px 2px 10px;
  margin: 14px 0 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tagesstreifen::-webkit-scrollbar { display: none; }

.tagesstreifen-tag {
  flex: 0 0 auto;
  min-width: 58px;
  min-height: 74px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 8px 6px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  color: var(--text);
  cursor: pointer;
}
.tagesstreifen-tag.aktiv {
  background: var(--primaer);
  border-color: var(--primaer);
  color: #fff;
}
.streifen-wochentag { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
.streifen-zahl { font-size: 1.25rem; font-weight: 700; line-height: 1.1; }
/* Der Punkt trägt die Zahl. Ein Punkt ohne Zahl beantwortet die Frage „wie
   viel?" nicht — und genau die stellt sich, wer auf den Streifen schaut. */
.streifen-punkt {
  min-width: 20px;
  height: 18px;
  border-radius: 9px;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 18px;
  color: transparent;
}
.streifen-punkt.voll { background: var(--primaer-hell); color: var(--primaer); }
.tagesstreifen-tag.aktiv .streifen-punkt.voll { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* Rückstand hängt an keinem Tag und braucht trotzdem einen Platz — sonst
   verschwindet er zwischen den Feldern. */
.tagesstreifen-rueckstand {
  flex: 0 0 auto;
  min-height: 74px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 8px 12px;
  background: var(--gefahr-blass);
  border: 1px solid var(--gefahr);
  border-radius: 12px;
  color: var(--gefahr);
  cursor: pointer;
}
.tagesstreifen-rueckstand .streifen-zahl { font-size: 1.35rem; }
.tagesstreifen-rueckstand .streifen-tag { font-size: 0.72rem; }

/* Eine Zeile: links die Uhr, in der Mitte der Satz, rechts EIN Knopf. Termin
   und Aufgabe unterscheiden sich nur durch die linke Spalte. */
.tagesplan-zeile {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  margin-bottom: 8px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
}
.tagesplan-zeit {
  flex: 0 0 auto;
  width: 52px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--primaer);
}
.tagesplan-zeile.rueckstand { border-left: 4px solid var(--gefahr); }
.tagesplan-zeile.rueckstand .tagesplan-zeit { color: var(--gefahr); }
.tagesplan-zeile.erledigt { opacity: 0.65; }
.tagesplan-zeile.erledigt .tagesplan-zeit { color: var(--ok); }

body.ansicht-mobil .tagesplan-zeile { flex-wrap: wrap; }
body.ansicht-mobil .tagesplan-zeile .aufgabe-knopf { width: 100%; margin-top: 4px; }

/* Die Frage nach der Erlaubnis. Sie steht über der Liste, mit einem Satz, der
   sagt, was sie bringt — und mit einem Weg heraus, der nicht „nie" heißt. */
.push-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  margin: 14px 0;
  background: var(--primaer-hell);
  border: 1px solid var(--primaer);
  border-radius: 12px;
}
.push-banner-text { display: flex; flex-direction: column; gap: 2px; flex: 1 1 260px; }
.push-banner-knoepfe { display: flex; gap: 8px; flex: 0 0 auto; }
body.ansicht-mobil .push-banner-knoepfe { width: 100%; }
body.ansicht-mobil .push-banner-knoepfe button { flex: 1 1 0; }

/* Blättern: eine Woche vor, eine zurück. Zurück erscheint erst, wenn der
   Streifen nicht bei heute steht — am ersten Tag wäre er nur eine Frage mehr. */
.tagesstreifen-blaettern {
  flex: 0 0 auto;
  min-width: 40px;
  min-height: 74px;
  background: transparent;
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  color: var(--primaer);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}

/* Aufgabe: verschieben und absagen. Zugeklappt kostet das keinen Millimeter —
   sichtbar ist nur das Wort „mehr" am Ende der Zeile. */
.tagesplan-zeile.aufklappbar .aufgabe-text { cursor: pointer; }
.zeile-mehr {
  font-size: 0.8rem;
  color: var(--primaer);
  text-decoration: underline;
  margin-top: 2px;
}
.aufgabe-aktionen {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 10px 16px 14px;
  margin: -8px 0 8px;
  background: var(--primaer-hell);
  border: 1px solid var(--rahmen);
  border-top: none;
  border-radius: 0 0 12px 12px;
}
.aufgabe-datum, .aufgabe-grund {
  min-height: 40px;
  padding: 6px 10px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  color: var(--text);
}
.aufgabe-grund { flex: 1 1 220px; }
body.ansicht-mobil .aufgabe-aktionen button,
body.ansicht-mobil .aufgabe-aktionen input { flex: 1 1 100%; }

/* Postfach einrichten: zwei Felder. Die Technik liegt zugeklappt darunter —
   wer sie aufklappt, weiß, was er tut. */
.postfach-form { display: flex; flex-direction: column; gap: 10px; margin-top: 12px; }
.postfach-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.92rem; }
.postfach-form input { min-height: 44px; padding: 8px 10px;
  border: 1px solid var(--rahmen); border-radius: 8px; background: var(--flaeche); color: var(--text); }
.postfach-technik-felder { display: grid; grid-template-columns: 2fr 1fr; gap: 8px; margin-top: 8px; }
#postfach-technik summary { cursor: pointer; font-size: 0.88rem; color: var(--gedaempft); }
body.ansicht-mobil .postfach-technik-felder { grid-template-columns: 1fr; }

/* Die vorbereitete Antwort. Dreistufig: schreiben lassen, LESEN, freigeben —
   eine Antwort auf einen Tastendruck ist ein Brief, den niemand gegengelesen hat. */
.antwort-wunsch, .antwort-betreff, .antwort-text {
  width: 100%;
  padding: 10px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  color: var(--text);
  font: inherit;
}
.antwort-wunsch { margin: 8px 0; }
.antwort-entwurf { display: flex; flex-direction: column; gap: 8px; margin-top: 12px;
  padding-top: 12px; border-top: 1px solid var(--rahmen); }
.antwort-text { white-space: pre-wrap; line-height: 1.5; }

/* Leistungen und Preise. Zwei Spalten entscheiden alles — Einkauf und Zeit.
   Sind sie gefüllt, rechnet das System und kennt die Marge. */
.katalog-zeile {
  padding: 12px 14px;
  margin-bottom: 10px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  position: relative;
}
.katalog-kopf { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.katalog-name {
  flex: 1 1 240px;
  min-height: 40px;
  padding: 6px 8px;
  font-size: 1rem;
  font-weight: 600;
  border: 1px solid transparent;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
}
.katalog-name:hover, .katalog-name:focus { border-color: var(--rahmen); background: var(--hintergrund); }
.katalog-preis {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--ok);
}
/* Knapp kalkuliert heißt: unter der eigenen Mindestmarge. Das muss man sehen,
   während man tippt — nicht erst im Angebot. */
.katalog-preis.knapp { color: var(--gefahr); }
.katalog-preis.fest { color: var(--gedaempft); font-weight: 600; }

.katalog-felder { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.katalog-feld { display: flex; align-items: center; gap: 6px; font-size: 0.85rem; }
.katalog-label { color: var(--gedaempft); white-space: nowrap; }
.katalog-einheit { color: var(--gedaempft); }
.katalog-feld input, .katalog-feld select, .katalog-stichworte input {
  min-height: 38px;
  padding: 6px 8px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  color: var(--text);
  font: inherit;
}
.katalog-feld input[type="number"] { width: 90px; }
.katalog-stichworte { display: flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 0.85rem; }
.katalog-stichworte input { flex: 1 1 auto; }
.katalog-weg { margin-top: 10px; }
body.ansicht-mobil .katalog-felder { flex-direction: column; align-items: stretch; }
body.ansicht-mobil .katalog-feld input[type="number"] { width: 100%; }

/* Kontenauswahl statt Kontonummer aus dem Kopf. Nummer und Klartext stehen
   beide da: Wer die Nummer kennt, findet sie; wer sie nicht kennt, liest
   „Wareneingang". Der Steuerberater will die Nummer sehen. */
.konto-auswahl {
  min-height: 40px;
  max-width: 320px;
  padding: 6px 8px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  color: var(--text);
  font: inherit;
}
body.ansicht-mobil .konto-auswahl { max-width: 100%; width: 100%; }

/* Lieferanteneingabe mit Vorschlagsliste. Vier Schreibweisen desselben Hauses
   heißen vier Kreditoren beim Steuerberater. */
.lieferant-eingabe {
  width: 100%;
  min-height: 44px;
  padding: 8px 10px;
  margin: 8px 0;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  color: var(--text);
  font: inherit;
}

/* Bewegungen: Das Vorzeichen sagt die Richtung, ohne dass man eine Spalte
   „Typ" lesen muss. */
.menge-ab { color: var(--gefahr); font-variant-numeric: tabular-nums; white-space: nowrap; }
.menge-zu { color: var(--ok); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* --- Bereiche: nach dem Weg gruppiert, den ein Auftrag nimmt ---------------
   Zwanzig gleichwertige Kacheln nebeneinander sind keine Ordnung, sondern eine
   Wand — man liest sie einmal und sucht danach immer wieder. */
.modul-start {
  width: 100%;
  min-height: 72px;
  margin-bottom: 18px;
  flex-direction: row;
  gap: 10px;
  background: var(--primaer-hell);
  border-color: var(--primaer);
}
.modul-gruppe { margin-bottom: 22px; }
.modul-gruppe h3 {
  margin: 0 0 8px;
  font-size: 0.82rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gedaempft);
}

/* Dieselben Gruppen in der Seitenleiste — zwei Ordnungen für dieselbe Liste
   wären schlimmer als keine. */
.nav-gruppe {
  margin: 16px 0 4px;
  padding: 0 14px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--gedaempft);
  opacity: 0.75;
}
.nav-gruppe:first-of-type { margin-top: 10px; }

/* --- Anlegen: zugeklappt, bis man es braucht -------------------------------
   Ein Formular, das dauerhaft über der Liste steht, kostet bei dreißig
   Einträgen den halben Bildschirm — und zwar jedes Mal, auch wenn man nur
   nachsehen wollte. Der Knopf sieht aus wie ein Knopf, ist aber natives HTML
   (<details>): Er funktioniert mit Tastatur und Vorlesesoftware ohne Zutun. */
.anlegen { margin-bottom: 14px; }
.anlegen > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 18px;
  border-radius: 10px;
  background: var(--primaer);
  color: #fff;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.anlegen > summary::-webkit-details-marker { display: none; }
/* Das Pluszeichen wird beim Aufklappen zum Minus — ohne Beschriftungswechsel. */
.anlegen > summary::before { content: "+"; font-size: 1.25rem; line-height: 1; }
.anlegen[open] > summary::before { content: "−"; }
.anlegen[open] > summary { background: var(--gedaempft); }
.anlegen > summary:hover { filter: brightness(1.08); }
.anlegen[open] > .formular {
  margin-top: 10px;
  padding: 14px;
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
}
body.ansicht-mobil .anlegen > summary { width: 100%; justify-content: center; }

/* --- Wochennavigation ------------------------------------------------------
   Vorher ein Datumsfeld: Wer eine Woche weiter wollte, musste ausrechnen,
   welcher Montag das ist, und ihn eintippen. */
.wochen-navigation {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 12px;
}
.wochen-navigation button { min-width: 44px; min-height: 44px; }
.wochen-titel { display: flex; flex-direction: column; flex: 1 1 auto; text-align: center; }
.wochen-titel strong { font-size: 1.05rem; }

/* ===== Mein Überblick: das Kachelband auf dem Startbildschirm =====
   Kein neues Formvokabular — die Kartenform von .karte mit einer Zahl darin.
   Auf dem Handy zwei Spalten: acht Kacheln sind vier Zeilen und damit rund
   340 Pixel; darüber schiebt das Band den Tagesstreifen unter den Falz und ist
   kein Überblick mehr, sondern ein zweiter Bildschirm. Deshalb der Deckel bei
   acht (KACHELN_MAX in app/kacheln.py). */
.kachel-band { margin: 14px 0 6px; }
.kachel-band-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.kachel-band-kopf h3 { margin: 0 0 8px; }
.btn-klein { padding: 6px 12px; font-size: 0.85rem; }
.kachel-raster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}
.kachel {
  background: var(--flaeche);
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  min-height: 84px;
  padding: 12px 14px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 2px;
  color: var(--text);
}
.kachel-zahl { font-size: 1.6rem; font-weight: 700; color: var(--primaer); line-height: 1.1; }
.kachel-titel { font-size: 0.9rem; font-weight: 600; }
.kachel-zusatz { font-size: 0.78rem; color: var(--gedaempft); }
/* Rot nur, wenn die Zahl größer als null ist: Eine rote Null ist eine
   Falschmeldung. */
.kachel.warnung .kachel-zahl { color: var(--gefahr); }
.kachel:active { background: var(--primaer-hell); }
body.ansicht-mobil .kachel-raster { grid-template-columns: repeat(2, 1fr); }

/* Der Editor: Pfeile statt Ziehen. Ein Arbeitshandschuh trifft einen 44er-Knopf
   jedes Mal, eine 6-Pixel-Ziehschwelle nicht — und eine vertikale Liste in einer
   scrollenden Schicht kann nicht gleichzeitig ziehbar sein. */
.kachel-sortzeile {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 52px;
  border-bottom: 1px solid var(--rahmen);
}
.kachel-sortzeile .kachel-name { flex: 1; font-weight: 600; }
.kachel-pfeil { min-width: 44px; min-height: 44px; padding: 0; }
.kachel-wahl {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--rahmen);
}
.kachel-wahl-text { flex: 1; }
.kachel-wahl-text .hinweis { display: block; }

/* Anwesenheit: die eine Frage um 7:55. Ganz oben, ein Knopf, der auch mit
   Handschuh zu treffen ist. */
.anwesenheit-karte { margin-bottom: 12px; }
.anwesenheit-karte strong { display: block; margin-bottom: 2px; }
.anwesenheit-karte .hinweis { margin: 0 0 8px; }
.anwesenheit-karte button { display: block; width: 100%; margin-top: 8px; }
.anwesenheit-karte .gross { min-height: 56px; font-size: 1.05rem; }
.anwesenheit-karte.laufend { border-left: 4px solid var(--primaer); }

/* =====================================================================
   GRUNDSCHICHT: Handschuh, Daumen, Fokus
   =====================================================================

   Vier Dinge einmal für die ganze App, statt an neunzig Stellen einzeln.
   Eine Prüfung im August 2026 hat sie alle vier als fehlend gefunden. */

/* 1. SICHTBARER FOKUS.
      In 1930 Zeilen CSS stand kein einziges `outline` — und in Zeile 96 steht
      `button { border: none }`. Wer mit der Tastatur bedient (oder mit einer
      Maus, die gerade nicht trifft), sah nirgends, wo er steht. `:focus-visible`
      statt `:focus`: Ein Mausklick soll keinen Rahmen hinterlassen, ein
      Tabulator schon. */
:where(button, a, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--primaer);
  outline-offset: 2px;
  border-radius: 8px;
}
/* Auf dunklen Flächen wäre der blaue Rahmen unsichtbar. */
.primaer:focus-visible,
#ptt:focus-visible,
#ptt-mobil:focus-visible,
#heute-mikro:focus-visible {
  outline-color: #fff;
  outline-offset: 3px;
}

/* 2. TREFFSICHERHEIT MIT ARBEITSHANDSCHUH.
      48 Pixel sind die Untergrenze für alles, was auf dem Handy bedient wird
      (WCAG 2.2, 2.5.8 fordert 24 — für einen Handschuh ist das zu wenig). Die
      Regel steht hier gesammelt, damit ein neuer Knopf sie erbt, statt sie zu
      brauchen. */
body.ansicht-mobil :where(button, .btn-ja, .btn-nein, .aktion-karte, .modul-kachel,
  .tab-eintrag, .kachel, .kachel-pfeil, summary) {
  min-height: 48px;
}
body.ansicht-mobil :where(input, select, textarea) {
  min-height: 48px;
  font-size: 16px; /* darunter zoomt iOS Safari beim Antippen in das Feld hinein */
}
/* Ein Häkchen ist 22 Pixel groß und bleibt es — angetippt wird die ganze Zeile. */
body.ansicht-mobil :where(.check-zeile, .ma-auswahl label) {
  min-height: 48px;
  display: flex;
  align-items: center;
  gap: 10px;
}
body.ansicht-mobil .tagesstreifen-blaettern { min-width: 48px; min-height: 48px; }

/* 3. DIE DAUMENZONE BLEIBT FREI.
      Unten sitzen Tab-Bar, Sprach-Knopf und Aufnahme-Bahn. Jede Fläche, die
      gescrollt wird, braucht darüber Luft — sonst liegt die letzte Zeile unter
      dem Knopf, den der Daumen gerade hält. Die Formel steht einmal hier. */
.daumenzone-frei,
body.ansicht-mobil .detail-panel {
  padding-bottom: calc(var(--chat-boden) + env(safe-area-inset-bottom, 0px)
                       + var(--tastatur-h) + 24px);
}

/* 4. DIE SCHICHTORDNUNG, BENANNT.
      Bei offener Akte lag der Sprach-Knopf UNTER dem Overlay: Sprechen ging
      nicht, solange man etwas ansah — genau die Trennung, die dieser Umbau
      abgeschafft hat. Die Akte ist modal für den INHALT, nicht für die Stimme. */
body.detail-offen #ptt-bereich,
body.detail-offen #ptt-mobil,
body.detail-offen .tab-bar { z-index: 26; }
body.detail-offen #ptt-leiste { z-index: 27; }
/* #detail-overlay liegt bei 25, der Toast bei 32 — beide bleiben, wo sie sind. */

/* Beschriftungen an den Feldern. Bis August 2026 hatte KEINES der 92 Felder
   eine: 43 hatten nur einen Platzhalter, und der verschwindet, sobald etwas im
   Feld steht. Seit die Sprache Formulare vorbefüllt, steht dort immer etwas —
   nach einem Diktat sah der Meister sieben gefüllte Felder und wusste bei
   keinem, was drinsteht. */
.formular label,
.filter-zeile label,
.postfach-form label,
.login-karte label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--gedaempft);
  margin: 2px 0 -4px;
}
/* Eine Beschriftung gehört zu ihrem Feld, nicht zum vorherigen: Der Abstand
   nach oben ist größer als der nach unten. */
.formular label + input,
.formular label + select,
.formular label + textarea { margin-top: 6px; }
/* Häkchen-Zeilen tragen ihre Beschriftung im Label selbst — dort gilt die
   Regel nicht. */
.formular .check-zeile,
.ma-auswahl label { display: flex; font-size: 0.95rem; font-weight: 500; color: var(--text); }

/* ======================================================================
   DIE FRAGE IN DER ZEILE
   ======================================================================
   Ersetzt window.confirm/prompt/alert (18 Fundstellen). Der graue Kasten des
   Browsers hat Systemschrift, winzige Knöpfe, keinen Kontrast in der Sonne und
   blockiert das ganze Fenster. Dieser Kasten steht dort, wo der Knopf steht,
   trägt die Farben der App und lässt sich mit Handschuh treffen. */
.frage-schicht {
  background: var(--primaer-hell);
  border: 2px solid var(--primaer);
  border-radius: 10px;
  padding: 14px;
  margin: 8px 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* Damit die Frage nicht in einer engen Tabellenzelle zerquetscht wird. */
  min-width: min(280px, 100%);
}
.frage-reihe > td { padding: 0 8px 8px; }
.frage-text { margin: 0; font-weight: 600; color: var(--text); }
.frage-schicht .hinweis { margin: 0; }
/* Der Hinweis traegt beim Fertigmelden und beim Freigeben eine Aufzaehlung dessen,
   was noch fehlt — eine Zeile je Sache. Als Fliesstext liest das niemand zu Ende. */
.frage-text + .hinweis, .frage-schicht .hinweis { white-space: pre-line; }
.frage-form { display: flex; flex-direction: column; gap: 10px; }
.frage-feld { display: flex; flex-direction: column; gap: 4px; }
.frage-feld label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--gedaempft);
}
.frage-feld input,
.frage-feld select,
.frage-feld textarea {
  padding: 10px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--flaeche);
  font-size: 1rem;
  width: 100%;
}
.frage-feld input[type="checkbox"] { width: 24px; height: 24px; }
/* Die Meldung ersetzt das alert(): Sie steht ÜBER den Knöpfen und lässt das
   Getippte stehen — vorher warf „Ungültige Menge" alle Eingaben davor weg. */
.frage-meldung {
  margin: 0;
  color: var(--gefahr);
  font-weight: 600;
  font-size: 0.9rem;
}
.frage-knoepfe { display: flex; gap: 10px; flex-wrap: wrap; }
.frage-knoepfe button { min-height: 44px; padding: 12px 18px; }
/* Auf dem Handy nebeneinander, aber jeder Knopf breit genug für den Daumen. */
body.ansicht-mobil .frage-knoepfe button { flex: 1 1 44%; min-height: 48px; }
/* Mehr als zwei Positionen im Wareneingang: Die Schicht scrollt, die Knöpfe
   bleiben sichtbar — sonst tippt man acht Mengen und findet „Buchen" nicht. */
.frage-form { max-height: 60vh; overflow-y: auto; }

/* Ein gesperrter Knopf muss gesperrt AUSSEHEN.
   In 2080 Zeilen CSS gab es dazu keine Regel, und .btn-ok/.btn-nein/.btn-klein
   setzen Hintergrund UND Schriftfarbe selbst — ein gesperrter Knopf sah also
   aus wie ein bedienbarer. Man drückt ihn, nichts passiert, man drückt noch
   einmal. Das ist zugleich die erste sichtbare Rückmeldung für JEDEN wartenden
   Knopf, auch außerhalb von Listen: arbeitet() sperrt, und ab hier sieht man
   das auch. */
button:disabled,
.knopf-gesperrt {
  opacity: 0.45;
  cursor: not-allowed;
}
/* Der Grund steht im title-Attribut — auf dem Handy gibt es keinen Mauszeiger,
   deshalb trägt die Zeile daneben den Satz (siehe zeichneListe: gesperrt.grund). */

/* Eine Zeile, die eine Warnung trägt. Bis August 2026 stand die Farbe als
   style.background direkt in der Tabellenzeile (Bestände unter Mindestbestand)
   — auf dem Handy, wo es keine Tabelle gibt, fehlte sie deshalb ganz. Jetzt
   trägt die Zeile eine Klasse, und zeichneListe() setzt sie in beiden
   Ansichten. */
tr.zeile-warnung { background: var(--gefahr-blass); }
.daten-karte.zeile-warnung { border-left: 4px solid var(--gefahr); }

/* Zustände, die noch grau waren. Eine Pille ohne Farbe ist ein grauer Chip —
   und der Sinn der Pille ist der Ampel-Effekt: Der Meister soll die Zeile
   sehen, bevor er sie liest.

   Die beiden ersten sind die wichtigsten des ganzen Systems: Ein Notfall-Anruf
   und eine eilige Mail müssen rot sein. Sie waren es nie — die Klassen gab es
   nicht, und statusPill() baut die Klasse aus dem Wert. */
.status.Notfall,
.status.eilig,
.status.ueberfaellig { background: var(--gefahr-blass); color: var(--gefahr); }
/* Wartet auf jemanden. */
.status.offen,
.status.eingegangen,
.status.beantragt,
.status.neu,
.status.unklar { background: var(--warn-blass); color: var(--warn); }
/* Läuft, ist aber noch nicht fertig. */
.status.aktiv,
.status.teilgeliefert,
.status.teilbezahlt,
.status.heiss,
.status.warm { background: var(--primaer-hell); color: var(--primaer); }
/* Erledigt. */
.status.erledigt,
.status.gebucht,
.status.gewonnen,
.status.genehmigt,
.status.exportiert { background: var(--ok-blass); color: var(--ok); }
/* Vorbei, ohne Erfolg — aber kein Fehler. */
.status.verloren,
.status.kalt,
.status.austritt,
.status.verfallen,
.status.abgesagt { background: var(--rahmen); color: var(--gedaempft); }

/* Die Termin-Notiz auf der Anfangen-Karte: Sie ist kein Hinweis am Rand,
   sondern der Grund, warum der Monteur nicht vor verschlossener Tuer steht. */
.notiz-zeile {
  margin: 6px 0 0;
  padding: 8px 10px;
  border-left: 3px solid var(--warn);
  background: rgba(208, 135, 0, 0.08);
  font-size: 0.95rem;
}

/* Rüsten ist nicht Aufnehmen: Solange das Mikrofon nicht offen ist, bleibt
   die Bahn neutral. Rot heißt in dieser App „es läuft" — und wer das rot
   sieht, spricht, während der Berechtigungsdialog noch offen steht. */
body.ptt-ruestet #ptt-leiste { background: var(--text); }

/* --- Zugang und PIN --------------------------------------------------------

   Die PIN steht EINMAL da und danach nie wieder — gespeichert wird nur ihr Hash.
   Deshalb muss sie in dem Moment, in dem sie entsteht, wirklich lesbar sein: groß,
   mit Abstand zwischen den Ziffern, kopierbar. Ein kleiner grauer Toast, der nach
   vier Sekunden verschwindet, wäre an dieser Stelle ein Fehler mit Folgen.

   Gilt in BEIDEN Ansichten, nicht nur am Desktop: Der Meister vergibt PINs auch
   auf dem Handy, während der Monteur neben ihm steht. */
.zugangs-karte { border-left: 3px solid var(--primaer); }

.pin-anzeige {
  margin: 10px 0 4px;
  padding: 10px 12px;
  border: 1px solid var(--primaer);
  border-radius: 6px;
  background: var(--flaeche-hoch, rgba(127, 127, 127, 0.08));
}

.pin-ziffern {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 2rem;
  font-weight: 600;
  letter-spacing: 0.35em;
  padding: 4px 0;
  /* Auswählbar, damit man sie kopieren statt abschreiben kann. */
  user-select: all;
}

.knopf-reihe { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* --- Testzugänge unter der Anmeldemaske ---------------------------------------
 * Sichtbar nur auf einer Anlage zum Ausprobieren (siehe index.html). Bewusst
 * schlicht und etwas leiser als die Karte darüber: Es ist ein Hilfsmittel, kein
 * Teil der Anmeldung.
 */
.testzugaenge {
  width: 100%;
  max-width: 400px;
  margin: 14px auto 0;
  background: var(--flaeche);
  border: 1px dashed var(--rahmen);
  border-radius: 12px;
  padding: 14px 16px;
}

.tz-titel {
  margin: 0 0 10px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gedaempft);
}

.tz-zeile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid var(--rahmen);
}
.tz-zeile:first-child { border-top: 0; }

.tz-text { flex: 1; min-width: 0; }
.tz-name { font-weight: 600; font-size: 0.94rem; }
/* Umbrechen statt abschneiden: Wer die Angaben abtippen will, muss sie ganz sehen. */
.tz-daten {
  font-size: 0.82rem;
  color: var(--gedaempft);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  overflow-wrap: anywhere;
}

.tz-knopf {
  flex: none;
  padding: 7px 12px;
  font-size: 0.85rem;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
  background: var(--grund);
  color: var(--text);
  cursor: pointer;
}
.tz-knopf:hover { border-color: var(--primaer); color: var(--primaer); }

.tz-fuss {
  margin: 10px 0 0;
  font-size: 0.76rem;
  color: var(--gedaempft);
}

/* --- Wartet auf Abnahme (P2) ---------------------------------------------------
 * Der Streifen über der Auftragsliste. Er zeigt Geld und Tage, nicht nur eine
 * Anzahl: „3 Aufträge" liest man weg, „12.400 €, ältester seit 38 Tagen" nicht.
 */
.abnahme-banner {
  border: 1px solid var(--warnung, var(--warn));
  border-left-width: 4px;
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 14px;
  background: var(--flaeche);
}

.abnahme-kopf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 12px;
  margin-bottom: 8px;
}
.abnahme-zahlen {
  color: var(--gedaempft);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
}

.abnahme-zeile {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 12px;
  padding: 6px 0;
  border-top: 1px solid var(--rahmen);
  font-size: 0.92rem;
}
.abnahme-titel { font-weight: 600; }
.abnahme-wer { color: var(--gedaempft); font-variant-numeric: tabular-nums; }

.abnahme-mehr {
  margin: 8px 0 0;
  font-size: 0.84rem;
  color: var(--gedaempft);
}

/* --- Das Anlagen-Datenblatt (P4) -----------------------------------------------
 * Die Lagemeldung steht ÜBER den Feldern. Wer das Blatt öffnet, will wissen, ob er
 * den Antrag jetzt machen kann — nicht vierzig Eingabefelder sehen.
 */
.anlage-kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 18px;
}
.anlage-kopf h3 { margin: 0; }

.antragslage {
  display: grid;
  gap: 8px;
  margin: 12px 0 18px;
}

.antrag-zeile {
  border: 1px solid var(--rahmen);
  border-left-width: 3px;
  border-left-color: var(--erfolg, var(--ok));
  border-radius: 8px;
  padding: 10px 12px;
}
.antrag-zeile.unvollstaendig { border-left-color: var(--warnung, var(--warn)); }

.antrag-titel { font-weight: 600; }
.antrag-stand { font-size: 0.88rem; color: var(--gedaempft); font-variant-numeric: tabular-nums; }
.antrag-stand.gut { color: var(--erfolg, var(--ok)); }
/* Die fehlenden Angaben NAMENTLICH: „3 Angaben fehlen" schickt jemanden suchen. */
.antrag-fehlt { font-size: 0.9rem; margin-top: 4px; }

.netzbetreiber-hinweis {
  border: 1px dashed var(--rahmen);
  border-radius: 8px;
  padding: 12px 14px;
  margin-bottom: 18px;
  display: grid;
  gap: 6px;
  font-size: 0.94rem;
}

.anlage-felder h4 {
  margin: 20px 0 4px;
  font-size: 0.98rem;
  border-bottom: 1px solid var(--rahmen);
  padding-bottom: 4px;
}
/* Markiert, was ein Antrag braucht und noch fehlt — sonst sucht man es in vierzig
   Feldern, und genau dann rät man den Wert. */
.feld-fehlt {
  margin-left: 8px;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warnung, var(--warn));
}
.feld-hinweis {
  margin: 2px 0 6px;
  font-size: 0.84rem;
  color: var(--gedaempft);
}

/* --- Die Nachweismappe (P3) ----------------------------------------------------
 * Der Satz steht über den Zahlen: „Es fehlen noch das Foto nachher und die
 * Unterschrift" sagt, was zu tun ist. „7 von 9" sagt es nicht.
 */
.mappe-stand {
  border: 1px solid var(--warnung, var(--warn));
  border-left-width: 4px;
  border-radius: 10px;
  padding: 12px 14px;
  margin: 14px 0;
  background: var(--flaeche);
}
.mappe-stand.gut { border-color: var(--erfolg, var(--ok)); }
.mappe-zahlen {
  margin-top: 4px;
  font-size: 0.86rem;
  color: var(--gedaempft);
  font-variant-numeric: tabular-nums;
}

.mappe-arbeiten { margin: 14px 0; }
.haken-zeile {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  font-weight: 400;
  cursor: pointer;
}
.haken-zeile input { width: auto; margin: 0; }

/* Die Überschrift über einem Listenblock. Sie trennt in der Rüstliste, was ins
 * Auto gehört, von dem, was der Auftraggeber stellt — zwei Blöcke, weil es zwei
 * verschiedene Handlungen sind: einpacken oder vor Ort prüfen. */
.mappe-abschnitt {
  margin: 20px 0 0;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--gedaempft);
}

.mappe-liste { display: grid; gap: 2px; margin: 14px 0; }
.mappe-zeile {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--rahmen);
  border-radius: 8px;
}
/* Erledigtes bleibt SICHTBAR, nur zurückgenommen — es verschwinden zu lassen nähme
   den Beleg dafür, dass es getan wurde. */
.mappe-zeile.erledigt { opacity: 0.62; }
.mappe-zeile input { width: auto; margin: 3px 0 0; flex: none; }
.mappe-text { flex: 1; min-width: 0; }
.mappe-titel { font-weight: 600; display: block; cursor: pointer; }
.mappe-zeile.erledigt .mappe-titel { text-decoration: line-through; }
.mappe-meta { font-size: 0.82rem; color: var(--gedaempft); }
.marke-soll {
  margin-left: 8px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--gedaempft);
}

/* --- Beleg: anklickbare Karte und das Dokument selbst ---------------------- */
.beleg-dokument {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 14px;
}
/* Der Zettel bekommt die volle Breite und darf hoch sein: Ein Kassenbon ist
   schmal und lang, und wer ihn prüft, will die Positionen lesen können. */
.beleg-bild {
  width: 100%;
  max-height: 62vh;
  object-fit: contain;
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  background: var(--flaeche-tief, var(--sand));
}
.beleg-pdf {
  width: 100%;
  height: 62vh;
  border: 1px solid var(--rahmen);
  border-radius: 12px;
  background: var(--flaeche);
}
.beleg-datei-wahl { font-size: 0.92rem; }
