/**
 * PKVbuddy App-Komponenten-Layer
 *
 * Frischer Komponenten-Layer aus dem Design-System-UI-Kit
 * (docs/design-system/ui_kits/dashboard/kit.css), adaptiert für die
 * bestehende Bootstrap-App. Nur im App-Bereich geladen (base.html), nicht Landing.
 *
 * Bewusst KEINE nackte .badge-Redefinition (würde Bootstrap app-weit clobbern) —
 * Status-Tags sind selbst-enthaltend (Layout + Farbe je Modifier).
 */

/* ============== APP-TYPOGRAFIE ============== */
/* App-UI nutzt Manrope; Landing (base_public) bleibt DM Sans. */
body {
  font-family: var(--font-app);
}

/* ============== APP-BUTTONS ============== */
.app-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 16px; border-radius: var(--radius-pill);
  font-family: inherit; font-weight: 600; font-size: var(--fs-13);
  border: 2px solid transparent; cursor: pointer; text-decoration: none;
  white-space: nowrap; /* U-14: Button-Label bricht nie um */
  transition: all var(--dur-base) var(--ease-out);
}
/* Weiß auf Türkis heißt --accent-dark (siehe tokens.css): --accent trägt nur
   3,32:1, AA verlangt 4,5. Der Ton MUSS derselbe sein wie bei .btn-primary in
   cappuccino.css — beide Knöpfe stehen auf 26 Bildschirmen nebeneinander, und
   zwei verschiedene Türkis für dieselbe Rolle wären schlimmer als der Fehler,
   den sie beheben. Hover ohne Hebung, aus demselben Grund wie dort
   (BUG-0266). */
.app-btn-primary { background: var(--accent-dark); color: white; }
.app-btn-primary:hover { background: var(--accent-deep); color: white; }
/* Audit B4C/A5-09: Rahmen über --control-border (3:1, SC 1.4.11) statt
   --stone-200 (1,34:1) — Hover dunkelt weiter ab statt aufzuhellen. */
.app-btn-outline { border-color: var(--control-border); background: white; color: var(--stone-600); }
.app-btn-outline:hover { border-color: var(--stone-600); color: var(--espresso); background: var(--stone-100); }
.app-btn-espresso { background: var(--espresso-light); color: white; }
.app-btn-espresso:hover { background: var(--espresso); color: white; }
.app-btn-sm { padding: 5px 12px; font-size: var(--fs-12); }
/* Klassen-Variante .app-btn.is-disabled abgebaut (Grep: 0 Konsumenten) —
   deaktiviert wird ausschließlich über das disabled-Attribut. */
/* Audit B4/UX5-19: Deaktiviert = Akzentfarbe abgeschwächt (statt des
   verwandtschaftslosen Literals #9FC8C1) — der Zustand folgt damit jeder
   Akzentänderung. 0.55 entspricht optisch dem bisherigen Ton. */
.app-btn:disabled {
  background: var(--accent-dark); color: white; opacity: 0.55; cursor: not-allowed;
  box-shadow: none; pointer-events: none; border-color: transparent;
}

/* ============== STATUS-TAGS (Belegstatus) ============== */
/* Flach, 6px, icon-first — ein Tag, nie ein Button. Selbst-enthaltend. */
/* .badge-storniert abgebaut (Grep: 0 Konsumenten in Templates, Python und JS;
   dashboard/services.py liefert für „storniert" nie eine css_class). */
/* Audit B4/UX5-04: EINE Geometrie für beide Etiketten-Systeme — die
   .badge.status-*-Selektoren (semantische Status-Badges, Farbzuordnung in
   app.css) teilen sich Polsterung, Rundung und Schrift mit den
   .badge-*-Klassen. Der frühere wertgleiche Geometrie-Block in app.css
   ist gestrichen. Das font-weight zieht hier NICHT für
   .badge.status-neutral mit (BUG-0390): Diese Klasse ist die einzige aus der Liste mit Konsumenten
   im öffentlichen Bereich, der Wert lebt deshalb nur noch in
   cappuccino.css statt an zwei Stellen. */
.badge-offen, .badge-eingereicht, .badge-teilw,
.badge-selbstbehalt, .badge-erstattet, .badge-abgelehnt,
.badge.status-open, .badge.status-pending, .badge.status-success,
.badge.status-neutral, .badge.status-error {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: var(--radius-xs);
  font-size: var(--fs-12); line-height: 1;
  white-space: nowrap;
}
.badge-offen, .badge-eingereicht, .badge-teilw,
.badge-selbstbehalt, .badge-erstattet, .badge-abgelehnt,
.badge.status-open, .badge.status-pending, .badge.status-success,
.badge.status-error {
  font-weight: 600;
}
.badge-offen i, .badge-eingereicht i, .badge-teilw i,
.badge-selbstbehalt i, .badge-erstattet i, .badge-abgelehnt i,
.badge-offen svg, .badge-eingereicht svg, .badge-teilw svg,
.badge-selbstbehalt svg, .badge-erstattet svg, .badge-abgelehnt svg,
.badge.status-open svg, .badge.status-pending svg, .badge.status-success svg,
.badge.status-neutral svg, .badge.status-error svg {
  width: var(--icon-xs); height: var(--icon-xs); font-size: var(--fs-12); flex: none;
}
/* Farbwerte aus den --status-*-Tokens (tokens.css) — dieselbe Quelle wie
   .badge.status-* in app.css (FEATURE-0134 AC-17, Entscheidung A).
   Audit B4C/UX5-02 (auf-pending): auch badge-teilw nutzt status-pending —
   die frühere Ausnahme (accent-muted/accent-dark, „kein Status-Token")
   widersprach frontend-design.md §6 (status-pending = Teil-Erfolg) und den
   drei anderen Listen (core/models.py, reimbursements/models.py liefern
   für denselben Sachverhalt status-pending). Türkis bleibt der
   Handlungsfarbe vorbehalten. */
.badge-offen       { background: var(--status-open-bg);    color: var(--status-open-fg); }
.badge-eingereicht { background: var(--status-pending-bg); color: var(--status-pending-fg); }
.badge-teilw       { background: var(--status-pending-bg); color: var(--status-pending-fg); }
/* FEATURE-0156: Selbstbehalt ist neutral, nicht rot. Der Kostentraeger hat
   abgerechnet und verrechnet — es gibt nichts zu bestreiten, und ein rotes
   Etikett haette genau dazu eingeladen. */
.badge-selbstbehalt { background: var(--status-neutral-bg); color: var(--status-neutral-fg); }
.badge-erstattet   { background: var(--status-success-bg); color: var(--status-success-fg); }
.badge-abgelehnt   { background: var(--status-error-bg);   color: var(--status-error-fg); }

/* ============== ZAHLUNGS-ACHSE (Mitglied bezahlt?) ============== */
/* Eigene Achse, getrennt vom Lifecycle-Status. Punkt in Listen, Tag im Detail. */
.pay-dot { width: 10px; height: 10px; border-radius: var(--radius-full); display: inline-block; flex: none; }
/* .pay-dot.beglichen/.offen/.teilweise entfernt (Audit B4GL Gruppe 6):
   Der Zahlungspunkt zeigt seit B4 receipts SVG-Formen statt eingefaerbter
   Kreise (_pay_dot_symbol.html, .pay-dot-symbol--*). Die drei
   Farbmodifikatoren hatten danach keinen Verwender mehr. */

/* BUG-0027: Form UND Farbe. A5-18 hatte die Farbe ganz aus der Zahlungsachse
   genommen, weil sie mit der Erstattungsskala verwechselbar war (A7-15) — die
   Form allein liess die drei Zustände aber erst beim genauen Hinsehen
   auseinanderhalten. Jetzt tragen sie beides: die Form bleibt der
   barrierefreie Träger (sie funktioniert in Graustufen und bei Farbenblindheit
   und wird von einem versteckten Statustext begleitet), die Farbe macht den
   Zustand auf einen Blick lesbar.

   Gesetzt wird `color`, nicht `fill`: das Symbol zeichnet mit currentColor und
   bleibt damit in einem anderen Umfeld überschreibbar, ohne dass dort eine
   zweite Punktkomponente entstehen muss. */
/* BUG-0045: `.pay-state--*` ist derselbe Zustand an einem TEXT-Container.
   Bewusst in denselben Regeln und nicht als zweiter Block: Punkt und
   Beschriftung müssen dieselbe Farbe tragen, und zwei Deklarationen laufen
   auseinander, sobald jemand nur eine anfasst. Genau das war der Zustand
   davor — `.money-hero.is-open .money-hero-status-icon` färbte den Punkt,
   eine zweite Regel daneben die Schrift. Das SVG erbt die Farbe hier ohnehin
   über `currentColor`; die Doppelung schadet nicht und hält die Komponente
   auch dort lesbar, wo sie ohne Textwrapper steht (Legenden, Belegliste). */
.pay-dot-symbol--beglichen, .pay-state--beglichen { color: var(--success); }
.pay-dot-symbol--teilweise, .pay-state--teilweise { color: var(--warning); }
.pay-dot-symbol--offen,     .pay-state--offen     { color: var(--danger); }

/* ============== KOSTENTRAEGER-BADGE (vereinheitlicht ueber payer_badge Tag) ============== */
/* Ein Component, drei Varianten, Farbe ausschliesslich aus den --payer-Tokens
   (app.css). Ersetzt die frueheren Payer-Pill-, Payer-Badge- und Text-Payer-
   Klassen (siehe tasks/CONCEPT-payer-badge-vereinheitlichung.md) - nur noch
   ueber das payer_badge Template-Tag nutzen, nicht direkt. */
.payer-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-weight: 600;
}
.payer-badge i, .payer-badge svg { width: var(--icon-sm); height: var(--icon-sm); font-size: var(--fs-14); flex: none; }

/* Variante: pill (Outline, Default) — heutiges .payer-pill */
.payer-badge--pill {
  padding: 3.5px 10px; border-radius: 8px;
  font-size: var(--fs-13);
  background: white; border: 1.5px solid;
}
.payer-badge--pill.beihilfe { border-color: var(--payer-beihilfe); color: var(--payer-beihilfe); }
.payer-badge--pill.pkv      { border-color: var(--payer-pkv);      color: var(--payer-pkv); }
.payer-badge--pill.bee      { border-color: var(--payer-bee);      color: var(--payer-bee); }
.payer-badge--pill.zusatz   { border-color: var(--payer-zusatz);   color: var(--payer-zusatz); }

/* Variante: icon (BUG-0039) — nur das Symbol in quadratischer beiger Fläche.
   Bewusst OHNE die typabhängigen --payer-Farben: Wo diese Kurzform steht,
   ist der Kostenträgername ausgeschrieben daneben; die Farbe müsste die
   Unterscheidung also nicht allein tragen. Eine gemeinsame ruhige Fläche
   bringt die Zeilen stattdessen auf dieselbe Kante wie die Belegliste.
   Größe, Radius und Fläche folgen deren Belegtyp-Icon (--icon-shell-bg). */
.payer-badge--icon {
  width: 26px; height: 26px; flex: none;
  justify-content: center;
  border-radius: 7px;
  background: var(--icon-shell-bg);
  color: var(--espresso-light);
}

/* Variante: text (nur farbiger Text, kein Rahmen/Hintergrund) — heutiges .text-payer-* */
.payer-badge--text { font-weight: inherit; }
.payer-badge--text.beihilfe { color: var(--payer-beihilfe); }
.payer-badge--text.pkv      { color: var(--payer-pkv); }
.payer-badge--text.bee      { color: var(--payer-bee); }
.payer-badge--text.zusatz   { color: var(--payer-zusatz); }

/* ============== TOGGLE-SWITCH ============== */
.toggle { display: inline-flex; align-items: center; gap: 11px; cursor: pointer; user-select: none; margin: 0; }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track { width: 40px; height: 23px; border-radius: var(--radius-full); background: var(--tasse-muted); position: relative; transition: background var(--dur-base) var(--ease-out); flex: none; }
.toggle .track::after { content: ''; position: absolute; top: 3px; left: 3px; width: 17px; height: 17px; border-radius: var(--radius-full); background: white; box-shadow: 0 1px 3px rgba(61,43,31,.22); transition: transform var(--dur-base) var(--ease-out); }
.toggle input:checked + .track { background: var(--accent); }
.toggle input:checked + .track::after { transform: translateX(17px); }
.toggle input:focus-visible + .track { box-shadow: 0 0 0 3px rgba(42,157,143,0.25); }
.toggle .t-label { font-size: var(--fs-14); font-weight: 500; color: var(--stone-600); }

/* ============== BELEGE-TABS (Belege / Dokumente) ============== */
.bl-tabstrip { display: flex; align-items: flex-end; justify-content: space-between; border-bottom: 1px solid var(--stone-200); margin-bottom: 18px; }
.bl-tabs { display: flex; gap: 6px; }
.bl-tab { padding: 10px 8px 12px; font-size: var(--fs-14); font-weight: 500; color: var(--stone-500); border-bottom: 2px solid transparent; margin-bottom: -1px; cursor: pointer; text-decoration: none; transition: color var(--dur-fast) var(--ease-out); }
.bl-tab:hover { color: var(--espresso); }
.bl-tab.is-active { font-weight: 700; color: var(--espresso); border-bottom-color: var(--accent); }
/* .bl-tab-count abgebaut (Audit B4/UX4-11+UX6-08, Grep: 0 Konsumenten). */
.bl-tabstrip-right { display: flex; align-items: center; }
/* U-16: mobil sitzt der "Neu"-Button sonst direkt auf der Tab-Unterkante */
@media (max-width: 767.98px) {
  .bl-tabstrip-right { margin-bottom: 10px; }
}

/* ============== LISTEN-OBERFLÄCHE (geteilt von allen Listen-Tabellen) ============== */
.list-surface {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
/* Mobile: Liste randlos & ohne Schatten (Belege-Redesign-Vorlage).
   Full-Bleed über negative Außenabstände statt width:100vw + transform:
   ein transform macht das Element zum Containing-Block für alle
   fixed-positionierten Nachfahren und hängte so die mobile Status-Legende
   vom Viewport ab (Audit B2/A4-04). Geometrie ist identisch. */
@media (max-width: 991.98px) {
  .list-surface {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
  }
}

/* Listen scrollen horizontal, nie vertikal. Bootstraps .table-responsive setzt
   nur overflow-x; die Overflow-Spec rechnet ein danebenstehendes
   overflow-y: visible zwangsweise auf auto hoch, womit jede Listen-Tabelle
   einen vertikalen Scroll-Kontext bekommt, den niemand bestellt hat. Die
   Tabellenhöhe ist fraktional, clientHeight rundet ab und scrollHeight auf —
   dieses eine Pixel Differenz genügt für eine Leiste, die nichts bewegt und
   Breite kostet. Gemessen 13.08.2026: Belege und Einreichungen je 1px, kein
   überstehendes Element, kein horizontaler Scroll. Die Höhe der Liste trägt
   immer der Seiten-Scroll, ohne Ausnahme: ein eigener .table-container
   der Gebührenziffern öffnete genau so einen zweiten Scroll-Kontext, in dem
   der haftende Tabellenkopf mitten in der Tabelle klebte. Einen haftenden
   Tabellenkopf gibt es deshalb nicht. */
.table-responsive { overflow-y: hidden; }

/* Toolbar über der Tabelle (Bulk-Select, Toggle, Submit) */
.belege-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 14px 16px; border-bottom: 1px solid var(--hairline-soft);
}
.belege-toolbar-left { display: flex; align-items: center; gap: 9px; }
.belege-toolbar-right { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.belege-selectall { display: inline-flex; align-items: center; gap: 9px; font-size: var(--fs-13); font-weight: 600; color: var(--stone-600); cursor: pointer; margin: 0; }

/* BUG-0238: Zeile über der mobilen Kartenliste mit dem "Auswählen"-Knopf.
   Eigene Klasse statt .belege-toolbar-Innenraum, weil sie — anders als die
   Toolbar — auch im Normalzustand (Modus aus) sichtbar ist. */
.bl-select-toggle-row { padding: 12px 16px 0; }

/* Tabelle: design-konformes Re-Styling der bestehenden <table>.
   Geteilt von allen Listen-Tabellen. Desktop-Interna in ZWEI Blöcken mit
   identischem Regelsatz (bei Änderungen beide pflegen!):
   1. ab 992px für alle Listen-Tabellen — unterhalb stapelt .list-card als
      Karte (A4-02: Tablet gilt als Mobil, Kartenschwelle = 991,98px wie
      mobiler Seitenkopf und randlose .list-surface).
   2. 769–991,98px nur für Tabellen OHNE Karten-Stacking (:not(.list-card),
      die .form-rows-Konsumenten der Settings-/Dashboard-Flächen) — deren
      mobiles Stacking greift weiterhin erst ≤768px.
   Klickbare Zeilen tragen data-href oder onclick (Hover + Cursor); die
   frühere Marker-Klasse .list-table-hover-row ist abgebaut
   (Audit B4/UX4-11+UX6-08, Grep: 0 Konsumenten). */
.list-table { width: 100%; border-collapse: collapse; margin: 0; }
@media (min-width: 992px) {
  .list-table thead th {
    text-align: left; padding: 10px 16px;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--stone-500);
    background: var(--stone-100); border-bottom: 1px solid var(--stone-200);
    white-space: nowrap;
  }
  .list-table thead th.text-end { text-align: right; }
  .list-table thead th.text-center { text-align: center; }
  /* `th` mit: Summenzeilen im tbody (tr.stmt-subtotal, tr.rcpt-subtotal)
     tragen ihre Beschriftung als Zeilenkopf. Nur `td` zu polstern liess die
     Personensumme der Abrechnung am linken Rand kleben, während „Gesamt" im
     tfoot (eigene Regel für th UND td) eingerückt stand (BUG-0032-012).
     Rahmen und Hover bleiben bewusst bei `td`: die Gruppenzeile
     (tr.stmt-group > th) setzt ihre Oberlinie selbst. */
  .list-table tbody td,
  .list-table tbody th {
    padding: 12px 16px;
    font-size: var(--fs-13); color: var(--stone-600);
    border-top: 1px solid var(--hairline-row); vertical-align: middle;
  }
  .list-table tbody tr { transition: background var(--dur-fast) var(--ease-out); }
  /* Hover nur auf klickbaren Zeilen — dort ist er das Affordance-Signal.
     Auf reinen Daten-Tabellen (Beiträge, Positionen) ist er reine Deko und
     entfällt. */
  .list-table tbody tr[data-href]:hover td,
  .list-table tbody tr[onclick]:hover td { background: var(--stone-100); }
  .list-table tbody tr:first-child td { border-top: 0; }
  .list-table tbody tr[data-href], .list-table tbody tr[onclick] { cursor: pointer; }
}
/* Block 2 — Kopie von Block 1, gescoped auf Tabellen ohne Karten-Stacking. */
@media (min-width: 768px) and (max-width: 991.98px) {
  .list-table:not(.list-card) thead th {
    text-align: left; padding: 10px 16px;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--stone-500);
    background: var(--stone-100); border-bottom: 1px solid var(--stone-200);
    white-space: nowrap;
  }
  .list-table:not(.list-card) thead th.text-end { text-align: right; }
  .list-table:not(.list-card) thead th.text-center { text-align: center; }
  .list-table:not(.list-card) tbody td,
  .list-table:not(.list-card) tbody th {
    padding: 12px 16px;
    font-size: var(--fs-13); color: var(--stone-600);
    border-top: 1px solid var(--hairline-row); vertical-align: middle;
  }
  .list-table:not(.list-card) tbody tr { transition: background var(--dur-fast) var(--ease-out); }
  .list-table:not(.list-card) tbody tr[data-href]:hover td,
  .list-table:not(.list-card) tbody tr[onclick]:hover td { background: var(--stone-100); }
  .list-table:not(.list-card) tbody tr:first-child td { border-top: 0; }
  .list-table:not(.list-card) tbody tr[data-href],
  .list-table:not(.list-card) tbody tr[onclick] { cursor: pointer; }
}

/* Zeilen-Link: trägt in Listen ohne Aktions-Spalte den Tastatur-Zugang zur
   Detailseite. Optisch unauffällig — das Klick-Affordance ist die ganze Zeile,
   ein unterstrichener Link in einer Zelle liest sonst wie ein Sonderziel. */
.list-table td .list-row-link { color: inherit; text-decoration: none; }
.list-table td .list-row-link:hover { text-decoration: underline; }

/* Zell-Bausteine */
.bl-date { font-size: var(--fs-13); font-weight: 500; color: var(--stone-600); white-space: nowrap; }
.bl-member { font-size: var(--fs-13); font-weight: 500; color: var(--stone-500); }
/* .bl-insurer abgebaut (Audit B4/UX4-11+UX6-08, Grep: 0 Konsumenten). */

/* Aussteller: Typ-Icon (+ Doc-Overlay) + Name */
.bl-issuer { display: flex; align-items: center; gap: 9px; min-width: 0; }
.bl-type { position: relative; display: inline-flex; flex: none; color: var(--espresso-light); }
.bl-type svg, .bl-type i { width: var(--icon-md); height: var(--icon-md); font-size: var(--fs-16); }
.bl-docs {
  position: absolute; top: -6px; right: -7px;
  min-width: 14px; height: 14px; padding: 0 3px;
  border-radius: var(--radius-full); background: #F1ECE5; border: 1px solid #DBCFBC;
  color: var(--stone-500); font-size: var(--fs-11); font-weight: 700;
  display: flex; align-items: center; justify-content: center; box-sizing: border-box;
}
.bl-name { font-size: var(--fs-13); font-weight: 600; color: var(--espresso); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Aussteller als Link — in den Todo-Queues der Tastatur-Zugang zur Detailseite,
   seit die Aktions-Spalte dort entfallen ist. Liest wie Text. */
.bl-name-link { color: var(--espresso); text-decoration: none; }
/* BUG-0034/BUG-0028: KEINE Hover-Unterstreichung mehr. Die Zeile hinterlegt
   sich beim Ueberfahren bereits — eine zweite Rueckmeldung fuer dieselbe Geste
   sagt nichts Neues. Und weil iOS `:hover` nach einer Beruehrung teilweise
   dauerhaft emuliert, blieb der Aussteller dort unterstrichen stehen; was es
   nicht gibt, kann nicht einrasten.

   Der Tastaturfokus steht bewusst allein und behaelt die Unterstreichung: er
   darf nicht nur an der Farbe erkennbar sein. Vorher teilten sich beide eine
   Regel — genau deshalb haette das Entfernen der einen die andere
   mitgenommen. */
.bl-name-link:focus-visible { text-decoration: underline; }
/* Dateiname in der Dokument-Queue (Todo): Icon + Link, der wie Text liest — der
   Link trägt den Weg zur Erfassung, weil der Erfassen-Button mobil ausgeblendet
   ist. Der Wrapper hält Icon und Name nebeneinander (Desktop); mobil löst ihn
   .list-card--queue auf, damit das Datum unter dem Namen bündig startet. */
.queue-file { display: flex; align-items: flex-start; gap: 8px; min-width: 0; }
.queue-name { font-size: var(--fs-13); font-weight: 600; color: var(--espresso); text-decoration: none; }
.queue-name:hover, .queue-name:focus-visible { text-decoration: underline; }
/* R-26c: erste .bl-issuer-note-Definition entfernt — die spätere Regel in der
   Belege-Redesign-Sektion gewinnt bei gleicher Spezifität (war wirkungslos). */

/* Betrag: Zahlungs-Punkt + Betrag, rechtsbündig */
.bl-amount { display: flex; align-items: center; justify-content: flex-end; gap: 7px; }
.bl-amount .amt { font-size: var(--fs-13); font-weight: 700; color: var(--espresso); white-space: nowrap; }
.bl-amount .pay-dot { cursor: pointer; }

/* A5-02: Beleg-Verlauf-Auslöser sind echte Buttons — neutral rendern, damit
   sie exakt wie die früheren spans aussehen. width:100% für .bl-amount, weil
   Buttons als Flex-Container auf Inhaltsbreite schrumpfen, der span aber die
   Zelle füllte (rechtsbündig via justify-content). */
button.bl-amount, button.erst-cell { border: 0; background: transparent; padding: 0; font: inherit; color: inherit; text-align: inherit; }
button.bl-amount { width: 100%; }

/* A5-02 also_fixed: Beitragszellen-Trigger (contributions.html) als Button —
   füllt die Zelle, damit die Klickfläche der des früheren klickbaren td entspricht. */
.contrib-cell-btn { border: 0; background: transparent; padding: 0; font: inherit; color: inherit; text-align: inherit; width: 100%; display: inline-block; }

/* Auswahl-Spaltenbreite (statt Inline-Style) */
.bl-col-check { width: 44px; }

/* Leistungsjahr-Chip am Belegdatum (FEATURE-0110) */
.bl-year {
  display: inline-flex; align-items: center;
  margin-left: 6px; padding: 1px 7px; border-radius: var(--radius-full);
  font-size: var(--fs-11); font-weight: 600;
  background: var(--stone-100); color: var(--stone-500);
}

/* Leere Liste */
.list-empty { padding: 40px 20px; text-align: center; color: var(--stone-500); }
.list-empty a { font-weight: 600; }

/* Klickbarkeits-Hinweis (statt Inline cursor) */
.is-clickable { cursor: pointer; }

/* ============== FILTER (Suche + Filter) — global ============== */
/* Design-Surface + Form-Felder nach Design-System (form-fields.html).
   Container: .filter-card; Felder: global auf .filter-form (alle Listen). */
.filter-card {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-flat);
  overflow: hidden;
}
.filter-card-body { padding: 22px; }
.filter-card-mobilehead { padding: 6px 10px; border-bottom: 1px solid var(--hairline); }
.filter-card-toggle {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  background: none; border: 0; padding: 8px 6px; cursor: pointer;
  font-family: inherit; font-size: var(--fs-14); font-weight: 600; color: var(--espresso);
}
/* BUG-0026: Beschriftung + Zähler der angewendeten Filter. Der Zähler steht im
   eingeklappten Kopf, weil dort sonst nichts verrät, dass die Liste gefiltert
   ist — mobil ist der eingeklappte Zustand der Normalfall, nicht die Ausnahme. */
.filter-card-toggle-label { display: inline-flex; align-items: center; gap: 8px; }
.filter-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--accent); color: white;
  font-size: var(--fs-11); font-weight: 700; line-height: 1;
}

/* BUG-0026: „Zurücksetzen" ist ein Button im Textlink-Stil — semantisch eine
   Aktion auf dieser Seite, optisch kein Wettbewerber zu „Filter anwenden".
   Die 44px-Hitbox kommt wie bei .app-btn-sm aus einem Pseudo-Element. */
.filter-reset {
  position: relative;
  background: none; border: 0; padding: 0;
  font-family: inherit; font-size: var(--fs-13); font-weight: 600;
  color: var(--text-secondary); text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer;
}
.filter-reset:hover { color: var(--espresso); }
.filter-reset::after {
  content: ''; position: absolute; left: 0; right: 0;
  top: 50%; height: 44px; transform: translateY(-50%);
}

/* BUG-0026: Ladeindikator der Ergebnisliste (includes/_list_loading.html).
   Er liegt zwischen Filterkarte und Liste statt im Filterpanel: mobil ist das
   Panel während des Requests längst zugeklappt und ein Spinner darin
   unsichtbar.

   BUG-0221: Die Fläche hat keine Höhe, auch während des Requests nicht. Vorher
   klappte sie dort als Zeile mit 22px Innenabstand auf und schob die Liste bei
   jeder Tipp-Pause um 76px nach unten und nach der Antwort wieder hoch.
   Jetzt ragt der Spinner über den Anfang der Liste — an dieselbe Stelle, an
   der er vorher stand, 22px unter der Kante — und die Liste tritt zurück,
   statt auszuweichen. Die Stelle im Dokument bleibt, deshalb gilt die
   BUG-0026-Zusage weiter: mobil steht der Indikator am Listenanfang. */
.filter-loading {
  display: none; justify-content: center;
  position: relative; z-index: 1; height: 0;
  color: var(--text-secondary);
}
.filter-loading.htmx-request { display: flex; }
/* Eigener Grund, weil der Ring sonst über den Spaltenköpfen der Liste steht. */
.filter-loading > .spinner-border {
  flex: none; margin-top: 22px;
  background: white; box-shadow: var(--shadow-md);
}
/* Dieselbe Deckkraft wie der Beschäftigt-Zustand des Steppers (B23). Der
   Geschwister-Selektor statt `+`, weil in der Belegliste die Live-Region
   `#list-live-status` zwischen Indikator und Liste steht. */
.filter-loading ~ #list-container {
  transition: opacity var(--dur-base) var(--ease-out);
}
.filter-loading.htmx-request ~ #list-container { opacity: 0.55; }
@media (prefers-reduced-motion: reduce) {
  .filter-loading ~ #list-container { transition: none; }
}

/* Der Feld-Layer (.filter-form/.app-form: Label, Eingabefeld, Auswahlfeld,
   Chevron) lebt seit FEATURE-0145 in cappuccino.css, Abschnitt
   „FORMULAR-FELDER". Grund: base_public.html laedt dieses Blatt nicht, die
   Auth-Seiten standen deshalb auf Bootstrap-Defaults. cappuccino.css laden
   beide Grundgeruste. Hier bleibt nur, was es ausserhalb der App nicht gibt. */

/* Suchfeld: Lupe links, Such-Input mit Platz dafür — bleibt hier, weil
   .filter-form ausschliesslich auf der App-Flaeche vorkommt. */
.filter-form input[type="search"] {
  padding-left: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237A7068' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: left 14px center;
}
/* Such-Clear-Button (X) farblich ins Design holen */
.filter-form input[type="search"] + button { color: var(--text-secondary); }
.filter-form input[type="search"] + button:hover { color: var(--espresso); }

/* ===== Touchziele (Audit B4C/A4-06) ===== */
/* Die Groesse der Auswahlkaestchen (20×20, Switch 36×20) steht seit
   FEATURE-0145 in cappuccino.css neben der ::after-Hitbox derselben Regel —
   die Hitbox rechnet mit genau diesen 20px, getrennte Blaetter machten das
   unlesbar. */

/* Text-Aktionen (Löschen-Link, Zeilen-Aktionen, kleine Buttons): 44px-Hitbox
   über ein unsichtbares Pseudo-Element — nur vertikal, eine horizontale
   Ausdehnung würde mit den 6–7px entfernten Nachbar-Bedienelementen
   kollidieren (deshalb tragen die Symbolknopf-Container jetzt 10px gap). */
.delete-link, .link-row-action, .app-btn-sm, .app-link-action { position: relative; }
.delete-link::after, .link-row-action::after, .app-btn-sm::after, .app-link-action::after {
  content: ''; position: absolute; left: 0; right: 0;
  top: 50%; height: 44px; transform: translateY(-50%);
}

/* ============== BELEGE-REDESIGN: Erstattung, Legende, Mobile ============== */

/* Notiz unter dem Aussteller (Desktop, Notizen-Toggle aktiv) */
.bl-issuer-note {
  display: flex; align-items: center; gap: 5px;
  font-size: var(--fs-12); font-weight: 400; color: var(--text-secondary);
  margin-top: 2px; min-width: 0;
}
.bl-issuer-note-icon { opacity: .7; flex: none; }
.bl-issuer-note span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Erstattungs-Zelle: klickbar (Timeline) */
.erst-cell { display: inline-flex; align-items: center; }

/* Split-Pille je Kostenträger (abweichende Status) */
.erst-split {
  display: inline-flex; align-items: stretch;
  border-radius: var(--radius-full); overflow: hidden;
  border: 1px solid var(--control-border);
}
.erst-seg {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 9px; font-size: var(--fs-11); font-weight: 700; line-height: 1;
}
/* Audit B4GL/A3-17: war 11px — die Skala kennt 12 als kleinste Stufe. */
.erst-seg svg, .erst-seg i { width: var(--icon-xs); height: var(--icon-xs); font-size: var(--fs-11); flex: none; }
.erst-seg-payer { opacity: .6; }
/* BUG-0032-009 / BUG-0032-016: Im Einreichungsformular bleibt die gewählte
   Police über ihr ungedämpftes, kräftigeres Kürzel erkennbar. Eine eigene
   Segmentkontur würde den gemeinsamen Außenrahmen rechteckig unterbrechen. */
.erst-seg.is-current .erst-seg-payer { opacity: 1; font-weight: 800; }
.erst-seg.s-offen       { background: #FEF3C7; color: #92610A; }
.erst-seg.s-eingereicht { background: #CFF4FC; color: #055160; }
.erst-seg.s-teilw       { background: var(--accent-muted); color: var(--accent-dark); }
.erst-seg.s-selbstbehalt { background: var(--status-neutral-bg); color: var(--status-neutral-fg); }
.erst-seg.s-erstattet   { background: rgba(34, 197, 94, .16); color: #166534; }
.erst-seg.s-abgelehnt   { background: var(--danger-muted); color: #DC2626; }
/* BUG-0032-007: kein sechster Fortschrittston. „Nicht einreichbar"
   ist ein neutraler Randzustand und verwendet die bestehenden Status-Tokens. */
.erst-seg.s-nicht_einreichbar {
  background: var(--status-neutral-bg); color: var(--status-neutral-fg);
}

/* Status-Legende (geteilte Surface-Fußzeile: Belegliste .bl-legend,
   Beitragsmatrix .contrib-legend — nur .bl-legend wird mobil fixiert) */
/* Audit B4GL/UX1-16: Trefferzähler oberhalb der Liste. Er ist eine
   Beschriftung, kein Titel — deshalb die Meta-Textgröße und die
   Sekundärfarbe, die Zahl selbst in Espresso. Der Abstand nach unten
   entspricht dem Abstand der Legende zur Tabelle. */
.list-count {
  margin: 0 0 10px;
  font-size: var(--fs-13);
  font-weight: 500;
  color: var(--text-secondary);
}

.list-count strong {
  font-weight: 700;
  color: var(--espresso);
}

.bl-legend, .contrib-legend {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 11px 16px; background: var(--milk-pure);
  border-top: 1px solid var(--hairline-soft);
}
.bl-legend-label {
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-secondary);
}
.bl-legend-item { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-11); font-weight: 600; color: var(--stone-500); }
.bl-legend-dot { width: 7px; height: 7px; border-radius: var(--radius-full); flex: none; }
.bl-legend-dot.s-offen       { background: #D97706; }
.bl-legend-dot.s-eingereicht { background: #0DCAF0; }
.bl-legend-dot.s-teilw       { background: #2A9D8F; }
/* FEATURE-0156: sechste Stufe, neutral wie .erst-seg.s-selbstbehalt */
.bl-legend-dot.s-selbstbehalt { background: var(--status-neutral-fg); }
/* Audit B3/A8-10: Legende führt alle Stufen — Farbton wie .erst-seg.s-abgelehnt */
.bl-legend-dot.s-abgelehnt   { background: #DC2626; }
.bl-legend-dot.s-erstattet   { background: #22C55E; }

/* Die Belegliste rendert die Legende als Geschwister NACH der .list-surface
   (Audit B2/UX6-01) — Desktop dockt sie optisch als Fußzeile an die Fläche
   an (gemeinsamer Rahmen, Radius wandert von der Fläche auf die Legende). */
@media (min-width: 992px) {
  .list-surface + .bl-legend {
    border: 1px solid var(--hairline);
    border-top: 1px solid var(--hairline-soft);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  }
  .list-surface:has(+ .bl-legend) {
    border-bottom: 0;
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }
}

/* ---- Belege-Liste: belege-spezifische Mobile-Rules ----
   Das generische Zeilen-Stacking liegt jetzt in .list-card--belege (Tabellen-
   Kanon Etappe 1). Hier bleiben nur die belege-eigenen Extras. Schwelle =
   Kartenschwelle (A4-02): solange die Karten die Checkboxen ausblenden, ist
   die Toolbar (Auswahl/Einreichen/Notizen) funktionslos. */
@media (max-width: 991.98px) {
  /* Mobile: Auswahl/Einreichen/Notizen entfallen → ganze Toolbar aus.
     Normalzustand (BUG-0238: Auswahlmodus aus) — A4-02 bleibt hier
     unverändert gültig. */
  .belege-toolbar { display: none; }

  /* BUG-0238: Auswahlmodus mobil. Der
     Knopf "Auswählen" (receipts/_receipt_table.html) setzt die Klasse
     receipt-selection-mode auf <body> — er überlebt damit jeden HTMX-Swap
     von #list-container von selbst, ohne dass ein Handler ihn nach jedem
     Swap neu setzen müsste. Im aktiven Modus zeigt sich dieselbe Toolbar,
     die im Normalzustand ausgeblendet ist: links die vorhandene
     "Alle auswählen"-Checkbox, rechts der Sammelbutton — letzterer per JS
     (receipt_list.html) zusätzlich mit der Klasse .submit-mobile-bar
     versehen, die ihn (wie im Einreichungsformular) an den unteren
     Bildschirmrand dockt und dort automatisch den FAB-Freiraum und die
     Scanner-FAB-Ausblendung mitbringt (siehe .submit-mobile-bar unten) —
     keine zweite Leisten-Implementierung. Der Notizen-Toggle bleibt
     ausgeblendet: er wirkt auf Karten ohnehin nicht (.bl-issuer-note ist
     dort schon immer aus), im Auswahlmodus hätte er in der fixierten
     Leiste keinen sichtbaren Effekt. */
  body.receipt-selection-mode .belege-toolbar { display: flex; }
  body.receipt-selection-mode .belege-toolbar-right .toggle { display: none; }

  /* BUG-0027: Die Statusleiste entfällt mobil vollständig. Sie klebte fixiert
     am unteren Bildschirmrand — dauerhaft rund 40 px weniger Liste, für eine
     Erklärung, die man beim Lesen einer Zeile gerade nicht braucht, und in der
     die Stufen ohnehin nur horizontal scrollbar waren.

     Ersatzlos ist das nicht: die aufklappbare Erklärung darüber
     (.bl-legend-help) zeigt seit diesem Ticket dieselben Stufen mit ihrem
     echten Badge und jeden Zahlungszustand mit seinem echten Punkt. Zwei
     Erklärungen derselben Sache nebeneinander wären die Doppelung, die dieses
     Ticket auflöst. Am Desktop bleibt die Leiste unverändert. */
  .bl-legend { display: none; }
}

/* ============== VERSICHERUNGS-KONFIGURATION (ins-*) ============== */
/* Insurance-Settings-Redesign: Config-Historie (Hero + Kompakt), Einreichungs-
   Stepper, kompakte Personen-Zeilen. Die Mitgliederliste bleibt technisch eine
   <table> (Views injizieren <tr>-Fragmente per OOB-Swap) — der Zeilen-Look
   entsteht per Grid auf tr/td[data-cell], analog zum list-card-Pattern. */

/* Seitentitel: langes Kompositum darf auf schmalen Screens umbrechen */
.ins-page-title { hyphens: auto; overflow-wrap: break-word; min-width: 0; }

/* ---- Config-Karte (Surface wie .list-surface/.filter-card) ---- */
.ins-config {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-flat);
  overflow: hidden; margin-bottom: 14px;
}
.ins-config-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; padding: 14px 18px;
}
.ins-config-hero .ins-config-head { border-bottom: 1px solid var(--hairline-soft); }
.ins-config-headline { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 0; }
.ins-config-title { font-size: var(--fs-16); font-weight: 700; color: var(--espresso); margin: 0; }
.ins-config-compact .ins-config-title { font-size: var(--fs-14); font-weight: 600; }
.ins-config-current {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: var(--radius-full);
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  background: var(--accent-muted); color: var(--accent-dark);
}
/* Kurzform der Sätze im Kompaktkopf früherer Konfigurationen. FEATURE-0163
   Punkt 8: schlichter Text statt Pill — die Pill trug vorher eine Zählung
   ohne Informationswert. */
.ins-config-rates { font-size: var(--fs-12); color: var(--stone-500); }
/* Leer, solange die Karte keine Policen hat; die Fläche bleibt als OOB-Ziel stehen. */
.ins-config-rates:empty { display: none; }
.ins-config-actions { display: flex; align-items: center; gap: 10px; flex: none; }
/* Änderungsgrund im Kartenkopf, links neben dem Datum (BUG-0406). Er benennt
   die Konfiguration; lange Gründe brechen innerhalb der Kopfzeile um. */
.ins-config-reason {
  font-size: var(--fs-14); font-weight: 600; color: var(--espresso);
  min-width: 0; overflow-wrap: anywhere;
}
.ins-config-compact .ins-config-reason { font-size: var(--fs-13); }

/* Hinweis zur Satzsumme je Person (BUG-0409). Die Fläche steht immer da,
   Abstand tragen nur die Hinweise selbst — leer nimmt sie keinen Platz ein. */
.ins-rate-note {
  display: flex; align-items: flex-start; gap: 6px;
  font-size: var(--fs-13); color: var(--stone-600); margin: 0 0 14px;
}
.ins-rate-note svg { flex: none; margin-top: 2px; }
.ins-config-body { padding: 16px 18px 18px; }

/* Kompakt-Karte: einklappbarer Header (Chevron rotiert bei aria-expanded) */
.ins-config-toggle {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: inherit; text-align: left; color: var(--espresso);
}
.ins-config-toggle .ins-chevron { color: var(--stone-400); flex: none; transition: transform var(--dur-base) var(--ease-out); }
.ins-config-toggle[aria-expanded="true"] .ins-chevron { transform: rotate(180deg); }
.ins-config-compact .ins-config-body { border-top: 1px solid var(--hairline-soft); }

/* Abschnitts-Überschrift "Frühere Konfigurationen" */
.ins-history-heading {
  display: flex; align-items: center; gap: 7px;
  margin: 26px 0 12px;
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-secondary);
}

/* Overline "Einreichungs-Reihenfolge". Steht seit BUG-0406 als erstes Kind
   im Stepper (Swap-Fläche) und nur bei mehr als einem Kostenträger;
   flex-basis: 100% hält sie im Desktop-Reihenlayout über den Ketten, der
   negative Rand gleicht die Stepper-Lücke (12px) auf die bisherigen 10px aus. */
.ins-section-label {
  flex-basis: 100%;
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-secondary);
  margin-bottom: -2px;
}

/* ---- Einreichungs-Stepper ---- */
/* Eine .ins-chain = eine sequenzielle Kette (data-testid="policy-group").
   Parallele Ketten stehen auf Desktop nebeneinander, mobil untereinander. */
.ins-stepper { display: flex; flex-direction: column; gap: 12px; }
@media (min-width: 768px) {
  .ins-stepper { flex-direction: row; flex-wrap: wrap; align-items: flex-start; }
  .ins-chain { flex: 1 1 340px; min-width: 0; }
}
.ins-chain {
  background: var(--milk-pure); border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-lg); padding: 12px;
}
.ins-step { display: grid; grid-template-columns: 30px 1fr; gap: 10px; align-items: start; }
/* Einziger Kostenträger (BUG-0406): keine Schrittnummer, die Karte nimmt die
   ganze Breite. */
.ins-step.ins-step-single { display: block; }
.ins-step-num {
  width: 26px; height: 26px; margin-top: 12px;
  border-radius: var(--radius-full);
  background: var(--accent-muted); color: var(--accent-dark);
  font-size: var(--fs-13); font-weight: 700;
  display: inline-flex; align-items: center; justify-content: center;
  flex: none;
}
/* Textlabel gehört nur zur Mobil-Variante (Media-Block am Ende des Abschnitts) */
.ins-step-label { display: none; }
.ins-step-connector {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 0 8px 7px; color: var(--stone-500);
  font-size: var(--fs-12); font-weight: 600;
}
.ins-step-connector svg { flex: none; color: var(--stone-400); }

/* Erklärender Satz zur Parallel-Regel (BUG-0215/FT7-01): steht als Kind im
   selben Flex-Container wie die .ins-chain-Ketten — flex-basis: 100% erzwingt
   den Zeilenumbruch darunter, sonst würde er im Desktop-Reihenlayout als
   weitere Kachel neben den Ketten landen statt darunter zu stehen. */
.ins-order-note {
  flex-basis: 100%;
  margin: 2px 0 0;
  font-size: var(--fs-12);
  color: var(--stone-500);
}

/* ---- Beschäftigt-Zustand des Steppers (B23) ---- */
/* Jede Workflow-Änderung rendert die ganze Fläche neu und sperrt dafür alle
   Dropdowns darin. Ein gesperrtes Feld, das aussieht wie ein bedienbares, wäre
   nur die leisere Fassung des stillen Verlusts — deshalb ist die Sperre hier
   sichtbar: die Ketten treten zurück, der Zeiger zeigt Arbeit an. Bewusst ohne
   Bewegung, damit `prefers-reduced-motion` nichts zu unterdrücken hat. */
.ins-stepper[aria-busy="true"] { cursor: progress; }
.ins-stepper[aria-busy="true"] .ins-chain { opacity: 0.55; }
.ins-stepper select:disabled {
  background-color: var(--stone-100);
  color: var(--text-secondary);
  cursor: progress;
}

/* ---- Policy-Karte im Stepper ---- */
.ins-policy {
  background: white; border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-md); padding: 14px;
}
.ins-policy-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.ins-policy-head > div:first-child { min-width: 0; }
/* FEATURE-0163 Punkt 7: Der Firmenname sitzt jetzt im geteilten Idiom
   `.payer-value` neben dem Kurzicon und behält seine Typografie. */
.ins-policy-head .payer-value-name { font-size: var(--fs-14); font-weight: 700; color: var(--espresso); }
.ins-policy-number { font-size: var(--fs-12); color: var(--stone-500); margin: 0 0 8px; }
.ins-inherited { font-size: var(--fs-11); color: var(--text-secondary); }

/* ---- Kompakte Personen-Zeilen (Table-Reset + Grid) ---- */
.ins-member-table { display: block; width: 100%; margin: 0; }
.ins-member-table tbody { display: flex; flex-direction: column; }
.ins-member-table tr {
  display: grid;
  /* BUG-0423: max-content-Spalten sind nicht schrumpfbar — eine lange
     Meta-Zeile (langer Tarifname) sprengte die Zeilenbreite und schob die
     Aktionsspalte aus der Karte. minmax(0, …) erlaubt das Schrumpfen bis
     zum Umbruch, statt zu überlaufen. */
  grid-template-columns: minmax(0, max-content) minmax(0, max-content) minmax(0, max-content) minmax(0, 1fr) auto;
  grid-template-areas:
    "name   name  name  name  actions"
    "tariff rate  sb    fill  actions";
  gap: 2px 14px; align-items: center;
  padding: 9px 0; border-top: 1px solid var(--hairline-row);
}
.ins-member-table tr:first-child { border-top: 0; }
.ins-member-table td { display: block; padding: 0; border: 0; background: transparent; }
.ins-member-table td[data-cell="name"] { grid-area: name; font-size: var(--fs-13); font-weight: 600; color: var(--espresso); min-width: 0; }
.ins-member-table td[data-cell="tariff"] { grid-area: tariff; }
.ins-member-table td[data-cell="rate"] { grid-area: rate; }
.ins-member-table td[data-cell="deductible"] { grid-area: sb; }
.ins-member-table td[data-cell="actions"] { grid-area: actions; display: flex; gap: 10px; justify-self: end; align-self: center; }
.ins-member-table td[data-cell="tariff"],
.ins-member-table td[data-cell="rate"],
.ins-member-table td[data-cell="deductible"] {
  /* BUG-0423: kein weißes nowrap mehr — die Spalte darf jetzt schrumpfen,
     der Inhalt muss dann brechen dürfen statt die Zeile zu sprengen. */
  font-size: var(--fs-12); color: var(--stone-500); white-space: normal; min-width: 0;
}
.ins-meta-label { font-weight: 600; color: var(--text-secondary); margin-right: 3px; }
/* Empty-Row (auch view-generiert per OOB-Swap, ohne data-cell) */
.ins-member-table tr[id^="empty-row-"] { display: block; padding: 10px 0; }
.ins-member-table tr[id^="empty-row-"] td { display: block; font-size: var(--fs-13); color: var(--text-secondary); text-align: left; }

.ins-badge-vn {
  display: inline-flex; align-items: center;
  margin-left: 6px; padding: 2px 7px; border-radius: var(--radius-full);
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .04em;
  background: var(--accent); color: white; vertical-align: middle;
}
/* Icon-Buttons (Bearbeiten/Löschen) — Audit B4C/A4-06: 40px statt 28px,
   damit Bearbeiten/Löschen nebeneinander sicher treffbar sind (dazu 10px
   gap in .ins-config-actions und der actions-Zelle der Mitglieder-Tabelle).
   Die 44px-Trefferfläche kommt seit dem Completeness-Check-Nachzug
   (09.08.2026) als zentrierte ::after-Hitbox aus der A4-06-Regel in
   cappuccino.css (position: relative dafür ebenfalls dort). */
.ins-icon-btn {
  width: 40px; height: 40px; border-radius: 8px;
  /* Audit B4C/A5-09: Rahmen über --control-border (3:1) statt --stone-200 */
  border: 1px solid var(--control-border); background: white; color: var(--stone-500);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; transition: all var(--dur-fast) var(--ease-out);
}
.ins-icon-btn:hover { border-color: var(--stone-600); color: var(--espresso); background: var(--stone-100); }
.ins-icon-btn.ins-icon-btn-danger:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-muted); }
/* Deaktiviert ist von SC 1.4.11 ausgenommen — Rahmen bewusst blass */
.ins-icon-btn:disabled { border-color: var(--stone-200); color: var(--stone-300); background: var(--stone-100); cursor: not-allowed; }

/* Leerzustand (keine Kostenträger) */
.ins-empty { padding: 22px 16px; text-align: center; font-size: var(--fs-13); color: var(--stone-500); }

/* ---- Mobil: Stepper kompakt ----
   Die Schrittnummer stand in einer eigenen 30px-Grid-Spalte plus 10px Gap und
   nahm der Policy-Karte 40px der ohnehin knappen Breite. Mobil steht sie
   deshalb mit Textlabel über der Karte, die Karte läuft über beide Spalten.
   Der Block steht am Ende des ins-Abschnitts, damit er die Paddings der
   Basisregeln (.ins-policy, .ins-chain, .ins-config-body) überschreibt. */
@media (max-width: 767.98px) {
  .ins-step {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "num    label"
      "policy policy";
    gap: 4px 8px;
    align-items: center;
  }
  .ins-step-num { grid-area: num; width: 22px; height: 22px; margin-top: 0; font-size: var(--fs-12); }
  .ins-step-label {
    grid-area: label; display: block; justify-self: start;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--text-secondary);
  }
  .ins-step > .ins-policy { grid-area: policy; margin-top: 4px; }
  .ins-step-single > .ins-policy { margin-top: 0; }
  .ins-chain { padding: 10px; }
  .ins-policy { padding: 12px; }
  .ins-config-body { padding: 12px; }
}

/* ---- Utilities ---- */
/* Wrapper-Tooltip auf disabled Buttons: Button darf keine Events schlucken */
.is-unclickable { pointer-events: none; }

/* Globaler HTMX-Lade-Spinner (ersetzt Inline-Styles im Template).
   Audit B4C/UX6-06: htmx setzt htmx-request auf das per hx-indicator
   benannte Element, NIE auf den body — die frühere Bedingung
   body.htmx-request trat deshalb nie ein. Der Spinner zeigt sich jetzt,
   sobald ein Request ihn über hx-indicator="#loading-indicator"
   referenziert (Template-Seite: insurance_settings.html, siehe Befund). */
.htmx-page-spinner {
  display: none; position: fixed; top: 50%; left: 50%;
  transform: translate(-50%, -50%); z-index: var(--z-loader);
}
.htmx-page-spinner.htmx-request { display: block; }
.htmx-page-spinner .spinner-border { width: 3rem; height: 3rem; }

/* ============== BEITRAGS-MATRIX (Settings → Beiträge) ============== */
/* Matrix Monate × Versicherte auf .list-table-Basis. Kein mobiles Stacking
   möglich — die Tabelle trägt list-table--scroll (FEATURE-0134: statt einer
   dritten Kopie des Kopf-Stylings) und scrollt horizontal (.table-responsive). */
.contrib-month-col  { min-width: 80px; }
.contrib-member-col { min-width: 100px; }
.contrib-table thead th { vertical-align: middle; }

/* Untertitel (Kostenträger-Zusammenfassung) im Company-Header */
.contrib-company-sub {
  display: block; margin-top: 2px;
  font-size: var(--fs-11); font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--text-secondary);
}
.contrib-member-name { display: block; margin-bottom: 3px; }

/* Monats-Label + Zeilensumme */
.contrib-month { font-weight: 600; color: var(--espresso); white-space: nowrap; }
.contrib-total { font-weight: 700; color: var(--espresso); white-space: nowrap; }

/* Betrags-Zustände: normal / fortgeschrieben / nicht versichert / undefiniert */
.contrib-amount { white-space: nowrap; }
.contrib-inherited { color: var(--text-secondary); }
/* BUG-0656: Tagesanteil im Beginn- oder Wechselmonat, je Anteil eine Zeile unter dem Betrag.
   --stone-600 statt --text-secondary: 7,5:1 auch auf --stone-100 (Hover), siehe tokens.css */
.contrib-anteil { display: block; font-size: var(--fs-12); line-height: 1.3; color: var(--stone-600); white-space: nowrap; }
.contrib-anteil-inline { display: inline; font-size: inherit; font-weight: 600; }
.contrib-empty { color: var(--text-secondary); }
.contrib-undefined {
  display: inline-flex; align-items: center; gap: 3px;
  font-weight: 700; color: #92610A;
}
.contrib-undefined svg { flex: none; }
.contrib-cell-undefined { background: var(--warning-muted); }

/* Jahres-Summenzeile */
.contrib-table .contrib-year-row td {
  background: var(--accent-muted);
  font-weight: 700; color: var(--accent-dark);
  border-top: 1px solid var(--stone-200);
}

/* Gesamt-Box im Beitrags-Dialog (BUG-0327): bei knapper Breite reicht der
   Platz für Label und Betrag ("663,75 €/Monat") nicht mehr nebeneinander —
   ohne Gegenmaßnahme brach der Text mitten zwischen Betrag und Einheit um.
   Gestapelt (Label über Betrag) statt Inline-Umbruch, analog zu anderen
   Summenzeilen im Projekt. */
@media (max-width: 400px) {
  .contrib-total-row {
    flex-direction: column;
    align-items: flex-start !important;
    gap: 4px;
  }
}

/* ============== BELEG-DETAIL (Detail D1 · Beleg-Detail-Redesign) ============== */
/* Verdichtete Detailansicht: Kopf mit Breadcrumb + Aussteller-Titel,
   Next-Action-Strip, Grid 1.45fr/1fr (Dokument-Viewer | Karten-Stack),
   Rechnungspositionen volle Breite. Mobil (<768px) Tab-Navigation. */

/* ---- Seitenkopf ---- */
.detail-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 16px;
}
/* Die Krümelzeile (.detail-crumbs / .detail-back) steht seit dem Angleich des
   Wissensbereichs in cappuccino.css — sie gilt jetzt auch im öffentlichen
   Bereich, und nur dieses Blatt laden beide Bases. Hier nichts nachbauen. */
/* Belegtyp-Chip im Seitenkopf (neutral, mit Typ-Icon) */
.type-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--stone-100); color: var(--espresso-light);
  font-size: var(--fs-12); font-weight: 600;
  padding: 4px 11px; border-radius: var(--radius-full); white-space: nowrap;
}
.detail-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.detail-title {
  font-family: var(--font-display); font-size: var(--fs-26); font-weight: 600;
  color: var(--espresso); margin: 0; overflow-wrap: anywhere;
  /* BUG-0262: hyphens:auto bricht lange, zusammengesetzte Überschriften mit
     echtem Trennstrich an einer Silbengrenze. overflow-wrap:anywhere bleibt
     als Fallback für Wörter, die der Browser nicht trennen kann. */
  hyphens: auto;
}
.detail-sub { font-size: var(--fs-14); font-weight: 500; color: var(--stone-500); margin-top: 6px; }
.detail-sub strong { color: var(--espresso); font-weight: 700; }
.detail-head-actions { display: flex; align-items: center; gap: 10px; flex: none; }
/* U-18: Bei mehreren Kopf-Aktionen mobil umbrechen statt aus dem Viewport zu laufen */
@media (max-width: 767.98px) {
  .detail-head-actions { flex-wrap: wrap; }
}

/* ---- Next-Action-Strip ---- */
.next-strip {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  background: var(--accent-muted); border: 1px solid rgba(42, 157, 143, 0.28);
  border-radius: var(--radius-lg); padding: 13px 18px; margin-bottom: 16px;
}
.next-strip-info { display: flex; align-items: center; gap: 11px; }
.next-strip-icon {
  width: 34px; height: 34px; flex: none; border-radius: var(--radius-full);
  background: var(--accent); color: white;
  display: inline-flex; align-items: center; justify-content: center;
}
.next-strip-title { font-size: var(--fs-14); font-weight: 700; color: var(--accent-dark); }
.next-strip-actions { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.next-strip-actions .btn { border-radius: var(--radius-full); font-size: var(--fs-13); font-weight: 600; }

/* ---- Layout: Grid + Karten ---- */
.detail-grid { display: grid; grid-template-columns: 1.45fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 1024px) { .detail-grid { grid-template-columns: 1fr; } }
.detail-stack { display: flex; flex-direction: column; gap: 16px; min-width: 0; }

/* padding: 0 neutralisiert das globale Marketing-`section`-Padding (cappuccino.css) */
.detail-card {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); overflow: hidden;
  padding: 0;
}
.detail-card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; padding: 12px 16px; border-bottom: 1px solid var(--hairline-soft);
}
.detail-card-title {
  font-family: var(--font-display); font-size: var(--fs-14); font-weight: 600;
  color: var(--espresso); margin: 0;
}
/* V-01b: Führende Inline-Icons in Überschriften vertikal zentrieren.
   Inline-SVGs erben Baseline-Ausrichtung und „hängen" dadurch zu tief.
   EINE Regel für alle Karten-/Detail-/Auth-Überschriften statt Pro-Screen-Fixes. */
.detail-card-title > svg,
.detail-title > svg,
.auth-card-col h1 > svg { vertical-align: -0.18em; }
.detail-card-count { font-family: var(--font-app); font-size: var(--fs-12); font-weight: 600; color: var(--text-secondary); }
.detail-card-body { padding: 16px 18px; }
.detail-card-foot { padding: 13px 16px; border-top: 1px solid var(--hairline-soft); }
/* BUG-0203: Kurzer Hinweistext direkt in .detail-card, OHNE
   .detail-card-body-Wrapper (analog .form-rows--incard: eine Formset-Tabelle
   sitzt bewusst ungewrappt im Kartenkörper, damit .table-responsive mobil
   randlos scrollen kann). Ohne eigenen Innenabstand klebt so ein Hinweis an
   der Kartenkante, während .detail-card-head/.detail-card-body ihn tragen —
   derselbe horizontale Wert (16px) wie .detail-card-head, auf allen Breiten. */
.detail-card-hint { padding-left: 16px; padding-right: 16px; }
.detail-count-pill {
  display: inline-flex; align-items: center;
  padding: 4px 11px; border-radius: var(--radius-full);
  font-size: var(--fs-12); font-weight: 600;
  background: var(--tasse-muted); color: var(--tasse);
}
.detail-overline {
  font-size: var(--fs-11); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-secondary); margin-bottom: 8px;
}
.detail-region-positions { margin-top: 16px; }

/* ===== Untere Aktionszeilen der Detailseiten (BUG-0040) =====
   Die Detailseiten kennen drei Ränge von Aktionen, und der Rang steckt in
   der Position: „Bearbeiten" im Seitenkopf, die Arbeitsaktionen eines
   Abschnitts direkt unter ihm, die destruktive Aktion ganz am Ende.

   .detail-actions-row  — Arbeitsaktionen unter ihrem Abschnitt (Widerspruch
                          und Zuordnung unter den Abrechnungspositionen).
   .detail-delete-row   — Löschen unter dem VOLLSTÄNDIGEN Seiteninhalt,
                          rechtsbündig und durch eine Haarlinie abgesetzt.
                          Die Trennlinie ist der sichtbare Teil der Aussage:
                          Was darunter steht, gehört nicht mehr zur täglichen
                          Arbeit. Farbe und Textlink-Form kommen weiterhin
                          aus .delete-link — hier steht nur die Platzierung. */
.detail-actions-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  margin-top: 16px;
}
.detail-delete-row {
  display: flex; justify-content: flex-end;
  margin-top: 32px; padding-top: 16px;
  /* --hairline, nicht --hairline-soft: Diese Zeile liegt direkt auf dem
     Seitengrund, nicht in einer Karte. Die weiche Variante ist für
     Trenner INNERHALB weisser Flächen gedacht und verschwindet auf dem
     warmen Untergrund fast vollständig. */
  border-top: 1px solid var(--hairline);
}
/* BUG-0219: Ist der Beleg gesperrt, steht statt des Buttons ein Satz mit
   Grund und Korrekturweg (BelegSperre.loeschen_hinweis) — dieselbe Zeile,
   dasselbe rechtsbündige Idiom. max-width verhindert eine über die ganze
   Kartenbreite laufende Zeile auf Desktop; mobil entfällt sie, siehe unten. */
.detail-delete-hint {
  max-width: 440px;
  margin: 0;
  font-size: var(--fs-13);
  color: var(--text-secondary);
  text-align: left;
}
.detail-delete-hint a { color: inherit; text-decoration: underline; }
@media (max-width: 767.98px) {
  /* Mobil tragen die Arbeitsaktionen die volle Breite — nebeneinander
     bliebe von „Zuordnung (3 offen)" sonst nichts Lesbares übrig. */
  .detail-actions-row { flex-direction: column; align-items: stretch; }
  .detail-actions-row .app-btn { justify-content: center; }
  /* Die Löschzeile folgt dem Inhalt und bleibt rechtsbündig; der Abstand
     hält sie von einer etwaigen fixierten Leiste am unteren Rand frei.

     24px statt 16px: `.delete-link::after` legt eine 44px hohe Trefferfläche
     über den Link, die den Text oben und unten um rund 12px überragt. Bei
     16px blieben darunter nur rund 6px — was auch immer BUG-0045 dort
     anfügt, wäre unsichtbar anklickbar. Die 24px sind die billige
     Absicherung dagegen. */
  .detail-delete-row { margin-bottom: 24px; }
  /* Auf schmalen Schirmen läuft der Hinweis über die volle Breite statt
     rechtsbündig in einer schmalen Spalte umzubrechen. */
  .detail-delete-hint { max-width: none; }
}

/* ---- Dokument-Viewer ---- */
/* ---- Dokument-Viewer: EINE Geometrie für jede eingebettete Dokumentfläche ----
   BUG-0037. Vorher trug jede Fläche ihre eigene Pixelhöhe im HTML-Attribut
   (sieben Templates, 600 oder 800 px) — unabhängig von Fenster, Spaltenhöhe
   und dem Hochformat, das jedes eingescannte Blatt nun einmal hat.

   Die Regel: DIN-A4-Hochformat aus der verfügbaren BREITE (Höhe = Breite ×
   1,414). Das deckt mobil und schmale Spalten vollständig ab — ein Blatt
   wird so groß gezeigt, wie es auf die Breite passt, ohne den Inhalt zu
   verzerren. Der Betrachter (.pdf-viewer, BUG-0684) scrollt darin
   senkrecht durch alle Seiten.

   Auf Desktop-Detailseiten kommt die Nachbarspalte dazu: Die Karte ist
   Grid-Element und wird auf die Zeilenhöhe gestreckt, der Viewer füllt sie
   (flex: 1). Damit wächst er MIT dem Kartenstapel — nach unten begrenzt
   durch 600 px, nach oben durch das A4-Hochformat (141.4cqw bezogen auf die
   Kartenbreite). Deshalb steht die Regel hier an .doc-viewer und nicht an
   einem Seiten-Selektor: Die nächste Dokumentfläche erbt sie, statt eine
   achte Pixelhöhe zu erfinden (Wächter: test_belegdetail_dokumentviewer.py). */
/* Die Geometrie hängt am Betrachter, nicht am Elternteil. Zwei Gründe:
   Der Leerzustand braucht dann keine Ausnahme (er hat keinen Betrachter,
   also greift die Regel gar nicht), und `:has()` bleibt raus, wo es
   tragend wäre — fehlt die Unterstützung, verwirft der Parser die ganze
   Regel, und der Betrachter fiele auf die Höhe seines Inhalts zurück.
   `:has()` steht deshalb nur noch vor der Fläche (rein optisch). */
.doc-viewer:has(.pdf-viewer) { background: var(--stone-200); }
.doc-viewer .pdf-viewer {
  aspect-ratio: 1 / 1.414;   /* A4-Hochformat aus der verfügbaren Breite */
}
/* Sicherer Rückfall für Browser ohne aspect-ratio: lieber eine feste
   Lesehöhe als ein 150px-Streifen. */
@supports not (aspect-ratio: 1 / 1) {
  .doc-viewer .pdf-viewer { height: 600px; }
}
/* Desktop-Detailseiten: Der Viewer wächst mit dem Kartenstapel daneben.
   Die Schwelle ist dieselbe, ab der .detail-grid zweispaltig wird (1024px) —
   darunter gibt es keine Nachbarspalte, dort gilt allein das A4-Format oben.
   align-self: stretch nur für die Dokumentkarte: .detail-grid setzt bewusst
   align-items: start, damit Karten nicht auf Zeilenhöhe gezogen werden. */
@media (min-width: 1025px) {
  .detail-grid > .detail-card.detail-region-doc {
    align-self: stretch;
    display: flex; flex-direction: column;
    /* container-type impliziert `contain: layout style`: Die Karte wird
       Stacking Context UND enthaltender Block für `position: fixed`.
       Ein Overlay INNERHALB dieser Karte (Modal, Popover, Sticky-Leiste)
       bliebe darin eingesperrt statt über der Seite zu liegen. Wer so
       etwas hier braucht, hängt es außerhalb der Karte ein. */
    container-type: inline-size;
  }
  .detail-card.detail-region-doc .doc-viewer { flex: 1 1 auto; display: flex; }
  .detail-card.detail-region-doc .doc-viewer .pdf-viewer {
    aspect-ratio: auto;      /* Höhe kommt aus der Spalte, nicht aus der Breite */
    height: 100%;
    min-height: 600px;       /* Untergrenze unabhängig von der Nachbarspalte */
    max-height: 141.4cqw;    /* Obergrenze: DIN-A4-Hochformat der Kartenbreite */
  }
}
.doc-empty { padding: 24px 18px; font-size: var(--fs-13); color: var(--stone-500); }

/* ===== Dokument-Betrachter (BUG-0684) =====
   Markup includes/_pdf_viewer.html, Verhalten static/js/pdf-viewer.js.
   Ein senkrecht scrollender Kasten; jede PDF-Seite ist ein Block in voller
   Breite mit dem Seitenverhältnis der Seite (setzt das Skript), die Canvas
   füllt ihn. So steht jede Seite auf Breite (Fit-to-Width), auch eine im
   Querformat, und waagrecht kann nichts überlaufen. Die Höhe des Kastens
   bestimmt die Fläche: .doc-viewer oben, .review-doc-card in der
   Prüfansicht. */
.pdf-viewer {
  display: block; width: 100%;
  overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain;
  padding: 8px;
  background: var(--stone-200);
}
.pdf-viewer:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.pdf-seite {
  width: 100%;
  background: var(--milk);
  box-shadow: var(--shadow-sm);
}
.pdf-seite + .pdf-seite { margin-top: 8px; }
.pdf-seite canvas { display: block; width: 100%; height: 100%; }
.pdf-viewer-bild { display: block; width: 100%; height: auto; }
.pdf-viewer-ersatz { margin: 0; padding: 16px 10px; font-size: var(--fs-13); }
.pdf-viewer-hinweis {
  max-width: 26rem; margin: 24px auto; padding: 16px;
  background: var(--milk); border-radius: var(--radius-md);
  font-size: var(--fs-13); color: var(--stone-600); text-align: center;
}
.pdf-viewer-hinweis strong { display: block; margin-bottom: 6px; color: var(--espresso); }
.pdf-viewer-hinweis p { margin-bottom: 10px; }

/* ---- Link-Rows (Originaldokumente, Einreichungen, Zahlungen) ---- */
.link-rows { display: flex; flex-direction: column; gap: 8px; }
.link-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 9px;
  background: var(--tint-row); border: 1px solid var(--hairline-soft);
  text-decoration: none; color: inherit;
  transition: background var(--dur-fast) var(--ease-out);
}
a.link-row:hover, button.link-row:hover { background: var(--stone-100); }
/* Row als Button (z.B. Zahlung öffnet Bearbeiten-Modal) */
button.link-row { width: 100%; text-align: left; font-family: inherit; cursor: pointer; }
.link-row-main { flex: 1; min-width: 0; }
.link-row-title { font-size: var(--fs-13); font-weight: 700; color: var(--espresso); }
.link-row-title.is-doc { color: var(--accent-dark); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.link-row-sub {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: var(--fs-12); font-weight: 500; color: var(--text-secondary); margin-top: 2px;
}
.link-row-chevron { color: var(--stone-400); flex: none; }
.doc-thumb {
  width: 30px; height: 38px; flex: none;
  border: 1px solid var(--stone-200); border-radius: 5px; background: white;
  color: var(--stone-400);
  display: inline-flex; align-items: center; justify-content: center;
}

/* ---- Belegdaten: Label/Value-Grid ---- */
.meta-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 13px 18px; }
.meta-item-full { grid-column: 1 / -1; }
.meta-sep { grid-column: 1 / -1; height: 1px; background: var(--hairline-soft); }
/* BUG-0036: Zeile aus mehreren kurzen Werten (Belegdatum, Betrag, Person).
   auto-fit statt fester Spaltenzahl: Solange jede Angabe ihre Mindestbreite
   bekommt, stehen sie nebeneinander; darunter bricht die Zeile von selbst
   um — ein Medienquery mit fester Schwelle träfe die Kartenbreite nicht,
   weil die Karte je nach Spaltenlayout unterschiedlich breit ist. */
.meta-grid-row {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  gap: 13px 18px;
}
/* Lange Werte ohne Leerzeichen (Aussteller, Notiz) brechen um, statt aus der
   Karte zu laufen. Bewusst hier statt an .bl-issuer: dieselbe Klasse trägt in
   der Belegliste eine EINZEILIGE Zelle mit Auslassungspunkten.

   Nur die vollbreiten Zeilen — das sind die Freitext-Felder. In der
   dreispaltigen Kennzahlenzeile darunter stehen Datum, Betrag und Person;
   dort bräche `anywhere` bei schmaler Spalte mitten in die Zahl
   („1.234.567,89 €" über zwei Zeilen), und eine getrennte Zahl liest sich
   falsch, statt nur unschön (Review M-8). */
.meta-grid .meta-item-full .meta-value { overflow-wrap: anywhere; }
.meta-grid .bl-issuer > span { min-width: 0; }
.meta-label {
  font-size: var(--fs-11); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-secondary); margin-bottom: 3px;
}
.meta-value { font-size: var(--fs-14); font-weight: 600; color: var(--espresso); }
.meta-value-strong { font-size: var(--fs-14); font-weight: 700; }
.meta-hint { font-size: var(--fs-11); font-weight: 500; color: var(--text-secondary); margin-top: 3px; line-height: 1.4; }
.meta-chip {
  display: inline-flex; align-items: center;
  margin-left: 8px; padding: 2px 8px; border-radius: var(--radius-full);
  font-size: var(--fs-11); font-weight: 600;
  background: var(--tasse-muted); color: var(--tasse);
}

/* ---- Zahlungen: Summe + Aktionen ---- */
.pay-summary {
  display: flex; justify-content: space-between; gap: 10px;
  padding-top: 12px; border-top: 1px solid var(--hairline-soft); margin-top: 12px;
}
.pay-summary-total { font-size: var(--fs-16); font-weight: 700; color: var(--espresso); }
.pay-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.pay-actions .app-btn { width: 100%; justify-content: center; }

/* ---- Rechnungspositionen: Re-Styling der bestehenden Tabelle ---- */
.positions-table thead th {
  background: var(--stone-100); border-bottom: 1px solid var(--stone-200);
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--stone-500);
}
.positions-table tbody tr.pos-group > td {
  background: var(--tint-warm);
  font-size: var(--fs-12); font-weight: 700; color: var(--espresso-light);
}
.positions-table tbody td { border-color: var(--hairline-row); }
/* Zeilen mit mehrzeiliger GOÄ-Beschreibung: alle übrigen Zellen an der ersten
   Textzeile ausrichten statt mittig schweben zu lassen. Bewusst auf die beiden
   read-only Detail-Tabellen gescopet — `.positions-table` teilen sich neun
   Tabellen, die Formular-Varianten (form-rows) brauchen ihre Inputs mittig. */
.list-card--positions tbody td,
.list-card--positions-rx tbody td { vertical-align: top; }
/* Summen-Label rechtsbündig ans Zahlenfeld heran — nur Desktop, mobil steht es
   als Überschrift über den Beträgen. Attribut-Selektor, weil `.list-table tfoot th`
   (weiter unten in dieser Datei) sonst mit gleicher Spezifität `left` gewinnt. */
@media (min-width: 768px) {
  .positions-table tfoot th[data-cell="sum-label"] { text-align: right; }

}

/* BUG-0037: Die Summen standen linksbündig unter rechtsbündigen Zahlen —
   dieselbe Spalte, zwei Kanten. Die Positionszellen tragen die
   text-end-Utility; für die Summenzellen wäre sie falsch, weil sie in der
   KARTENANSICHT zur beschrifteten Zeile werden. Schwelle deshalb 992px,
   nicht 768px: Zwischen 768 und 991,98px ist die Tabelle noch Karte, und
   dort entschied bisher allein die Quellposition, welche Regel gewinnt
   (Review M-14). */
@media (min-width: 992px) {
  .positions-table tfoot td[data-cell^="sum-"] { text-align: right; }
}

/* Zustands-Tint der Positionszeilen. Ersetzt Bootstrap .table-danger/.table-warning
   (Vorbild .list-table tr.doc-missing td): die Beleg-Detail-Tabelle trägt seit der
   Kanon-Migration kein .table mehr, und Bootstrap malt den Tint über
   `.table > :not(caption) > * > *` — ohne .table setzt es nur tote Custom Properties.
   Tint liegt auf tr UND td: Kanon-Punkt 4 ("nie auf die tr") schützt die
   :active-Rückmeldung klickbarer Listen; Positionszeilen sind nicht klickbar, und
   reiner td-Tint ließe mobil das 16px-Kartenpadding und die grid-gaps weiß. */
.positions-table tbody tr.is-error,
.positions-table tbody tr.is-error > td { background: var(--danger-muted); }
.positions-table tbody tr.is-warn,
.positions-table tbody tr.is-warn > td  { background: var(--warning-muted); }

/* Mobiler Aufklapper (Details zu einer Position). Chevron sitzt in der
   Betrags-Zelle, das Ziel-Collapse in der Beschreibungs-Zelle — beide per
   d-md-none nur mobil sichtbar, deshalb keine eigenen Tabellenspalten. */
.pos-toggle {
  border: 0; background: transparent; padding: 0; line-height: 0;
  color: var(--text-secondary); cursor: pointer;
}
.pos-toggle-chevron { transition: transform var(--dur-fast) var(--ease-out); }
.pos-toggle[aria-expanded="true"] .pos-toggle-chevron { transform: rotate(180deg); }
.pos-detail-list {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  margin: 8px 0 0; padding-top: 8px;
  border-top: 1px dashed var(--stone-200); font-size: var(--fs-12);
}
.pos-detail-list dt {
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-secondary);
  /* Label an der ersten Textzeile des Werts, nicht mittig dazu — bei
     mehrzeiligen GOÄ-Beschreibungen rutscht es sonst aus der Leserichtung. */
  align-self: start; padding-top: 1px;
}
.pos-detail-list dd { margin: 0; color: var(--stone-600); overflow-wrap: anywhere; }
/* Spaltenbreiten (ersetzen Inline-Styles) */
.pos-col-status { width: 50px; }
.pos-col-code   { width: 80px; }
.pos-col-date   { width: 110px; }
.pos-col-pzn    { width: 110px; }
.pos-col-anz    { width: 50px; }
.pos-col-factor { width: 70px; }
.pos-col-amount { width: 90px; }
.pos-col-amount-lg { width: 100px; }
.pos-col-anz-lg { width: 60px; }
/* Legende (Desktop: eine umbrechende Zeile wie bisher) */
.pos-legend {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 11px 18px; border-top: 1px solid var(--hairline-soft);
  font-size: var(--fs-12); font-weight: 500; color: var(--stone-600);
}
.pos-legend-label {
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-secondary);
}
.pos-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.pos-legend-key { display: inline-flex; align-items: center; gap: 6px; }
.pos-legend-mark {
  width: 17px; height: 17px; border-radius: var(--radius-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--fs-11); font-weight: 700;
}
.pos-legend-mark.is-ok   { background: rgba(34, 197, 94, .16); color: #166534; }
.pos-legend-mark.is-warn { background: var(--warning-muted); color: #92610A; }
.pos-legend-mark.is-err  { background: var(--danger-muted); color: #DC2626; }
.pos-legend .text-note { color: var(--text-secondary); }
/* BUG-0037: Mobil eine stabile zweispaltige Zeile je Zustand — links Symbol
   plus Bezeichnung (.pos-legend-key), rechts die Erklärung. Als umbrechende
   Flex-Zeile hatten die drei Teile keinen Spaltenbezug: Sie brachen je
   Zustand an anderer Stelle um und wirkten gegeneinander verschoben.
   subgrid, damit die Kante der Erklärungen über alle vier Zeilen dieselbe
   ist; ohne subgrid-Unterstützung bleiben die Zeilen gestapelt lesbar.
   Schwelle wie bei der Positionstabelle (Kartenansicht ab 991,98px). */
@media (max-width: 991.98px) {
  .pos-legend {
    display: grid; grid-template-columns: auto 1fr;
    align-items: baseline; gap: 8px 12px;
  }
  .pos-legend-label { grid-column: 1 / -1; }
  .pos-legend-item {
    display: grid; grid-column: 1 / -1;
    grid-template-columns: subgrid; align-items: baseline;
  }
  /* Lange Erklärungen brechen um, statt die Zeile über den Rand zu schieben */
  .pos-legend .text-note { overflow-wrap: anywhere; }
}
/* Leerzustand */
.pos-empty { padding: 28px 18px; text-align: center; color: var(--stone-500); }
.pos-empty svg { color: var(--stone-300); margin-bottom: 8px; }

/* ---- Mobile Tabs (Übersicht / Dokument / Positionen) ---- */
.detail-tabs {
  display: flex; gap: 4px;
  background: var(--stone-100); padding: 4px; border-radius: 10px;
  margin-bottom: 14px;
}
.detail-tab {
  flex: 1; text-align: center; padding: 8px;
  border: 0; border-radius: 7px; background: transparent;
  font-family: inherit; font-size: var(--fs-12); font-weight: 600; color: var(--stone-500);
  cursor: pointer;
}
.detail-tab.is-active {
  background: white; color: var(--espresso); font-weight: 700;
  box-shadow: 0 1px 2px rgba(61, 43, 31, .08);
}
@media (max-width: 767.98px) {
  .detail-body[data-active-region="overview"] .detail-region-doc,
  .detail-body[data-active-region="overview"] .detail-region-positions,
  .detail-body[data-active-region="doc"] .detail-region-overview,
  .detail-body[data-active-region="doc"] .detail-region-positions,
  .detail-body[data-active-region="positions"] .detail-region-doc,
  .detail-body[data-active-region="positions"] .detail-region-overview { display: none; }
  .detail-region-positions { margin-top: 0; }
}

/* ============== BELEG-BEARBEITEN (Beleg-Bearbeiten-Redesign) ============== */
/* Grid: sticky Dokument-Spalte links, Formular-Karten rechts.
   Mobil (<768px) Tab-Wechsel Formular/Dokument (gleiche Mechanik wie Detail). */
.edit-grid {
  display: grid; grid-template-columns: minmax(0, 472px) minmax(0, 1fr);
  gap: 18px; align-items: start;
}
@media (max-width: 1024px) { .edit-grid { grid-template-columns: 1fr; } }
.edit-doc-col { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
/* FEATURE-0330 Folgefund: Mit Vorschau, Liste und Upload-Status wurde die
   Spalte höher als der Viewport — ihr unteres Ende war erst am Seitenende
   erreichbar, obwohl sie oben "hängen" bleibt. max-height + overflow-y
   begrenzen sie auf den Viewport (top-Versatz oben und unten symmetrisch)
   und lassen sie ab dann intern scrollen. */
@media (min-width: 1025px) {
  .edit-doc-col {
    position: sticky; top: 14px;
    max-height: calc(100vh - 28px); overflow-y: auto;
  }
}
@media (max-width: 767.98px) {
  .detail-body[data-active-region="form"] .detail-region-doc,
  .detail-body[data-active-region="doc"] .detail-region-form { display: none; }
}

/* Belegtyp: Segmented Control (statt btn-group) */
.type-toggle { display: flex; gap: 4px; background: var(--stone-100); padding: 4px; border-radius: 11px; }
.type-toggle .btn {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: 7px;
  border: 0; border-radius: 8px; background: transparent;
  color: var(--stone-500); font-size: var(--fs-13); font-weight: 600; padding: 10px;
}
.type-toggle .btn-check:checked + .btn,
.type-toggle .btn.is-active {
  background: white; color: var(--espresso); font-weight: 700;
  box-shadow: 0 1px 2px rgba(61, 43, 31, .08);
}

/* KI-Belegerfassung: Banner-Button (IDs bleiben, JS unverändert) */
.ai-banner {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--accent-muted); border: 1px solid rgba(42, 157, 143, 0.28);
  border-radius: var(--radius-lg); padding: 13px 18px;
  font-family: inherit; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.ai-banner:hover:not(:disabled) { background: rgba(42, 157, 143, 0.16); }
.ai-banner:disabled { opacity: .55; cursor: not-allowed; }
.ai-banner-icon {
  width: 34px; height: 34px; flex: none; border-radius: var(--radius-full);
  background: var(--accent); color: white;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Spinner ersetzt das Funken-Icon, solange er sichtbar ist (JS-Variante, Belegerfassung:
   Spinner startet mit .d-none, JS toggelt die Klasse beim Request). Explizit auf
   :not(.htmx-indicator) beschränkt, damit die HTMX-Variante (nächster Kommentar) mit
   eigenem Toggle-Mechanismus nicht kollidiert — sonst bleibt das Funken-Icon dort
   permanent unsichtbar (der Spinner trägt nie .d-none, sondern .htmx-indicator). */
.ai-banner-icon .spinner-border:not(.d-none):not(.htmx-indicator) + span { display: none; }
/* HTMX-Variante (U-04, Vertrags-Analyse): der hx-request-State auf dem Button
   blendet den Spinner ein und das Funken-Icon aus. Ergänzt die JS-Variante
   (d-none-Toggle) der Belegerfassung — kein Layout-Sprung, hx-* unberührt. */
.ai-banner .ai-banner-icon .htmx-indicator { display: none; }
.ai-banner.htmx-request .ai-banner-icon .htmx-indicator { display: inline-block; opacity: 1; }
.ai-banner.htmx-request .ai-banner-sparkle { display: none; }
.ai-banner-main { flex: 1; min-width: 0; }
.ai-banner-title { display: block; font-size: var(--fs-14); font-weight: 700; color: var(--accent-dark); }
.ai-banner-sub { display: block; font-size: var(--fs-12); font-weight: 500; color: var(--stone-500); margin-top: 1px; }
.ai-banner-chevron { color: var(--accent); flex: none; }

/* Verknüpfte Dokumente: Aktionen in Link-Rows + gestrichelter Hinzufügen-Button */
.link-row-action {
  border: 0; background: none; padding: 0; flex: none;
  font-family: inherit; font-size: var(--fs-12); font-weight: 600; color: var(--text-secondary);
  cursor: pointer;
}
.link-row-action:hover { color: var(--espresso); }
.link-row-action.is-danger:hover { color: var(--danger); }
.doc-add-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  border: 1.5px dashed var(--stone-300); border-radius: 9px; background: none;
  padding: 11px; font-family: inherit; font-size: var(--fs-13); font-weight: 700;
  color: var(--accent-dark); cursor: pointer;
  transition: all var(--dur-fast) var(--ease-out);
}
.doc-add-btn:hover { border-color: var(--accent); background: var(--accent-muted); }

/* Rechnungspositionen (Formset): kompakte Feld-Optik in der Tabelle */
.line-items-table .form-control,
.line-items-table .form-select { padding: 7px 9px; border-radius: var(--radius-md); font-size: var(--fs-13); }

.pos-add-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; background: none; padding: 2px 0;
  font-family: inherit; font-size: var(--fs-13); font-weight: 700; color: var(--accent-dark);
  cursor: pointer;
}
.pos-add-btn:hover { color: var(--accent); }

/* Speichern/Abbrechen/Löschen */
.edit-actions { display: flex; flex-direction: column; gap: 10px; }
.edit-actions .app-btn { width: 100%; justify-content: center; padding: 13px 16px; font-size: var(--fs-14); }
.edit-delete { display: flex; justify-content: center; margin-top: 4px; }

/* ---- Mobile: vereinfachter Kopf (Abbrechen · Titel · Speichern) ---- */
/* Ersetzt auf fokussierten Screens den globalen Mobile-Header komplett
   (Seite leert dazu den mobile_header-Block). Fixed ist hier bewusst:
   die Leiste ist Viewport-verankert wie der globale .mobile-header
   (das frühere "sticky bricht an overflow-x:hidden"-Argument ist mit
   Audit B2/UX6-04 entfallen — fixed bleibt trotzdem das richtige Muster,
   die Tabs- und Dokument-Offsets unten setzen die feste Kopfhöhe voraus). */
.edit-mobile-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: calc(var(--z-overlay) + 1);
  height: 48px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--milk); border-bottom: 1px solid var(--stone-200);
  padding: 0 16px;
}
@media (max-width: 991.98px) {
  /* Ohne globalen Mobile-Header: dessen 72px-Padding durch Bar-Höhe ersetzen */
  body:not(:has(.mobile-header)) .main-panel { padding-top: 0; }
  body:has(.edit-mobile-bar):not(:has(.mobile-header)) .main-panel { padding-top: 62px; }

  /* Audit B4C/A4-05: FAB-Freiraum GLOBAL statt je Seite. Der Scanner-FAB
     (60px hoch, 32px über der Unterkante) belegt am Seitenende die unteren
     92px — ohne Freiraum verdeckt er in jeder Liste die letzte Zeile und
     schluckt deren Taps (elementFromPoint liefert das FAB-SVG). Ersetzt die
     früheren Einzellösungen an .list-surface (Belegliste, 60px) und
     .detail-card (Einreichungs-Detail, 92px). Die Bar-Screens sind
     ausgenommen: dort ist der FAB per body:has(...)-Regeln ausgeblendet
     und die Leisten bringen ihre eigene Freiraum-Rechnung mit (88px bzw.
     Bottom-Sheet). */
  body:has(.scanner-fab):not(:has(.submit-mobile-bar)):not(:has(.edit-mobile-bar)) .main-panel {
    padding-bottom: calc(92px + env(safe-area-inset-bottom, 0px));
  }
}
.edit-mobile-cancel {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-13); font-weight: 600; color: var(--accent-dark); text-decoration: none;
}
.edit-mobile-title { font-family: var(--font-display); font-size: var(--fs-14); font-weight: 600; color: var(--espresso); }
.edit-mobile-save {
  border: 0; background: none; padding: 0; font-family: inherit;
  font-size: var(--fs-13); font-weight: 700; color: var(--accent-dark); cursor: pointer;
}

/* ---- Mobile: Abschluss-Leiste am unteren Rand (Summe + Absenden) ---- */
/* Gegenstück zu .edit-mobile-bar, nur unten verankert: bei der Belegeinreichung
   wird in der Liste ausgewählt: die Aktion muss dort bleiben, wo der Daumen ist,
   statt über der Liste zu stehen. Fixed ist für die Viewport-verankerte
   Aktionsleiste bewusst gewählt (siehe Kommentar bei .edit-mobile-bar). */
.submit-mobile-bar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: calc(var(--z-sticky) + 15);
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--milk); border-top: 1px solid var(--stone-200);
  box-shadow: 0 -6px 20px rgba(61, 43, 31, .10);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
}
.submit-mobile-sum { font-size: var(--fs-14); color: var(--stone-600); }
.submit-mobile-sum strong { color: var(--espresso); white-space: nowrap; }
.submit-mobile-sep { color: var(--stone-300); margin: 0 2px; }
.submit-mobile-bar .app-btn { flex: none; }
@media (max-width: 991.98px) {
  /* Platz für die Leiste, damit die letzte Beleg-Karte erreichbar bleibt */
  body:has(.submit-mobile-bar) .main-panel { padding-bottom: 88px; }
  /* Der Scanner-FAB (--z-sticky + 10, bottom 2rem) läge sonst auf dem Button */
  body:has(.submit-mobile-bar) .scanner-fab { display: none !important; }
}

/* ---- Mobile: fokussierter Positions-Editor mit Blätter-Navigation ---- */
/* Spiegelt die Formset-Zeilen (Quelle bleibt die Tabelle im Formular-Tab).
   Unter 768px als Bottom-Sheet am unteren Rand fixiert (Mockup Frame C). */
.pos-editor {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); padding: 16px;
}
@media (max-width: 767.98px) {
  .pos-editor {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-sticky) + 15);
    border: 0; border-top: 1px solid var(--stone-200);
    border-radius: 16px 16px 0 0;
    box-shadow: 0 -8px 24px rgba(61, 43, 31, .12);
    padding: 14px 16px calc(14px + env(safe-area-inset-bottom));
    max-height: 60vh; overflow-y: auto;
  }
  /* Scanner-FAB würde die Blätter-Buttons überdecken */
  body:has(.edit-mobile-bar) .scanner-fab { display: none !important; }

  /* Tabs unter dem fixen Kopf fixieren (bleiben in beiden Modi erreichbar) */
  body:has(.edit-mobile-bar) .detail-tabs {
    position: fixed; top: 56px; left: 16px; right: 16px; z-index: var(--z-overlay);
    margin-bottom: 0;
  }
  body:has(.edit-mobile-bar) .main-panel { padding-top: 116px; }

  /* Dokument-Modus: Dokument bleibt zum Vergleich oben stehen (eigener
     Scrollbereich zwischen Tabs und Bottom-Sheet), das Sheet blättert
     durch die Formular-Sektionen. Dokument randlos und möglichst groß.

     NUR im Erfassen-/Bearbeiten-Kontext (erkennbar an der fixen Kopfleiste) —
     die 112px setzen deren Höhe plus die darüber fixierten Tabs voraus. Ohne
     diesen Scope legte sich das Dokument in den Detail-Ansichten (receipt_detail,
     reimbursement_detail — dort scrollen die Tabs mit) fixiert über die
     Tab-Leiste und machte den Dokument-Tab zur Sackgasse. */
  body:has(.edit-mobile-bar) .detail-body[data-active-region="doc"] .detail-region-doc {
    position: fixed; top: 112px; bottom: 0; left: 0; right: 0; z-index: 1;
    overflow-y: auto;
    padding: 8px 0 320px;
  }
  body:has(.edit-mobile-bar) .detail-body[data-active-region="doc"] .detail-region-doc .detail-card {
    border-radius: 0; border-left: 0; border-right: 0;
  }
  /* Erfassen/Bearbeiten: feste Lesehöhe im Bottom-Sheet-Flow. `height`
     schlägt das aspect-ratio der Grundregel (BUG-0037) — die Fläche bleibt
     also genau 68vh hoch, ohne dass das Elternteil eine Höhe erzwingt. */
  body:has(.edit-mobile-bar) .detail-body[data-active-region="doc"] .doc-viewer .pdf-viewer {
    height: 68vh; aspect-ratio: auto;
  }
}
.pos-editor-head {
  display: flex; align-items: center; gap: 8px; margin-bottom: 12px;
  font-family: var(--font-display); font-size: var(--fs-16); font-weight: 600; color: var(--espresso);
}
.pos-editor-head-actions { margin-left: auto; display: flex; gap: 6px; }
.pos-editor-body { display: flex; gap: 14px; align-items: stretch; }
.pos-editor-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.pos-editor-row { display: flex; gap: 10px; }
.pos-editor-row > div { flex: 1; min-width: 0; }
.pos-editor-nav {
  flex: none; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
}
.pos-editor-nav button {
  width: 44px; height: 44px; border-radius: var(--radius-full);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit; cursor: pointer;
  transition: all var(--dur-fast) var(--ease-out);
}
.pos-editor-prev { border: 1px solid var(--stone-200); background: white; color: var(--stone-500); }
.pos-editor-prev:hover:not(:disabled) { border-color: var(--stone-300); color: var(--espresso); }
.pos-editor-next { border: 0; background: var(--accent); color: white; }
.pos-editor-next:hover:not(:disabled) { background: var(--accent-dark); }
.pos-editor-nav button:disabled { opacity: .4; cursor: not-allowed; }
.pos-editor-count {
  text-align: center; font-size: var(--fs-12); font-weight: 700; color: var(--espresso); line-height: 1.3;
}
.pos-editor-count .sep { display: block; width: 14px; height: 1px; background: var(--stone-300); margin: 2px auto; }

/* ============== ABRECHNUNGS-DETAIL (Abrechnung-Detail-Redesign) ============== */
/* Ein Rechenweg statt Kachel-Raster: Money-Hero (Auszahlung + Rechenweg),
   Meta-Strip, Dokument | Zahlungseingänge, eine Positionen-Karte mit
   Personen-Gruppen. */

/* ---- Money-Hero (ist zugleich OOB-Swap-Target #payment-status-cards) ---- */
.money-hero {
  display: flex; align-items: stretch;
  background: white; border: 1px solid var(--hairline);
  border-radius: 14px; overflow: hidden;
}
.money-hero-main { flex: 1; padding: 24px 28px; display: flex; flex-direction: column; justify-content: center; }
.money-hero-label {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent-dark); margin-bottom: 10px;
}
/* .money-hero-dot entfernt (Design-Konsistenz Batch 2): ersetzt durch
   .money-hero-status-icon (Status-Icon statt bedeutungsfreiem Farbpunkt) —
   Grep-Nachweis 0 Template-Konsumenten zum Zeitpunkt des Abbaus. */
.money-hero-amount {
  font-family: var(--font-display); font-weight: 700; line-height: 1;
  font-size: clamp(28px, 4vw, 44px); color: var(--accent-dark);
}
.money-hero-sub { font-size: var(--fs-13); font-weight: 500; color: var(--stone-500); margin-top: 12px; }
.money-hero-calc {
  flex: none; width: 360px;
  border-left: 1px solid var(--hairline-soft); background: var(--milk-pure);
  padding: 20px 24px;
}
@media (max-width: 900px) {
  .money-hero { flex-direction: column; }
  .money-hero-calc { width: 100%; border-left: 0; border-top: 1px solid var(--hairline-soft); }
}
.calc-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 5px 0; font-size: var(--fs-13); font-weight: 600; color: var(--espresso);
}
.calc-row .calc-label { color: var(--stone-600); font-weight: 500; }
.calc-row.calc-total { font-size: var(--fs-16); font-weight: 700; padding: 3px 0; }
.calc-sep { height: 1px; background: var(--hairline-soft); margin: 7px 0; }
.calc-sep-strong { height: 2px; background: var(--stone-200); margin: 8px 0; }

/* Dashboard Beleg-Status (U-07): zentrale Status-Badges statt Zähl-Chips.
   Grid mit drei Spalten — Badge (links) · Anzahl · Betrag (rechts) — sorgt für
   eine durchgehende Flucht statt uneinheitlicher Einrückung. */
.dash-status-list {
  display: grid;
  /* Audit B4C/UX6-11: minmax(0, 1fr) statt 1fr — Grid-Kinder schrumpfen
     sonst nicht unter ihre Inhaltsbreite (min-width: auto) und die Kachel
     schnitt auf Tablet-Breite (768px) rechts ~10px ohne Hinweis ab. */
  grid-template-columns: minmax(0, 1fr) auto auto;
  /* BUG-0258: start statt center — Anzahl und Betrag richten sich an der
     ERSTEN Zeile des Badges aus, nicht an der Mitte des ganzen Badge-Blocks.
     Bei einem einzeiligen Badge ist der Unterschied nicht sichtbar, bei
     einem zweizeiligen verhindert es, dass Anzahl/Betrag mittig zwischen
     beide Badge-Zeilen rutschen. */
  align-items: start;
  gap: 8px 12px;
  padding: 4px 0;
}
.dash-status-list .dash-status-badge {
  justify-self: start;
  /* Audit B4C/UX6-11: Badge-Text darf hier umbrechen statt (unsichtbar)
     abgeschnitten zu werden — hebt das nowrap der Badge-Geometrie auf. */
  min-width: 0;
  white-space: normal;
  /* BUG-0258 („Umbruch abfedern"): Innerhalb dieser
     Liste bekommt JEDE Badge-Zeile dieselbe Zeilenhöhe — auch die
     einzeiligen. Die frühere Sorge „ändert die Höhe auf allen Breiten"
     bleibt richtig, ist hier aber die Absicht: eine einheitliche Zeilenhöhe
     über die ganze Liste, statt eines Sonderfalls nur für den seltenen
     Umbruch (den CSS ohnehin nicht gezielt adressieren kann). Das globale
     line-height:1 der Badge-Geometrie (Zeile 61ff., .badge-offen etc.)
     bleibt für alle anderen Konsumenten unverändert. */
  line-height: 1.3;
  align-items: flex-start;
  padding-block: 5px;
}
/* Das Icon folgt der ersten Zeile des (ggf. umgebrochenen) Labels, nicht der
   Mitte des ganzen Badge-Blocks — passend zu align-items: flex-start oben. */
.dash-status-list .dash-status-badge svg {
  margin-top: 0.1em;
}
.dash-status-list .dash-status-count {
  justify-self: end; font-size: var(--fs-13); font-weight: 600; color: var(--stone-500);
  font-variant-numeric: tabular-nums;
  /* BUG-0258: gleicht die 5px Top-Polsterung des Badges aus (align-items: start
     oben), damit Anzahl und Betrag auf der ersten Badge-Zeile stehen. */
  padding-top: 5px;
}
.dash-status-list .dash-status-amount {
  justify-self: end; font-size: var(--fs-13); font-weight: 700; color: var(--espresso);
  padding-top: 5px;
}
.amount-reimbursed { color: var(--accent-dark); }
.amount-declined { color: var(--danger); }
.amount-deductible { color: #92610A; }

/* .meta-strip/.meta-strip-item (alle Varianten) und .detail-grid--half
   abgebaut (Audit B4/UX4-11+UX6-08, Grep: 0 Konsumenten; der Styleguide
   dokumentierte meta-strip bereits als abgelöst). */

/* ---- Positionen: Personen-Gruppen ----
   BUG-0045: `.person-head` samt `-main`, `.person-avatar`, `.person-name` und
   `.person-count` abgebaut (Grep: 0 Konsumenten, Abbauregel §6b). Die
   Personengruppe ist keine Leiste ÜBER einer eigenen Tabelle mehr, sondern
   eine Gruppenzeile IN der gemeinsamen Tabelle — siehe
   `.list-card--stmt-positions` weiter unten. Der runde Initialen-Avatar
   entfällt dabei ersatzlos: Er wiederholte den ersten Buchstaben des Namens,
   der unmittelbar daneben steht. Der Benutzeravatar im globalen Header
   (`navbar-avatar`) ist eine andere Komponente und bleibt. */
.sb-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-12); font-weight: 600; color: #92610A;
  background: var(--warning-muted); padding: 4px 11px; border-radius: 7px;
}
/* Ablehnungsgrund als dezenter Hinweis statt kräftigem Rot */
.pos-note {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 5px; font-size: var(--fs-12); font-weight: 400;
  color: #92610A; line-height: 1.45;
}
.pos-note svg { flex: none; margin-top: 1px; opacity: .8; }
/* Kein Abzug: Strich statt "0,00 €" */
.amount-none { color: var(--stone-300); }
/* BUG-0198: Erstattet über Eingereicht — Warnsymbol am Betrag */
.amount-over { color: var(--status-open-fg); }
.amount-over svg { vertical-align: -2px; }
/* BUG-0198: Bestätigung im Positionsformular. Frage und Fehlertext sind
   inhaltlich eine Warnung — sie übernehmen die Farbe des Warnhinweises statt
   Grau (text-muted liest --bs-secondary-color) und Fehlerrot. */
.over-reimbursed-confirm { --bs-secondary-color: var(--status-open-fg); }
.over-reimbursed-confirm .invalid-feedback,
.over-reimbursed-confirm .form-check-input.is-invalid ~ .form-check-label { color: inherit; }
.over-reimbursed-confirm .form-check-input.is-invalid { border-color: var(--status-open-fg); }
.over-reimbursed-confirm .form-check-input.is-invalid:checked { background-color: var(--status-open-fg); }
.over-reimbursed-confirm .form-check-input.is-invalid:focus { box-shadow: 0 0 0 .25rem var(--status-open-bg); }
/* `.stmt-positions-table` entfällt mit BUG-0045: Die Zellabstände kommen
   jetzt aus dem Listen-Kanon (`.list-table`), nicht aus einer Regel neben
   Bootstrap. */

/* ============== EINREICHUNGS-DETAIL (Einreichung-Detail-Redesign) ============== */
.detail-grid--side { grid-template-columns: minmax(0, 372px) minmax(0, 1fr); }
/* Hervorgehobene Beträge (Details-Karte / Gesamtsummen-Karte) */
.meta-amount { font-family: var(--font-display); font-size: var(--fs-26); font-weight: 600; color: var(--accent); }
.total-amount { font-family: var(--font-display); font-size: var(--fs-26); font-weight: 600; color: var(--espresso); }
/* Dezenter Text-Link (z.B. "Belege als ZIP") */
.ghost-link {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-13); font-weight: 600; color: var(--accent-dark); text-decoration: none;
}
.ghost-link:hover { color: var(--accent); }
/* Danger-Variante des Outline-Pills (z.B. Löschen im Seitenkopf) */
.app-btn-outline.is-danger { color: var(--danger); }
.app-btn-outline.is-danger:hover { border-color: var(--danger); color: var(--danger); background: var(--danger-muted); }

/* ===== Löschen-Textlink (Änderungsrunde Q2, U-04) =====
   Löschen erscheint in Detail-Screens als dezenter roter Textlink OHNE Icon
   — als <a> und <button> nutzbar. Confirm-Delete-Seiten und Modals behalten
   ihre Buttons (dort ist die Bestätigungs-Aktion primär).

   BUG-0040: Der Ort ist NICHT mehr „links neben dem Bearbeiten-Button".
   Löschen steht seitdem rechtsbündig ganz unten auf der Seite, abgesetzt
   durch eine Linie (.detail-delete-row) — eine seltene, destruktive Aktion
   gehört nicht in die Reihe der Arbeitsaktionen im Seitenkopf. */
.delete-link {
  display: inline-flex; align-items: center;
  background: none; border: 0; padding: 0;
  font-size: var(--fs-13); font-weight: 500;
  /* Audit B4C/A3-07: EIN Fehler-Rot (--danger) statt --danger-light —
     Hover unterscheidet sich über die Unterstreichung. */
  color: var(--danger);
  text-decoration: none; cursor: pointer;
}
.delete-link:hover { color: var(--danger); text-decoration: underline; }

/* ===== Textaktion in Tabellen/Formularen (Audit B4C/A3-22) =====
   Benanntes Idiom für Inline-Textaktionen (Zeilen-Aktionen, kleine
   Formular-Aktionen) — ERSATZ für nackte Bootstrap btn-link, die mit
   Framework-Blau und Unterstreichung aus der Cappuccino-Palette fallen.
   Als <a> und <button> nutzbar (Button-Resets inklusive). Visuell die
   Schwester von .ghost-link (dezenter Anker-Link ohne Button-Resets);
   destruktive Aktionen nutzen weiterhin .delete-link. Die 44px-Hitbox
   kommt aus der A4-06-Regel weiter oben. */
.app-link-action {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0;
  font-family: inherit; font-size: var(--fs-13); font-weight: 600;
  color: var(--accent-dark); text-decoration: none; cursor: pointer;
}
.app-link-action:hover,
.app-link-action:focus-visible { color: var(--accent); text-decoration: underline; }

/* ---- Aus Template-Inline-Styles migriert (Line-Items + KI-Confidence) ---- */
/* Line Items: Spinner bei Number-Inputs ausblenden */
.line-items-table input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
.line-items-table input[type="number"]::-webkit-outer-spin-button,
.line-items-table input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  appearance: none;
  margin: 0;
}
/* Feste Spalten: Inhalt bestimmt Breite */
.line-items-table th.col-shrink,
.line-items-table td.col-shrink { width: 1%; white-space: nowrap; }
/* Faktor-Farbmarkierung (GOÄ §5) — Audit B4C/UX4-07: Projektfarben direkt
   statt über die remappten --bs-*-Variablen (Wert identisch seit B2-Glue,
   hier stimmt jetzt auch die Quelle). */
.factor-standard { color: var(--success) !important; }  /* <=2.3 Regelsatz */
.factor-elevated { color: var(--warning) !important; }  /* 2.3-3.5 erhöht */
.factor-excessive { color: var(--danger) !important; }  /* >3.5 Höchstsatz */
/* FEATURE-0111: Belegtyp-abhängige Spalten ein-/ausblenden */
.line-items-table.receipt-type-medical_bill .col-prescription { display: none; }
.line-items-table.receipt-type-prescription .col-medical_bill { display: none; }
/* KI-Confidence-Markierungen für Formularfelder — Audit B4C/UX4-07
   (tokens-und-scope): Rahmen aus den Semantik-/-fg-Tokens (sichtbar statt
   blasser Flächenfarbe), Flächen aus den -bg-Tokens. Selektoren auf
   Feld-Scope gehoben (0-3-0 schlägt .app-form .form-control, 0-2-0) —
   die sechs !important entfallen. Vergeben per classList.add() in
   _ai_analyze_button.html / reimbursement_form.html, immer auf Feldern
   innerhalb von .app-form. */
.app-form .form-control.ai-confidence-high,
.app-form .form-select.ai-confidence-high {
  border-color: var(--success);
  background-color: var(--status-success-bg);
}
.app-form .form-control.ai-confidence-medium,
.app-form .form-select.ai-confidence-medium {
  border-color: var(--status-open-fg);
  background-color: var(--status-open-bg);
}
.app-form .form-control.ai-confidence-low,
.app-form .form-select.ai-confidence-low {
  border-color: var(--status-error-fg);
  background-color: var(--status-error-bg);
}

/* ===== formulare (Welle 2) ===== */
/* Formular-Seiten ohne Dokument-Spalte: zentrierte schmale Spalte */
.form-single { max-width: 720px; margin: 0 auto; }

/* Leerzustand-Bausteine (Icon + Titel) für .list-empty-Karten */
.list-empty-icon { color: var(--stone-300); margin-bottom: 10px; }
.list-empty-title {
  font-family: var(--font-display); font-size: var(--fs-16); font-weight: 600;
  color: var(--espresso); margin-bottom: 6px;
}

/* Upload-Dropzone (Beleg erfassen, S3-Direct-Upload) */
.upload-dropzone {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  border: 1.5px dashed var(--stone-300); border-radius: var(--radius-lg);
  padding: 36px 20px; text-align: center; color: var(--stone-300);
  transition: all var(--dur-fast) var(--ease-out);
}
.upload-dropzone.is-dragover { border-color: var(--accent); background: var(--accent-muted); }
.upload-dropzone-hint { font-size: var(--fs-13); font-weight: 500; color: var(--stone-500); margin: 0; }
.upload-progress-track { height: 25px; }
.upload-progress-track .progress-bar { width: 0%; background-color: var(--accent); }

/* FEATURE-0330: Dokumentbereich der Anlegeformulare */
.dok-liste-hinweis { font-size: var(--fs-13); color: var(--stone-500); margin: 0 0 12px; }
.dok-aktionen { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 8px; }
.dok-auswahl { list-style: none; padding: 0; margin: 0 0 12px; display: flex; flex-direction: column; gap: 6px; }
.dok-auswahl:empty { display: none; }
.dok-auswahl-eintrag {
  display: flex; align-items: center; gap: 8px; justify-content: space-between;
  border: 1px solid var(--stone-200); border-radius: var(--radius-sm); padding: 6px 8px;
}
.dok-auswahl-eintrag.is-active { border-color: var(--accent); background: var(--accent-muted); }
.dok-auswahl-name {
  background: none; border: 0; padding: 0; text-align: left; color: inherit;
  font-weight: 500; overflow-wrap: anywhere;
}
.dok-vorschau { margin-bottom: 12px; }
.dok-oeffnen { display: inline-block; margin-top: 6px; font-size: var(--fs-13); }
.dok-upload-status:empty { display: none; }
.dok-upload-status { margin-bottom: 12px; font-size: var(--fs-13); }
.dok-upload-status ul { margin: 4px 0 0; padding-left: 18px; }
.dok-optionen { list-style: none; padding: 0; margin: 0; max-height: 360px; overflow-y: auto; }
.dok-option {
  display: flex; align-items: center; gap: 8px; padding: 8px 4px;
  border-bottom: 1px solid var(--stone-200); cursor: pointer;
}
.dok-option-name { flex: 1; overflow-wrap: anywhere; }
.dok-option-datum { font-size: var(--fs-13); color: var(--stone-500); white-space: nowrap; }

/* ===== einreichung-formular (Welle 2) ===== */
/* Kostenträger-Auswahl: verstecktes Radio + Karten-Optik (aus submission_form-
   Inline-Styles migriert und tokenisiert; Klassen-Namen/JS-HTMX unverändert) */
.policy-card-label { cursor: pointer; width: 100%; margin: 0; }
.policy-radio { position: absolute; opacity: 0; pointer-events: none; }
.policy-card {
  display: flex; align-items: center; gap: 10px;
  background: var(--tint-row); border: 1px solid var(--hairline-soft);
  border-radius: 9px; padding: 10px 12px;
  transition: all var(--dur-fast) var(--ease-out);
}
.policy-card:hover { background: var(--stone-100); }
.policy-card-main { flex: 1; min-width: 0; }
.policy-card-company { font-size: var(--fs-13); font-weight: 700; color: var(--espresso); }
.policy-card-sub {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: var(--fs-12); font-weight: 500; color: var(--text-secondary); margin-top: 3px;
}
.policy-check-icon { color: var(--accent); opacity: 0; flex: none; transition: opacity var(--dur-fast) var(--ease-out); }
.policy-radio:checked + .policy-card { border-color: var(--accent); background: var(--accent-muted); }
.policy-radio:checked + .policy-card .policy-check-icon { opacity: 1; }
.policy-radio:focus-visible + .policy-card { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Mitglieds-Zwischenzeile in einer nach Mitgliedern gruppierten Liste. Idiom
   übernommen von tr.pos-group der Positionstabelle — eine Tabelle mit Gruppen
   statt einer Tabelle je Gruppe, damit Desktop durchgehende Spaltenbreiten und
   einen thead behält. Die frühere .check-row-Liste ist damit abgelöst
   (Grep: 0 Konsumenten).

   Zwei Konsumenten (FEATURE-0139): die Beleg-Auswahl des Einreichungs-
   Formulars (_receipt_selection.html, list-card--receipt) und die Belegtabelle
   des Einreichungs-Details (submission_detail.html, list-card--belege).
   Deshalb auf .list-table statt auf eine einzelne Karten-Map gescopet —
   gleiche Deklarationen, breiterer Geltungsbereich. Die Spezifität ist dabei
   identisch, nicht geringer: `.list-card--receipt tbody tr.rcpt-group > td`
   und `.list-table tbody tr.rcpt-group > td` wiegen beide (0,2,3). */
.list-table tbody tr.rcpt-group > td {
  background: var(--tint-warm);
  font-size: var(--fs-12); font-weight: 700; color: var(--espresso-light);
}
/* Zwischensumme je Mitglied (FEATURE-0139): dezent — feine Oberlinie, halbfett.
   Der Gesamtbetrag im tfoot bezieht seine Prominenz aus `.list-table tfoot
   th|td` (kräftigere Schrift, --espresso). So entsteht die Hierarchie
   "Zwischensumme < Gesamt" ohne eine zweite Regel für den Fuß. */
.list-table tbody tr.rcpt-subtotal > td,
.list-table tbody tr.rcpt-subtotal > th {
  border-top: 1px solid var(--stone-200);
  font-weight: 600;
  color: var(--stone-600);
}
/* Bereits eingereichte Belege bleiben wählbar (Wiedereinreichung), treten
   aber zurück. */
.list-card--receipt tbody tr.is-muted .bl-name,
.list-card--receipt tbody tr.is-muted .bl-amount .amt { color: var(--text-secondary); }
.list-card--receipt .bl-issuer { cursor: pointer; }

/* Summen-Box (Ausgewählte Belege / Gesamtbetrag) — nutzt .calc-row-Zeilen */
.calc-box {
  background: var(--milk-pure); border: 1px solid var(--hairline-soft);
  border-radius: 9px; padding: 10px 14px;
}

/* Prior-Statements-Container reiht sein HTMX-Fragment direkt in den
   detail-stack ein (leeres Fragment erzeugt so keine Leerlücke) */
#prior-statements-container { display: contents; }

/* Fix (Welle 2): Der Grid-Modifier --side steht im Quelltext NACH der
   mobilen 1fr-Regel von .detail-grid und gewann daher auch <=1024px
   — die zweite Spalte kollabierte zum Sliver (sichtbar u.a. auf
   submission_detail mobil). Der Modifier kollabiert jetzt wie der
   Basis-Grid. (--half ist abgebaut, Audit B4/UX4-11+UX6-08.) */
@media (max-width: 1024px) {
  .detail-grid--side { grid-template-columns: 1fr; }
}

/* ===== abrechnungs-formular (Welle 2) ===== */
/* Formset-Tabellen (Positionen / Selbstbehalte): kompakte Feld-Optik +
   Spaltenbreiten (ersetzen Inline width-Styles) */
.stmt-table .form-control,
.stmt-table .form-select { padding: 7px 9px; border-radius: var(--radius-md); font-size: var(--fs-13); }
/* Datumsfelder: iOS-Safari rendert den Wert sonst mittig in der Feldbreite,
   Desktop-Browser linksbündig — gleiche Optik auf allen Geräten. */
.form-control[type="date"] { text-align: left; -webkit-appearance: none; appearance: none; }
/* U-20: Selbstbehalt-Inputs in Standard-Inputgröße (statt kompakter Formset-Optik) */
#deductibles-table .form-control,
#deductibles-table .form-select { padding: 11px 14px; border-radius: var(--radius-lg); }
/* Schriftgröße erst ab `sm`: Unter 576px gilt die 16-px-Regel für Felder
   (BUG-0497); die ID-Spezifität würde sie sonst überstimmen (R497-01). */
@media (min-width: 576px) {
  #deductibles-table .form-control,
  #deductibles-table .form-select { font-size: var(--fs-14); }
}
/* Innerhalb der Input-Group bleiben die inneren Ecken eckig (Suffix "€" bündig) */
#deductibles-table .input-group .form-control { border-top-right-radius: 0; border-bottom-right-radius: 0; }
#deductibles-table .input-group .input-group-text { border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }
/* U-20/U-17: Eingabe-Tabellen mobil als gestapelte Feldgruppen (kein horizontales
   Scrollen) — Zellen-Label via data-label, Breiten via .stmt-cell--* Modifier.
   Konsumenten: Abrechnungs-Formsets (Positionen/Selbstbehalte), Belege zuordnen. */
@media (max-width: 767.98px) {
  .form-rows thead { display: none; }
  .form-rows,
  .form-rows tbody { display: block; }
  .form-rows tbody tr {
    display: flex; flex-wrap: wrap; gap: 10px;
    padding: 14px 2px; border-bottom: 1px solid var(--hairline-row);
  }
  /* Fix 10.07.: .list-surface ist mobil randlos (width:100vw, border:0) und
     liefert selbst keinen horizontalen Innenabstand — die gestapelten Zeilen
     müssen ihn tragen (analog .list-card: 16px). Bewusst NUR im
     Listen-Kontext gescopet; die in .detail-card gewrappten Formset-Tabellen
     (Positionen, Zuordnung) behalten die schmale 2px-Version, sonst doppelte
     Einrückung. Betrifft account-balance, settlement-entries, bank-accounts,
     user, member u.a. */
  .list-surface .form-rows tbody tr,
  .list-surface .form-rows tfoot tr {
    padding-left: 16px; padding-right: 16px;
  }
  /* V-07: Bootstrap-Collapse-Zeilen (Buchungs-Erklärung) bleiben eingeklappt —
     die display:flex-Regel oben würde .collapse:not(.show){display:none}
     sonst per Spezifität überschreiben. */
  .form-rows tbody tr.collapse:not(.show) { display: none; }
  /* white-space: normal schlägt die Legacy-Mobilregel .table td { nowrap } (app.css) */
  .form-rows tbody td { display: block; border: 0; padding: 0; flex: 1 1 40%; min-width: 0; white-space: normal; }
  .form-rows tbody td.stmt-cell--full { flex: 1 1 100%; }
  .form-rows tbody td.stmt-cell--del { flex: 0 0 auto; margin-left: auto; align-self: flex-end; padding-bottom: 8px; }
  /* Auswahl-Checkbox behält ihre Breite, der Titel daneben nimmt den Rest —
     zusammen bilden sie die Kopfzeile der gestapelten Zeile (Widerspruch-Panel). */
  .form-rows tbody td.stmt-cell--check { flex: 0 0 auto; }
  .form-rows tbody td.stmt-cell--grow { flex: 1 1 auto; font-weight: 600; color: var(--espresso); }
  .form-rows td[data-label]::before {
    content: attr(data-label); display: block;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--stone-500); margin-bottom: 4px;
    /* V-03: lange Labels dürfen umbrechen, auch wenn die Zelle text-nowrap
       trägt (der Betrag bleibt einzeilig — das ::before ist eine eigene Box). */
    white-space: normal;
  }
  /* U-28: Summenzeile (tfoot) einer gestapelten Positions-Tabelle als
     flache Label→Betrag-Zeile (kein Tabellen-Rest bei display:block). */
  .form-rows tfoot { display: block; }
  /* Padding symmetrisch: die 2px unten ließen die Summenzeile auf der
     Trennlinie kleben (betraf alle form-rows-tfoots — Positionen,
     Abrechnung, Selbstbehalte, Belege zuordnen). */
  .form-rows tfoot tr {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 10px; padding: 12px 2px; border-top: 1px solid var(--hairline-row);
  }
  .form-rows tfoot th { display: block; border: 0; padding: 0; }
  .form-rows tfoot th:empty { display: none; }
  /* BUG-0032-008: dieselbe Rücksetzung für td. Als dieser Block entstand,
     hatten alle form-rows-tfoots nur th-Zellen; Audit A5-19 stellte danach die
     Button- und Wertzellen der Positions-Tabelle auf td um. Ohne Regel bleiben
     dort die Bootstrap-Unterlinie (--bs-table-border-color) und das Zellpolster
     aus app.css stehen — im Flex-Layout der Zeile als Strich in Zellbreite
     sichtbar. Die einzige gewollte Linie ist die border-top der Zeile. */
  .form-rows tfoot td { display: block; border: 0; padding: 0; }
  /* U-27: Infinite-Scroll-/Ende-Zeilen sind keine Datenzeilen — flach ohne
     Rahmen (analog .table-stacked). */
  .form-rows tbody tr.infinite-scroll-trigger,
  .form-rows tbody tr.end-of-list {
    display: block; border: 0; padding: 0.5rem 0;
  }
  .form-rows tbody tr.infinite-scroll-trigger td,
  .form-rows tbody tr.end-of-list td {
    display: block; text-align: center; padding: 0.25rem 0;
  }
}
.stmt-col-member { width: 20%; }
.stmt-col-desc { width: 30%; }
.stmt-col-amount { width: 12%; }
.stmt-col-reason { width: 20%; }
.stmt-col-del { width: 6%; }
/* Selbstbehalt-Spalten: Jahr + Betrag brauchen mehr Platz, sonst schneiden die
   Inputs "2024"/"500,00 €" am rechten Rand ab (bei 1440 gemessen). */
.stmt-col-member-lg { width: 24%; }
.stmt-col-year { width: 16%; }
.stmt-col-amount-lg { width: 24%; }
.stmt-col-note { width: 26%; }
.stmt-col-del-lg { width: 10%; }

/* ===== zuordnung (Welle 2) ===== */
/* Beleg-Zuordnung: Treffer-Markierung passender Beträge in den Selects
   (aus assignment.html-Inline-Styles migriert und tokenisiert) */
.assign-form .receipt-match { color: var(--success); font-weight: 500; }
.assign-form select option.receipt-match { color: var(--success); font-weight: 700; }
/* Nicht wählbare Gruppen (disabled) gedämpft */
.assign-form select optgroup[label*="Nicht eingereicht"],
.assign-form select optgroup[label*="Nach Abrechnungsdatum"] { color: var(--stone-500); }

/* ===== app-modal (Welle 2) ===== */
/* Generisches Modal-Chrome des Design-Systems, extrahiert aus .bv-modal
   (timeline.css, Beleg-Verlauf-Modal). Nutzung: auf .modal-dialog zusätzlich
   .app-modal-dialog, auf .modal-content .app-modal. Bootstrap-Modal-JS
   (data-bs-*) bleibt unverändert. Konsumenten: Timeline-Modal (Belegliste),
   Zahlungs-Modal (Beleg-Detail); weitere Modals folgen in Welle 4. */
.app-modal-dialog { max-width: 560px; }
.app-modal {
  background: var(--milk);
  border: 0;
  border-radius: 18px;
  box-shadow: var(--shadow-2xl);
  overflow: hidden;
}
.app-modal .modal-header {
  padding: 16px 22px;
  background: var(--milk-pure);
  border-bottom: 1px solid var(--stone-200);
}
.app-modal .modal-title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--fs-20);
  color: var(--espresso);
}
.app-modal .modal-body { padding: 16px 22px 20px; }
@media (max-width: 767.98px) {
  .app-modal .modal-body { padding: 14px 16px 18px; }
}

/* ===== zahlungs-modal: sepa-qr-sektion (Welle 2, UX-6) ===== */
/* "Mit Banking-App zahlen" — Collapse-Sektion im Zahlungsformular.
   QR-Inhalt (_payment_qr.html) wird via HTMX in .pay-qr-body geladen. */
.pay-qr {
  border-top: 1px solid var(--hairline-soft);
  margin: 16px 0;
  padding-top: 10px;
}
.pay-qr-toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 0;
  border: 0;
  background: none;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--stone-600);
  cursor: pointer;
}
.pay-qr-toggle:hover { color: var(--espresso); }
.pay-qr-chevron {
  margin-left: auto;
  transition: transform var(--dur-fast) var(--ease-out);
}
.pay-qr-toggle[aria-expanded="true"] .pay-qr-chevron { transform: rotate(180deg); }
.pay-qr-body { padding-top: 12px; }
.pay-qr-img { max-width: 250px; }
.pay-qr-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 14px;
  background: var(--tint-row);
  border: 1px solid var(--hairline-soft);
  border-radius: 9px;
  padding: 10px 14px;
  margin-bottom: 10px;
  font-size: var(--fs-13);
}
.pay-qr-facts dt { font-weight: 500; color: var(--text-secondary); }
.pay-qr-facts dd {
  margin: 0;
  font-weight: 600;
  color: var(--espresso);
  overflow-wrap: anywhere;
}
/* IBAN als <code>: Bootstrap-Pink neutralisieren, Ton des Design-Systems */
.pay-qr-facts code { color: var(--stone-600); font-size: var(--fs-12); }
.pay-qr-facts .pay-qr-amount { color: var(--success); }
.pay-qr-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: var(--fs-12);
  color: var(--text-secondary);
  text-align: center;
  margin: 0;
}
.pay-qr-hint svg { flex: none; }

/* ===== confirm-delete (Welle 2, AC-24) ===== */
/* Gemeinsames Lösch-Bestätigungs-Pattern (templates/confirm_delete_base.html):
   zentrierte detail-card + confirm-facts + Aktionen. Die Überschrift trägt
   kein Icon (BUG-0395), wie alle Modal-Überschriften im App-Bereich. */
.confirm-delete { max-width: 560px; margin: 0 auto; }
.confirm-delete-title {
  display: flex;
  align-items: center;
  gap: 8px;
}
.confirm-delete-lead {
  font-size: var(--fs-14);
  color: var(--stone-600);
  margin-bottom: 14px;
}
.confirm-facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 14px;
  background: var(--tint-row);
  border: 1px solid var(--hairline-soft);
  border-radius: 9px;
  padding: 10px 14px;
  margin-bottom: 12px;
  font-size: var(--fs-13);
}
.confirm-facts dt { font-weight: 500; color: var(--text-secondary); }
.confirm-facts dd {
  margin: 0;
  font-weight: 600;
  color: var(--espresso);
  overflow-wrap: anywhere;
}
.confirm-delete-actions {
  display: flex;
  justify-content: space-between;
  gap: 10px;
}

/* ===== dokument-upload (Welle 2, AC-25) ===== */
/* Ergänzungen zur .upload-dropzone (Welle 2a): klickbare Fläche,
   Auswahl-Zeile und Hinweis-Text der Upload-Seite. */
.upload-dropzone-clickable { cursor: pointer; }
.upload-selected {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--tint-row);
  border: 1px solid var(--hairline-soft);
  border-radius: 9px;
  padding: 10px 14px;
  color: var(--stone-500);
}
.upload-selected-main { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.upload-selected-main strong { color: var(--espresso); }
.upload-note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  font-size: var(--fs-13);
  color: var(--text-secondary);
  margin: 12px 0 0;
}
.upload-note svg { flex: none; margin-top: 2px; }

/* ===== dashboard (Welle 3) ===== */
/* Scroll-Deckel des Aktivitätsfeeds (ersetzt Inline-Style) */
.activity-scroll { max-height: 400px; overflow-y: auto; }
/* Chart.js-Canvas des Gesundheitskosten-Graphen (ersetzt Inline-Style) */
.health-cost-canvas { min-height: 300px; max-height: 500px; }

/* Listen-Tabellen ohne mobiles Stacking (Monatsübersicht, Konten-Ausgleich,
   Buchungen): scrollen horizontal (.table-responsive) — der Desktop-Look der
   .list-table gilt darum auch unterhalb von 769px (gleicher Ansatz wie
   .contrib-table bei den Beiträgen). */
@media (max-width: 767.98px) {
  .list-table--scroll thead th {
    text-align: left; padding: 10px 16px;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.08em;
    text-transform: uppercase; color: var(--stone-500);
    background: var(--stone-100); border-bottom: 1px solid var(--stone-200);
    white-space: nowrap;
  }
  .list-table--scroll thead th.text-end { text-align: right; }
  .list-table--scroll tbody td {
    padding: 12px 16px;
    font-size: var(--fs-13); color: var(--stone-600);
    border-top: 1px solid var(--hairline-row); vertical-align: middle;
  }
  .list-table--scroll tbody tr:first-child td { border-top: 0; }
}
/* Summenzeile (tfoot) in Listen-Tabellen — Fix 4.5a: kein Beige-Fill hinter
   der Summenzeile ("Aktueller Stand", settlement-entries); die Zeile trägt
   Bedeutung über Fettung + Trennlinie, nicht über eine Fläche. */
.list-table tfoot th, .list-table tfoot td {
  padding: 12px 16px; font-size: var(--fs-13); font-weight: 700;
  color: var(--espresso); text-align: left;
  border-top: 1px solid var(--stone-200);
}
.list-table tfoot th.text-end, .list-table tfoot td.text-end { text-align: right; }

/* ===== globale-suche (Welle 2, AC-27) ===== */
/* Ergebnis-Gruppen sind detail-cards mit link-rows; darunter der
   "Alle X anzeigen"-Link bzw. statischer Hinweis (Mitglieder). */
.search-more {
  display: inline-block;
  margin-top: 10px;
  font-size: var(--fs-13);
  font-weight: 600;
  color: var(--accent-dark);
  text-decoration: none;
}
.search-more:hover { color: var(--accent); }
.search-more.is-static { color: var(--text-secondary); font-weight: 500; }
.search-reset { color: var(--text-secondary); text-decoration: none; }
.search-reset:hover { color: var(--espresso); }

/* ===== filter-actions (V-08): Aktionszeile in Filter-Bars ===== */
/* Desktop: nebeneinander (Bootstrap align-items-* auf dem Wrapper bleibt
   erhalten). Mobil füllt die Hauptaktion die Breite statt klein linksbündig zu
   „schweben". EIN Fix für alle Filter-Bars.

   BUG-0026: In den sieben Listen steht hier „Filter anwenden" (nur mobil) und
   daneben „Zurücksetzen" als Textlink. Der Spinner ist aus dieser Zeile
   ausgezogen (includes/_list_loading.html) — er gehört zur Liste. Auf den
   Flächen ausserhalb des Listenstandards (Dashboard, Gebührenordnung,
   Positionen-Werkzeug) stehen weiterhin zwei app-btn nebeneinander.

   Deshalb bleibt die Grundregel unverändert: kein `align-items` (die
   Templates setzen es als Utility, und eine Regel hier gewänne gegen
   Bootstrap) und 8px Abstand. Nur wo ein Textlink neben einem Knopf steht,
   braucht es mehr Luft — das trifft genau die Listen des Standards. */
.filter-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.filter-actions:has(.filter-reset) { gap: 14px; }
@media (max-width: 575.98px) {
  .filter-actions > .app-btn { flex: 1 1 0; justify-content: center; }
  .filter-actions > .htmx-indicator { flex-basis: 100%; }
}

/* ===== app-stat (Welle 3, AC-30) ===== */
/* FEATURE-0336: aktuelle Bestandszahlen vor dem Jahresfilter. */
.detail-head:has(+ .dash-current) { margin-bottom: 8px; }
.dash-current { margin-bottom: 16px; padding: 0; }
/* Zwei Spalten erst ab `xl` (BUG-0421). Die Kacheln tragen ab `md` die
   Einzelposten-Tabelle mit fünf Spalten, und deren schmalste Form ist nicht
   verhandelbar: Datum, Belegbetrag, Erstattungssatz und Ergebnis brechen nicht
   um (ein Geldbetrag darf nicht in zwei Zeilen zerfallen). Gemessen in der
   Kachel „Noch nicht eingereicht" braucht sie 403 px mit gewöhnlichen
   vierstelligen Beträgen und 461 px mit dem siebenstelligen aus dem Ticket.

   Zwischen `md` und `xl` lief der Umbruchpunkt der Tabelle dem des Rasters
   entgegen: Ab 768 px erschien die Tabelle, und im selben Moment halbierte
   das Raster die Kachel — sie bot 310 px statt der 688 px, die sie eine
   Pixelbreite darunter hatte. Die Tabelle stand damit über ihrer Kachel und
   über der Seite (gemessen 110 px Seitenlauf bei 768 px, 44 px bei 900 px,
   0 px bei 1086 px erst durch Zufall: dort trafen sich 461 px Bedarf und
   461 px Angebot auf den Pixel genau).

   Ab 1200 px bietet die halbe Kachel 528 px und damit Luft. Darunter steht
   eine Spalte — dieselbe Form, die unter 768 px ohnehin gilt. `xl` statt
   eines gemessenen Zwischenwerts, damit der Punkt in der Bootstrap-Leiter
   liegt (.claude/rules/frontend-design.md §7). */
.dash-current-grid { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 1200px) {
  .dash-current-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.dash-current-card {
  min-width: 0; padding: 22px 24px; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); background: white;
}
.dash-current-split { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.dash-current-metric { display: flex; flex-direction: column; min-width: 0; }
.dash-current-label { display: flex; align-items: center; gap: 7px; position: relative; }
.dash-current-help {
  flex: none; display: inline-grid; place-items: center;
  min-width: 24px; min-height: 24px;
  border: 0; background: transparent; color: var(--accent-dark);
  font-size: var(--fs-11); line-height: 1; padding: 0; border-radius: var(--radius-full);
}
.dash-current-help:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.dash-current-tooltip {
  position: absolute; z-index: 10; top: calc(100% + 6px); left: 0;
  width: min(300px, 80vw); padding: 10px 12px; background: var(--espresso);
  color: white; border-radius: var(--radius-sm); font-size: var(--fs-13);
  line-height: 1.45; box-shadow: 0 6px 20px rgb(0 0 0 / 15%);
}
.dash-current-tooltip[hidden] { display: none; }
.dash-current-value {
  margin: 14px 0 0; font-family: var(--font-display); font-size: var(--fs-26);
  font-weight: 700; line-height: 1.15; color: var(--espresso);
  font-variant-numeric: tabular-nums; white-space: nowrap;
  min-width: 0; overflow-x: auto; overflow-y: hidden;
}
.dash-current-metric .dash-current-value { margin-top: auto; padding-top: 14px; }
.dash-current-secondary .dash-current-tooltip { left: auto; right: 0; }
/* Zwei Spalten, solange zwei Spalten passen. Fest gesetzt blieben auf 320 px
   je 115 px für einen Betrag, der 132 px braucht: „3.033,27 €" reichte bis
   x=300, die Innenkante der Karte lag bei x=283, und das `€` war von der
   Rundung angeschnitten. `overflow-x: auto` am Wert fing das nicht auf — es
   ist die Notluke für ungewöhnlich große Beträge und soll für eine
   vierstellige Summe gar nicht erst greifen.

   `auto-fit` statt eines weiteren Umbruchpunkts: Die Spaltenzahl folgt dem
   vorhandenen Platz, nicht einer Fensterbreite, die jemand pflegen muss.
   Unter 140 px + 16 px Zwischenraum je Spalte stapelt das Raster von selbst —
   auf 320 px eine Spalte von 246 px, ab 390 px wieder zwei von je 150 px. Die
   140 px sind gemessen: der breiteste gewöhnliche Wert (132 px bei --fs-26)
   plus Luft. `min(100%, …)` hält die Spalte in einem noch schmaleren Kasten
   innerhalb seiner Grenzen. */
.dash-current-pair {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 140px), 1fr));
}
.dash-current-caption { margin: 4px 0 0; color: var(--stone-500); font-size: var(--fs-13); }
@media (max-width: 767.98px) {
  .dash-current-card { padding: 18px 20px; }
}
/* StatCard nach docs/design-system/ui_kits/dashboard/kit.css, gemäß
   Entscheidung B: Kategorie über 7px-Dot vor dem Label — KEIN farbiger
   Left-Border. Wert in Comfortaa (--font-display). Modifier setzen nur --dot.
   Radius/Rahmen folgen dem App-Karten-Idiom (detail-card/list-surface). */
.app-stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
@media (max-width: 1100px) { .app-stat-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 575.98px) { .app-stat-grid { grid-template-columns: 1fr; } }
.app-stat {
  --dot: var(--accent);
  display: flex; flex-direction: column;
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); padding: 18px 20px;
}
.app-stat.is-success { --dot: var(--success-light); }
.app-stat.is-warning { --dot: var(--warning); }
.app-stat.is-info    { --dot: var(--info); }
.app-stat.is-danger  { --dot: var(--danger); }
.app-stat.is-muted   { --dot: var(--stone-300); }
.app-stat-label, .dash-current-label h3, .dash-current-label h4 {
  display: inline-flex; align-items: center; gap: 7px;
  margin: 0; font-family: inherit; line-height: inherit;
  font-size: var(--fs-11); font-weight: 600; color: var(--stone-500);
  text-transform: uppercase; letter-spacing: 1.2px;
}
.app-stat-label::before {
  content: ''; width: 7px; height: 7px; border-radius: var(--radius-full);
  background: var(--dot); flex: none;
}
.app-stat-value {
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-26);
  color: var(--espresso); margin-top: 8px; line-height: 1.15;
  overflow-wrap: anywhere;
}
/* Beisatz neben der Leitzahl (B3: „90,00 € (10,8 %)", FEATURE-0157). */
.app-stat-beisatz {
  margin-left: 8px; font-family: var(--font-sans); font-size: var(--fs-13);
  font-weight: 600; color: var(--stone-500);
}
.app-stat-sub { font-size: var(--fs-13); font-weight: 600; color: var(--stone-500); margin-top: 4px; }
.app-stat-detail { font-size: var(--fs-12); color: var(--text-secondary); margin-top: 2px; }
.app-stat-trend { margin-top: 8px; }
.app-stat-action {
  display: inline-flex; align-items: center; gap: 5px;
  margin-top: auto; padding-top: 10px; align-self: flex-start;
  font-size: var(--fs-13); font-weight: 600; color: var(--accent-dark); text-decoration: none;
}
.app-stat-action:hover { color: var(--accent); }
/* Kompakte Variante (z.B. Ø-Werte im Cashflow-Simulator) */
.app-stat--compact { padding: 12px 14px; }
.app-stat--compact .app-stat-value { font-size: var(--fs-20); margin-top: 5px; }
/* Fortschrittsbalken in Stat-Karten (Selbstbehalt): schlank + tokenisiert,
   Bootstrap-.progress-Mechanik (aria) bleibt */
.app-stat .progress {
  height: 8px; border-radius: var(--radius-full); background: var(--stone-100);
}
/* Träger-Spalten in der Bearbeitungszeit-Kachel (FEATURE-0158, Baustein B4).
   Eine Spalte je Kostenträger mit eigener Ampel (F5): Die Beihilfe ist von Haus
   aus langsamer als die PKV, dieselbe Schwelle hätte sie dauerhaft rot gefärbt.
   Der Punkt sitzt am Trägernamen und nicht am Kachel-Label, weil zwei Träger
   zwei Farben brauchen; bei nur einer Spalte trägt ihn wie überall sonst das
   Label der Kachel. */
.app-stat-traeger { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 575.98px) { .app-stat-traeger { grid-template-columns: 1fr; } }
.app-stat-traeger .app-stat-value { font-size: var(--fs-20); }
.app-stat-traeger-name {
  --dot: var(--accent);
  display: inline-flex; align-items: center; gap: 7px; margin-top: 10px;
  font-size: var(--fs-12); font-weight: 700; color: var(--espresso);
}
.app-stat-traeger-name::before {
  content: ''; width: 7px; height: 7px; border-radius: var(--radius-full);
  background: var(--dot); flex: none;
}
.app-stat-traeger-name.is-success { --dot: var(--success-light); }
.app-stat-traeger-name.is-warning { --dot: var(--warning); }
.app-stat-traeger-name.is-danger  { --dot: var(--danger); }
.app-stat-traeger-name.is-muted   { --dot: var(--stone-300); }

/* Einreichungs-Entscheidung: Ampel und Zeile je Person (FEATURE-0159, B6).
   Der Punkt sitzt am Zustand und nicht am Kachel-Label — bei „Alle Personen"
   traegt jede Person ihre eigene Ampel, und der Kopf traegt gar keine (F20).
   Bauart wie .app-stat-traeger-name: ein ::before-Punkt ueber --dot, damit
   beide Familien dieselbe Ampel zeigen und nicht zwei aehnliche. */
.app-stat-ampel {
  --dot: var(--accent);
  display: inline-flex; align-items: baseline; gap: 7px;
}
.app-stat-ampel::before {
  content: ''; width: 7px; height: 7px; border-radius: var(--radius-full);
  background: var(--dot); flex: none; align-self: center;
}
.app-stat-ampel.is-success { --dot: var(--success-light); }
.app-stat-ampel.is-warning { --dot: var(--warning); }
.app-stat-ampel.is-danger  { --dot: var(--danger); }
.app-stat-person {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 6px 0; border-top: 1px solid var(--hairline-row);
  font-size: var(--fs-12); color: var(--text-secondary);
}
.app-stat-person:first-child { border-top: 0; }
.app-stat-person-name { font-weight: 700; color: var(--espresso); flex: none; }
.app-stat-person-wert { text-align: right; }

/* Personen-Block im Selbstbehalt-Widget */
.app-stat-row { padding: 9px 0; border-top: 1px solid var(--hairline-row); }
.app-stat-row:first-child { border-top: 0; padding-top: 12px; }
.app-stat-row-name { font-size: var(--fs-13); font-weight: 700; color: var(--espresso); margin-bottom: 6px; }

/* ===== auswertung (FEATURE-0157) ===== */
/* Vier Familien, die mit der Auswertung dazugekommen sind: Aufschlüsselung je
   Person, Träger-Zeilen im Beleg-Status, Linkzeile „Weitere Übersichten" und
   die reservierten Höhen der nachgeladenen Bausteine. */

/* Aufschlüsselung je Person (FEATURE-0157, Entscheidung E4).
   Ein Schalter je Kachel klappt eine Zeile je Person auf; das Muster ist in
   dashboard/includes/_je_person.html einmal gebaut und wird von mehreren
   Kacheln eingebunden. Der Chevron dreht sich über [aria-expanded], nicht
   über eine zweite Klasse — ein Zustand, eine Quelle. */
.app-stat-toggle {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 8px; padding: 0; border: 0; background: none;
  font-size: var(--fs-12); font-weight: 600; color: var(--accent-dark);
}
.app-stat-toggle:hover { color: var(--accent); }
.app-stat-toggle svg { transition: transform var(--dur-fast) var(--ease-out); }
.app-stat-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.app-stat-persons {
  width: 100%; margin-top: 6px;
  font-size: var(--fs-12); color: var(--text-secondary);
  border-collapse: collapse;
}
.app-stat-persons th,
.app-stat-persons td { padding: 4px 0; text-align: right; font-weight: 400; }
.app-stat-persons th:first-child,
.app-stat-persons td:first-child { text-align: left; }
.app-stat-persons thead th {
  font-size: var(--fs-11); font-weight: 600; color: var(--stone-500);
  border-bottom: 1px solid var(--hairline-row);
}
.app-stat-persons tbody th { font-weight: 700; color: var(--espresso); }
.app-stat-persons tbody td { font-variant-numeric: tabular-nums; }

/* Träger-Zeilen im Beleg-Status (FEATURE-0157, Entscheidung E3).
   Ab md eine Tabelle mit einer Spalte je Stufe, darunter ein Aufklapper je
   Träger — fünf Stufen mal Anzahl und Summe passen auf 375px nicht in eine
   Zeile. */
.dash-traeger-table { width: 100%; margin-top: 4px; font-size: var(--fs-13); border-collapse: collapse; }
.dash-traeger-table th,
.dash-traeger-table td { padding: 6px 0; text-align: right; font-weight: 400; }
.dash-traeger-table th:first-child,
.dash-traeger-table td:first-child { text-align: left; }
.dash-traeger-table thead th {
  font-size: var(--fs-11); font-weight: 600; color: var(--stone-500);
  border-bottom: 1px solid var(--hairline-row);
}
.dash-traeger-table tbody th { font-weight: 700; color: var(--espresso); }
.dash-traeger-table tbody td { font-variant-numeric: tabular-nums; color: var(--espresso); }
.dash-traeger-toggle {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 0; border: 0; border-top: 1px solid var(--hairline-row);
  background: none; font-size: var(--fs-13);
}
.dash-traeger-name { font-weight: 700; color: var(--espresso); }
.dash-traeger-anzahlen {
  margin-left: auto; color: var(--stone-500); font-variant-numeric: tabular-nums;
}
.dash-traeger-toggle svg { transition: transform var(--dur-fast) var(--ease-out); }
.dash-traeger-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* Einzelposten der Finanzstand-Kacheln (FEATURE-0339).
   Die Zeilenoptik erbt `.dash-traeger-table`: erste Spalte links, Beträge
   rechts mit tabular-nums, kleine Schrift, Haarlinie zwischen den Zeilen. Neu
   nötig ist wenig — ein Abstand nach oben, der Gruppenkopf und die gestapelte
   Form unter md. Der Schalter kommt aus `.app-stat-toggle` und bringt seine
   Chevron-Drehung mit; hier steht dazu nichts. */
/* Der Schalter steht rechts im Kachelfuß (Wireframe). `.app-stat-toggle` ist
   inline-flex; ein `margin-left: auto` bleibt an einem Inline-Kasten wirkungslos.
   Er wird hier deshalb zum Blockkasten mit eigener Breite. */
.dash-current-card > .app-stat-toggle {
  display: flex; width: fit-content; margin-left: auto;
}
.dash-posten { margin-top: 10px; border-top: 1px solid var(--hairline-row); padding-top: 4px; }
.dash-posten-hinweis {
  margin: 8px 0 2px; font-size: var(--fs-12); color: var(--stone-500); line-height: 1.45;
}
.dash-posten-table tbody + tbody tr:first-child > * { padding-top: 12px; }
/* `width: 1%` schrumpft die Datumsspalte auf ihren Inhalt und gibt den Rest der
   Textspalte — derselbe Griff wie `.line-items-table td.col-shrink` weiter oben.
   Ohne ihn verteilt die automatische Tabellenbreite den freien Platz auf beide
   Spalten, und der Text rutscht vom Datum weg: gemessen bei 638 px Kartenbreite
   238 px Datumsspalte statt 87 px, sobald die Texte kurz sind (Kachel 4 zeigt
   dort nur „Beihilfe" oder „PKV"). Die Zeile liest sich dann nicht mehr von
   links nach rechts. `white-space: nowrap` verhindert weiterhin, dass das Datum
   umbricht.

   Der Wert gilt nur in der Tabelle, aus demselben Grund wie das Polster eine
   Regel weiter unten: `width: 1%` ist ein Tabellengriff und heißt dort „so
   breit wie der Inhalt". Dieselbe Klasse sitzt aber auch am Span des
   gestapelten Blocks, und in einem `display: flex`-Absatz heißt derselbe Wert
   wörtlich ein Prozent der Zeilenbreite. Der Kasten des Datums maß damit
   3,16 px bei 390 px Fensterbreite und 2,45 px bei 320 px, während sein Text
   83,09 px breit gemalt wurde — der Aussteller lief mitten durch das Datum
   („1Paradies Apotheke" statt „16.04.2020 Paradies Apotheke"). Die Begrenzung
   auf die Tabelle statt einer Gegenregel für die gestapelte Form: Der Griff
   gehört dorthin, wo er etwas bedeutet, und die nächste Form, die dazukommt,
   erbt ihn dann nicht. Farbe, Ziffernbreite und `nowrap` gelten in beiden
   Formen und bleiben deshalb an der Klasse. */
.dash-posten-table .dash-posten-datum { width: 1%; }
.dash-posten-datum {
  color: var(--stone-500); white-space: nowrap; font-variant-numeric: tabular-nums;
}
/* Die Lücke zwischen den Spalten. `.dash-traeger-table td` setzt
   `padding: 6px 0` — waagerecht null. Zusammen mit `width: 1%` schrumpfte die
   Datumsspalte damit auf exakt ihre Textbreite, und die Zeile las sich als
   „17.09.2024CMP Apotheke"; zwischen Belegbetrag und Erstattungssatz stand
   dasselbe Problem eine Spalte weiter („1.234.567,89 € 50 %", gemessen 5 px
   bei 1440 px und 0 px bei 1086 px). Eine Regel für alle Zellen statt einer
   je Spalte: Die nächste Spalte, die dazukommt, hat ihr Polster dann von
   selbst. Die letzte Zelle behält ihre rechte Kante, sonst rückte die
   Wertspalte vom Tabellenrand ab. Die Auswahlkette braucht Klasse plus
   Element, weil `.dash-traeger-table td` genauso schwer wiegt und später
   käme. Nur in der Tabelle: In der gestapelten Form unter md sind die
   Zellen Inline-Kästen, dort trennt bereits der Wortzwischenraum. */
.dash-posten-table td { padding-right: 10px; }
.dash-posten-table td:last-child { padding-right: 0; }
/* `.dash-traeger-table` stellt alles rechts außer der ersten Spalte. Hier ist
   die erste Spalte das Datum und die zweite der Aussteller; beide gehören nach
   links, sonst driftet der Name an die Beträge heran und die Zeile liest sich
   nicht mehr von links nach rechts. */
/* Die einzige Spur, die schrumpfen darf, darf es auch bis unter ein Wort
   (BUG-0421). Die vier Zahlenspalten brechen nicht um, also entscheidet die
   Textspalte über die schmalste Tabelle — und ohne diese Regel ist ihre
   Untergrenze das längste Wort des Ausstellers („Universitätsklinikum": 140 px
   gemessen). Die Breitengrenze des Rasters eine Datei-Seite weiter oben hält
   die gewöhnlichen Fälle davon fern; diese Regel ist die Zusage für den
   ungewöhnlichen: ein Aussteller mit einem sehr langen Wort schiebt die
   Tabelle nicht mehr über die Kachel, sondern bricht das Wort.

   `anywhere` und nicht `break-word`: Nur `anywhere` senkt die min-content-Breite
   und damit das, was die Tabellenbreite bestimmt. `break-word` bricht zwar
   ebenfalls, rechnet die Spalte aber weiter mit dem ganzen Wort — der Überlauf
   bliebe. */
.dash-posten-table .dash-posten-text {
  text-align: left; padding-right: 12px; overflow-wrap: anywhere;
}
.dash-posten-text a { color: var(--espresso); text-decoration: none; }
.dash-posten-text a:hover { color: var(--accent-dark); text-decoration: underline; }
.dash-posten-wert { font-variant-numeric: tabular-nums; white-space: nowrap; }
.dash-posten-gruppenkopf th,
.dash-posten-gruppenkopf td { font-weight: 700; color: var(--espresso); }
.dash-posten-zusatz {
  display: block; margin: 2px 0 0; font-size: var(--fs-11); color: var(--stone-500);
}
/* Die Fettung entscheidet hier, was wie gelesen wird, und `.dash-traeger-table`
   bringt für `th` bereits eigene Regeln mit. Beide Auswahlketten sind deshalb
   so lang wie die geerbten: Die Abzugszeile ist eine gewöhnliche Zeile und darf
   nicht wie ein Gruppenkopf aussehen, die Schlusszeile ist das Ergebnis der
   Rechnung und muss sich von den Gruppensummen darüber abheben. */
.dash-posten-table tbody th.dash-posten-text,
.dash-posten-mobil .dash-posten-abzug { font-weight: 500; color: var(--stone-600); }
.dash-posten-table tbody .dash-posten-gruppenkopf th { font-weight: 700; color: var(--espresso); }
.dash-posten-table tfoot .dash-posten-schluss > * {
  border-top: 1px solid var(--hairline-soft); padding-top: 8px;
  font-weight: 700; color: var(--espresso);
}
/* Unter md dieselben Werte gestapelt: Datum und Aussteller oben, Betrag, Satz
   und Ergebnis darunter. Fünf Spalten passen auf 320px nicht nebeneinander,
   und ein waagerecht verschiebbarer Bereich in einer Karte wird übersehen. */
.dash-posten-mobil { font-size: var(--fs-13); color: var(--espresso); }
.dash-posten-mobil .dash-posten-gruppenkopf {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 12px 0 2px; font-weight: 700;
}
.dash-posten-mobil-zeile { padding: 6px 0; border-top: 1px solid var(--hairline-row); }
.dash-posten-mobil-kopf {
  display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 0; min-width: 0;
}
.dash-posten-mobil-kopf a { color: var(--espresso); text-decoration: none; }
.dash-posten-mobil-werte {
  display: flex; justify-content: space-between; gap: 12px;
  margin: 2px 0 0; color: var(--stone-600); min-width: 0;
}
.dash-posten-mobil .dash-posten-zusatz { margin-top: 2px; }
/* Der Trennstrich der Schlusszeile gehört mobil an den Absatz und nicht an
   seine Kinder. In der Tabelle läuft er durch benachbarte Zellen und ergibt
   eine Linie; hier ist die Schlusszeile ein Flex-Absatz, und `> *` sind zwei
   Spans an entgegengesetzten Enden — der Strich zerfiel in zwei Segmente mit
   einer Lücke dazwischen. Fettung und Farbe bringt
   `.dash-posten-mobil .dash-posten-gruppenkopf` bereits mit; die Schlusszeile
   trägt beide Klassen. */
.dash-posten-mobil .dash-posten-schluss {
  border-top: 1px solid var(--hairline-soft); padding-top: 8px;
}

/* Linkzeile „Weitere Übersichten" (FEATURE-0157). */
.dash-weitere {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
  margin-bottom: 24px; font-size: var(--fs-13);
}
.dash-weitere-label { font-weight: 700; color: var(--espresso); }
.dash-weitere-trenner { color: var(--stone-300); }
.dash-weitere a { color: var(--accent-dark); text-decoration: none; }
.dash-weitere a:hover { color: var(--accent); text-decoration: underline; }

/* Reservierte Höhe der per HTMX nachgeladenen Bausteine (AC-F-08).
   Ohne sie springt die Seite, sobald Graph und Simulator eintreffen. */
.dash-platzhalter { display: flex; align-items: center; justify-content: center; }
.dash-platzhalter--graph { min-height: 420px; }
.dash-platzhalter--simulator { min-height: 360px; }

/* ===== rowlist-generalisierung (Welle 3, AC-31) ===== */
/* .link-rows/.link-row (FEATURE-0133/Welle 2) IST die generische RowList —
   Dashboard- (Aktivitätsfeed) und Todo-Listen verwenden sie wieder.
   Neu hier nur, was fehlte: führendes Icon-Rondell und nicht-klickbare Zeile. */
.link-row-icon {
  width: 30px; height: 30px; flex: none; border-radius: var(--radius-full);
  background: var(--accent-muted); color: var(--accent-dark);
  display: inline-flex; align-items: center; justify-content: center;
}
div.link-row { cursor: default; }

/* app-range (Welle 3, AC-66) ist mit BUG-0256 nach cappuccino.css gewandert:
   base_public.html laedt dieses Blatt nicht, der oeffentliche
   Cashflow-Simulator-Slider blieb deshalb Bootstrap-Blau. cappuccino.css
   laden beide Bases. */

/* ===== todo-hub (Welle 3, AC-34) ===== */
/* Phasen-Sektion: padding:0 neutralisiert das globale Marketing-`section`-
   Padding aus cappuccino.css (8rem) — Ursache der riesigen Leerräume
   zwischen ERFASSEN/EINREICHEN/ABRECHNEN/PRÜFEN im Alt-Layout. */
.todo-phase { padding: 0; margin-bottom: 26px; }
.todo-phase-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.todo-phase-head::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--hairline); }
.todo-phase-title {
  margin: 0; font-size: var(--fs-11); font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--stone-500);
}

/* Kategorie-Karte: Bootstrap-Accordion im detail-card-Idiom */
.todo-acc {
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg); overflow: hidden;
}
.todo-acc + .todo-acc { margin-top: 10px; }
.todo-acc .accordion-button {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; background: white; color: inherit; box-shadow: none;
}
.todo-acc .accordion-button:not(.collapsed) { background: white; color: inherit; box-shadow: none; }
.todo-acc .accordion-button:focus-visible { box-shadow: 0 0 0 3px rgba(42, 157, 143, 0.25); }
.todo-acc-main { flex: 1 1 auto; min-width: 0; }
.todo-acc-title { font-family: var(--font-display); font-size: var(--fs-14); font-weight: 600; color: var(--espresso); }
.todo-acc-sub { font-size: var(--fs-12); font-weight: 500; color: var(--stone-500); margin-top: 1px; }
.todo-acc-count {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  min-width: 26px; padding: 3px 9px; border-radius: var(--radius-full);
  font-size: var(--fs-12); font-weight: 700;
  background: var(--tasse-muted); color: var(--tasse);
}
.todo-acc-done { color: var(--accent); flex: none; }
.todo-acc .accordion-body { padding: 0; }

/* Erledigte Kategorie: ruhig, nicht aufklappbar */
.todo-acc.is-complete .accordion-button { cursor: default; pointer-events: none; }
.todo-acc.is-complete .accordion-button::after { display: none; }
.todo-acc.is-complete .todo-acc-sub { color: var(--accent-dark); }
.todo-acc.is-complete .link-row-icon { background: var(--success-muted); color: var(--success); }

/* Erfolgs-Zustand: alle Aufgaben erledigt */
.todo-all-done { text-align: center; padding: 32px 20px; color: var(--accent-dark); }
.todo-all-done h2 { font-family: var(--font-display); font-size: var(--fs-20); color: var(--espresso); margin: 12px 0 4px; }
.todo-all-done p { margin: 0; color: var(--stone-500); font-size: var(--fs-13); }

/* Werkzeugleiste im Kategorie-Body (Mehrfachauswahl "Belege einreichen") */
.todo-list-toolbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--hairline-soft);
}
/* Zwei Schalter in einer Leiste (Beleg-Auswahl der Einreichung): die 8px des
   Basis-Idioms sind für zwei Labels zu eng. Schmale Viewports brechen die
   zweite Checkbox weiterhin um (flex-wrap). */
.todo-list-toolbar--dual { column-gap: 18px; }
/* Deaktivierter Zustand für <a class="app-btn"> (JS toggelt .disabled) */
.app-btn.disabled { pointer-events: none; opacity: 0.55; }

/* Hinweis-/Link-Zeile im Kategorie-Body (z.B. Verweis auf den Prüf-Hub) */
.todo-list-note {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  flex-wrap: wrap; padding: 10px 16px; border-bottom: 1px solid var(--hairline-soft);
  font-size: var(--fs-13); color: var(--stone-500);
}

/* HTMX-Slot fürs Widerspruch-Panel: nur mit Inhalt Platz einnehmen */
.todo-objection-slot:not(:empty) {
  padding: 12px 16px; border-bottom: 1px solid var(--hairline-soft);
}

/* Fälligkeits-Zustände "Zu zahlen" (semantisch, muted statt Bootstrap-Solid) */
.list-table tbody tr.row-overdue td { background: var(--danger-muted); }
.list-table tbody tr.row-due-soon td { background: var(--warning-muted); }
.due-flag-overdue { color: var(--danger); }
.due-flag-soon { color: var(--warning); }

/* Prüf-Ansicht (todo/review): Split-View mit PDF links */
.review-doc-card { position: sticky; top: 80px; }
@media (max-width: 991.98px) { .review-doc-card { position: static; } }
.review-doc-card .pdf-viewer {
  height: calc(100vh - 220px); min-height: 480px;
}
.review-actions {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
}
/* FEATURE-0337: „Zur Abrechnung" und „Widerspruch erledigt" nebeneinander */
.review-disputed-actions {
  display: inline-flex; align-items: center; justify-content: flex-end;
  gap: 8px; flex-wrap: wrap;
}
.review-disputed-actions form { margin: 0; }

/* FEATURE-0337: Nachfrage „Ersetzt/Ergänzt" unter der Belegauswahl */
.assign-nachfrage {
  margin-top: 12px; padding: 12px 14px;
  border: 1px solid var(--hairline); border-radius: var(--radius-lg);
}
.assign-nachfrage[hidden], .assign-nachfrage [hidden] { display: none; }
.assign-nachfrage-frage {
  float: none; width: auto; margin: 0 0 6px;
  font-size: inherit; font-weight: 600;
}
.assign-nachfrage-ersetzt { margin-top: 10px; }

/* ===== settings (Welle 4) ===== */
/* Settings-Hub: Karten-Grid der Einstellungsbereiche (settings/index.html).
   Surface im detail-card-Idiom, Icon-Rondell analog .link-row-icon. */
.hub-card {
  display: flex; align-items: flex-start; gap: 14px;
  height: 100%; padding: 18px;
  background: white; border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  text-decoration: none; color: inherit;
  transition: border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}
.hub-card:hover { border-color: var(--accent); background: var(--tint-row); color: inherit; }
.hub-card-icon {
  width: 40px; height: 40px; flex: none; border-radius: var(--radius-full);
  background: var(--accent-muted); color: var(--accent-dark);
  display: inline-flex; align-items: center; justify-content: center;
}
.hub-card-title {
  display: block; font-size: var(--fs-14); font-weight: 700;
  color: var(--espresso); margin-bottom: 3px;
}
.hub-card-desc { display: block; font-size: var(--fs-13); font-weight: 500; color: var(--stone-500); }

/* app-modal-Ergänzung: Footer-Chrome (die Welle-4-Modals — Mitglieder,
   Bankkonten — haben anders als Timeline/Zahlung einen .modal-footer). */
.app-modal .modal-footer {
  padding: 13px 22px;
  background: var(--milk-pure);
  border-top: 1px solid var(--stone-200);
}

/* ===== settings-storage (Welle 4) ===== */
/* Scroll-Container der Ordner-Auswahl im Folder-Picker-Modal
   (ersetzt Inline-Styles min/max-height + overflow aus storage.html). */
.folder-pick-list {
  min-height: 200px;
  max-height: 400px;
  overflow-y: auto;
}

/* ===== onboarding (Welle 4, AC-40) ===== */
/* todo-acc setzt .accordion-body auf padding:0 (Listen laufen im Todo-Hub
   edge-to-edge) — die Onboarding-Schritte sind Text + CTA und brauchen
   Innenabstand. */
.todo-acc .onboarding-step-content { padding: 14px 16px 16px; }

/* ============== DOKUMENT-BROWSER (Welle 5, UX-7/AC-42) ============== */
/* Fehlende Cloud-Dateien im geteilten Browser-Partial
   (includes/_document_browser_table.html): gedämpfte Danger-Fläche,
   Zeile ist nicht klickbar (ersetzt Bootstrap .table-danger). */
.list-table tr.doc-missing td { background: var(--danger-muted); }
.list-table tr.doc-missing { cursor: not-allowed; }

/* ===== contracts (Welle 5, AC-41) ===== */
/* Markdown-Render-Ziel der KI-Analyse (contract_detail — ersetzt den
   Inline-<style>-Block; Farben tokenisiert). */
.markdown-content h1 { font-size: var(--fs-26); margin-top: 1.5rem; }
.markdown-content h2 { font-size: var(--fs-20); margin-top: 1.25rem; }
.markdown-content h3 { font-size: var(--fs-16); margin-top: 1rem; }
.markdown-content table { width: 100%; margin: 1rem 0; }
.markdown-content table th,
.markdown-content table td {
  border: 1px solid var(--hairline);
  padding: 0.5rem;
}
.markdown-content table th { background-color: var(--milk); }
.markdown-content ul,
.markdown-content ol { margin-left: 1.5rem; }

/* Fortschrittsbalken der Multi-Page-Analyse (_analysis_progress.html —
   ersetzt style="height: 20px"; Balkenfarbe folgt dem Upload-Idiom). */
.analysis-progress-track { height: 20px; }
.analysis-progress-track .progress-bar { background-color: var(--accent); }

/* ===== scanner-fab (Welle 5, AC-43) ===== */
/* Floating Action Button für den Scanner (base.html, mobile-only) —
   1:1 aus dem base.html-Inline-<style> migriert (FEATURE-0035).
   Audit B4/UX4-13: Auf Desktop blendet AUSSCHLIESSLICH die Hilfsklasse
   d-lg-none im Markup (base.html) den Knopf aus — die frühere, ohnehin
   wirkungslose Media-Query (min-width: 992px) ist gestrichen. Wer die
   Breiten-Bedingung ändern will, ändert sie im Markup. */
.scanner-fab {
    position: fixed;
    /* Audit B4C/A4-12: Federung gegen Home-Indicator (unten) und
       Aussparung im Querformat (rechts) — env() ist sonst 0px. */
    bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
    right: calc(2rem + env(safe-area-inset-right, 0px));
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: var(--accent);
    color: white;
    display: flex;
    justify-content: center;
    align-items: center;
    /* Audit B4GL/UX5-10: Espresso statt reinem Schwarz. Der FAB schwebt über
       der Belegliste, nicht im Kamera-UI — die Schwarz-Ausnahme aus
       scanner.css:7 gilt hier nicht. */
    box-shadow: 0 4px 8px rgba(61, 43, 31, 0.2);
    z-index: calc(var(--z-sticky) + 10);
    transition: background-color var(--dur-base) var(--ease-out),
        box-shadow var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out),
        opacity var(--dur-base) var(--ease-out);
    text-decoration: none;
}

.scanner-fab:hover {
    background: var(--accent);
    color: white;
    transform: scale(1.1);
    box-shadow: 0 6px 12px rgba(61, 43, 31, 0.3);
}

/* BUG-0204: Beim Scrollen nach unten ausblenden, beim Hochscrollen wieder
   zeigen — der FAB verdeckte sonst in jeder Scrollposition mobil den
   rechten Rand der Listenzeile (Betrag, Status-Badge). Zustand kommt aus
   scanner-fab-scroll.js (Klasse setzen/entfernen), die Bewegung
   ausschließlich aus dieser Regel: transform/opacity statt
   Layout-Eigenschaften, damit kein Reflow entsteht.
   `visibility` schaltet erst nach derselben Dauer wie die Transition um
   (transition-delay) — erst dann ist der FAB aus dem Tab-Fokus. Nicht
   klickbar ist er schon vorher: `pointer-events` wird nicht transitioniert
   und greift sofort. */
.scanner-fab--hidden {
    opacity: 0;
    transform: translateY(calc(100% + 1rem));
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out),
        visibility 0s var(--dur-base);
    visibility: hidden;
}

/* Audit-Wiederholung A5-27 (app.css): "Bewegung reduzieren" respektieren —
   der FAB springt dann ohne Übergang aus/ein statt zu gleiten. */
@media (prefers-reduced-motion: reduce) {
  .scanner-fab,
  .scanner-fab--hidden {
    transition: none;
  }
}

/* Audit B4C/A4-05 Querformat-Sonderregel: Auf kurzen Viewports (Handy quer,
   844×390) deckt der 60px-FAB überproportional viel Fläche ab und lag auf
   dem Suchfeld der Belegliste — kleiner und dichter in die Ecke. */
@media (max-height: 480px) {
  .scanner-fab {
    width: 48px;
    height: 48px;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    right: calc(1rem + env(safe-area-inset-right, 0px));
  }
}


/* ===== Ausgleichsbuchungen (Design-Konsistenz Batch 1) ===== */
/* Fix 4.5b: Toggle "neutrale Buchungen anzeigen" links über der Tabelle
   (eigene Zeile), damit er dem Erfassen-Button im Kopf nicht in die Quere
   kommt. */
.settlement-toolbar {
  display: flex; align-items: center;
  margin: 4px 0 12px;
}

@media (max-width: 767.98px) {
  /* Kopf-Aktionen: Button + Toggle stapeln statt nebeneinander umzubrechen
     (U-18 lässt nur umbrechen — auf schmalen Viewports wurde der
     "Ausgleichszahlung erfassen"-Button dadurch neben dem Toggle abgeschnitten).
     DOM-Reihenfolge in settlement_entries.html: Button zuerst, Toggle danach. */
  .detail-head-actions.stmt-actions {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }
  .detail-head-actions.stmt-actions .app-btn { justify-content: center; }

  /* Summenzeile ("Aktueller Stand") im selben gestapelten Card-Format wie die
     Einträge darüber statt als unbeschriftete Pills: eigene th[data-label]
     analog zu .form-rows td[data-label], per Spezifität ([data-label]
     zählt als Klasse) höher gewichtet als die generische Flat-Summenzeile aus
     .form-rows (dort für einspaltige Summen wie Positionen/Selbstbehalte). */
  .stmt-table tfoot tr {
    display: flex; flex-wrap: wrap; justify-content: flex-start;
    gap: 10px; padding: 14px 16px 2px;
  }
  .stmt-table tfoot th[colspan] {
    flex: 1 1 100%; text-align: left; padding: 0 0 4px;
  }
  .stmt-table tfoot th[data-label] {
    display: block; flex: 1 1 40%; min-width: 0; text-align: left;
  }
  .stmt-table tfoot th[data-label]::before {
    content: attr(data-label); display: block;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--stone-500); margin-bottom: 4px;
  }
}

/* ===== Beitragstabelle: zweizeiliger Kopf ohne Zwischenlinie (Design-Konsistenz Batch 1) =====
   .list-table thead th setzt border-bottom auf JEDEM th - bei .contrib-table
   trennt das die Versicherungs-Kopfzeile (Reihe 1) sichtbar von der
   Mitglied/Kostenträger-Kopfzeile (Reihe 2), während die rowspan="2"-Zellen
   (Monat/Gesamt) keine solche Linie zeigen. Ergebnis: eine "schwebende",
   nicht bis zum Rand reichende Linie mitten im Kopf. Nur die erste Kopfzeile
   bekommt den Trennstrich entfernt - die zweite (untere) Kopfzeile behält ihn
   als einzige, durchgehende Trennung zum Tabellenkörper. */
.contrib-table thead tr:first-child th:not([rowspan]) { border-bottom: 0; }

/* ===== form-rows direkt in .detail-card (Design-Konsistenz Batch 1) =====
   Die generische .list-surface .form-rows-Regel liefert das
   mobile Innenabstands-Polster (16px) nur für Tabellen unter .list-surface
   (Top-Level-Listenseiten wie bank_accounts.html/member.html). settings/user.html
   zeigt zwei Tabellen als eigene .detail-card-Sections OHNE .detail-card-body-
   Wrapper (die Tabelle sitzt direkt im card, kein Padding-Träger) - auf Mobile
   dadurch ohne jeden horizontalen Abstand ("gequetscht"). .form-rows--incard
   markiert diesen Fall gezielt statt die .list-surface-Regel (mit ihrem
   full-bleed-100vw-Mobile-Verhalten, das in einer .detail-card fehlplatziert
   wäre) zu erweitern. */
@media (max-width: 767.98px) {
  .form-rows--incard.form-rows tbody tr {
    padding-left: 16px; padding-right: 16px;
  }
}

/* ===== Abrechnungsliste: Zuordnungs-Zähler (Design-Konsistenz Batch 2) =====
   Ersetzt die eigene Tabellenspalte "Positionen" (und das kryptische "# 0/2"-
   Badge auf Mobile) durch eine gedämpfte Zeile unter dem Status-Badge. Spart
   auf Desktop eine von zehn Spalten — die Abrechnungstabelle lief mit
   Kostenträger-Spalte sonst über die Viewport-Breite hinaus, wodurch die
   Aktionen-Spalte aus dem sichtbaren Bereich scrollte. */
/* ===== Abrechnungsliste: Absender, Auszahlung, Referenz (BUG-0044) ===== */
/* Kostenträger: Kurzicon plus konkreter Name. Das Icon kommt aus
   payer_badge(variant='icon') und bringt seine eigene Fläche mit — hier steht
   nur, wie beide zueinander liegen. */
.stmt-payer { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.stmt-payer-name {
  font-size: var(--fs-13); font-weight: 600; color: var(--espresso);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Auszahlungsbetrag mit Zahlungspunkt. Der Punkt steht RECHTS vom Betrag und
   bricht nie um: Beide gehören zu einer Aussage, und ein Punkt in der
   nächsten Zeile gehörte optisch zur Zeile darunter. */
.stmt-payout { display: inline-flex; align-items: center; justify-content: flex-end; gap: 7px; }
.stmt-pay-dot { display: inline-flex; align-items: center; flex: none; }

/* Referenz als Tastaturweg zur Detailseite. Sie liest sich wie Text — der
   Zeilenklick ist der übliche Weg, der Link der barrierefreie. Sichtbar wird
   er beim Tabben, und dafür braucht es den Fokusring: In einer Liste aus 25
   gleich aussehenden Zeilen ist er die einzige Ortsangabe. */
.stmt-ref-link { color: var(--espresso); text-decoration: none; }
.stmt-ref-link:hover { color: var(--espresso); }
.stmt-ref-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.stmt-assign-count {
  font-size: var(--fs-11);
  color: var(--text-secondary);
  white-space: nowrap;
}

/* ===== Kostenträger-Wert: Badge + Name (Design-Konsistenz Batch 2) =====
   Gemeinsames Idiom für "Kostenträger" auf Detailseiten (Einreichung,
   Leistungsabrechnung): Payer-Badge und Name des Kostenträgers stehen in einer
   Zeile. Ohne diese Regel bricht der Name mitten im Wort um, weil er als
   Inline-Text direkt hinter dem Badge läuft — der Name rückt jetzt als Ganzes
   in die nächste Zeile, wenn der Platz nicht reicht. */
.payer-value {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.payer-value .payer-badge { flex: none; }
.payer-value-name { min-width: 0; overflow-wrap: anywhere; }

/* Kostenträger-Lead in der Einreichungsliste (BUG-0039): Kurzicon + Name in
   einer Zeile, gebaut wie der Aussteller der Belegliste (.bl-issuer/.bl-name).
   Der Name bekommt dieselbe Gewichtung — er ist die Antwort auf „wer bekommt
   die Einreichung?"; das Icon bleibt schmal und rutscht nicht mit. */
.payer-lead { display: flex; align-items: center; gap: 9px; min-width: 0; }
.payer-lead-name {
  font-size: var(--fs-13); font-weight: 600; color: var(--espresso);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ===== Ausgleichszahlungen: Betragsspalten mobil einzeilig (Design-Konsistenz Batch 2) =====
   Die generische .form-rows-Zelle ist flex: 1 1 40% — Betrag, "Saldo
   Von" und "Saldo Auf" landen dadurch verteilt auf zwei Zeilen und sind als
   zusammengehoerige Groessen nicht mehr lesbar. Als Drittel-Zellen teilen sie
   sich eine Zeile. */
@media (max-width: 767.98px) {
  .form-rows tbody td.stmt-cell--amount {
    flex: 1 1 0;
    min-width: 0;
    text-align: right;
  }
}

/* ===== Zahlungseingang als Punkt plus Name (BUG-0045) =====
   Abgebaut: `.money-hero-status-icon` und die vier Modifier-Regeln
   (`is-partial`/`is-open` x Icon/Label) — Grep: 0 Konsumenten, Abbauregel
   frontend-design.md 6b. Sie waren die zweite Haelfte einer Zuordnung, deren
   erste im Template stand: dort Status → Lucide-Icon, hier Status → Farbe.
   Zwei Haelften an zwei Orten laufen auseinander; genau das war passiert, als
   die Liste mit BUG-0044 auf den Zahlungspunkt umstieg und der Hero seine
   Uhr behielt.

   Jetzt liegt beides in EINER Komponente (`_statement_zahlungsstand.html`),
   und die Farbe kommt ueber `pay-state--*` aus derselben Regel wie der Punkt
   selbst (siehe „ZAHLUNGS-ACHSE" weiter oben). */
.stmt-paystate { display: inline-flex; align-items: center; gap: 7px; }
.stmt-paystate-name { color: inherit; }
/* Der Zahlungsstand ueber den Eingaengen, seit der Kartenkopf sein Badge
   abgegeben hat. */
.pay-state-row { margin-bottom: 12px; font-size: var(--fs-13); font-weight: 600; }

/* ===== Abrechnungs-Positionen: eine Tabelle, ein Raster (BUG-0045) =====
   Vorher: je Mitglied eine Tabelle plus eine Gesamttabelle. Weil jede ihre
   Spaltenbreiten selbst berechnete, standen die Summen nicht unter den
   Betraegen — dagegen half nur `table-layout: fixed` mit handgezaehlten
   Pixelbreiten (116px, 260px) und, weil dieselbe Rechnung mobil nicht
   aufging, eine zweite Ebene aus Padding-Ausnahmen fuer erste und letzte
   Spalte. Rund 90 Zeilen CSS gegen ein Problem, das die Struktur erzeugt hat.

   Mit EINER Tabelle verschwindet der ganze Apparat: Ein Raster richtet alle
   Zeilen aus, Gruppierung und Summen bleiben Tabellensemantik (ein `tbody`
   je Person, `th scope="colgroup"` als Gruppenzeile, `tfoot` fuer Gesamt).
   Geblieben ist die Hierarchie der Summen — Zwischensumme dezent, Gesamt
   prominent — und die Klasse `.stmt-grandtotal`, an der ein fremder Waechter
   die Lage der Positionsaktionen misst (BUG-0040).

   Kanon ist `.list-table .list-card` (§6b), nicht `.form-rows`: Das war das
   Vokabular editierbarer Tabellen und hier von Anfang an das falsche Idiom
   fuer eine Leseansicht. */

/* Gruppenzeile: die Person, ihre Positionszahl und etwaige Selbstbehalte. */
.list-card--stmt-positions tr.stmt-group > th {
  background: var(--tint-warm);
  border-top: 1px solid var(--hairline);
  padding: 9px 12px;
  font-weight: 400;
  text-align: left;
}
.stmt-group-name { font-size: var(--fs-14); font-weight: 700; color: var(--espresso); }
.stmt-group-count {
  font-size: var(--fs-11); font-weight: 600; color: var(--text-secondary);
  margin-left: 9px;
}
.list-card--stmt-positions tr.stmt-group .sb-chip { margin-left: 9px; }

/* Belegzelle: Symbol und Aussteller in Zeile 1, darunter Datum, Beschreibung
   und Ablehnungsgrund. Der Aussteller wird NICHT mehr abgeschnitten — die
   Ellipse kostete an 24 von 31 Positionen genau die Information, wegen der
   man hinsieht. Er darf stattdessen umbrechen. */
.stmt-pos-link { display: block; text-decoration: none; color: inherit; }
.stmt-pos-link:hover .stmt-pos-issuer { text-decoration: underline; }
.stmt-pos-head {
  display: grid; align-items: center; gap: 0 7px;
  grid-template-columns: auto 1fr;
  grid-template-areas: "icon issuer" ".    datum";
}
.stmt-pos-head > .bl-type { grid-area: icon; display: inline-flex; }
.stmt-pos-issuer {
  grid-area: issuer;
  font-size: var(--fs-13); font-weight: 600; color: var(--espresso);
  overflow-wrap: anywhere;
}
.stmt-pos-datum {
  grid-area: datum;
  font-size: var(--fs-11); color: var(--text-secondary);
}
/* Ohne zugeordneten Beleg gibt es kein Ziel — also auch keinen Link, sondern
   einen benannten neutralen Zustand. */
.stmt-pos-head.is-leer .stmt-pos-issuer {
  grid-area: issuer / icon / issuer / issuer;
  font-weight: 400; color: var(--stone-500);
}
/* FEATURE-0337: Badge „Korrektur" mit Erklärsatz unter dem Beleg */
.stmt-pos-korrektur { display: block; margin-top: 4px; }
.stmt-pos-korrektur-text {
  display: block; margin-top: 2px;
  font-size: var(--fs-13); color: var(--stone-600);
}
.stmt-pos-text {
  display: block; margin-top: 4px;
  font-size: var(--fs-13); color: var(--stone-600);
}
.stmt-pos-unassign { margin-top: 6px; }
/* Auf dem Desktop trägt die Aktion ihren Text, mobil das X — EIN Knopf, zwei
   Erscheinungen, ein zugänglicher Name. Das Symbol ist hier die Ausnahme und
   nicht der Normalfall; deshalb steht die Ausblendung in der Grundstufe und
   das Einblenden in der Media Query (Bauplan `.list-card--stmt-positions`).
   Der Fokusring gilt in beiden Breiten: In einer Karte aus fünf gleichen
   Knöpfen ist er die einzige Ortsangabe. */
.stmt-unassign-icon { display: none; }
.stmt-pos-unassign button:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Summen-Hierarchie: Zwischensumme dezent, Gesamt prominent. Der Rahmen sitzt
   auf den Zellen, nie auf der <tr> — sonst faerbt mobil der grid-gap mit. */
.list-card--stmt-positions tr.stmt-subtotal > th,
.list-card--stmt-positions tr.stmt-subtotal > td {
  background: transparent;
  border-top: 1px solid var(--stone-200);
  font-weight: 600;
  color: var(--stone-600);
  text-align: right;
}
.list-card--stmt-positions tr.stmt-subtotal > th { text-align: left; }
.list-card--stmt-positions tr.stmt-grandtotal > th,
.list-card--stmt-positions tr.stmt-grandtotal > td {
  background: transparent;
  border-top: 2px solid var(--espresso);
  font-weight: 700;
  font-size: var(--fs-14);
  color: var(--espresso);
  padding-top: 13px;
  padding-bottom: 13px;
  text-align: right;
}
.list-card--stmt-positions tr.stmt-grandtotal > th { text-align: left; }

/* ===== Abrechnungs-Formular: Positionszeile zweizeilig (Design-Konsistenz Batch 2) =====
   Die sechs Felder einer Position standen auf Desktop in einer Tabellenzeile.
   Bei realen Daten waren sie dadurch so schmal, dass Werte abgeschnitten
   wurden (Mitglied "Moritz Hel", Betrag "113," statt "113,95 €").

   form-rows--wide nutzt oberhalb des Mobile-Breakpoints dasselbe
   flex-wrap-Idiom wie das mobile Stacking (.form-rows), nur mit
   groesseren Basisbreiten: Zeile 1 traegt Mitglied/Beschreibung/Betraege,
   Zeile 2 den Ablehnungsgrund und den Loeschen-Button. Damit gibt es EIN
   Zeilen-Layout fuer alle Breiten statt Tabelle auf Desktop und Stack auf
   Mobile. Die Spaltenkoepfe entfallen zugunsten der data-label-Labels. */
@media (min-width: 768px) {
  .form-rows--wide thead { display: none; }
  .form-rows--wide,
  .form-rows--wide tbody { display: block; }
  .form-rows--wide tbody tr {
    display: flex; flex-wrap: wrap; gap: 10px 12px;
    padding: 14px 16px; border-bottom: 1px solid var(--hairline-row);
  }
  .form-rows--wide tbody td {
    display: block; border: 0; padding: 0; min-width: 0; white-space: normal;
  }
  .form-rows--wide tbody td[data-label]::before {
    content: attr(data-label); display: block;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--stone-500); margin-bottom: 4px;
    white-space: normal;
  }
  /* Zeile 1 — die Breiten sind so gewaehlt, dass alle vier Felder in die
     schmalere Formularspalte (~686px) passen; die Beschreibung waechst mit. */
  .form-rows--wide tbody td.stmt-cell--member { flex: 0 0 170px; }
  .form-rows--wide tbody td.stmt-cell--desc   { flex: 1 1 200px; }
  .form-rows--wide tbody td.stmt-cell--money  { flex: 0 0 120px; }
  /* Zeile 2 — der grosse Basiswert erzwingt den Umbruch, der Loeschen-Button
     passt daneben und sitzt am Zeilenende. */
  .form-rows--wide tbody td.stmt-cell--reason { flex: 1 1 300px; }
  /* BUG-0198: Bestätigung Erstattet über Eingereicht, eigene Zeile */
  .form-rows--wide tbody td.stmt-cell--confirm { flex: 1 1 100%; }
  .form-rows--wide tbody td.stmt-cell--del {
    flex: 0 0 auto; align-self: flex-end;
  }
  /* Der Loeschen-Button traegt sein Label im aria-label, nicht sichtbar. */
  .form-rows--wide tbody td.stmt-cell--del::before { content: none; }
}

/* ===== Kopf-Aktionen mobil (Design-Konsistenz Batch 4) ===== */
@media (max-width: 767.98px) {
  /* Ursachenfix zu U-18: `.detail-head-actions` traegt `flex: none`
     (= flex-shrink 0) und wird damit immer auf max-content aufgezogen — das
     dort gesetzte `flex-wrap: wrap` konnte nie greifen. Die Button-Zeile lief
     deshalb aus dem Viewport (Abrechnungs-Detail bei 390px: 540px breit).
     Shrink erlauben + auf die Kopfbreite deckeln laesst den Umbruch wirken;
     gilt zentral fuer alle Detailseiten mit diesem Idiom (Beleg, Einreichung,
     Vertrag, Settings, Todo, Onboarding, Einladungen, Dashboard). */
  .detail-head-actions { flex: 0 1 auto; max-width: 100%; }
}

/* ============================================================================
   TABELLEN-KANON: list-card — kanonische mobile Datenlisten-Karte (Etappe 1)
   ----------------------------------------------------------------------------
   EIN Mechanismus für ALLE read-only Datenlisten. Desktop bleibt <table>,
   Mobile (<=991.98px, A4-02: Tablet gilt als Mobil — gleiche Schwelle wie
   mobiler Seitenkopf und randlose .list-surface) stapelt jede <tr> per
   grid-template-areas zu einer Karte.

   Ersetzt die vormals read-only Ad-hoc-Stacking-Varianten (belege-stacked,
   table-stacked-statement/-submission/-queue/-document/-todo, .table-stacked,
   ins-member-table). Editierbare Eingabe-Tabellen laufen dagegen über den
   zweiten Archetyp .form-rows (Etappe 2, vormals .table-stacked-form).

   Vertrag — für jede Aufgabe gibt es GENAU EINEN Weg:
   1. Karten-Bauplan  = grid-template-areas je Liste (.list-card--NAME), als
      lesbare Karte an EINER Stelle (dieser Block) — nie rohe column/row-Nummern.
   2. Zelle → Region  = td[data-cell="X"] { grid-area: … } im selben --NAME-Block.
   3. Betrag rechts   = td[data-cell="amount"] mit justify-self: end im
      --NAME-Block (Template ergänzt .text-end fürs Desktop-Layout).
   4. Tint (fällig)   = auf die td (tr.row-overdue/.row-due-soon td), NIE auf
      die tr — sonst färbt der grid-gap mit (Fix 4.1).
   5. Optionales Label = data-label="…" rendert ein Overline über der Zelle.
   6. Desktop-only Zelle = .lc-desktop oder td[data-cell="hide"] (mobil aus).
   7. Empty-/Fehlzeile = td[colspan] (volle Kartenbreite).
   Barrierefreiheit: Markup bleibt <table>; nur CSS reshaped die Darstellung.

   Abgebaut (07.08.2026, je 0 Konsumenten): .lc-amount, .lc-empty sowie die
   Tint-Zwillinge tr.is-overdue/.is-due-soon/.is-missing. Sie waren die nie
   gewählte Hälfte eines doppelt spezifizierten Vertrags — die Praxis nutzt
   durchgängig data-cell/row-*. Fehlende Dokumente markiert .list-table
   tr.doc-missing; braucht eine list-card das, wird doc-missing erweitert
   statt ein zweiter Name eingeführt.
   ============================================================================ */

@media (max-width: 991.98px) {
  .list-card thead { display: none; }
  .list-card tbody { display: flex; flex-direction: column; gap: 0; }
  .list-card tr {
    display: grid;
    gap: 3px 12px;
    align-items: center;
    border: 0;
    border-bottom: 1px solid var(--stone-200);
    border-radius: 0;
    padding: 11px 16px;
    background: #fff;
    box-shadow: none;
    transition: background-color 0.15s ease;
  }
  .list-card tr[data-href],
  .list-card tr[data-schedule],
  .list-card tr[onclick] { cursor: pointer; }
  .list-card tr[data-href]:active,
  .list-card tr[data-schedule]:active { background-color: var(--stone-100); }
  .list-card td {
    border: 0; padding: 0; background: transparent;
    height: auto; min-width: 0;
  }
  .list-card td.lc-desktop,
  .list-card td[data-cell="hide"] { display: none; }

  /* Optionales Label-Overline (opt-in je Zelle) */
  .list-card td[data-label]::before {
    content: attr(data-label); display: block;
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--text-secondary);
    margin-bottom: 2px; white-space: normal;
  }

  /* Tint auf die Zellen, nicht auf die tr (Fix 4.1: kein gefärbter gap) */
  .list-card tr.row-overdue td  { background: var(--danger-muted); }
  .list-card tr.row-due-soon td { background: var(--warning-muted); }

  /* Nicht-Daten-Zeilen (Infinite-Scroll, Ende, Empty) flach.
     Aufklappbares Detail gehört NICHT hierher: das Idiom ist ein div.collapse
     in einer vorhandenen Zelle (siehe .list-card--positions), nicht eine
     Geschwister-<tr class="collapse">. Die Zeilen-Variante existiert nur noch
     als --fee-Sonderfall, dessen Desktop-Markup sie erzwingt. */
  .list-card tr.infinite-scroll-trigger,
  .list-card tr.end-of-list,
  .list-card tr.htmx-indicator {
    display: block; border: 0; background: transparent;
    box-shadow: none; cursor: default; padding: 0;
  }
  .list-card tr.infinite-scroll-trigger td,
  .list-card tr.end-of-list td { display: block; text-align: center; padding: 8px 0; }
  /* Empty-/colspan-Zeile: volle Kartenbreite */
  .list-card td[colspan] {
    display: block; grid-column: 1 / -1;
    text-align: center; padding: 12px 0; color: var(--text-secondary);
  }

  /* ---- Belegliste: Icon | Aussteller/Meta | Betrag/Status ----
     ZWEI Konsumenten (FEATURE-0139), Änderungen betreffen beide Screens:
     1. receipts/_receipt_table.html + _receipt_row.html — Belegliste,
        mit Checkbox, Mitglied und Erstattungs-Status.
     2. receipts/submission_detail.html — Belegtabelle der Einreichung,
        ohne diese drei. Die Map ist deckungsgleich, weil die fehlenden
        Zellen mobil ohnehin ausgeblendet sind; --receipt scheidet aus,
        weil dessen lead-Region per Vertrag die Checkbox ist.
     Die Zwischensummen-/Fuß-Regeln am Ende dieses Blocks nutzt nur
     Konsument 2. */
  .list-card--belege tr {
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "lead title  amount"
      "lead sub    status";
  }
  .list-card--belege td[data-cell="typeicon"] { grid-area: lead; display: flex; align-self: center; }
  .list-card--belege td[data-cell="issuer"]   { grid-area: title; font-size: var(--fs-13); font-weight: 600; color: var(--espresso); overflow: hidden; }
  .list-card--belege td[data-cell="issuer"] .bl-type { display: none; }
  .list-card--belege td[data-cell="issuer"] .bl-issuer-note { display: none; }
  .list-card--belege td[data-cell="meta"]      { grid-area: sub; display: block; font-size: var(--fs-11); color: var(--text-secondary); }
  .list-card--belege td[data-cell="meta"] .meta-separator { color: var(--stone-300); margin: 0 2px; }
  .list-card--belege td[data-cell="amount"]    { grid-area: amount; justify-self: end; }
  .list-card--belege td[data-cell="status"]    { grid-area: status; justify-self: end; }
  .list-card--belege td[data-cell="checkbox"],
  .list-card--belege td[data-cell="date"],
  .list-card--belege td[data-cell="member"] { display: none; }
  /* BUG-0238: Auswahlmodus mobil — Kästchen als eigene Spalte VOR dem
     Typ-Icon. Nur die Checkbox kehrt zurück; Datum und Mitglied bleiben
     ausgeblendet (sie stehen ohnehin in der Meta-Zeile der Karte). Höhere
     Spezifität (Body-Klasse) gewinnt unabhängig von der Regel-Reihenfolge
     gegen die display:none-Regel direkt darüber. */
  body.receipt-selection-mode .list-card--belege tr {
    grid-template-columns: auto auto 1fr auto;
    grid-template-areas:
      "check lead title  amount"
      "check lead sub    status";
  }
  body.receipt-selection-mode .list-card--belege td[data-cell="checkbox"] {
    grid-area: check; display: flex; align-items: center; align-self: center;
  }
  .list-card--belege td[data-cell="typeicon"] .bl-type {
    display: inline-flex; width: 26px; height: 26px; border-radius: 7px;
    background: #F1ECE5; align-items: center; justify-content: center;
    color: var(--espresso-light);
  }
  .list-card--belege .bl-name { font-size: var(--fs-13); }
  /* FAB-Freiraum der Belegliste: seit Audit B4C/A4-05 global gelöst
     (body:has(.scanner-fab) … .main-panel, siehe oben). */

  /* --- Einreichungs-Detail: Gruppenzeile, Zwischensumme, Gesamt-Fuß ---
     Gruppenzeile gegen die generische td[colspan]-Regel oben abgrenzen —
     die formatierte sie sonst als zentrierte graue Empty-Zeile
     (gleiche Behandlung wie tr.pos-group bei .list-card--positions). */
  .list-card--belege tr.rcpt-group { display: block; padding: 0; border-bottom: 0; }
  .list-card--belege tr.rcpt-group > td { display: block; text-align: left; padding: 7px 16px; }

  /* Ohne eigene Regel bliebe das tfoot ein table-footer-group neben dem
     flex-tbody. Und: padding/border der Zellen aus `.list-table tfoot th|td`
     (0,1,2) müssen zurückgesetzt werden — sonst polstert die Karte doppelt
     (12px/16px Zelle PLUS 11px/16px Zeile) und die Summenzeile steht
     sichtbar versetzt. Dieselbe Falle wie bei .list-card--positions tfoot. */
  .list-card--belege tfoot { display: flex; flex-direction: column; }
  /* `tbody` gehört zwingend in den Selektor: die Desktop-Regel oben ist
     `.list-table tbody tr.rcpt-subtotal > td` (0,2,3). Ohne tbody wäre diese
     hier (0,2,2) und verlöre — die Zellen-Oberlinie ragte dann als abgehackter
     Strich über die Label-Spalte in die Karte. Mobil trennt die Zeile über
     `.list-card tr` (border-bottom), nicht über ihre Zellen. */
  .list-card--belege tbody tr.rcpt-subtotal > td,
  .list-card--belege tbody tr.rcpt-subtotal > th,
  .list-card--belege tfoot th,
  .list-card--belege tfoot td { padding: 0; border: 0; }
  /* Schriftgrößen explizit: die 13px aus `.list-table tbody td` gelten erst ab
     992px, die 12.5px aus `.list-table tfoot th|td` dagegen immer. Ohne diese
     Regel erbte die Zwischensumme mobil die Body-Größe (16px) und überragte
     damit den Gesamtbetrag — die Hierarchie stand auf dem Kopf. */
  .list-card--belege tbody tr.rcpt-subtotal > td {
    font-size: var(--fs-13); font-weight: 600; color: var(--stone-600);
  }
  .list-card--belege tfoot th,
  .list-card--belege tfoot td { font-size: var(--fs-14); }
  .list-card--belege tr.rcpt-subtotal,
  .list-card--belege tfoot tr {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "sumlabel sumamount";
  }
  .list-card--belege tfoot tr { border-bottom: 0; border-top: 1px solid var(--stone-200); }
  .list-card--belege th[data-cell="sum-label"],
  .list-card--belege td[data-cell="sum-label"] { grid-area: sumlabel; text-align: left; }
  .list-card--belege th[data-cell="sum-amount"],
  .list-card--belege td[data-cell="sum-amount"] { grid-area: sumamount; justify-self: end; text-align: right; }

  /* FAB-Freiraum des Einreichungs-Details: seit Audit B4C/A4-05 global
     gelöst (body:has(.scanner-fab) … .main-panel, 92px aus der
     FAB-Geometrie — Herleitung dort). */

  /* ---- Abrechnungsliste: Datum | Referenz/Zuordnung | Auszahlung ----
     BUG-0030: `amount` stand in BEIDEN Zeilen und reservierte seine Breite
     auch für Zeile 2 — in der gar kein Betrag steht. Diese Breite fehlte der
     Referenz darüber. Jetzt endet die Betragsspalte nach Zeile 1, und `sub`
     läuft über die volle Restbreite. Genau das machen `--submission` und
     `--receipt` seit jeher; die Abrechnungskarte war die Ausnahme.

     Bewusst NICHT geändert: `1fr` bleibt `1fr`. Der Reflex wäre
     `minmax(0, 1fr)`, damit die Titelspalte unter ihre Inhaltsbreite
     schrumpfen darf — hier ohne Wirkung, weil `.list-card td` bereits
     `min-width: 0` setzt und der Spurenmindestwert damit ohnehin 0 ist.
     Gemessen: Die Ellipse der langen Referenz greift mit und ohne. Die
     Nachbarkarten führen es redundant mit. */
  .list-card--statement tr {
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "lead title  amount"
      "lead sub    sub";
  }
  /* Fix 4.3: Datum an der ersten Zeile ausrichten (nicht über die Karte zentriert) */
  .list-card--statement tr { align-items: start; }
  .list-card--statement td[data-cell="date"]  { grid-area: lead; align-self: start; font-weight: 600; font-size: var(--fs-13); color: var(--stone-500); white-space: nowrap; }
  .list-card--statement td[data-cell="title"] { grid-area: title; display: block; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .list-card--statement td[data-cell="badges"] { grid-area: sub; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
  /* Audit B4C/UX5-05 also_fixed: white-space normal statt nowrap — die
     auto-Betragsspalte (breites Zahlungs-Badge) quetscht die Mittelspalte;
     das Zuordnungs-Badge lief dort schon vor der Skala in die Nachbarspalte,
     seit der Rundung auf 11px sichtbar. Lange Badge-Texte brechen jetzt um,
     statt zu überlappen. */
  .list-card--statement td[data-cell="badges"] .badge { font-size: var(--fs-11); padding: .2em .5em; white-space: normal; text-align: left; }
  /* Betrag und Zahlungspunkt sind seit BUG-0044 EINE Komponente und stehen
     nebeneinander in einer Zeile — nicht mehr untereinander. */
  .list-card--statement td[data-cell="amounts"] { grid-area: amount; display: flex; align-self: start; justify-content: flex-end; align-items: center; gap: 4px; text-align: right; white-space: nowrap; }
  .list-card--statement td[data-cell="amounts"] .amount-value { font-weight: 600; font-size: var(--fs-13); color: var(--espresso); white-space: nowrap; }

  /* ---- Einreichungsliste: Payer-Badge | Kostenträger/Meta | Betrag/Status ----
     Derselbe Bauplan wie --belege: Lead-Spalte trägt das Kostenträger-Badge,
     Titel und Meta-Zeile stehen bündig daneben. Datum und Kostenträger-Name der
     Desktop-Spalten erscheinen mobil in title/meta, deshalb dort ausgeblendet. */
  .list-card--submission tr {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "lead title  amount"
      "lead sub    status";
    align-items: start;
  }
  .list-card--submission td[data-cell="payer"]  { grid-area: lead; align-self: start; display: flex; }
  .list-card--submission td[data-cell="title"]  { grid-area: title; display: block; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .list-card--submission td[data-cell="meta"]   { grid-area: sub; display: flex; align-items: center; gap: 4px; font-size: var(--fs-11); color: var(--text-secondary); }
  .list-card--submission td[data-cell="meta"] .meta-separator { color: var(--stone-300); }
  .list-card--submission td[data-cell="amount"] { grid-area: amount; justify-self: end; align-self: start; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); white-space: nowrap; }
  .list-card--submission td[data-cell="status"] { grid-area: status; justify-self: end; }
  .list-card--submission td[data-cell="date"],
  .list-card--submission td[data-cell="provider"] { display: none; }

  /* ---- Offene-Belege-Liste (Todo, mit Mehrfachauswahl) ----
     Betrag steht in Zeile 1 auf Höhe des Ausstellers, Status darunter — derselbe
     Bauplan wie .list-card--todo, damit die Queues des Todo-Hubs untereinander
     gleich lesen. Typo bewusst an --todo angeglichen (15px Titel/Wert), nicht
     umgekehrt: --todo hat 8 Konsumenten außerhalb des Hubs. */
  .list-card--receipt tr {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "lead title  amount"
      "lead sub    status";
    align-items: start;
  }
  /* Checkbox-Zelle als Tap-Target: Padding vergrößert die Trefferfläche,
     negative Margins gleichen es aus — die sichtbare Position der Checkbox
     (netto 3px oben / 2px rechts) und das Grid (lead) verschieben sich nicht. */
  .list-card--receipt td[data-cell="checkbox"] {
    grid-area: lead; align-self: start;
    padding: 11px 10px 12px 8px;
    margin: -8px -8px -12px -8px;
  }
  /* Kein overflow: hidden auf der Zelle — das Dokument-Badge (.bl-docs, top:-6px)
     wurde davon oben gekappt. Das Schrumpfen im Grid regelt .list-card td
     (min-width: 0), die Ellipsis .bl-name; das Badge ragt jetzt ins
     Zeilen-Padding statt aus der Zelle heraus. */
  .list-card--receipt td[data-cell="issuer"]   { grid-area: title; font-weight: 600; font-size: var(--fs-16); color: var(--espresso); }
  .list-card--receipt td[data-cell="issuer"] .bl-type {
    display: inline-flex; width: 24px; height: 24px; border-radius: 7px;
    background: var(--stone-100); align-items: center; justify-content: center;
  }
  .list-card--receipt td[data-cell="issuer"] .bl-type svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--stone-500); }
  .list-card--receipt td[data-cell="meta"]   { grid-area: sub; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: var(--fs-14); color: var(--stone-500); }
  .list-card--receipt td[data-cell="meta"] .meta-separator { color: var(--stone-300); }
  /* Betrag: fett in Ausstellerfarbe statt groß und grün. Der Zahlungs-Punkt
     bleibt der Desktop-Spalte vorbehalten — mobil trägt die Karte ihn nicht. */
  .list-card--receipt td[data-cell="amount"] {
    display: block; grid-area: amount; justify-self: end; align-self: start;
    white-space: nowrap;
  }
  .list-card--receipt td[data-cell="amount"] .pay-dot { display: none; }
  .list-card--receipt td[data-cell="amount"] .amt { font-size: var(--fs-16); font-weight: 700; color: var(--espresso); }
  .list-card--receipt td[data-cell="status"] { grid-area: status; justify-self: end; align-self: center; }
  /* FEATURE-0163: Kurzicon + Trägername statt Pille. Der Name läuft mobil in
     der Schrift der Meta-Zeile — sonst stünde er in Titelgröße neben dem
     Betrag und konkurrierte mit dem Aussteller. */
  .list-card--receipt td[data-cell="status"] .payer-value { flex-wrap: nowrap; }
  .list-card--receipt td[data-cell="status"] .payer-value-name { font-size: var(--fs-14); color: var(--stone-500); }
  .list-card--receipt td[data-cell="date"],
  .list-card--receipt td[data-cell="member"],
  .list-card--receipt td[data-cell="actions"] { display: none; }
  /* Mitglieds-Zwischenzeile gegen die generische td[colspan]-Regel abgrenzen —
     die formatiert sonst zur zentrierten grauen Empty-Zeile (wie tr.pos-group). */
  .list-card--receipt tr.rcpt-group { display: block; padding: 0; border-bottom: 0; }
  .list-card--receipt tr.rcpt-group > td { display: block; text-align: left; padding: 7px 16px; }

  /* ---- Dokument-Browser (+ Verträge): Titel/Datum | Status ---- */
  .list-card--document tr {
    grid-template-columns: 1fr auto;
    grid-template-areas: "title status";
    align-items: start;
  }
  .list-card--document td[data-cell="info"]  { grid-area: title; display: block; min-width: 0; }
  .list-card--document td[data-cell="info"] .doc-name { display: block; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); word-break: break-word; overflow-wrap: break-word; hyphens: auto; line-height: 1.4; }
  .list-card--document td[data-cell="info"] .doc-date { font-size: var(--fs-11); color: var(--text-secondary); }
  /* BUG-0028: `start` statt `center`. Das Badge war an der ganzen zweizeiligen
     Textflaeche aus Dateiname und Datum ausgerichtet und rutschte dadurch
     zwischen die Zeilen; buendig gehoert es zur ERSTEN Zeile des Dateinamens.
     Bei mehrzeiligen Namen wandert es sonst immer weiter nach unten. */
  .list-card--document td[data-cell="status"] {
    grid-area: status; justify-self: end; align-self: start;
  }
  .list-card--document td[data-cell="name"],
  .list-card--document td[data-cell="date"],
  .list-card--document td[data-cell="actions"] { display: none; }

  /* ---- Dokument-Queue (Todo): Icon | Dateiname/Datum | Größe ----
     Das Icon zieht in eine eigene Zelle (Muster wie --belege typeicon), damit
     das Datum links bündig unter dem Dateinamen startet statt unter dem Icon. */
  .list-card--queue tr {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "lead title title"
      "lead sub   metaB";
    align-items: start;
  }
  .list-card--queue td[data-cell="m-fileicon"] {
    display: flex; grid-area: lead; align-self: start; padding-top: 2px;
    color: var(--crema);
  }
  .list-card--queue td[data-cell="filename"] { grid-area: title; font-weight: 600; font-size: var(--fs-16); color: var(--espresso); }
  /* Desktop-Struktur der Zelle mobil auflösen — das Icon steckt hier in der
     eigenen lead-Zelle, der Name füllt die ganze Spalte. */
  .list-card--queue td[data-cell="filename"] .queue-file { display: block; }
  .list-card--queue td[data-cell="filename"] .queue-file-icon { display: none; }
  /* Dateiname einzeilig mit Ellipsis: mehrzeilige Namen (die es hier häufig
     gibt) rissen die Karte auseinander und schoben Datum und Größe weit nach
     unten. Vormals bewusst word-break — Konsument ist allein dieses Partial. */
  .list-card--queue td[data-cell="filename"] .queue-name {
    display: block; font-size: var(--fs-16);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .list-card--queue td[data-cell="date"] { grid-area: sub; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--queue td[data-cell="size"] { grid-area: metaB; justify-self: end; align-self: end; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--queue td[data-cell="action"] { display: none; }

  /* Hinweis: Die Mitgliederliste (.ins-member-table) ist bewusst NICHT auf
     list-card migriert — sie ist nicht media-scoped, sondern ein permanentes
     Kompakt-Grid (Personenzeilen innerhalb einer Policy-Karte, gleich auf
     Desktop und Mobile). list-card stapelt nur <992px; ein <table>-Look auf
     Desktop wäre hier falsch. Sie nutzt bereits denselben grid-template-areas-
     Mechanismus und bleibt als dokumentierter Sonderfall stehen. */

  /* ---- Ausgleichszahlungen (Maximalausprägung, 8 Spalten) ----
     Datum + Betrag oben, Konten-Fluss darunter, Salden mit Label,
     Notiz/Erstellt-von als Meta, Aktionen rechts. Beträge rechtsbündig.
     Löst den Settlements-Overlap-Bug konstruktiv (grid statt Flex). */
  .list-card--settlement tr {
    grid-template-columns: 1fr 1fr auto;
    grid-template-areas:
      "date    date    amount"
      "flow    flow    flow"
      "saldoa  saldob  actions"
      "note    creator actions";
    gap: 4px 12px;
    align-items: start;
  }
  .list-card--settlement td[data-cell="date"]    { grid-area: date; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); white-space: nowrap; }
  .list-card--settlement td[data-cell="amount"]  { grid-area: amount; justify-self: end; align-self: start; font-weight: 600; font-size: var(--fs-13); color: var(--espresso); white-space: nowrap; }
  .list-card--settlement td[data-cell="flow"]    { grid-area: flow; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
  .list-card--settlement td[data-cell="saldoa"]  { grid-area: saldoa; }
  .list-card--settlement td[data-cell="saldob"]  { grid-area: saldob; }
  .list-card--settlement td[data-cell="saldoa"],
  .list-card--settlement td[data-cell="saldob"] { font-size: var(--fs-13); font-weight: 600; white-space: nowrap; }
  .list-card--settlement td[data-cell="note"]    { grid-area: note; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--settlement td[data-cell="creator"] { grid-area: creator; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--settlement td[data-cell="actions"] { grid-area: actions; display: flex; gap: 6px; justify-self: end; align-self: center; }

  /* ---- Gebührenordnung (öffentlich, 10 Spalten) ----
     Toggle links; Ziffer+Ordnung-Badge oben; Beschreibung; drei Sätze mit
     Label (Einfach/Regel/Höchst); Abschnitt/Punkte/Faktoren als Meta.
     Löst den GOÄ-Overlap-Bug (Label::before über Badge) konstruktiv. */
  .list-card--fee tr {
    grid-template-columns: auto 1fr 1fr 1fr;
    grid-template-areas:
      "tog code    code   ordnung"
      "tog desc    desc   desc"
      "tog einfach regel  hoch"
      "tog section points faktor";
    gap: 4px 10px;
    align-items: start;
  }
  .list-card--fee td[data-cell="toggle"]  { grid-area: tog; align-self: center; }
  .list-card--fee td[data-cell="ordnung"] { grid-area: ordnung; justify-self: end; }
  .list-card--fee td[data-cell="code"]    { grid-area: code; font-weight: 700; font-size: var(--fs-14); }
  .list-card--fee td[data-cell="desc"]    { grid-area: desc; font-size: var(--fs-13); color: var(--stone-500); }
  .list-card--fee td[data-cell="einfach"] { grid-area: einfach; }
  .list-card--fee td[data-cell="regel"]   { grid-area: regel; }
  .list-card--fee td[data-cell="hoch"]    { grid-area: hoch; }
  .list-card--fee td[data-cell="einfach"],
  .list-card--fee td[data-cell="regel"],
  .list-card--fee td[data-cell="hoch"] { text-align: right; justify-self: end; font-size: var(--fs-13); white-space: nowrap; }
  .list-card--fee td[data-cell="section"] { grid-area: section; }
  .list-card--fee td[data-cell="points"]  { grid-area: points; }
  .list-card--fee td[data-cell="faktor"]  { grid-area: faktor; justify-self: end; text-align: right; }
  .list-card--fee td[data-cell="section"],
  .list-card--fee td[data-cell="points"],
  .list-card--fee td[data-cell="faktor"] { font-size: var(--fs-11); color: var(--text-secondary); }
  /* Detail-Collapse-Zeile bleibt volle Breite (kein Karten-Grid) */
  .list-card--fee tr.collapse { display: none; }
  .list-card--fee tr.collapse.show { display: block; padding: 0 16px 12px; border-bottom: 1px solid var(--stone-200); }
  .list-card--fee tr.collapse td { display: block; grid-column: auto; }

  /* ---- Todo/Aufgaben-Listen: Titel/Meta | Wert; Sub; Aktionen ----
     Vormals table-stacked-todo (nutzte schon grid-areas). Behält seine
     mobile-only m-*-Zellen als dokumentierte Listen-Vokabel. */
  .list-card--todo tbody,
  .list-card--todo tfoot { display: flex; flex-direction: column; gap: 0; }
  .list-card--todo tr {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "lead    title   side"
      "lead    meta    meta"
      "sub     sub     sub"
      "actions actions actions";
    gap: 2px 10px;
    align-items: start;
  }
  /* Optionale Icon-Zelle vorn (Belegtyp bzw. Abrechnung). Fehlt sie, kollabiert
     die auto-Spalte auf 0 — die Listen ohne Icon bleiben unverändert. */
  .list-card--todo td[data-cell="m-icon"] {
    display: flex; grid-area: lead; align-self: start; padding-top: 1px;
  }
  .list-card--todo td[data-cell="m-icon"] .bl-type {
    display: inline-flex; width: 24px; height: 24px; border-radius: 7px;
    background: var(--stone-100); align-items: center; justify-content: center;
  }
  .list-card--todo td[data-cell="m-icon"] .bl-type svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--stone-500); }
  .list-card--todo td,
  .list-card--todo tfoot th { display: none; }
  .list-card--todo td[data-cell="m-title"],
  .list-card--todo th[data-cell="m-title"] {
    display: block; grid-area: title;
    font-weight: 600; font-size: var(--fs-16); color: var(--espresso);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .list-card--todo td[data-cell="m-meta"],
  .list-card--todo th[data-cell="m-meta"] {
    display: flex; grid-area: meta;
    flex-wrap: wrap; align-items: center; gap: 8px;
    font-size: var(--fs-14); color: var(--stone-500);
  }
  .list-card--todo [data-cell="m-meta"] .meta-separator { color: var(--stone-300); }
  .list-card--todo [data-cell="m-meta"] .meta-amount { font-weight: 600; color: var(--accent); }
  /* Wert rechts oben, auf Höhe des Titels — nicht über die Karte zentriert. */
  .list-card--todo td[data-cell="m-side"],
  .list-card--todo th[data-cell="m-side"] {
    display: flex; grid-area: side;
    flex-direction: column; align-items: flex-end; align-self: start;
    text-align: right; gap: 2px;
  }
  .list-card--todo .m-side-label {
    font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--text-secondary);
  }
  .list-card--todo .m-side-value { font-weight: 700; font-size: var(--fs-16); color: var(--espresso); white-space: nowrap; }
  .list-card--todo td[data-cell="m-sub"],
  .list-card--todo th[data-cell="m-sub"] {
    display: block; grid-area: sub;
    font-size: var(--fs-13); color: var(--stone-500); padding-top: 2px;
  }
  .list-card--todo td[data-cell="action"] {
    display: flex; grid-area: actions;
    justify-content: flex-end; gap: 6px; padding-top: 8px;
  }
  .list-card--todo td[data-cell="empty"] {
    display: block; grid-column: 1 / -1; text-align: center; padding: 8px 0;
  }
  /* Desktop-only-Zellen (echte Spalten) mobil aus */
  .list-card--todo td[data-cell^="d-"],
  .list-card--todo th[data-cell^="d-"] { display: none; }

  /* ---- Rechnungspositionen Arztrechnung: Ampel | Ziffer + Beschreibung | Werte ----
     Kompaktzeile oben, Beschreibung darunter eingerückt. GOÄ-Text, Erwartet und
     Differenz sind mobil ausgeblendet (.lc-desktop) und leben stattdessen im
     Aufklapper, der zusammen mit dem Chevron in vorhandenen Zellen sitzt
     (d-lg-none, Kartenschwelle 991,98px). Deshalb bleibt die Tabelle 9-spaltig
     und alle colspan unverändert. */
  .list-card--positions tr {
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    grid-template-areas:
      "status code qty  factor amount"
      ".      desc desc desc   desc";
    gap: 2px 8px;
    align-items: center;
  }
  .list-card--positions td[data-cell="status"] { grid-area: status; align-self: start; }
  .list-card--positions td[data-cell="code"]   { grid-area: code; font-size: var(--fs-14); color: var(--espresso); }
  .list-card--positions td[data-cell="qty"]    { grid-area: qty; font-size: var(--fs-13); color: var(--stone-500); }
  .list-card--positions td[data-cell="factor"] { grid-area: factor; font-size: var(--fs-13); color: var(--stone-500); }
  /* Multiplikations-Glue „2 × 2,30×" — das Einheiten-× rendert der Faktor selbst */
  .list-card--positions td[data-cell="factor"]::before { content: "× "; color: var(--text-secondary); }
  .list-card--positions td[data-cell="amount"] {
    grid-area: amount; justify-self: end;
    display: flex; align-items: center; gap: 6px;
    font-weight: 700; font-size: var(--fs-14); white-space: nowrap;
  }
  .list-card--positions td[data-cell="desc"] {
    grid-area: desc; display: block;
    font-size: var(--fs-13); color: var(--stone-500); overflow-wrap: anywhere;
  }
  /* Gruppen- und Begründungszeile gegen die generische td[colspan]-Regel oben
     abgrenzen — die formatiert sonst beide als zentrierte graue Empty-Zeile. */
  .list-card--positions tr.pos-group { display: block; padding: 0; border-bottom: 0; }
  .list-card--positions tr.pos-group > td { display: block; text-align: left; padding: 7px 16px; }
  .list-card--positions tr.pos-note { display: none; }

  /* ---- Rechnungspositionen Rezept: Medikament zuerst, Meta darunter ---- */
  .list-card--positions-rx tr {
    grid-template-columns: auto auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "desc desc desc desc   desc"
      "date pzn  .    qty    amount";
    gap: 3px 8px;
    align-items: baseline;
  }
  .list-card--positions-rx td[data-cell="desc"] {
    grid-area: desc; font-weight: 600; font-size: var(--fs-13);
    color: var(--espresso); overflow-wrap: anywhere;
  }
  .list-card--positions-rx td[data-cell="date"] { grid-area: date; font-size: var(--fs-12); color: var(--text-secondary); white-space: nowrap; }
  .list-card--positions-rx td[data-cell="pzn"]  { grid-area: pzn; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--positions-rx td[data-cell="qty"]  { grid-area: qty; font-size: var(--fs-12); color: var(--text-secondary); }
  .list-card--positions-rx td[data-cell="qty"]::after { content: "×"; }
  .list-card--positions-rx td[data-cell="amount"] {
    grid-area: amount; justify-self: end;
    font-weight: 700; font-size: var(--fs-14); white-space: nowrap;
  }

  /* Summenzeile beider Varianten. Ohne eigene Regel bliebe das tfoot ein
     table-footer-group neben dem flex-tbody (Vorbild .list-card--todo tfoot).
     padding/border der Zellen aus `.list-table tfoot th|td` (0,1,2) müssen hier
     zurückgesetzt werden, sonst polstert die Karte doppelt. */
  .list-card--positions tfoot,
  .list-card--positions-rx tfoot { display: flex; flex-direction: column; }
  .list-card--positions tfoot th[data-cell],
  .list-card--positions tfoot td[data-cell],
  .list-card--positions-rx tfoot th[data-cell],
  .list-card--positions-rx tfoot td[data-cell] { padding: 0; border: 0; text-align: left; }
  .list-card--positions tfoot tr {
    grid-template-columns: repeat(3, 1fr);
    grid-template-areas:
      "label label label"
      "sum   exp   diff";
    padding: 11px 16px; background: var(--stone-100); border-bottom: 0;
  }
  .list-card--positions tfoot th[data-cell="sum-label"]    { grid-area: label; }
  .list-card--positions tfoot td[data-cell="sum-amount"]   { grid-area: sum; }
  .list-card--positions tfoot td[data-cell="sum-expected"] { grid-area: exp; }
  .list-card--positions tfoot td[data-cell="sum-diff"]     { grid-area: diff; }
  .list-card--positions-rx tfoot tr {
    display: flex; justify-content: space-between; align-items: baseline;
    padding: 11px 16px; background: var(--stone-100); border-bottom: 0;
  }

  /* ---- Abrechnungs-Positionen (BUG-0045) ----
     Drei Zeilenarten, EIN Raster: Position, Personensumme, Gesamt. Genau
     daran scheiterte die Vorgängerlösung — vier Tabellen mit je eigener
     Spaltenberechnung, deren Werte sichtbar versetzt standen, plus eine
     Ebene handjustierter Paddings, die es nicht heilte. Fluchten ist hier
     Folge der Struktur; wer eine Zeilenart anfasst, kann sie nicht mehr
     alleine verschieben. Gemessen in
     tests/e2e/test_bug_0045_positionen_mobil.py bei 320 und 390px. */
  .list-card--stmt-positions tbody tr,
  .list-card--stmt-positions tfoot tr {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas:
      "beleg     beleg      beleg"
      "submitted reimbursed cut";
  }
  .list-card--stmt-positions td[data-cell="beleg"],
  .list-card--stmt-positions th[data-cell="beleg"] { grid-area: beleg; }
  .list-card--stmt-positions td[data-cell="submitted"]  { grid-area: submitted; text-align: left; }
  .list-card--stmt-positions td[data-cell="reimbursed"] { grid-area: reimbursed; text-align: center; }
  .list-card--stmt-positions td[data-cell="cut"]        { grid-area: cut; text-align: right; }

  /* `.list-card tbody { display: flex }` liesse das tfoot als
     table-footer-group zurück — dieselbe Falle wie bei --belege und
     --positions. */
  .list-card--stmt-positions tfoot { display: flex; flex-direction: column; }
  /* Zellen-Padding und -Rahmen kommen mobil von der ZEILE, nicht von den
     Zellen: `.list-table tfoot th|td` (weiter oben) gilt in jeder Breite und
     versetzte die Summenwerte sonst gegen die Positionsbeträge.

     `tr.stmt-grandtotal` steht hier mit ABSICHT im Selektor: Die Desktop-Regel
     ist `.list-card--stmt-positions tr.stmt-grandtotal > th|td` (0,2,2) und
     gilt in jeder Breite. Ein kürzeres `tfoot th` (0,1,2) verlöre gegen sie —
     die Oberlinie der Gesamtzeile erschien dann als DREI abgehackte Striche
     über den Betragsspalten, je einer pro Rasterzelle (im Browser gesehen). */
  .list-card--stmt-positions tbody tr.stmt-subtotal > th,
  .list-card--stmt-positions tbody tr.stmt-subtotal > td,
  .list-card--stmt-positions tfoot tr.stmt-grandtotal > th,
  .list-card--stmt-positions tfoot tr.stmt-grandtotal > td { padding: 0; border: 0; }
  .list-card--stmt-positions tbody tr.stmt-subtotal,
  .list-card--stmt-positions tfoot tr { border-bottom: 0; }
  .list-card--stmt-positions tbody tr.stmt-subtotal { border-top: 1px solid var(--stone-200); }
  /* Gesamt bleibt prominenter als die Personensummen — kräftigere Oberlinie
     und dunklere, größere Schrift, wie auf dem Desktop. */
  .list-card--stmt-positions tfoot tr { border-top: 2px solid var(--espresso); }
  .list-card--stmt-positions tfoot th,
  .list-card--stmt-positions tfoot td { font-size: var(--fs-14); color: var(--espresso); }

  /* Die Summenzeilen wiederholen die Spaltenüberschrift nicht: „Eingereicht"
     steht an der Position darüber, und in einer Karte aus fünf Zeilen wäre
     dieselbe Überschrift fünfmal mehr Rauschen als Hilfe. */
  .list-card--stmt-positions tbody tr.stmt-subtotal td[data-label]::before,
  .list-card--stmt-positions tfoot td[data-label]::before { content: none; }

  /* Gruppenzeile über die volle Kartenbreite. `th` statt `td` — die
     generische `.list-card td[colspan]`-Regel greift hier also nicht. */
  .list-card--stmt-positions tr.stmt-group > th {
    grid-column: 1 / -1;
    padding: 9px 16px; margin: 0 -16px;
  }

  /* Die Belegzelle ist selbst ein kleines Raster: Kopfzeile links, X oben
     rechts, Beschreibung und Ablehnungsgrund darunter über die volle
     Breite. Das X steht im Markup NACH dem Text (es gehört nicht in den
     Beleglink); die Fläche holt es optisch nach oben. */
  .list-card--stmt-positions td[data-cell="beleg"] {
    display: grid; gap: 2px 8px;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "kopf   aktion"
      "korr   korr"
      "text   text"
      "notiz  notiz";
  }
  .list-card--stmt-positions .stmt-pos-korrektur { grid-area: korr; }
  .list-card--stmt-positions .stmt-pos-link,
  .list-card--stmt-positions .stmt-pos-head { grid-area: kopf; }
  .list-card--stmt-positions .stmt-pos-text { grid-area: text; }
  .list-card--stmt-positions .pos-note      { grid-area: notiz; }
  .list-card--stmt-positions .stmt-pos-unassign {
    grid-area: aktion; align-self: start; margin: 0;
  }

  /* Kopfzeile mobil: Symbol, fetter Aussteller, unmittelbar danach das
     normal gewichtete Datum. Flex statt Raster, damit ein langer Aussteller
     umbrechen darf, statt die Karte aufzuziehen. */
  .list-card--stmt-positions .stmt-pos-head {
    display: flex; flex-wrap: wrap; align-items: center; gap: 3px 7px;
  }
  .list-card--stmt-positions .stmt-pos-datum { font-weight: 400; }

  /* Das X: Symbol sichtbar, Text nur noch hörbar. `visually-hidden` und
     nicht `display: none` — sonst verlöre der Knopf seinen Namen. */
  .list-card--stmt-positions .stmt-unassign-icon { display: inline-flex; }
  .list-card--stmt-positions .stmt-unassign-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  /* 44px Trefferfläche — die Fläche zählt, nicht das 16px-Symbol. */
  .list-card--stmt-positions .stmt-pos-unassign button {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: 0;
  }
}

/* Desktop: mobile-only Zellen ausblenden. WICHTIG: in @media (min-width) gescopet,
   damit diese Regeln nicht die mobilen display-Regeln der Media-Query oben
   überschreiben (gleiche Spezifität, spätere Regel gewinnt sonst auch mobil). */
@media (min-width: 992px) {
  .list-card--belege td[data-cell="meta"],
  .list-card--belege td[data-cell="typeicon"] { display: none; }
  .list-card--statement td[data-cell="title"],
  .list-card--statement td[data-cell="badges"],
  .list-card--statement td[data-cell="amounts"] { display: none; }
  .list-card--submission td[data-cell="payer"],
  .list-card--submission td[data-cell="title"],
  .list-card--submission td[data-cell="meta"] { display: none; }
  .list-card--document td[data-cell="info"] { display: none; }
  /* --receipt fehlte hier: die Meta-Zelle rutschte auf Desktop als vierte
     Spalte neben die Aktionen (Datum · Mitglied · Betrag doppelt). */
  .list-card--receipt td[data-cell="meta"] { display: none; }
  .list-card--queue td[data-cell="m-fileicon"] { display: none; }
  .list-card--todo td[data-cell^="m-"],
  .list-card--todo th[data-cell^="m-"] { display: none; }
}

/* ===== Gebührenordnung (öffentliche Liste, 10 Spalten) =====
   Ergänzt den mobilen .list-card--fee-Bauplan oben um das, was auf dem
   Desktop gilt: feste Spaltenbreiten, umbruchfreie Faktoren-Spalte und den
   Aufklapp-Chevron der Abrechnungsregeln (Vorbild .pos-toggle).
   Voller App-Standard: kein haftender Kopf, kein eigener Scroll-Container
   (Grund siehe .table-responsive). */
.fee-col-toggle { width: 30px; }
.fee-col-80  { width: 80px; }
.fee-col-90  { width: 90px; }
.fee-col-100 { width: 100px; }
/* 140 statt 120: „1,00 / 2,30 / 3,50" passt damit in eine Zeile. */
.fee-col-140 { width: 140px; }
.list-card--fee td[data-cell="faktor"] { white-space: nowrap; }

.fee-toggle {
  border: 0; background: transparent; padding: 0; line-height: 0;
  color: var(--text-secondary); cursor: pointer;
}
.fee-toggle-chevron { transition: transform var(--dur-fast) var(--ease-out); }
.fee-toggle[aria-expanded="true"] .fee-toggle-chevron { transform: rotate(90deg); }

/* Aufgeklappte Regelzeile: getönter Grund aus der Token-Skala statt
   Bootstraps .bg-light (kein App-Token). */
.fee-details { background: var(--stone-100); }

/* ---- App-Inhalt in einer öffentlichen Sektion ----
   cappuccino.css gibt JEDER <section> im öffentlichen Bereich
   `padding: 8rem 0` — die Marketing-Rhythmik der Startseite. Wer dort eine
   App-Komponente einsetzt (list-surface, list-table, filter-card), erbt sie
   ungefragt: 128 px über und unter dem Inhalt.

   Bis 13.08.2026 verdeckte das eine Bootstrap-Karte um die Sektion, deren
   `.card`-Regel mit 24 px gewann. Mit dem Umbau auf list-surface fiel die
   Karte weg (list-surface bringt den Rahmen selbst mit) und die
   Marketing-Regel schlug durch: gemessen an
   `.fee-detail-wrap > section:first-of-type` 128 px oben und unten, Höhe
   511 px bei rund 250 px Inhalt.

   Die Klasse ist die Gegenansage und gilt nur dort, wo sie im Markup steht —
   eine ungescopete `section { padding: 0 }` träfe die Marketing-Seiten. Der
   Abstand zur nächsten Sektion kommt weiterhin aus `mb-4`, der Rahmen aus
   list-surface.

   Wächter: TestDetailSektionsPolster in
   core/tests/test_views_fee_schedule_app_standard.py. Berechnete Layoutwerte
   sind nur im echten Browser messbar; der Test prüft deshalb Klasse und
   Regel, nicht das Polster.

   Bekannter zweiter Kandidat, bewusst nicht mitgezogen: die klassenlose
   <section> in md_content/index.html misst dieselben 128 px, hat zusätzlich
   kein aria-labelledby und gehört damit in ein eigenes Ticket. */
.app-section { padding-top: 0; padding-bottom: 0; }

/* ===== Rechnungspositionen: form-rows-Zellraster (Tabellen-Kanon O1) =====
   Die Zeilen nutzen den kanonischen form-rows-Mechanismus. Eigene Modifier
   beschreiben nur die fachlichen Feldbreiten; Labels kommen ausschließlich
   aus data-label. Die Belegtyp-Spalten bleiben über die bestehenden
   receipt-type-Klassen und col-Modifier ausgeblendet. */
@media (min-width: 768px) {
  .form-rows--wide tfoot { display: block; }
  .form-rows--wide tfoot tr {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 10px; padding: 12px 16px; border-top: 1px solid var(--hairline-row);
  }
  .form-rows--wide tfoot th { display: block; border: 0; padding: 0; }
  .form-rows--wide tfoot th:empty { display: none; }
  /* BUG-0032-008: siehe Mobil-Block — dieser hier wurde von jenem
     abgeschrieben, samt der Lücke bei td. */
  .form-rows--wide tfoot td { display: block; border: 0; padding: 0; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--date     { flex: 0 0 130px; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--code     { flex: 0 0 90px; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--status   { flex: 0 0 56px; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--pzn      { flex: 0 0 120px; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--quantity { flex: 0 0 72px; }
  .line-items-table.form-rows--wide tbody td.stmt-cell--factor   { flex: 0 0 84px; }

  /* BUG-0407: An der Grenze tbody→tfoot trägt sonst sowohl die letzte
     tbody-Zeile (border-bottom) als auch die erste tfoot-Zeile (border-top)
     je eine eigene 1px-Kante; dazu kam die 2px-Oberkante am <tfoot> aus
     app.css (`.table > tfoot`, mit BUG-0407 entfernt) — zusammen 3px statt
     1px. Die tbody-Zeilen behalten ihre Kante (gilt
     einheitlich für jede Zeilengrenze zwischen Positionen), die erste
     tfoot-Zeile verzichtet auf ihre eigene — genau wie die allererste
     tbody-Zeile keine eigene Oberkante gegen den (versteckten) Tabellenkopf
     trägt. Scoped auf diese Tabelle, andere form-rows--wide-Fußzeilen bleiben
     unangetastet. */
  .line-items-table.form-rows--wide tfoot tr:first-child { border-top: 0; }

  /* BUG-0407: Betragsfeld
     und Löschen-Knopf teilen sich die Betragszelle (.li-money). Die Zelle
     ist die letzte der Zeile und steht per margin-left: auto immer am
     Zeilenende — auch wenn sie in Zeile 2 umbricht; in Zeile 1 nimmt die
     wachsende Beschreibung den freien Platz vorher auf. Die Betragskante
     liegt damit in jedem Umbruchfall bei „Zeilenende − Innenabstand −
     Lücke − Knopfbreite", und der Fuß bildet genau das per padding-right
     nach. Keine Messung in JavaScript. */
  .line-items-table.form-rows--wide tbody td.stmt-cell--money {
    flex: 0 0 calc(120px + var(--pos-del-gap) + var(--pos-del-w));
    margin-left: auto;
  }
  .line-items-table.form-rows--wide tfoot tr:not(:first-child) {
    padding-right: calc(16px + var(--pos-del-gap) + var(--pos-del-w));
  }
}
@media (max-width: 767.98px) {
  .line-items-table.form-rows tbody td.stmt-cell--date { flex: 1 1 42%; }
  .line-items-table.form-rows tbody td.stmt-cell--code,
  .line-items-table.form-rows tbody td.stmt-cell--pzn { flex: 1 1 24%; }
  .line-items-table.form-rows tbody td.stmt-cell--status {
    flex: 0 0 auto; padding-bottom: 8px;
  }
  .line-items-table.form-rows tbody td.stmt-cell--quantity { flex: 1 1 16%; }
  .line-items-table.form-rows tbody td.stmt-cell--factor { flex: 1 1 20%; }
  .line-items-table.form-rows tbody td.stmt-cell--money { flex: 1 1 28%; }
  .line-items-table.form-rows--incard tfoot tr {
    padding-left: 16px; padding-right: 16px;
  }

  /* BUG-0407: dieselbe Doppel-Border-Mechanik wie im Desktop-Block oben,
     hier für den Mobil-Kanon (`.form-rows`, ohne `--wide`). */
  .line-items-table.form-rows tfoot tr:first-child { border-top: 0; }

  /* BUG-0407 (Option A): mobil wächst die Betragszelle (flex 1 1 28%) als
     letzte Zelle bis zum Zeilenende — dieselbe Konstante wie im
     Desktop-Block. */
  .line-items-table.form-rows--incard tfoot tr:not(:first-child) {
    padding-right: calc(16px + var(--pos-del-gap) + var(--pos-del-w));
  }
}
/* BUG-0407 (Option A): Betrag + Löschen als Einheit. Der Knopf hat eine feste
   Breite (Token), damit der Tabellenfuß die Betragskante als Konstante
   nachbilden kann. */
.line-items-table { --pos-del-w: 24px; --pos-del-gap: 12px; }
.line-items-table .li-money {
  display: flex; align-items: center; gap: var(--pos-del-gap);
}
.line-items-table .li-money-field { flex: 1 1 auto; min-width: 0; }
.line-items-table .li-money-del {
  flex: 0 0 var(--pos-del-w); width: var(--pos-del-w);
  display: inline-flex; align-items: center; justify-content: center;
}
/* Die kanonische tfoot-Flexregel ist spezifischer als Bootstrap .d-none. */
.line-items-table.form-rows tfoot tr.d-none { display: none; }
/* Die letzte Summenzeile schloss bündig mit der detail-card ab. Am tfoot statt
   an tr:last-child, weil die Differenz-Zeile meistens d-none trägt. */
.line-items-table tfoot { padding-bottom: 6px; }

/* ===== positions-tabellen: konfidenz + summenzeile (design-fix) =====
   1) KI-Konfidenz der Positionszeilen: markiert wird der Rahmen des
      Eingabefeldes, nicht die Tabellenzelle. Die Bootstrap-Flächenklassen
      (.table-success/-warning/-danger) sind aus _line_item_row.html raus —
      gleiche Entscheidung wie im Document-Browser (FEATURE-0134).
   2) Summenzeile und "Position hinzufügen" ohne Beige-Fill: app.css setzt
      `.table > tfoot th/td` auf --stone-50; in den Positions-Tabellen trägt
      die Zeile ihre Bedeutung über Fettung + Trennlinie (analog Fix 4.5a
      bei .list-table). */
.li-row--conf-high .form-control,
.li-row--conf-high .form-select { border-color: var(--status-success-fg); }
.li-row--conf-mid .form-control,
.li-row--conf-mid .form-select { border-color: var(--warning); }
.li-row--conf-low .form-control,
.li-row--conf-low .form-select { border-color: var(--danger); }
/* Formfehler schlagen die Konfidenz-Markierung. */
.li-row--conf-high .form-control.is-invalid,
.li-row--conf-mid .form-control.is-invalid,
.li-row--conf-low .form-control.is-invalid { border-color: var(--danger); }

.table.positions-table > tfoot th,
.table.positions-table > tfoot td { background: transparent; }

/* ===== positions-tabellen: status-markierung =====
   Das Icon der Status-Spalte ist in allen drei Zuständen ein Popover-Button
   (_line_item_status.html). Es saß bisher an der Oberkante der Zelle, während
   die Nachbarfelder ihre Mitte tiefer haben — die min-height entspricht der
   Höhe von .line-items-table .form-control (2x7px Padding + Zeile + Rahmen),
   dadurch liegt das Icon auf der Feldlinie statt darüber. */
.line-items-table td.stmt-cell--status { display: flex; flex-direction: column; }
.line-items-table .li-status {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 35px; width: 100%;
  border: 0; background: none; padding: 0; color: inherit; cursor: pointer;
}
/* Popover mobil im Viewport halten (Default sind 276px ab Zellmitte). */
.li-status-pop { max-width: min(280px, calc(100vw - 32px)); }


/* ==========================================================================
   Aus dem Frontend-Audit 2026-08-08 (Block B4 receipts)
   --------------------------------------------------------------------------
   Diese Regeln lebten bis zum Audit-Block B4 Global in
   receipts/static/receipts/receipts-audit-b4.css — einer app-eigenen Datei,
   weil code/static/css/** im Parallelbetrieb einem anderen Block gehoerte.
   Hier sind sie am kanonischen Ort; die Uebergangsdatei ist geloescht und die
   vier <link>-Zeilen in receipt_list, receipt_detail, submission_list und
   submission_detail sind entfallen.
   ========================================================================== */

/* --- UX1-08: Statuslegende oberhalb der Liste (Desktop) -------------------
   Die Legende hing als Fußzeile unter einer Liste mit 188 Zeilen und
   Nachladen. Jetzt steht sie im DOM VOR der .list-surface; unterhalb von
   992 px bleibt sie unverändert am Bildschirmrand fixiert (Regel in
   app-components.css), die DOM-Position ist dort ohne Wirkung. */
@media (min-width: 992px) {
  .bl-legend--top {
    border: 1px solid var(--hairline);
    border-bottom: 1px solid var(--hairline-soft);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }
  .bl-legend--top + .list-surface {
    border-top: 0;
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }
}

/* --- UX1-08: aufklappbare Erklärung der Statuswörter ---------------------
   Die Kurztexte der Legende sagen, WELCHE Stufen es gibt, nicht was sie
   bedeuten. Der Satz je Stufe steht in einem nativen <details> statt in
   einem title-Attribut: title ist auf Touch-Geräten unerreichbar und wird
   von Screenreadern nur unzuverlässig vorgelesen. */
.bl-legend-help {
  margin-bottom: 10px;
  font-size: var(--fs-12);
  color: var(--text-secondary);
}
.bl-legend-help > summary {
  cursor: pointer;
  font-size: var(--fs-11);
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-secondary);
  list-style: none;
}
.bl-legend-help > summary::-webkit-details-marker { display: none; }
.bl-legend-help > summary::before {
  content: '＋';
  margin-right: 6px;
  font-weight: 400;
}
.bl-legend-help[open] > summary::before { content: '－'; }
.bl-legend-help > summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.bl-legend-help dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 12px;
  margin: 8px 0 0;
  padding: 10px 14px;
  background: var(--milk-pure);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--radius-md);
}
.bl-legend-help dt { font-weight: 700; color: var(--espresso); }
/* BUG-0044: Zwischenüberschrift, wo eine Liste mehrere Statusachsen erklärt.
   Sie steht über die ganze Breite, damit die beiden Achsen nicht als eine
   durchgehende Reihe gelesen werden. */
.bl-legend-help-gruppe {
  grid-column: 1 / -1; margin-top: 8px;
  font-size: var(--fs-11); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-secondary);
}
.bl-legend-help dl > .bl-legend-help-gruppe:first-child { margin-top: 0; }
.bl-legend-help dd { margin: 0; }
@media (max-width: 575.98px) {
  .bl-legend-help dl { grid-template-columns: 1fr; gap: 2px; }
  .bl-legend-help dd { margin-bottom: 6px; }
}

/* --- A7-04 / A7-17: eine Kürzungsregel für lange Freitexte ---------------
   Ein Aussteller mit 200 Zeichen zog die Belegtabelle auf 2826 px auf und
   schob Person, Betrag und Status aus dem Sichtfeld. `white-space: nowrap`
   allein genügt im Auto-Layout nicht — ohne Breitendeckel dehnt es die
   Spalte nur weiter. Der volle Wert bleibt im title-Attribut erreichbar. */
.u-clip {
  /* inline-block statt block: die Regel trifft Tabellenzellen ebenso wie
     Wörter innerhalb einer Meta-Zeile („Datum · Person"), die bei block
     umbrechen würden. In Flex-Containern wirkt sie unverändert. */
  display: inline-block;
  vertical-align: bottom;
  max-width: var(--u-clip-max, 32ch);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Der Deckel gehört auf das innere Element: max-width auf einer <td> wirkt
   im Auto-Layout nicht. 32ch lassen normale Praxisnamen ganz stehen
   („AXA Krankenversicherung AG" = 26 Zeichen) und bremsen erst die Ausreißer. */
.u-clip--sm { --u-clip-max: 18ch; }
/* Einzeiler ohne festen Deckel — für Überschriften, die die volle Breite
   ihres Containers nutzen dürfen, aber nicht umbrechen sollen. */
.u-clip--line { --u-clip-max: 100%; }

@media (max-width: 991.98px) {
  /* Mobile Karten sind ohnehin schmal — dort deckelt die Kartenbreite. */
  .u-clip { --u-clip-max: 100%; }
}

/* Der Seitenkopf ist eine Flex-Zeile; ohne min-width: 0 wächst sein linker
   Block mit dem Titel mit, und `max-width: 100%` am h1 bezieht sich auf eine
   Breite, die es selbst verursacht hat (gemessen: 2761 px bei 1440 px
   Fenster). Erst die Schrumpferlaubnis macht die Kürzung wirksam. */
.detail-head > div:first-child,
.detail-title-row { min-width: 0; }
/* 0 1 auto, nicht 1 1 auto: Der Titel darf schrumpfen, aber nicht wachsen —
   sonst schöbe er den Belegtyp-Chip auch bei kurzen Namen in die nächste Zeile. */
.detail-title.u-clip { flex: 0 1 auto; }

/* Dasselbe eine Ebene tiefer: Grid-Elemente haben min-width: auto und
   weigern sich, unter ihre Inhaltsbreite zu schrumpfen — die Karte
   „Belegdaten" wuchs dadurch auf 1354 px statt der Kartenbreite. */
.meta-grid > * { min-width: 0; }

/* ===== pagi (klassische Blätterleiste, BUG-0035) ===== */
/* Eigenes Vokabular statt der Bootstrap-Klassen .pagination/.page-item/
   .page-link: für die existierte im Cappuccino-Layer keine vollständige
   Überschreibung, und die Leiste blieb blau, während die Liste ringsum warm
   ist. Sie sitzt als volle Zeile am Fuss der Tabelle
   (includes/_infinite_scroll_trigger.html) und liegt damit im Swap-Ziel —
   beim Blättern wird sie mitgetauscht. */
.pagi-row > td { padding: 0; }
.pagi {
  display: flex; align-items: center; justify-content: center;
  gap: 6px; padding: 14px 16px;
}
.pagi-link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  background: white; color: var(--espresso); text-decoration: none;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
.pagi-link:hover {
  background: var(--tint-warm); border-color: var(--control-border);
  color: var(--espresso);
}
/* Der Fokusring ist kein Detail: die Leiste besteht aus vier Symbolzielen,
   die beim Durchtabben ohne ihn nicht zu unterscheiden sind. */
.pagi-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pagi-link.is-disabled {
  background: var(--stone-100); border-color: var(--hairline-soft);
  color: var(--stone-300); pointer-events: none;
}
/* Die aktuelle Seite ist der einzige Zustand, den die Leiste anzeigt — es gibt
   keine Seitenzahlenreihe. Sie trägt deshalb dieselbe Fläche wie ein Ziel,
   aber warm gefüllt: klar als „hier bist du" lesbar, ohne wie eine
   Schaltfläche zum Klicken einzuladen. */
.pagi-current {
  display: inline-flex; align-items: center; justify-content: center;
  height: 38px; min-width: 72px; padding: 0 14px;
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  background: var(--tint-warm);
  font-size: var(--fs-13); font-weight: 700; color: var(--espresso);
  font-variant-numeric: tabular-nums;
}

/* ===== Kostenträger-Übersicht der Beleg-Detailseite (FEATURE-0163 Punkt 10) =====

   Je Kostenträger ein Block: Kopfzeile (Kurzicon, Trägertyp, Firmenname links,
   Fortschritts-Stufe rechts), darunter die Einreichungen und Abrechnungen als
   `link-rows`, darunter die nächste Handlung. Die Blöcke trennt eine Haarlinie
   statt einer Karte in der Karte — sie stehen bereits in `.detail-card-body`. */
.payer-block { padding: 14px 0; border-top: 1px solid var(--hairline-soft); }
.payer-block:first-child { padding-top: 0; border-top: 0; }
.payer-block:last-child { padding-bottom: 0; }

/* Auf schmalen Schirmen bricht die Stufe unter den Namen, statt ihn zu quetschen. */
.payer-block-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 10px;
  margin-bottom: 10px;
}
.payer-block-head .payer-value { min-width: 0; }
/* Die Stufe bleibt rechts, auch wenn sie unter den Namen rutscht —
   sonst wandert sie mobil unter das Kurzicon und liest sich als Teil
   des Namens statt als Statusspalte. */
.payer-block-stage { margin-left: auto; }
.payer-block-title {
  font-size: var(--fs-13);
  font-weight: 700;
  color: var(--espresso);
  margin: 0;
}
/* Der Trägertyp trägt den Namen mit: Eine Konfiguration darf denselben
   Versicherer mehrfach führen (AXA als PKV und als Zusatzversicherung). */
.payer-block-type { font-weight: 700; color: var(--espresso); }
.payer-block-note {
  font-size: var(--fs-12);
  font-weight: 500;
  color: var(--text-secondary);
  margin: 6px 0 0;
}
.payer-block-action { margin-top: 10px; }

/* ============== GESUNDHEITSKOSTEN-GRAPH (B7, FEATURE-0160) ============== */
/* Umschalter Monatsverlauf | Jahresvergleich im Kartenkopf (AC-B7-02).
   Erbt das Segmented Control der Belegtyp-Auswahl (.type-toggle) und macht es
   schmal genug für eine Kopfzeile neben zwei Schaltern. */
.graph-view-toggle { flex: none; }
.graph-view-toggle .btn { padding: 6px 12px; white-space: nowrap; }

/* „Vorjahr einblenden" gibt es nur im Monatsverlauf (AC-B7-02): Ein zweites
   Jahr neben einem Vergleich aller Jahre wäre dasselbe Jahr zweimal. Die Regel
   steht hier und nicht zusätzlich im Template — zwei Quellen für dieselbe
   Sichtbarkeit laufen auseinander, sobald eine von beiden angefasst wird. */
#health-cost-filters:has(#view-year:checked) #previous-year-toggle { display: none; }

/* ===== einrichtungshinweis (BUG-0657) =====
   Stand der Einrichtung auf den vier Einstellungsseiten
   (settings/_einrichtungshinweis.html). Farben und Rundung kommen aus
   .alert.alert-info (cappuccino.css); hier steht nur die Anordnung: Stand und
   nächster Schritt links, Rückweg zur Einrichtung rechts, auf schmalen
   Schirmen untereinander. Die Links sind unterstrichen, weil Farbe allein sie
   in der getönten Fläche nicht vom Text trennt. */
.einrichtungshinweis {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 24px;
}
.einrichtungshinweis a {
  text-decoration: underline;
}

/* ============== BUG-0497: Felder mobil mindestens 16 px ============== */
/* iOS Safari zoomt beim Fokus in ein Feld unter 16 px hinein und zoomt nicht
   von selbst zurück. Das war der Grund der früheren Zoomsperre (Audit R6-06);
   mit 16 px an der Wurzel braucht die App keine Sperre mehr. Gilt bis zum
   Bootstrap-Breakpoint `sm` (unter 576px), nur in der eingeloggten Oberfläche
   (`data-app`) und für Textfelder: Checkbox, Radio, Range, Datei und Buttons
   lösen keinen Fokuszoom aus. Die Selektorliste steht bewusst nach allen
   Feldregeln (.app-form, .filter-form, .line-items-table …), damit eine
   spätere Feldregel mit gleicher Spezifität sie nicht überstimmt. ID-Regeln
   (z. B. `#deductibles-table`) gewinnen trotzdem; sie setzen `font-size`
   deshalb nur ab 576 px (R497-01). */
@media (max-width: 575.98px) {
  [data-app] :is(input, select, textarea):not(
    [type="checkbox"], [type="radio"], [type="range"], [type="file"],
    [type="hidden"], [type="submit"], [type="button"], [type="reset"],
    [type="image"], [type="color"]
  ) {
    font-size: var(--fs-16);
  }
}
