/* Schriftgrößen-Regler (siehe Controllers/HomeController.cs SetFontScale, Views/Shared/
   _Layout.cshtml): ein einziger zentraler Faktor statt Einzelanpassungen - da praktisch alle
   Schriftgrößen im Projekt in rem/em gesetzt sind (Bootstrap-Standard), skaliert das Ändern der
   html-Basisgröße automatisch die gesamte Oberfläche. Default 1 = Standard, wird von _Layout.cshtml
   je nach Cookie-Wert auf 1.15 (Groß) bzw. 1.3 (Sehr groß) überschrieben. */
:root {
  --font-scale: 1;
}

/* VOO-0029 zweite Reihe #1: Die Grundschrift war auf dem Handy 14 px und erst ab 768 px 16 px -
   also genau dort kleiner, wo schlechter gelesen wird (Sonne, Staub, Armlänge). Die Richtlinie
   dreht das um: "Auf dem Handy nicht kleiner als am Schreibtisch. Die schlechtere Leseumgebung
   ist die mobile." Jetzt eine einzige Größe für alle Breiten; der Schriftgrößen-Regler skaliert
   sie weiterhin über --font-scale.

   Nebenwirkung, die beabsichtigt ist: Da praktisch alle Maße in rem/em stehen, wachsen damit
   auch alle Bedienelemente um rund 14 % mit - das ist die halbe Miete für Punkt #2. */
html {
  font-size: calc(16px * var(--font-scale));
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--voovena-accent);
}

/* VOO-0029 zweite Reihe #2: Touch-Zielgrößen auf mindestens 48 x 48 DP.

   Der Befund zählte 46 kleine Bedienelemente allein im Projektbildschirm; nach dem Umbau
   (VOO-0034) sind es 47 - der Umbau hat sie umsortiert, nicht verkleinert. Die allermeisten
   davon entstehen erst zur Laufzeit in JavaScript-Vorlagen (Bilderraster, Feed, Dokumentzeilen,
   Materialzeilen, Einladungstabelle). Sie einzeln aus den Zeichenketten zu entfernen hieße, 47
   Stellen zu treffen und bei der nächsten neuen Zeile wieder eine zu verpassen.

   Deshalb greift die Regel hier: auf Zeigegeräten, die grob sind (Finger, Handschuh), bekommt
   JEDES tippbare Element die Mindestgröße - auch die -sm-Varianten, auch die, die es noch nicht
   gibt. Am Schreibtisch mit Maus bleibt die dichte Darstellung, dort ist die Genauigkeit eine
   andere und Bildschirmfläche knapper als Fingerfläche.

   Bewusst über pointer:coarse statt über eine Breitenabfrage: Ein Tablet im Querformat ist breit
   UND wird mit dem Finger bedient - die Bildschirmbreite sagt über die Zielgröße nichts aus. */
@media (pointer: coarse) {
  .btn,
  .form-control,
  .form-select,
  .page-link,
  .nav-link,
  .dropdown-item {
    min-height: 48px;
  }

  /* ⚠️ min-height ALLEIN reicht nicht - es streckt die Box nach UNTEN, und der Text bleibt
     oben stehen. Genau das hat der CEO am 28.08.2026 gemeldet: "unter Mein Konto die Buttons
     für Firmenprofil etc. passen nicht, allerdings nur am IPAD. Desktop passt es."

     Gemessen bei nachgestelltem Touch-Zeiger: "Anmeldedaten verwalten" 16 px Luft oben,
     33 px unten - der Text saß 8 px zu hoch. Navigationslinks 4 px. Ein quadratischer
     Symbolknopf war unauffällig, weil dort ohnehin kein Platz übrig blieb.

     Am Rechner ist davon nichts zu sehen: pointer:coarse greift dort nicht, die Knöpfe
     behalten ihre natürliche Höhe, und der Text sitzt von selbst mittig. Ein Fehler, den
     man auf dem Gerät sehen muss, auf dem er entsteht.

     Deshalb Flex mit align-items:center - die Höhe kommt weiterhin von min-height, aber der
     Inhalt sitzt in der Mitte davon. */
  .btn,
  .nav-link,
  .page-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Menüeinträge bleiben linksbündig und volle Breite - sie sind eine Liste, keine Knöpfe. */
  .dropdown-item {
    display: flex;
    align-items: center;
    justify-content: flex-start;
  }

  /* ⚠️ Knöpfe, deren Text bewusst links steht, behalten das: justify-content oben würde ihr
     text-align überstimmen, sobald sie zu Flex-Elementen werden. */
  .vorlagen-pille {
    justify-content: flex-start;
  }

  /* Buttons ohne Text (Symbole, Pfeile) brauchen zusätzlich die Breite - sonst bleibt ein
     48 px hoher, aber 20 px schmaler Streifen. */
  .btn {
    min-width: 48px;
  }

  /* Das Schließen-Kreuz und die Kästchen bringen ihre eigene, sehr kleine Grundgröße mit und
     hören nicht auf min-height. */
  /* min-width zusätzlich zu width und flex-shrink: 0 - das Kreuz sitzt oft als Flex-Element in
     einer engen Zeile (Cookie-Hinweis, Meldungsbalken) und wurde dort trotz gesetzter Breite auf
     20 px zusammengedrückt. Gemessen, nicht vermutet. */
  .btn-close {
    width: 48px;
    height: 48px;
    min-width: 48px;
    flex-shrink: 0;
    background-size: 1rem;
  }

  /* ⚠️ Bootstrap legt bei einer schliessbaren Meldung ein eigenes Innenpolster auf das Kreuz
     (.alert-dismissible .btn-close, padding: 1.25rem 1rem) und positioniert es absolut in der
     Ecke. Zusammen mit den 48 px oben wird die Flaeche viel groesser als gedacht, und das
     Symbol sitzt in DEREN Mitte - also zu tief und zu weit links.

     Der CEO hat es am iPad gemeldet (27.08.2026: "Auch das X bei der Fehlermeldung ist
     verschoben"). Am Rechner faellt es nicht auf: Dort greift pointer:coarse nicht, das Kreuz
     behaelt seine kleine Grundgroesse, und Bootstraps Polster ist genau richtig dafuer.

     Das Polster muss hier weg, nicht die 48 px: Die Tippflaeche bleibt, sie besteht jetzt nur
     aus dem Knopf selbst statt aus Knopf plus Polster. */
  .alert-dismissible .btn-close {
    padding: 0;
  }

  .form-check-input {
    width: 1.5rem;
    height: 1.5rem;
    margin-top: 0.15rem;
  }

  /* Reine Textlinks in Fließtext bleiben ausgenommen: Sie stehen mitten im Satz, eine
     Mindesthöhe würde die Zeile auseinanderreißen. Die Regel gilt für Bedienelemente. */
  .btn-link.p-0 {
    min-height: 48px;
    min-width: 48px;
  }
}

html {
  position: relative;
  min-height: 100%;
}

/* Sticky Footer: body als Flex-Spalte über volle Viewport-Höhe, damit der Footer auf
   kurzen Seiten am unteren Rand klebt statt eine Lücke zu lassen. Das Element mit
   .voovena-page-content (der Container um <main> in _Layout.cshtml) wächst dafür mit
   flex-grow und schiebt den Footer nach unten. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.voovena-page-content {
  flex: 1 0 auto;
}

/* Voovena-Markenfarben - eigene Adobe-Color-Palette des Kunden, abgestimmt auf das Logo:
   https://color.adobe.com/de/create/color-wheel?color-palette=21557C,3C7D22,7D5922,7D2275,7FAED2
   - ink (#21557C): Primärblau (Logo-Schrift) - Text, Nav, Footer-Hintergrund, Primär-Buttons.
   - accent (#5A8FBD): das Logo-Blau des Auges, seit VOO-0029 zweite Reihe #5 abgedunkelt (vorher
     #7FAED2) - Verläufe, Hover-/Chip-/Card-Flächen, Rahmen, Fokusring. Bleibt trotzdem Flächen
     und Rahmen vorbehalten: Als TEXTFARBE reicht er mit 3,44:1 nur für große Schrift, für
     Fließtext und Links wird weiterhin "ink" selbst verwendet (7,91:1).
   - success (#3C7D22) / warning (#7D5922) / highlight (#7D2275): die drei restlichen Paletten-
     Farben, gezielt für Status-Badges (erledigt/offen), sekundäre UI-Akzente bzw. besondere
     Hervorhebungen (E-Mail-CTAs) eingesetzt - siehe Bootstrap-Variablen weiter unten. */
/* VOO-0029 zweite Reihe #5: Standardpalette auf WCAG AA nachgebessert. GEMESSEN, nicht
   geschätzt - Kontrastverhältnis nach WCAG 2.1 (relative Luminanz), Ziel 4,5:1 für Text und
   3:1 für Rahmen und Bedienelemente (so auch in design-richtlinien.md, Welt A).

   Was gemessen wurde und was dabei herauskam:

     ink       #21557C auf weiß   7,91:1  ok, bleibt
     success   #3C7D22 auf weiß   5,06:1  ok, bleibt
     warning   #7D5922 auf weiß   6,32:1  ok, bleibt
     highlight #7D2275 auf weiß   8,91:1  ok, bleibt
     muted     #5B7184 auf weiß   5,07:1  ok, bleibt
     accent    #7FAED2 auf weiß   2,36:1  ZU WENIG (Fokusring, Rahmen)  -> #5A8FBD = 3,44:1
     border    #CFE3F0 auf weiß   1,32:1  ZU WENIG (Rahmen)             -> #5A8FBD = 3,44:1

   Warum ausgerechnet #5A8FBD: Es ist der erste Ton dieser Blaureihe, der BEIDE Untergründe
   schafft - 3,44:1 auf Weiß und 3,09:1 auf --voovena-paper-alt (#EAF4FB). Der nächsthellere
   (#6194C1) schafft Weiß mit 3,22:1, fällt auf paper-alt aber auf 2,89:1 zurück, und genau dort
   sitzen die Tabellenköpfe.

   Der Akzent bleibt damit erkennbar derselbe Logo-Blauton, nur tiefer. Als FLÄCHE (Verlauf im
   Kopfbereich, Footer-Punkt) braucht er ohnehin keinen Kontrast; die Änderung wirkt dort, wo er
   Information trägt: Fokusring und Rahmen.

   Ein Zielkonflikt, der nicht auflösbar war: Derselbe Ton kann nicht gleichzeitig auf Weiß
   dunkel genug und auf dem dunklen Footer hell genug sein. Der Footer-Hover (accent auf ink,
   vorher 3,35:1) ist deshalb auf Weiß umgestellt - siehe .voovena-footer-links a:hover.

   Der Hoch-Kontrast-Schalter bleibt zusätzlich bestehen; er ist die Steigerung, nicht der
   Ersatz für eine Standardpalette, die die Latte reißt. */
:root {
  --voovena-ink: #21557C;
  --voovena-accent: #5A8FBD;
  --voovena-success: #3C7D22;
  --voovena-warning: #7D5922;
  --voovena-highlight: #7D2275;
  --voovena-highlight-dark: #631A5C;
  --voovena-muted: #5B7184;
  /* --voovena-paper fehlte (Befund B1 aus dem zweiten UX-Durchgang): .tool-section griff darauf
     zu, die Variable gab es nie - die Werkzeuge-Kästen waren dadurch durchsichtig, der
     "sichtbar abgesetzte Container" existierte nur im Kommentar. Der Fehler fiel bei der
     Kontrastmessung nicht auf, weil gemessen wurde, was DEFINIERT ist: Was es nicht gibt, kann
     man nicht messen. */
  --voovena-paper: #FFFFFF;
  --voovena-paper-alt: #EAF4FB;
  --voovena-border: #5A8FBD;
  /* Der Chat-Untergrund stand fuenfmal als Inline-Style in den beiden Projektansichten und war
     damit fuer den Hoch-Kontrast-Schalter unerreichbar - der Schalter arbeitet ueber Variablen.
     Derselbe Ton, jetzt an EINER Stelle. */
  --voovena-chat-bg: #E5DDD5;

  /* Bootstrap 5.1 liest --bs-primary/--bs-success/--bs-secondary-rgb bereits selbst aus
     (siehe .text-primary/.bg-primary/.bg-success/.bg-secondary in bootstrap.min.css) - damit
     übernehmen Badges/Text-Utilities automatisch die Markenfarben. Alle anderen Primary-Klassen
     (.btn-primary, .border-primary, .progress-bar) sind in Bootstrap 5.1 fest verdrahtet und
     werden weiter unten gezielt überschrieben. --bs-danger/--bs-warning bleiben bewusst
     Bootstrap-Standard (Rot/Gelb) - Fehler-/Warnsemantik soll nicht von der Markenfarbe abhängen. */
  --bs-primary: #21557C;
  --bs-primary-rgb: 33, 85, 124;
  --bs-success: #3C7D22;
  --bs-success-rgb: 60, 125, 34;
  /* --bs-secondary stand auf dem Warnton #7D5922 (Befund aus dem zweiten UX-Durchgang).
     Gemeint war "eine weitere Markenfarbe für sekundäre Akzente" - benutzt wird .bg-secondary
     im Produkt aber ausnahmslos für den NEUTRALEN Zustand:

       Meilenstein "offen" · Material "Bestellt" · Foto-Schlagwort ·
       Auswahl-Kandidat "?" · Log-Stufe unbekannt · "nicht konfiguriert" · "Inaktiv"

     Kein einziger dieser Fälle ist eine Warnung - nebeneinander gestellt las sich jedes
     neutrale Kennzeichen wie eine. Jetzt derselbe blaugraue Ton wie --voovena-muted: neutral,
     zur Palette passend, und weißer Text darauf erreicht 5,07:1.

     Die Lehre daraus steht hier, weil sie beim nächsten Mal wieder greift: Eine
     Bootstrap-Variable zu setzen heißt, jede Klasse mitzuentscheiden, die sie liest. Der
     Blick gehört auf die VERWENDUNG im Produkt, nicht auf den Namen der Variablen. */
  --bs-secondary: #5B7184;
  --bs-secondary-rgb: 91, 113, 132;
}

/* Kontrast-Schalter (siehe Controllers/HomeController.cs SetHighContrast): unabhängig von der
   Schriftgröße, eigener Cookie. Überschreibt Bootstraps eigene CSS-Variablen (--bs-body-color/
   -bg/-link-color/-border-color), die die meisten Komponenten bereits selbst auslesen - dadurch
   wirkt die Klasse auf <html> projektweit, ohne jede Komponente einzeln anfassen zu müssen. */
.high-contrast {
  --bs-body-color: #000000;
  --bs-body-bg: #ffffff;
  --bs-link-color: #0000ee;
  --bs-link-hover-color: #0000aa;
  --bs-border-color: #000000;
  --voovena-muted: #000000;
  --voovena-border: #000000;
  /* Auch der Wartestatus-Rahmen: Im Hoch-Kontrast-Modus blieb er vorher gelb, weil er über
     Bootstraps .border-warning lief und damit an dieser Umschaltung vorbei. */
  --voovena-warning: #000000;
  /* Der Chat-Untergrund verschwindet im Hoch-Kontrast-Modus ganz: Ein warmer Beigeton ist
     Zierde, und Zierde ist genau das, was dieser Schalter abstellen soll. */
  --voovena-chat-bg: #FFFFFF;
}

/* Die Statuspunkte im Hoch-Kontrast-Modus: Farbe allein trägt hier nicht mehr, weil alles
   schwarz wird. Deshalb unterscheiden sich "erledigt" und "aktuell" hier durch die FÜLLUNG -
   gefüllt gegen weiß mit dickem Ring - statt durch den Farbton. Der Punkt bleibt lesbar, auch
   wenn man die beiden Grüntöne nicht auseinanderhält.

   Jeder Zustand steht einzeln da, obwohl sich "border-color: #000" wiederholt. Der erste
   Versuch war eine gemeinsame Regel `.high-contrast .status-head-dot` - die verliert bei
   gleicher Spezifität gegen die später notierten `.status-head-dot.is-done/.is-current`, und
   der Rand blieb blau. Im Browser gemessen, nicht überlegt. */
.high-contrast .status-head-dot,
.high-contrast .status-head-dot.is-done,
.high-contrast .status-head-dot.is-current {
  border-color: #000000;
}

.high-contrast .status-head-dot.is-done {
  background: #000000;
}

.high-contrast .status-head-dot.is-current {
  background: #ffffff;
  border-width: 5px;
  box-shadow: none;
}

.high-contrast .text-muted {
  color: #000000 !important;
}

.high-contrast .btn-outline-secondary,
.high-contrast .btn-outline-primary,
.high-contrast .btn-outline-danger {
  border-width: 2px;
}

.high-contrast .card,
.high-contrast .list-group-item,
.high-contrast .table {
  border-color: #000000;
}

.voovena-header-accent {
  height: 3px;
  background: linear-gradient(90deg, var(--voovena-ink), var(--voovena-accent));
}

.voovena-navbar {
  box-shadow: 0 1px 3px rgba(33, 85, 124, .12);
}

.voovena-navbar .nav-link {
  font-weight: 500;
  color: var(--voovena-ink) !important;
  border-radius: .375rem;
  transition: background-color .15s ease-in-out;
}

/* Hover als Flächen- statt Textfarbwechsel: beide Logofarben (--voovena-ink, --voovena-accent)
   sind entweder schon die Standardfarbe oder auf Weiß zu kontrastarm als Textfarbe - eine
   dezente Hintergrundfläche in der hellen Paletten-Variante gibt trotzdem sichtbares Feedback. */
.voovena-navbar .nav-link:hover,
.voovena-navbar .nav-link:focus,
.voovena-navbar .dropdown-toggle:hover {
  background-color: var(--voovena-paper-alt);
}

.voovena-navbar .dropdown-item:active,
.voovena-navbar .dropdown-item.active {
  background-color: var(--voovena-ink);
}

/* Dunkler Footer (statt des vorherigen hellen Grau-Kastens) - bewusst deutlicher Kontrast zum
   Seiteninhalt, damit klar erkennbar ist "hier endet die Seite", ein in modernen SaaS-Produkten
   verbreitetes Muster. Nutzt dieselbe Tinte (--voovena-ink) wie die Markenschrift, nur als
   Hintergrund statt als Textfarbe. */
.voovena-footer {
  background: var(--voovena-ink);
  margin-top: 3rem;
}

/* ⚠️ padding-top/-bottom EINZELN, nicht als Kurzform.
   Hier stand "padding: 2.5rem 0 2.25rem" - und die mittlere Null setzt links und rechts auf
   null. Damit war der Seitenabstand geloescht, den .container von Bootstrap mitbringt.

   Auf breiten Schirmen faellt das nicht auf: Dort hat .container eine Maximalbreite, und der
   Rand entsteht ohnehin durch den freien Platz daneben. Auf dem Telefon ist er randlos - dort
   klebte der ganze Footer am linken Bildschirmrand (gemeldet vom CEO am 27.08.2026).

   Wer hier wieder eine Kurzform einsetzt, nimmt den Seitenabstand erneut mit. Ein fehlender
   Wert in einer Kurzform ist kein "unveraendert", sondern eine Null. */
.voovena-footer-inner {
  padding-top: 2.5rem;
  padding-bottom: 2.25rem;
}

.voovena-footer-brand {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-weight: 700;
  color: #fff;
  letter-spacing: .04em;
  font-size: 1rem;
}

.voovena-footer-brand .voovena-footer-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--voovena-accent);
  display: inline-block;
}

.voovena-footer-copyright {
  color: #B7CFE0;
  font-size: .8rem;
  margin-top: .25rem;
}

.voovena-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem 1.25rem;
  list-style: none;
  padding: 0;
  margin: 1rem 0 0;
}

.voovena-footer-links a {
  color: #D7E9F5;
  text-decoration: none;
  font-size: .85rem;
}

/* Nicht var(--voovena-accent): Der Akzent ist für Weiß dunkel genug gemacht worden und auf dem
   dunklen Footer damit zu schwach (3,35:1 vorher, danach noch weniger). Weiß auf ink sind
   7,91:1 - und der Unterstrich trägt den Hover-Zustand ohnehin zusätzlich zur Farbe. */
.voovena-footer-links a:hover {
  color: #FFFFFF;
  text-decoration: underline;
}

.voovena-footer-lang {
  padding-top: .1rem;
}

.voovena-footer-lang label {
  font-size: .8rem;
  color: #B7CFE0;
  margin-right: .4rem;
}

.voovena-footer-lang select {
  font-size: .85rem;
}

/* ==== Buttons: Bootstrap-Primärfarbe auf Markenmagenta umstellen ====
   .btn-primary/.border-primary/.progress-bar sind in Bootstrap 5.1 fest verdrahtete Hex-Werte
   (keine CSS-Variablen wie ab 5.2) und werden daher hier direkt überschrieben, statt jede
   einzelne View anzupassen. Rollenverteilung wie auf der Marketing-Homepage (marketing.css):
   Blau bleibt Struktur (Navigation, Tabellenköpfe, Rahmen wie .border-primary, Fortschrittsbalken),
   Magenta ist ab jetzt ausschließlich Handlungs-Buttons vorbehalten (Checkout, "Plan wählen",
   Feedback-Absenden, Speichern, Senden, Einladen, Hochladen, Posten) - deckungsgleich mit der
   Portal-CTA-Farbe, die die E-Mail-Buttons schon länger verwenden. */
.btn-primary {
  background-color: var(--voovena-highlight);
  border-color: var(--voovena-highlight);
}

.btn-primary:hover,
.btn-check:focus + .btn-primary,
.btn-primary:focus,
.btn-check:checked + .btn-primary,
.btn-primary:active,
.btn-primary.active,
.show > .btn-primary.dropdown-toggle {
  background-color: var(--voovena-highlight-dark);
  border-color: var(--voovena-highlight-dark);
}

.btn-check:focus + .btn-primary,
/* Hier stand ein eigener Fokusring für .btn-primary: rgba(125, 34, 117, .5) = 2,64 : 1.
   Er überschrieb den kräftigeren Ring von ganz oben (weiß + Akzent, 3,44 : 1) - gleiche
   Spezifität, die spätere Regel gewinnt. Betroffen waren ausgerechnet Senden, Speichern,
   Einladen, Hochladen, Posten und die Foto-Kachel. Ersatzlos entfernt (Befund B3 aus dem
   zweiten UX-Durchgang); es gilt wieder die allgemeine Regel. */

/* .border-primary bleibt bewusst Blau (nicht das neue Magenta von .btn-primary) - dient der
   strukturellen Hervorhebung (z. B. aktuelle Plankarte auf der Konto-Seite), keiner Handlung,
   analog zu .mk-price-highlight auf der Marketing-Homepage, die ebenfalls Blau nutzt. */
.border-primary {
  border-color: var(--voovena-ink) !important;
}

.progress-bar {
  background-color: var(--voovena-ink);
}

/* ==== Grids: einheitlicher Tabellenkopf für Admin-/Listenansichten ====
   .table-striped/.table-hover lesen ihre Hintergrundfarbe bereits aus den Bootstrap-eigenen
   --bs-table-*-bg-Variablen (component-scoped auf .table selbst, siehe bootstrap.min.css) -
   hier auf einen dezenten Blauton statt Bootstraps neutralem Grau umgestellt. */
.table {
  --bs-table-striped-bg: rgba(33, 85, 124, .05);
  --bs-table-hover-bg: rgba(33, 85, 124, .08);
}

.table thead th {
  background-color: var(--voovena-paper-alt);
  color: var(--voovena-ink);
  border-bottom: 2px solid var(--voovena-border);
  font-weight: 600;
}
/* ==== Statuskopf und Kernaktionen (VOO-0033 / VOO-0034) ====
   Gemeinsam von Kundenseite (Project/Overview) und Betriebsseite (Project/Index) genutzt.
   Die Werte stehen hier und nicht in den Views, damit es EINE Stelle bleibt - siehe
   design-richtlinien.md, Abschnitt "Farben, Radien, Abstandswerte gehören in site.css". */
.status-head-card {
  border-radius: 1rem;
}

/* Wartezustand. Vorher trug der Kopf Bootstraps .border-warning (#ffc107) - 1,63 : 1 auf Weiß,
   also ein Rahmen, der um die wichtigste Aussage der Seite herum praktisch verschwindet
   (Befund B2 aus dem zweiten UX-Durchgang). Der Markenton "warning" schafft 6,32 : 1.
   Die Farbe trägt die Aussage ohnehin nicht allein - daneben stehen das Sanduhr-Zeichen und
   der Satz selbst. */
.status-head-card.is-waiting {
  border-color: var(--voovena-warning);
}

.status-head-dots {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin-top: .9rem;
}

/* Kein Pastell: Der offene Punkt trägt einen kräftigen Rand, damit er auch bei Sonnenlicht
   als Punkt erkennbar bleibt und nicht mit dem Hintergrund verschwimmt.

   VOO-0036 (11): Die drei Punkte trugen rohe Bootstrap-Farben (#495057/#198754/#0d6efd) und
   waren damit vom Hoch-Kontrast-Schalter nicht erreichbar - derselbe Fehler wie beim
   Wartestatus-Rahmen, nur eine Ecke weiter. Jetzt Palettenvariablen.

   Gemessen auf Weiß: Rand ink 7,91:1 (vorher 8,18:1 - minimal weniger, dafür schaltbar),
   erledigt success 5,06:1 (vorher 4,53:1), aktuell accent 3,44:1 (vorher 4,50:1).
   Der letzte Wert liegt unter 4,5:1 und darf es: Die FÜLLUNG ist Zierde, die Form des Punktes
   kommt vom Rand, und der steht mit 7,91:1 weit über den 3:1, die für grafische Objekte
   gelten. Zwischen Rand und Füllung bleiben 2,3:1 - der Ring bleibt sichtbar. */
.status-head-dot {
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  border: 2px solid var(--voovena-ink);
  background: #fff;
}

.status-head-dot.is-done {
  background: var(--voovena-success);
  border-color: var(--voovena-ink);
}

.status-head-dot.is-current {
  background: var(--voovena-accent);
  border-color: var(--voovena-ink);
  box-shadow: 0 0 0 3px rgba(33, 85, 124, .25);
}

/* Kernaktions-Kachel: groß genug für einen Handschuh, mit Beschriftung statt bloßem Symbol.
   Deutlich über den 48 x 48 DP der Richtlinie - eine Kachel ist keine Schaltfläche am Rand,
   sondern das Ziel des Bildschirms. */
.core-action {
  min-height: 104px;
  font-size: 1.05rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .35rem;
  border-radius: 1rem;
}

.core-action .core-action-icon {
  font-size: 1.9rem;
  line-height: 1;
}

/* VOO-0036 (11): Die Kacheln laufen über .btn-outline-primary, und dessen Schriftfarbe ist in
   Bootstrap 5.1 fest auf #0d6efd verdrahtet - exakt 4,50:1, also die Latte gerissen, sobald
   irgendetwas daneben liegt. Dieselbe Tinte, die schon .btn-primary trägt, schafft 7,91:1.
   Nebenbei behebt das die optische Ungleichrangigkeit: Die Kacheln sind jetzt so dunkel
   beschriftet wie alles andere Wichtige auf der Seite. */
.core-action.btn-outline-primary {
  color: var(--voovena-ink);
  border-color: var(--voovena-ink);
}

.core-action.btn-outline-primary:hover,
.core-action.btn-outline-primary:focus,
.core-action.btn-outline-primary:active {
  background-color: var(--voovena-ink);
  border-color: var(--voovena-ink);
  color: #ffffff;
}

/* Chat-Untergrund: siehe --voovena-chat-bg. Die Klasse ersetzt fünf gleichlautende
   Inline-Styles, die der Hoch-Kontrast-Schalter nicht erreichen konnte. */
.chat-surface {
  background-color: var(--voovena-chat-bg);
}

/* VOO-0036 (5): Dieselbe Reaktionsleiste stand zweimal im Produkt und maß zweimal anders -
   auf der Betriebsseite als btn-sm mit 0,85rem, auf der Kundenseite mit inline gesetzten
   48 px. Genau die Doppelung, die status-head.js vermeiden sollte.

   Jetzt EINE Klasse und KEINE Größenangabe hier: Die Zielgröße kommt aus der bereits
   vorhandenen @media (pointer: coarse)-Regel weiter oben, die jedem .btn 48 x 48 gibt. Wer
   die Zielgröße ändern will, ändert sie dort - an einer Stelle, für alles. */
.reaction-btn {
  font-size: .95rem;
  padding: .25rem .5rem;
}

/* VOO-0036 (4): Das Mikrofon im Composer ist kein Beiwerk neben der Bueroklammer - auf der
   Baustelle ist es der schnellste Weg zu einem Statustext. Es steht deshalb gefuellt da, mit
   groesserem Symbol; der Anhang bleibt bewusst das kleine Umriss-Symbol.

   BEWUSST NICHT .btn-primary: Magenta ist im Produkt ausschliesslich der Handlungs-Farbe
   vorbehalten (siehe die Rollenverteilung weiter oben) - der Absenden-Knopf steht direkt
   daneben, und zwei gleich aussehende Magenta-Knoepfe waeren keine Hervorhebung, sondern eine
   Verwechslung. Das Mikrofon bekommt deshalb die gefuellte Struktur-Tinte: deutlich mehr
   Gewicht als der Anhang, klar weniger als "Absenden". */
.composer-mic:not(.btn-danger) {
  background-color: var(--voovena-ink);
  border-color: var(--voovena-ink);
  color: #ffffff;
}

.composer-mic:not(.btn-danger):hover,
.composer-mic:not(.btn-danger):focus {
  background-color: #17405f;
  border-color: #17405f;
  color: #ffffff;
}

.composer-mic .composer-mic-icon {
  font-size: 1.35rem;
  line-height: 1;
}

/* Werkzeuge-Bereich: jeder Abschnitt ein eigener, sichtbar abgesetzter Container statt einer
   Reihe von <hr>-Strichen - der Unterschied zwischen "getrennt" und "gegliedert". */
.tool-section {
  border: 1px solid var(--voovena-border);
  border-radius: .75rem;
  padding: 1.25rem;
  margin-bottom: 1.25rem;
  background: var(--voovena-paper);
}

.tool-section > h2,
.tool-section > h3 {
  margin-bottom: .75rem;
}

/* VOO-0029 zweite Reihe #5, zweiter Teil: Bootstraps eigenes .text-muted (#6C757D) schafft auf
   Weiss 4,69:1, auf --voovena-paper-alt (#EAF4FB) aber nur 4,21:1 - und genau dort steht es,
   in Tabellenkoepfen und hellen Flaechen. Der bereits vorhandene Markenton --voovena-muted
   (#5B7184) schafft beide: 5,07:1 auf Weiss, 4,55:1 auf paper-alt.

   Die Variable gab es schon, sie wurde nur nirgends benutzt. Jetzt hat sie ihre Aufgabe. */
.text-muted {
  color: var(--voovena-muted) !important;
}

/* Aktionsknöpfe einer Tabellenzeile - gleiche Breite, auch beim Umbruch.

   Der Befund (CEO, Mobilansicht der Projektliste): "Bearbeiten", "Archivieren" und "Löschen"
   stapelten sich auf schmalen Bildschirmen untereinander, jeder so breit wie sein eigenes Wort
   und rechtsbündig. Das liest sich als Unordnung, nicht als Gruppe.

   flex-basis: 0 statt auto ist hier der Kern: Damit teilen sich die Knöpfe den Platz zu gleichen
   Teilen, unabhängig von der Wortlänge. Die min-width sorgt dafür, dass sie umbrechen statt
   unleserlich zu schrumpfen - und ein umgebrochener Knopf füllt seine Zeile ganz aus, weil er
   dort der einzige ist, der wachsen kann. */
.zeilen-aktionen {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .25rem;
}

.zeilen-aktionen > .btn {
  flex: 1 1 0;
  min-width: 6.5rem;
}

/* VOO-0085: Reiter mit Symbol - der aktive braucht eine FLAECHE, nicht nur einen Rand.

   Bootstrap kennzeichnet den aktiven Reiter ueber den Rahmen: Er bekommt oben und seitlich
   eine Linie und unten keine, wodurch er mit dem Inhalt darunter verschmilzt. Das ist bei
   fuenf Textreitern gut lesbar - bei fuenf Symbolen ohne Text ist es zu wenig.

   ⚠️ Das war hier schon einmal die Ursache einer Verwechslung: Bei der umgebrochenen Leiste
   sahen zwei Reiter gleichzeitig aktiv aus, weil der abgerutschte oben eine Linie hatte und
   der echte aktive auch. Zwei Rahmen unterscheidet das Auge schlechter als zwei Flaechen.

   Farbe allein reicht nicht - aria-selected setzt Bootstrap, und aria-label steht am Knopf.
   Die Flaeche ist die zusaetzliche, nicht die einzige Auskunft. */
#projectTabs .nav-link.active {
    background-color: #e7f1ff;
    font-weight: 600;
}

/* Die Beschriftung neben dem Symbol erscheint ab der md-Stufe (768 px), und diese Zahl ist
   gemessen, nicht gewaehlt. Mit fuenf Reitern - also als Projektadmin, nur er hat Werkzeuge:

     Text braucht      621 px (Deutsch)   638 px (Ungarisch)
     Leiste hat        516 px (bis 767)   696 px (ab 768)   936 px (ab 992)

   Die 638 passen in 696 und nicht in 516. Dass die Bootstrap-Stufe md genau dort liegt, wo
   der Container von 516 auf 696 springt, ist der Grund, warum hier keine eigene Zahl noetig
   ist - nicht Zufall, sondern dieselbe Stufenfolge.

   ⚠️ Wer eine Sprache dazunimmt ODER einen Reitertext in einer vorhandenen aendert, misst neu.
   Beides kippt dieselbe Grenze. Alle 28 Fassungen sind gemessen; die knappste ist
   Niederlaendisch mit 678 px - 18 px Reserve bis 696. Ein einziges laengeres Wort in einem
   der fuenf Reiter bringt sie darueber.

   ⚠️ Und was dann NICHT hilft: den laengsten Reitertext kuerzen. Bei jeder knappen Sprache
   gibt ein anderer Reiter den Ausschlag - Luxemburgisch die Werkzeuge (193 px, fast ein
   Drittel der Leiste), Niederlaendisch die Bilder, Ungarisch die Dokumente, Deutsch die
   Nachrichten. Es gibt keinen einzelnen Engpass-Text, den man kurz halten koennte; eine
   Kuerzung traefe in jeder Sprache einen anderen.
   Messung: BreitenDurchsicht.AbWelcherBreitePasstDieReiterleiste (Skip entfernen). */

/* VOO-0087: Die Projektzeile oeffnet das Projekt.

   ZWEI Kennzeichen, und keines davon braucht einen Mauszeiger - auf einem Telefon gibt es
   keinen Hover-Zustand, an dem man erkennen koennte, dass eine Zeile klickbar ist:

     1. Der Projektname ist ein Link und sieht auch so aus: Linkfarbe UND Unterstreichung,
        wie ueberall sonst. Er trug zuerst text-decoration-none - vertretbar, solange ein
        Pfeil daneben stand, aber nicht mehr, seit er das einzige Kennzeichen ist, das VOR
        dem Tippen wirkt.
     2. :active faerbt beim Antippen die ganze Zeile - das ist die Rueckmeldung DANACH,
        kein Ersatz fuer die Anzeige davor.

   ⚠️ Ein drittes gab es: ein Pfeilsymbol am Zeilenende. Der CEO hat es zurueckgenommen,
   und der Grund ist NICHT, dass die Zeile ein Element zu viel hatte:

     Der Pfeil war ein zweiter Weg zu einer Handlung, die schon am Namen haengt.

   Das schliesst auch alle Abwandlungen aus - ihn kleiner machen, anders faerben oder
   woandershin setzen loest nichts, weil das Problem nicht sein Aussehen ist. Dass er neben
   dem Menueknopf wie ein zweiter Bedienknopf aussah, war die Beobachtung, an der es auffiel;
   sie steht hier bewusst NACH der Ursache, weil sie sonst zu einer Umgestaltung einlaedt
   statt zum Weglassen.

   ⚠️ Der z-index am Menue ist keine Kosmetik. stretched-link legt eine unsichtbare Flaeche
   ueber die ganze Zeile; ohne einen hoeheren z-index faengt sie jeden Klick auf das Menue ab,
   und Bearbeiten, Archivieren und Loeschen waeren gar nicht mehr erreichbar. Der Fehler waere
   schlimmer als der behobene: Vorher waren die Knoepfe verdeckt, dann waeren sie tot. */
/* ⚠️ position: relative ist hier KEINE Formatierung, sondern die Bedingung dafuer, dass
   der Link jeder Zeile bei seiner Zeile bleibt.

   stretched-link legt seine unsichtbare Flaeche relativ zum naechsten POSITIONIERTEN
   Vorfahren an. Ohne diese Zeile ist das nicht das tr, sondern der Kasten der ganzen
   Tabelle - und dann deckt die Flaeche EINER Zeile alle anderen zu. Bei gleichem z-index
   gewinnt die letzte im Dokument.

   Der Fehler war im Quelltext nicht zu sehen: Jede Zeile trug das richtige href. Nur ein
   Klick landete immer im selben Projekt. Gemeldet hat es der CEO - vier Zeilen, viermal
   dasselbe Ziel.

   Wer diese Zeile entfernt, weil ein tr ohnehin keine Positionierung braucht, holt genau
   das zurueck. Reise 22 prueft es je Zeile. */
#ownProjectsTableBody tr,
#sharedProjectsTableBody tr {
    position: relative;
}

#ownProjectsTableBody tr:active,
#sharedProjectsTableBody tr:active {
    background-color: #e7f1ff;
}


.zeilen-menue {
    position: relative;
    z-index: 2;
    display: inline-block;
}

/* VOO-0087: Ein Loeschknopf in einer Tabellenzeile, der nur sein Symbol zeigt.

   Rang 3 der Rangfolge - dieselbe Regel wie bei den Reitern: Die Beschriftung weicht, das
   Symbol bleibt. Anders als in der Projektliste gibt es hier nichts aufzuteilen; wo nur EIN
   Knopf steht, braucht es kein Menue, sondern weniger Breite.

   ⚠️ Rang 1 geht vor Rang 3, und das ist der Grund fuer die Mindestmasse: Die Tippflaeche
   bleibt 48x48 DP, auch wenn das Zeichen darin klein ist. Ein Knopf, der auf die Groesse
   seines Symbols schrumpft, waere auf dem Telefon nicht mehr sicher zu treffen - und ein
   Loeschknopf, den man daneben antippt, ist schlimmer als einer, der Platz braucht. */
.zeilen-symbolknopf {
    min-width: 3rem;
    min-height: 3rem;
    line-height: 1;
}

/* Ein Feed-Eintrag, der zum Kommentar springt, muss auch aussehen wie ein Bedienelement.
   Der Fokusrahmen ist dabei kein Beiwerk: Die Karte traegt tabindex, ist also per Tastatur
   erreichbar - ohne sichtbaren Rahmen sieht man nur nicht, wo man steht.

   Warum ueberhaupt ein Sprung: Ein Kommentar steht am Bild, und das Bild ist nach vierzig
   Fotos nicht mehr auffindbar. Der Eintrag im Strom ist der Weg zurueck; ohne den Sprung
   zeigt er nur an, DASS kommentiert wurde. */
.feed-eintrag-klickbar { cursor: pointer; }
.feed-eintrag-klickbar:focus-visible { outline: 3px solid #0d6efd; outline-offset: -3px; }

/* ⚠️ Das Mikrofon IM Eingabefeld (seit 27.08.2026) ist bewusst leiser als das daneben.
   .composer-mic gibt ihm oben gefuellte Struktur-Tinte und ein 1,35rem-Symbol - mit der
   Begruendung von VOO-0036: "deutlich mehr Gewicht als der Anhang, klar weniger als Absenden".

   Diese Begruendung galt fuer die Position NEBEN dem Feld, in einer Reihe mit drei anderen
   Knoepfen. Im Feld steht es allein und braucht kein Gewicht mehr - dort wirkte die Fuellung
   staerker als der Senden-Knopf darunter. Gemeldet vom CEO: "So ist das Mikrofon von der
   Wirkung groesser als der Senden Button."

   ⚠️ Die TIPPFLAECHE bleibt bei 48 DP (zeilen-symbolknopf, Rang 1 der Design-Richtlinie) - nur
   das Sichtbare wird kleiner. Wer hier min-width/min-height setzt, um es "wirklich" zu
   verkleinern, nimmt Rang 1 zurueck: Ein Knopf, den man auf dem Telefon danebentippt, ist
   schlimmer als einer, der etwas zu praesent aussieht.

   Der Aufnahmezustand (.btn-danger, per JS) ist ausgenommen und bleibt kraeftig - waehrend
   aufgenommen wird, IST es der wichtigste Knopf im Bild. */
.composer-mic.composer-mic-im-feld:not(.btn-danger) {
    background-color: transparent;
    border-color: #e9ecef;
    color: var(--voovena-ink);
}

.composer-mic.composer-mic-im-feld:not(.btn-danger):hover,
.composer-mic.composer-mic-im-feld:not(.btn-danger):focus {
    background-color: #f8f9fa;
    border-color: #dee2e6;
    color: var(--voovena-ink);
}

.composer-mic-im-feld .composer-mic-icon {
    font-size: 1rem;
}

/* ⚠️ Bedienleisten, die auf schmalen Schirmen umbrechen: Dort nimmt jedes Element die volle
   Breite - sonst steht eine Treppe aus lauter verschiedenen Breiten untereinander.

   Der Befund kam vom CEO am 27.08.2026 aus dem Dokumente-Reiter: "die ganzen Felder sehen sehr
   unordentlich aus". Sechs Bedienelemente untereinander, sechs Breiten - das Suchfeld 220 px
   (max-width), die Auswahl 200 px, die Knoepfe jeweils so breit wie ihre Beschriftung. Und die
   Auswahl "Allgemeines Dokument" war bei 200 px abgeschnitten.

   In einer Zeile ist das richtig: Dort begrenzt max-width, damit ein Suchfeld nicht den ganzen
   Platz nimmt. Sobald umgebrochen wird, gibt es keine Zeile mehr, in der es sich einordnen
   koennte - und die Begrenzung erzeugt nur noch Unruhe.

   ⚠️ !important ist hier noetig und kein Versehen: Die Begrenzungen stehen als style-Attribut
   direkt an den Elementen. Wer sie dort entfernt und in Klassen ueberfuehrt, kann das
   !important hier mitnehmen.

   WO DIE GRENZE LIEGT, IST GEMESSEN, NICHT GEWAEHLT: Die Leiste bricht bis 767 px um und steht
   ab 768 in einer Zeile. Der Sprung kommt nicht von der Fensterbreite, sondern von der
   Stufe des Bootstrap-Containers - bei 767 sind innen 482 px Platz, bei 768 sind es 662, und
   die Dokumenteleiste braucht 568. Die Grenze faellt damit mit DEC-0033 zusammen ("Mobil
   unter 768"), aber das ist das Ergebnis, nicht die Begruendung.

   ⚠️ Eine fruehere Fassung stand auf 575.98 - der Bootstrap-Wert "sm", ohne Messung
   uebernommen. Zwischen 576 und 767 blieb die Treppe dadurch vollstaendig stehen, und
   die Zusicherung bei 375 war trotzdem gruen.

   Versteckte Elemente (d-none, etwa der Datei-Auswahldialog) bleiben versteckt - deren
   display:none traegt selbst !important. */
@media (max-width: 767.98px) {
    .bedienleiste > *,
    .bedienleiste > .bedienleiste-gruppe > * {
        width: 100%;
        max-width: none !important;
    }

    /* ⚠️ Untergruppen muessen EINZELN ausgezeichnet werden - eine Regel auf ".bedienleiste > div"
       waere bequemer und richtet Schaden an: In manchen Leisten ist das Kind-div kein Behaelter
       fuer Knoepfe, sondern eine Beschriftungsgruppe (label ueber Feld, etwa der Album-Reiter).
       Die wuerde dadurch zur Flex-Zeile - Beschriftung NEBEN dem Feld statt darueber.

       Der Abstand muss hier mitkommen, weil ein div ohne d-flex kein gap kennt. */
    .bedienleiste > .bedienleiste-gruppe {
        display: flex;
        flex-wrap: wrap;
        gap: .5rem;
    }
}
}

/* Ein Dokumenteintrag ist EINE SPALTE - in jeder Breite dieselbe Anordnung.

   Vorher waren es drei nebeneinander: Auswahlkaestchen, Textblock, Knopfspalte. Die beiden
   aeusseren nahmen sich ihren Platz zuerst, und bei 375 px blieben dem Textblock 110 px - der
   Dateiname zerfiel in fuenf Zeilen mit je einem Wort. CEO-Befund vom 27.08.2026: "da kann
   man praktisch nichts erkennen, die komplette Anordnung ist verkehrt."

   Eine Zwischenfassung hing an einer Breitengrenze - unter 768 umbrechend, darueber wieder
   dreispaltig. Das ist bewusst wieder heraus: Zwei Anordnungen fuer dieselbe Sache sind zwei
   Stellen zum Kaputtgehen, und die schmale traegt auch am Rechner. Was nicht in die Kopfzeile
   passt, steht im Punktemenue rechts oben.

   ⚠️ Kein flex hier und keine d-flex-Utility am Eintrag: Er ist ein gewoehnlicher Block,
   seine Kinder stapeln sich von selbst. Wer d-flex ergaenzt, holt das alte Verhalten zurueck -
   und die Utilities von Bootstrap tragen !important, sind von hier aus also nicht mehr zu
   ueberstimmen. */
.dokument-aktionen {
    margin-top: .5rem;
}

@media (max-width: 767.98px) {
    /* Typ-Auswahl und Beschreibung tragen eigene Breitenbegrenzungen (max-width:180px am
       style-Attribut). Untereinander ergeben die dieselbe Treppe wie in den Bedienleisten:
       jedes Feld so breit, wie es zufaellig darf. */
    .dokument-eintrag .form-select,
    .dokument-eintrag .form-control {
        max-width: none !important;
    }
}

/* Gilt in JEDER Breite: Ein Dateiname ohne Leerzeichen ("Rechnung_2026_08_Muster_final.pdf")
   hat keine Umbruchstelle und ragt sonst aus dem Rahmen - am Telefon aus dem Bildschirm.
   anywhere statt break-all: Es bricht erst, wenn die Zeile sonst uebersteht, und zerhackt
   nicht jedes Wort. */
.dokument-name {
    overflow-wrap: anywhere;
}

/* Vorlagen ueber dem Eingabefeld ("Fliesen verlegt", "Fugen gezogen").

   Vorher schmucklose Rechtecke in lauter verschiedenen Breiten, untereinander gestapelt -
   fuenf Stueck ergaben 204 px in vier Zeilen, direkt ueber dem Feld, in das man schreiben
   will. Auf einem 812 px hohen Telefon ist das ein Viertel des Bildschirms.

   Zwei Griffe: Die Pillenform mit knapperem Innenabstand laesst mehr pro Zeile zu, und ab der
   vierten Vorlage wandert der Rest ins Punktemenue daneben (VORLAGEN_SICHTBAR im View).

   ⚠️ DIE HOEHE BLEIBT BEI 48 DP. Eine Vorlage ist ein Tippziel wie jedes andere, und Rang 1
   der Design-Richtlinie steht ueber der kompakten Form (Rang 4). Schmaler ja, flacher nein -
   wer hier min-height streicht, macht die Reihe huebscher und schlechter bedienbar.

   ⚠️ text-align:left ist kein Beiwerk: Bootstrap zentriert Knopfbeschriftungen. Bricht eine
   lange Vorlage auf zwei Zeilen um, steht die zweite sonst mittig unter der ersten und die
   Reihe wirkt zerfasert. */
.vorlagen-pille {
    min-height: 3rem;
    padding-left: .85rem;
    padding-right: .85rem;
    text-align: left;
}

/* Aufklapper mit rundem Pfeil rechts - Wartestatus und Material.

   Vorbild ist der CEO selbst: Er hat die Google-Suche danebengehalten ("bei Google ist das
   so, schaut auch gut aus"). Dort steht die Frage links, ein grau hinterlegter Chevron
   rechts, und er dreht sich beim Aufklappen.

   Der Gewinn ist nicht nur Optik: Vorher war der Ausloeser ein blauer Text ohne
   Unterstreichung - er sah aus wie eine Beschriftung, nicht wie etwas Antippbares. Der Pfeil
   sagt, dass sich hier etwas oeffnet, und in welche Richtung.

   ⚠️ Die ganze ZEILE ist der Knopf, nicht nur der Pfeil. Ein 36-px-Kreis als einziges Ziel
   laege unter der Tippflaeche von 48 DP (Rang 1) - min-height haelt die Zeile darueber.

   ⚠️ Die Drehung haengt an aria-expanded, das Bootstrap selbst umschaltet. Wer den Pfeil per
   JS dreht, baut einen zweiten Zustand neben den echten, und der laeuft irgendwann auseinander. */
.aufklapper-zeile {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    width: 100%;
    min-height: 3rem;
    text-align: left;
}

/* ⚠️ KEIN Rahmen und kein Schattenring, wenn der Aufklapper den Fokus hat - ausdruecklicher
   Wunsch des CEO (27.08.2026: "wenn der Fokus auf z.B. Material ist, wuerde ich keine Rahmen
   drum herum machen"). Bootstrap legt bei :focus einen breiten blauen Ring um den ganzen
   Knopf, und da der Knopf hier die volle Zeilenbreite hat, umrandet er den halben Abschnitt.

   ⚠️ Aber NUR fuer :focus, nicht fuer :focus-visible. Der Unterschied ist der ganze Punkt:
   :focus trifft auch den Mausklick - dort ist der Ring ueberfluessig, man sieht ja, wohin man
   getippt hat. :focus-visible trifft die Tastatur, und dort ist er die EINZIGE Anzeige, wo
   man gerade steht. Wer ihn auch dort abschaltet, macht die Seite mit der Tastatur
   unbedienbar; das faellt niemandem auf, der eine Maus benutzt. */
.aufklapper-zeile:focus {
    box-shadow: none;
}

.aufklapper-zeile:focus-visible {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
    box-shadow: none;
}

.aufklapper-pfeil {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background-color: var(--bs-secondary-bg, #e9ecef);
    color: var(--bs-secondary-color, #6c757d);
    transition: transform .2s ease;
}

.aufklapper-zeile[aria-expanded="true"] .aufklapper-pfeil {
    transform: rotate(180deg);
}

/* Punktemenues ohne Rahmen (CEO: "die drei Punkte ohne Rahmen sehen auch gut aus").

   ⚠️ Randlos heisst nicht unsichtbar: Beim Ueberfahren, bei Tastaturfokus und solange das
   Menue offen ist (.show) kommt ein runder Hintergrund. Ohne den gaebe es keine Rueckmeldung,
   dass hier etwas anklickbar ist - und mit der Tastatur waere gar nicht erkennbar, wo man steht.

   Die Tippflaeche bleibt bei 48 DP: Die kommt von .zeilen-symbolknopf, der weiterhin
   danebensteht. Wer diese Klasse allein verwendet, verliert sie. */
.punktemenue-knopf {
    border: none;
    background-color: transparent;
    color: var(--bs-secondary-color, #6c757d);
    line-height: 1;
    border-radius: 50%;
}

.punktemenue-knopf:hover,
.punktemenue-knopf:focus-visible,
.punktemenue-knopf.show {
    background-color: var(--bs-secondary-bg, #e9ecef);
    color: var(--bs-body-color, #212529);
}

.punktemenue-knopf:focus {
    box-shadow: none;
}

/* "Abmelden" steht als einziger Eintrag der Kopfleiste in einem Formular - es ist ein
   Absendeknopf, kein Link. Beides muss so aussehen und sitzen wie die Links daneben.

   ⚠️ font: inherit ist die wichtigste Zeile. Ein button erbt Schriftart und -groesse NICHT
   vom Elternelement, sondern bekommt die des Systems; ohne diese Zeile steht "Abmelden" in
   einer anderen Schrift als "Mein Konto" daneben, und die abweichende Zeilenhoehe verschiebt
   ihn zusaetzlich nach unten. Am Rechner faellt der Unterschied kaum auf, am iPad deutlich -
   dort ist die Systemschrift eine andere. */
.abmelden-formular {
    display: flex;
    align-items: center;
    margin: 0;
}

.abmelden-knopf {
    background: none;
    border: 0;
    font: inherit;
    cursor: pointer;
}

/* Die Fassungsmarke in der Fusszeile - bewusst sehr klein und blass ("ganz klein", CEO).

   Sie richtet sich nicht an Kunden, sondern beantwortet eine Betriebsfrage: Laeuft am Server
   die Fassung, die gerade hochgeladen wurde? Deshalb darf sie da sein, aber nichts an sich
   ziehen.

   ⚠️ Keine Angabe unter 0.7rem und kein blasserer Wert als 0.55 Deckkraft: Wer sie ablesen
   soll, muss sie auch ablesen koennen - sonst ist sie Zierrat und man greift doch wieder zum
   Entwicklerwerkzeug. */
.voovena-fassung {
    margin-top: .35rem;
    font-size: .7rem;
    line-height: 1.2;
    opacity: .55;
    font-variant-numeric: tabular-nums;
}

/* ⚠️ VERMUTETE Gegenmassnahme gegen einen Befund, den ich NICHT nachstellen konnte.

   CEO, 28.08.2026: "wenn ich auf den Reiter Archiviert klicke, dann oeffnet sich das erste
   Projekt. Am Desktop mit Maus geht es, am Handy und IPAD geht es nicht."

   Was ich mit nachgestelltem Touch-Zeiger AUSGESCHLOSSEN habe - jeweils gemessen, nicht
   ueberlegt:

     - Der stretched-link der Projektzeilen ueberdeckt den Reiter nicht. Sein positionierter
       Vorfahre ist die Zeile selbst (TR:relative), Bereich 524-590; der Reiter liegt 403-451.
     - Kein Overlay faengt den Tipp ab. elementFromPoint auf der Reitermitte liefert den
       Reiter, der Stapel darunter ist nav-item / nav / main.
     - Beim Umschalten verschiebt sich nichts. Reiterposition vorher 382, nachher 382; die
       Liste wechselt korrekt von 10 auf 3 Zeilen.

   Damit bleibt als wahrscheinlichster Mechanismus der GEISTKLICK von iOS: Safari stellt den
   click nach touchend verzoegert zu (Doppeltipp-Zoom-Erkennung). Trifft er ein neu
   gerendertes Element, landet er dort statt auf dem urspruenglichen. Die Tabelle wird beim
   Reiterwechsel vollstaendig neu aufgebaut - genau die Lage, in der das passiert.

   touch-action: manipulation schaltet die Doppeltipp-Erkennung fuer diese Elemente ab; die
   Verzoegerung entfaellt und mit ihr das Zeitfenster. Die Massnahme ist verbreitet, hier aber
   NICHT verifiziert - das geht nur auf dem Geraet. Wer nachmisst und feststellt, dass es
   nicht daran lag, soll diesen Block wieder entfernen statt ihn stehen zu lassen.

   Ohne Nebenwirkung ist sie nicht: Auf diesen Elementen ist Doppeltipp-Zoom danach nicht mehr
   moeglich. Das Zoomen der SEITE bleibt unberuehrt (Aufziehen mit zwei Fingern). */
.nav-link,
.nav-pills .nav-link,
.btn,
.dropdown-item,
.page-link {
    touch-action: manipulation;
}

/* ⚠️ Solange ein Punktemenue offen ist, darf die Tabelle nicht abschneiden.

   Befund des CEO vom 28.08.2026: "Wenn man den Button drei Punkte anklickt, scheint die Liste
   irgendwo zu verschwinden, tritt ueberall auf, Desktop, Ipad, Handy."

   Ursache, gemessen an der archivierten Projektliste: .table-responsive traegt
   overflow-x: auto, und CSS macht daraus zwangslaeufig auch overflow-y: auto - eine Achse
   allein laesst sich nicht auf "sichtbar" halten. Das aufgeklappte Menue der letzten Zeile
   ragt unten heraus (gemessen: 91 px) und macht den Behaelter scrollbar: Die Scrollhoehe
   sprang beim Oeffnen von 123 auf 214 px. Der Behaelter springt daraufhin an das Menue, und
   die Namensspalte wandert aus dem Bild.

   ⚠️ EIN ERSTER VERSUCH UEBER JAVASCRIPT IST GESCHEITERT und steht deshalb nicht mehr hier:
   Poppers Strategie auf "fixed" zu setzen (bootstrap.Dropdown mit eigenem popperConfig) blieb
   in Bootstrap 5.1 wirkungslos - gemessen, das Menue behielt position: absolute und die
   Scrollflaeche entstand weiterhin. Wer die Bibliothek auf 5.2+ hebt, kann es mit dem
   Attribut data-bs-strategy="fixed" erneut versuchen und diesen Block dann pruefen.

   Was diese Regel kostet: Waehrend das Menue offen ist, laesst sich die Tabelle nicht
   seitlich schieben. Das ist der kleinere Preis - ein Menue ist ein kurzer Zustand.

   ⚠️ :has() braucht Safari 15.4+ / Chrome 105+. Aeltere Browser verhalten sich wie bisher,
   also fehlerhaft - aber nicht schlechter als vorher. */
.table-responsive:has(.dropdown-menu.show) {
    overflow: visible;
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   Die Projektkarte - eine Liste aus drei Quellen, seit 28.08.2026 anstelle von drei Tabellen.
   Eine Tabellenzeile behandelt jede Spalte gleich wichtig. Eine Karte kann eine RANGFOLGE
   zeigen - oben der Name, darunter der Zustand (wartet auf wen, bis wann), ganz unten das
   Beiwerk. Genau die fehlte vorher: Dass ein Projekt auf einen wartet, erfuhr man erst beim
   Oeffnen.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
/* ⚠️ position: relative IST DIE WICHTIGSTE ZEILE DIESES ABSCHNITTS.

   Der Projektname traegt stretched-link, damit die ganze Karte klickbar ist. Bootstrap
   legt dafuer eine unsichtbare Flaeche ueber den naechsten POSITIONIERTEN Vorfahren -
   ist die Karte static, sucht der Browser weiter oben und findet erst den body.

   Gemessen am 28.08.2026, nachdem der CEO es gemeldet hatte ("wenn ich auf Eigene Extern
   Archiviert oder Neues Projekt klicke, oeffnet sich immer das Projekt"): Die Flaeche des
   ERSTEN Links reichte von 0 bis 1619 px - ueber die ganze Seite. Ein Klick auf die
   Filterzeile oder auf "Neues Projekt" traf A.projekt-name.

   Die alte Tabellenzeile hatte position:relative; beim Umbau auf Karten ist es
   verlorengegangen. Wer es hier entfernt, macht die halbe Seite unbedienbar - und zwar
   ohne Fehlermeldung, die Klicks kommen ja an, nur woanders. */
.projekt-karte {
    position: relative;
    display: block;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: .75rem;
    padding: 1rem;
    background-color: var(--bs-body-bg, #fff);
    transition: box-shadow .15s ease, border-color .15s ease;
}

/* ⚠️ Nur auf Geraeten mit Mauszeiger. Auf dem Telefon gibt es kein Ueberfahren; dort bliebe
   der Zustand nach dem Antippen haengen und die Karte saehe dauerhaft ausgewaehlt aus. */
@media (hover: hover) {
    .projekt-karte:hover {
        border-color: var(--bs-primary, #0d6efd);
        box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .08);
    }
}

.projekt-kopf {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
}

/* ⚠️ min-width: 0 an einem Flex-Kind ist Pflicht, sobald sein Text kuerzbar sein soll: Ein
   Flex-Element hat von Haus aus min-width: auto und schrumpft nie unter seinen Inhalt - der
   Name wuerde die Karte aufreissen statt umzubrechen. */
/* ⚠️ UNTERSTRICHEN, und das ist eine Zusage, keine Geschmacksfrage: Reise22 prueft sie
   (DerProjektnameSiehtAusWieEinLink). Mein erster Entwurf hatte text-decoration:none - in
   einer Karte sieht eine Ueberschrift ueblicherweise so aus -, und der Test wurde rot.
   Zu Recht: Der Name IST der Link, der das Projekt oeffnet. Nimmt man ihm die
   Unterstreichung, bleibt nur die Farbe, und wer Farben schlecht unterscheidet, sieht gar
   nichts mehr. Die Karte hebt sich zwar beim Ueberfahren - aber nur mit Maus. */
.projekt-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.projekt-zustand {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-top: .5rem;
}

.projekt-marke {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    padding: .2rem .6rem;
    border-radius: 2rem;
    font-size: .8rem;
    font-weight: 500;
}

/* Wartet auf den Kunden: ruhig. Es liegt gerade nicht am Betrieb. */
.projekt-marke-warten {
    background-color: rgba(255, 193, 7, .18);
    color: #7a5b00;
}

/* Wartet auf den Betrieb: das ist der Handlungsfall und darf auffallen. */
.projekt-marke-dran {
    background-color: rgba(13, 110, 253, .12);
    color: #0a58ca;
}

.projekt-frist {
    font-size: .8rem;
    color: var(--bs-secondary-color, #6c757d);
}

.projekt-frist-ueberfaellig {
    color: #b02a37;
    font-weight: 600;
}

/* Zwei Zeilen, dann Schluss: Die Beschreibung ist hier Beiwerk. Wer sie ganz lesen will,
   oeffnet das Projekt - eine Liste, in der ein Eintrag zehn Zeilen hat, ist keine Liste. */
.projekt-text {
    margin: .5rem 0 0;
    font-size: .9rem;
    color: var(--bs-secondary-color, #6c757d);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.projekt-fuss {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .75rem;
    margin-top: .75rem;
    font-size: .78rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* ⚠️ KEINE text-bg-* KLASSEN VERWENDEN, solange Bootstrap 5.1 eingebunden ist.

   Die Kurzform (text-bg-success, text-bg-secondary, ...) kam erst in Bootstrap 5.2. In 5.1
   ist sie schlicht nicht definiert - sie setzt also GAR NICHTS. Ein Abzeichen damit ist
   weisse Schrift auf durchsichtigem Grund und praktisch unsichtbar; die weisse Schrift kommt
   von .badge selbst.

   Genau so gefunden am 28.08.2026: Der Musterhinweis "Muster" war im Bildschirmfoto nicht zu
   sehen, obwohl das Element im DOM stand. Gemessen: backgroundColor rgba(0,0,0,0),
   color rgb(255,255,255).

   Betroffen waren SECHS Stellen, nicht nur die neue - darunter das Abzeichen "Aktuelle
   Fassung" an Dokumenten, auf Betriebs- UND Kundenseite. Das war seit seiner Einfuehrung
   unsichtbar, ohne dass es jemandem auffiel: Ein Abzeichen, das fehlt, sieht aus wie ein
   Dokument ohne Kennzeichnung.

   Richtig in 5.1: "badge bg-success", "badge bg-secondary", und fuer helle Gruende
   "badge bg-light text-dark" - dort braucht es die dunkle Schrift ausdruecklich.

   Wer Bootstrap auf 5.2+ hebt, kann zurueckwechseln; bis dahin ist jede text-bg-Klasse ein
   stiller Fehler. Ein Fund per Textsuche ueber lq/Views und lq/Areas zeigt sie alle. */

/* Abstand zwischen den Karten - der Container, nicht die Karte selbst. Ein margin-bottom an
   der Karte haette hinter der letzten einen Rest gelassen. */
.projekt-liste {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

/* Herkunft ("Extern", "Archiviert") - ein ruhiger Hinweis, kein Alarm. Deshalb ohne
   farbigen Grund: Er sagt, WOHER der Eintrag kommt, nicht dass etwas zu tun ist. */
.projekt-herkunft {
    font-size: .78rem;
    color: var(--bs-secondary-color, #6c757d);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 2rem;
    padding: .1rem .5rem;
}

/* ⚠️ Eine Einladung ist eine AUFFORDERUNG, kein Projekt - sie bekommt deshalb einen
   farbigen linken Rand. Ohne den saehe sie in der Liste aus wie ein weiterer Eintrag, den
   man auch spaeter ansehen kann. */
.projekt-karte-einladung {
    border-left: 4px solid var(--bs-primary, #0d6efd);
}

.projekt-marke-einladung {
    background-color: rgba(13, 110, 253, .12);
    color: #0a58ca;
}

/* ⚠️ Die Knoepfe stehen IN der Karte und muessen ueber dem stretched-link liegen - sonst
   faengt der Link den Klick ab und oeffnet ein Projekt, statt die Einladung zu beantworten.
   Bei Einladungskarten gibt es zwar keinen stretched-link, aber die Regel gilt auch, wenn
   spaeter einer dazukommt. */
.projekt-einladung-aktionen {
    position: relative;
    z-index: 2;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .75rem;
}

.projekt-einladung-aktionen > .btn {
    flex: 1 1 auto;
}

/* Die letzte Aktivitaet auf der Projektkarte ("vor 2 Tagen").

   ⚠️ Ruhig gehalten, obwohl sie zu den Zustandsangaben gehoert: Sie sagt, WANN zuletzt etwas
   geschah, nicht dass jemand handeln muss. Der Wartestatus daneben tut das - bekaeme die
   Zeitangabe dieselbe Farbe, waeren beide gleich laut und keiner mehr auffaellig. */
.projekt-aktiv {
    font-size: .8rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* ⚠️ "Noch keine Aktivitaet" ist ein Befund, kein Fehler - deshalb kursiv statt rot. Ein
   frisch angelegtes Projekt hat berechtigterweise keine, und wer es rot einfaerbt, macht
   aus jedem Erststart eine Warnung. */
.projekt-aktiv-nie {
    font-style: italic;
    opacity: .8;
}

/* Ungelesene Nachrichten auf der Projektkarte ("3 neu").

   ⚠️ Als EINZIGE Angabe der Zustandszeile gefuellt statt nur getoent: Sie ist das einzige
   dort, was jemand jetzt tun soll. Waertestatus, Frist und letzte Aktivitaet beschreiben nur.
   Bekaemen alle dieselbe Aufmerksamkeit, haette keine mehr welche.

   ⚠️ Die Farbe traegt die Aussage nicht allein - die ZAHL steht daneben. Wer Farben schlecht
   unterscheidet, liest "3 neu" und weiss genug. */
.projekt-marke-ungelesen {
    background-color: var(--bs-primary, #0d6efd);
    color: #fff;
    font-weight: 600;
}

/* Das Eingabefeld klebt am unteren Rand, solange man im Nachrichtenbereich ist.

   Wunsch des CEO (28.08.2026): "das mit dem Scrollen ist laestig. Kann man das fuers Handy
   oder Ipad machen, dass eine neue Nachricht schreiben unten gebunden ist, so wie bei
   WhatsApp". Der Weg zum Feld ging bisher ueber die halbe Seite: Zurueck-Knopf, Ueberschrift,
   Hinweistext, dann erst die Liste und darunter das Feld.

   ⚠️ STICKY UND NICHT FIXED - UND DAS IST DIE ANTWORT AUF DIE FUSSZEILEN-FRAGE.

   Ein fest positionierter Balken wie bei WhatsApp belegt den unteren Bildschirmrand dauerhaft
   und verdeckt die Fusszeile. Dort steht die Kuendigungsschaltflaeche nach § 312k BGB, die
   "staendig verfuegbar, unmittelbar und leicht zugaenglich" sein muss - so steht es als
   Begruendung im Layout selbst. Ob ein Balken darueber diese Anforderung verletzt, ist eine
   Rechtsfrage und keine Gestaltungsentscheidung.

   sticky loest das, ohne sie zu stellen: Das Feld klebt unten, solange der Nachrichtenbereich
   im Bild ist, und wandert mit weg, sobald man darueber hinausscrollt. Die Fusszeile ist einen
   Wisch entfernt und wird nie verdeckt.

   ⚠️ Der eigene Hintergrund ist Pflicht, nicht Zierde: Ohne ihn scrollen die
   Nachrichtenblasen sichtbar unter dem Feld durch.

   ⚠️ safe-area-inset-bottom: Auf iPhones ohne Knopf liegt unten die Home-Leiste. Ohne den
   Abstand sitzt der Senden-Knopf darunter und ist schwer zu treffen. max() statt des blossen
   Wertes, damit auf Geraeten ohne Home-Leiste der normale Abstand bleibt.

   Nur bis 767 px: Am Rechner ist der Weg zum Feld kurz, und ein klebender Balken naehme dort
   nur Platz weg. */
@media (max-width: 767.98px) {
    .chat-composer {
        position: sticky;
        bottom: 0;
        z-index: 3;
        margin-bottom: 0;
        padding-top: .5rem;
        padding-bottom: max(.5rem, env(safe-area-inset-bottom, .5rem));
        background-color: var(--bs-body-bg, #fff);
        border-top: 1px solid var(--bs-border-color, #dee2e6);
    }
}
