/* ==========================================================================
   Finanztracker — app.css
   Design system implementation of DESIGN.md (Swiss-modern, hell und dunkel
   nach Einstellungen › Darstellung — die Farben stehen als light-dark() in
   tokens.css; nie @media (prefers-color-scheme), das sähe nur das System).

   Inhalt:
     01  Tokens — ausgelagert nach assets/tokens.css, dort verlinkt
         (§2 Farben, §3 Typografie, §5 Abstände, §6 Elevation)
     02  Reset & Basis
     03  Typografie-Klassen
     04  Layout-Gerüst (Sidebar, Content, Sections, Grids)
     05  Navigation (Sidebar, Tabbar, Menu)
     06  Buttons
     07  Cards
     08  Formulare (field, input, select, textarea, money-input, checkbox)
     09  Tabellen & Listen (inkl. .table-scroll)
     10  Badges & Chips
     11  Stats & Money
     11b Diagramm-Container (.chart-scroll)
     12  Progress (Budget / Ziel)
     13  Segmented control
     14  Flash / Meldungen
     15  Empty state
     16  Modal & Sheet
     17  Split-Buchung
     18  Utilities & Accessibility
     19  Responsive (§8) — Tablet, Handy-Grundschicht, Standalone/PWA
     20  Reduced motion & Print
     21  Nachtrag — App-Shell und Seite «Heute» (Icons, Seitenleiste, Tabbar,
         Reiter, fw-momo-zeile, fw-zustand, fw-quest, fw-monat,
         fw-ziel, fw-desk/fw-phone)
     22  Nachtrag — Buchungsformular (Modal «+ Buchung» und Bearbeiten-Maske)
     23  Buchungsliste (Tagesgruppen, Filter, Sammelaktion, Karten am Handy)

   Regeln: keine hart kodierten Hexwerte in Komponenten, nur die Spacing-Skala
   4/8/12/16/20/24/32/40/56/72, keine Schatten ausser Level 2/3. Dunkel
   entsteht allein ueber die Tokens: hier steht nie eine eigene Dunkel-Farbe.
   ========================================================================== */

/* ==========================================================================
   01  TOKENS — stehen in tokens.css und werden von jedem Einstieg selbst
       verlinkt: templates/layout.php und templates/login.php, beide ueber
       fw_asset() mit ?v=<mtime>. Kein @import hier: er truege keine
       Versionsnummer, und .htaccess cacht text/css ein Jahr — geaenderte
       Tokens erreichten ein Geraet dann nie. Der Link spart ausserdem
       einen zweiten, serialisierten Rundlauf vor dem ersten Bild.
   ========================================================================== */


/* ==========================================================================
   02  RESET & BASIS
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-regular);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-wrap: break-word;
}

/* Die Anmeldung steht auf Papier, alles andere (auch Momo) auf dem Gruppengrund. */
body.page--auth { background: var(--bg-plain); }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
}

ul[class], ol[class] { list-style: none; }

/* Nummerierte Anleitung: der Reset oben nimmt jeder ol mit Klasse die Ziffern,
   und eine Anleitung ohne Schritt 1, 2, 3 ist keine Anleitung mehr. Eine
   Regel für alle Seiten — vorher stand sie nur im Kopf der Einstellungen.
   «ol.fw-steps», nicht «.fw-steps»: der Reset «ol[class]» wiegt gleich viel
   wie eine Klasse, und nur die spätere Regel gleicher Spezifität gewinnt. */
ol.fw-steps {
  list-style: decimal;
  padding-left: var(--sp-20);
}

.fw-steps > li + li { margin-top: var(--sp-12); }
.fw-steps > li::marker { color: var(--text-muted); }

img, svg, video, canvas {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: var(--tint);
  text-decoration: none;
}

a:hover { color: var(--accent-hover); text-decoration: underline; }

button, input, select, textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button { background: none; border: 0; padding: 0; cursor: pointer; }

hr {
  border: 0;
  border-top: 1px solid var(--separator);
  margin: var(--sp-24) 0;
}

::placeholder { color: var(--text-subtle); opacity: 1; }

::selection { background: var(--accent-weak); color: var(--text); }

/* Sichtbarer Fokus — niemals ohne Ersatz entfernen (§4) ---------------------- */
:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-control);
}

/* Fallback für Browser ohne :focus-visible */
:focus:not(:focus-visible) { outline: none; }

/* ==========================================================================
   03  TYPOGRAFIE (§3)
   ========================================================================== */

.display,
.t-display {
  font-size: var(--fs-display);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-tight);
}

h1, .h1, .t-h1 {
  font-size: var(--fs-h1);
  font-weight: var(--fw-semibold);
  line-height: 1.25;
}

h2, .h2, .t-h2 {
  font-size: var(--fs-h2);
  font-weight: var(--fw-semibold);
  line-height: 1.3;
}

h3, .h3, .t-h3 {
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: 1.4;
}

.body-sm,
.t-body-sm {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
}

.label,
.t-label {
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  line-height: 1.4;
  color: var(--text-muted);
}

.caption,
.t-caption {
  font-size: var(--fs-caption);
  line-height: 1.4;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.muted     { color: var(--text-muted); }
.subtle    { color: var(--text-subtle); }
.prose     { max-width: var(--reading-max); }
.prose p + p { margin-top: var(--sp-12); }

.text-positive { color: var(--positive); }
.text-negative { color: var(--negative); }
.text-warning  { color: var(--warning); }
.text-accent   { color: var(--tint); }

/* Alles, was Zahlen zeigt, läuft tabellarisch (§3) --------------------------- */
.money,
.money-lg,
.money-display,
.num,
.date,
time,
.tabular {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ==========================================================================
   04  LAYOUT-GERÜST (§5)
   ========================================================================== */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  min-height: 100vh;
  min-height: 100dvh;
}

.app > * { min-width: 0; }

.main {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.content {
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--sp-32) var(--sp-24) var(--sp-72);
  flex: 1;
}

.content--narrow { max-width: 720px; }

/* Seitenkopf ---------------------------------------------------------------- */
.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--sp-16);
  margin-bottom: var(--sp-24);
}

.page-header__text { min-width: 0; }

.page-title { font-size: var(--fs-h1); font-weight: var(--fw-semibold); }

.page-subtitle {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-muted);
}

.page-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  flex-wrap: wrap;
}

/* Sections: 32px zwischen Seitenabschnitten (§5) ----------------------------- */
.section + .section { margin-top: var(--sp-32); }

.section__header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-12);
  margin-bottom: var(--sp-16);
}

.section__title { font-size: var(--fs-h2); font-weight: var(--fw-semibold); }

.section__hint {
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
}

/* Grids & Stacks ------------------------------------------------------------ */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--sp-16);
}

.card-grid--wide { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

.stack        { display: flex; flex-direction: column; }
.stack > * + * { margin-top: var(--sp-16); }
.stack-4  > * + * { margin-top: var(--sp-4); }
.stack-8  > * + * { margin-top: var(--sp-8); }
.stack-12 > * + * { margin-top: var(--sp-12); }
.stack-16 > * + * { margin-top: var(--sp-16); }
.stack-24 > * + * { margin-top: var(--sp-24); }
.stack-32 > * + * { margin-top: var(--sp-32); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-8);
}

.cluster-12 { gap: var(--sp-12); }
.cluster-16 { gap: var(--sp-16); }
.cluster--between { justify-content: space-between; }
.cluster--end { justify-content: flex-end; }

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-12);
  margin-bottom: var(--sp-16);
}

.toolbar__spacer { flex: 1 1 auto; }

/* Zwei gleich breite Haelften — «Handbuchung links, Importzeile rechts».
   Auf dem Handy untereinander (Block D). */
.pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-16);
}

.pair > * { min-width: 0; }

.divider {
  height: 1px;
  background: var(--separator);
  border: 0;
  margin: var(--sp-16) 0;
}

/* ==========================================================================
   05  NAVIGATION
   ========================================================================== */

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  gap: var(--sp-24);
  padding: var(--sp-24) var(--sp-12);
  background: var(--bg);
  border-right: 1px solid var(--separator);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  padding: 0 var(--sp-8);
  color: var(--text);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  letter-spacing: -0.01em;
  text-decoration: none;
  min-height: var(--control-h-sm);
}

.sidebar__brand:hover { color: var(--text); text-decoration: none; }

.sidebar__mark {
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-tile);
  background: var(--accent);
  color: var(--on-accent);
  display: grid;
  place-items: center;
  font-size: var(--fs-label);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
}

.sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.sidebar__group + .sidebar__group { margin-top: var(--sp-20); }

.sidebar__group-label {
  display: block;
  padding: 0 var(--sp-8) var(--sp-8);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--text-muted);   /* Gruppentitel sind Inhalt, kein Schmuck */
}

.sidebar__footer { margin-top: auto; }

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  min-height: var(--control-h);
  padding: 0 var(--sp-12);
  border-radius: var(--radius-control);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  transition: background-color var(--t-fast), color var(--t-fast);
}

.nav-item:hover {
  background: var(--fill);
  color: var(--text);
  text-decoration: none;
}

.nav-item.is-active,
.nav-item[aria-current="page"] {
  background: var(--accent-weak);
  color: var(--tint);
}

.nav-item__icon {
  flex: none;
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  color: currentColor;
}

.nav-item__icon svg { width: 18px; height: 18px; stroke: currentColor; fill: none; }

.nav-item__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-item__badge {
  margin-left: auto;
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);   /* Zahl, die man lesen koennen muss */
}

/* Menü / Popover — Elevation Level 2 (§6) ------------------------------------ */
.menu {
  min-width: 200px;
  padding: var(--sp-4);
  background: var(--surface-elevated);
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-2);
}

.menu__item {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  width: 100%;
  min-height: var(--control-h-sm);
  padding: 0 var(--sp-8);
  border-radius: var(--radius-tile);
  color: var(--text);
  font-size: var(--fs-body-sm);
  text-align: left;
  text-decoration: none;
}

.menu__item:hover { background: var(--fill); text-decoration: none; color: var(--text); }
.menu__item--danger { color: var(--negative); }
.menu__item--danger:hover { background: var(--negative-weak); color: var(--negative); }
.menu__sep { height: 1px; background: var(--separator); margin: var(--sp-4) 0; }

/* Vorschlagsliste (Combobox) — DESIGN.md «Vorschlagsliste (Combobox)» -------
   Liegt IM FLUSS direkt unter dem Feld, kein Popup: .modal__body scrollt, ein
   absolut gesetztes Menü würde dort abgeschnitten, und im Modal (Ebene 3)
   stünde sonst ein zweiter Schatten. Darum Ebene 1: Fläche und Haarlinie. Die
   aktive Option trägt aria-selected; der Fokus bleibt im Eingabefeld, dessen
   Fokusring stehen bleibt. */
.haendler-liste {
  margin: var(--sp-4) 0 0;
  /* Sechs Optionen sind über 270 px hoch: im scrollenden .modal__body mit
     offener Bildschirmtastatur läge die Liste sonst ganz unter dem Rand.
     Viereinhalb Zeilen zeigen, dass es weitergeht. */
  max-height: calc(var(--control-h-touch) * 4.5);
  overflow-y: auto;
  padding: var(--sp-4);
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
}
.haendler-liste[hidden] { display: none; }

.haendler-liste__option {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: var(--control-h-touch);
  padding: var(--sp-4) var(--sp-8);
  border-radius: var(--radius-control);
  color: var(--text);
  cursor: pointer;
}
.haendler-liste__option:hover { background: var(--fill); }
.haendler-liste__option[aria-selected="true"] {
  background: var(--accent-weak);
  color: var(--tint);
}

.haendler-liste__name {
  font-size: var(--fs-body);
  line-height: var(--lh-tight);
}
.haendler-liste__meta {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-muted);
}

/* Mobile Tabbar — erst unter 768px sichtbar (§8) ------------------------------ */
.tabbar { display: none; }

/* Kopfzeile nur auf dem Phone (Titel + eine Aktion) --------------------------- */
.topbar { display: none; }

/* ==========================================================================
   06  BUTTONS (§4)
   ========================================================================== */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-border: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-8);
  height: var(--control-h);
  padding: 0 var(--sp-16);
  border: 1px solid var(--btn-border);
  border-radius: var(--radius-pill);   /* Kapsel (§4) */
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast), border-color var(--t-fast),
              color var(--t-fast), transform var(--t-fast);
}

.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn:disabled,
.btn.is-disabled,
.btn[aria-disabled="true"] {
  opacity: 0.4;
  pointer-events: none;
  cursor: not-allowed;
}

.btn__icon { flex: none; width: 16px; height: 16px; }
.btn__icon svg { width: 16px; height: 16px; stroke: currentColor; fill: none; }

/* Varianten ----------------------------------------------------------------- */
.btn-primary {
  --btn-bg: var(--accent);
  --btn-fg: var(--on-accent);
  --btn-border: var(--accent);
}
.btn-primary:hover { --btn-bg: var(--accent-hover); --btn-border: var(--accent-hover); --btn-fg: var(--on-accent); }

.btn-secondary {
  --btn-bg: var(--surface);
  --btn-fg: var(--text);
  --btn-border: var(--separator);
}
.btn-secondary:hover { --btn-bg: var(--fill); --btn-border: var(--border-strong); --btn-fg: var(--text); }

/* Textknopf: traegt den Tint wie ein Link (iOS «plain»). */
.btn-ghost {
  --btn-bg: transparent;
  --btn-fg: var(--tint);
  --btn-border: transparent;
}
.btn-ghost:hover { --btn-bg: var(--fill); --btn-fg: var(--text); }

.btn-danger {
  --btn-bg: transparent;
  --btn-fg: var(--negative);
  --btn-border: transparent;
}
.btn-danger:hover { --btn-bg: var(--negative-weak); --btn-fg: var(--negative); }

/* Grössen ------------------------------------------------------------------- */
.btn--sm {
  position: relative;
  height: var(--control-h-sm);
  padding: 0 var(--sp-12);
  font-size: var(--fs-body-sm);
}
/* 34px sichtbar, 44px Trefferfeld: das Pseudo-Element verschiebt kein Layout. */
.btn--sm::after { content: ""; position: absolute; inset: -5px 0; }

.btn--lg { height: var(--control-h-lg); padding: 0 var(--sp-24); font-weight: var(--fw-semibold); }

.btn--block { display: flex; width: 100%; }

.btn--icon {
  width: var(--control-h);
  padding: 0;
  flex: none;
}

.btn--icon.btn--sm { width: var(--control-h-sm); }

/* Textlink im Fliesstext ----------------------------------------------------- */
.link {
  color: var(--tint);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--border-strong);
}
.link:hover { color: var(--accent-hover); text-decoration-color: currentColor; }

/* ==========================================================================
   07  CARDS (§4, §6 Level 1)
   ========================================================================== */

/* Randlos: die Karte trennt sich ueber die Helligkeit vom Gruppengrund --bg.
   Der Rand bleibt transparent stehen, damit Hover und «Mehr Kontrast» ihn
   einfaerben koennen, ohne dass etwas springt. */
.card {
  background: var(--surface);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  padding: var(--sp-20);
}

/* Cards verschachteln nicht — innen trennen Hairlines (§4) -------------------- */
.card .card {
  border: 0;
  border-radius: 0;
  padding: 0;
  background: none;
}

.card > * + * { margin-top: var(--sp-12); }

.card__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-12);
}

.card__title { font-size: var(--fs-h3); font-weight: var(--fw-semibold); }

.card__meta {
  font-size: var(--fs-caption);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.card__footer {
  margin-top: var(--sp-16);
  padding-top: var(--sp-12);
  border-top: 1px solid var(--separator);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-12);
}

.card__divider {
  height: 1px;
  background: var(--separator);
  margin: var(--sp-16) calc(var(--sp-20) * -1);
}

/* Card ohne Innenabstand, damit eine Tabelle bündig sitzt --------------------- */
/* Ohne Rand: sonst stuende um den Tageskopf ein 1px-Kranz in Kartenfarbe. */
.card--flush { padding: 0; overflow: hidden; border: 0; }
.card--flush > .card__header { padding: var(--sp-20) var(--sp-20) var(--sp-12); }
.card--flush > .card__footer { margin: 0; padding: var(--sp-12) var(--sp-20); }

.card--accent { background: var(--accent-weak); border-color: transparent; }
/* Auf dem Gruppengrund waere --fill mit 1.00:1 unsichtbar: oben steht sie wie
   eine normale Karte, erst in einer Karte vertieft sie sich. */
.card--sunken { background: var(--surface); border-color: transparent; }
.card .card--sunken { background: var(--fill); }

/* Mehr Kontrast: die randlose Karte bekommt ihre Linie zurueck. Steht hinter
   .card--flush/--accent/--sunken, sonst gewinnt deren border bei gleicher
   Spezifitaet. */
@media (prefers-contrast: more) {
  .card, .table-wrap, .table-scroll, .list { border: 1px solid var(--separator); }
}

/* Anklickbare Card (z. B. Konto) --------------------------------------------- */
a.card,
.card--link {
  display: block;
  color: inherit;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}
a.card:hover,
.card--link:hover { border-color: var(--border-strong); text-decoration: none; color: inherit; }

/* ==========================================================================
   08  FORMULARE (§4)
   ========================================================================== */

.form { display: flex; flex-direction: column; gap: var(--sp-16); }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-16);
}

.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-8);
  margin-top: var(--sp-8);
}

.form-actions--split { justify-content: space-between; }

.field { display: flex; flex-direction: column; gap: var(--sp-8); min-width: 0; }

.field__label {
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--text-muted);
}

.field__label .req { color: var(--negative); margin-left: var(--sp-4); }

.field__hint {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-muted);
}

.field__error {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--negative);
}

.input,
.select,
.textarea {
  width: 100%;
  min-width: 0;
  height: var(--control-h);
  padding: 0 var(--sp-12);
  background: var(--surface);
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
  color: var(--text);
  font-size: var(--fs-body);
  font-family: inherit;
  line-height: normal;
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background-color var(--t-fast);
  appearance: none;
  -webkit-appearance: none;
}

.textarea {
  height: auto;
  min-height: 96px;
  padding: var(--sp-12);
  line-height: var(--lh-body);
  resize: vertical;
}

.select {
  padding-right: var(--sp-32);
  /* Winkel aus zwei Verlaeufen statt einer data:-URI: dort greift var() nicht,
     und im Dunkeln stuende ein fest eingetragenes Grau. So folgt er dem Token. */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-muted) 50%),
    linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-repeat: no-repeat;
  background-size: 5px 5px, 5px 5px;
  background-position: right 19px center, right 14px center;
  cursor: pointer;
}

.input:hover,
.select:hover,
.textarea:hover { border-color: var(--border-strong); }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--tint);
  box-shadow: 0 0 0 3px var(--accent-weak);
}

/* Tastaturfokus zusätzlich mit Ring, damit die Regel „nie ohne Ersatz“ hält --- */
.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: var(--focus-offset);
  box-shadow: none;
}

.input:disabled,
.select:disabled,
.textarea:disabled,
.input[readonly] {
  background: var(--fill);
  color: var(--text-subtle);
  cursor: not-allowed;
  border-color: var(--separator);
}

/* Fehlerzustand -------------------------------------------------------------- */
.field--error .input,
.field--error .select,
.field--error .textarea,
.input.is-invalid,
.select.is-invalid,
[aria-invalid="true"].input {
  border-color: var(--negative);
}

.field--error .input:focus,
.input.is-invalid:focus { box-shadow: 0 0 0 3px var(--negative-weak); }

/* Betragsfeld: rechtsbündig, tabellarisch, mit CHF-Präfix (§4) --------------- */
.money-input { position: relative; display: block; }

.money-input__prefix {
  position: absolute;
  left: var(--sp-12);
  top: 0;
  height: var(--control-h);
  display: flex;
  align-items: center;
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  color: var(--text-muted);   /* die Waehrung ist Information (§7) */
  pointer-events: none;
}

.input--amount {
  padding-left: var(--sp-56);
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-money);
  font-weight: var(--fw-medium);
}

.input--date {
  font-variant-numeric: tabular-nums;
}

/* Schmales Betragsfeld in einer Tabellenzelle oder Zeile (z. B. «Ab Betrag» bei
   den Regeln): ohne CHF-Praefix, nur so breit wie ein Betrag. In einem Flex-
   Container (.cluster) teilt es sich die Zeile mit dem Knopf; als Tabellenzelle
   haelt es seine 140px. Auf dem Handy volle Breite (Block F). */
.input--narrow {
  flex: 1 1 100px;
  width: 140px;
  max-width: 140px;
  min-width: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Suchfeld ------------------------------------------------------------------- */
/* Die Lupe ist eine Maske, gefaerbt mit currentColor: ein <input> traegt kein
   ::before, darum sitzt sie auf dem .field darum herum. */
.input--search { padding-left: var(--sp-40); }
.field:has(> .input--search) { position: relative; color: var(--text-muted); }
.field:has(> .input--search)::after {
  content: "";
  position: absolute;
  left: var(--sp-12);
  bottom: 0;
  width: 14px;
  height: var(--control-h);
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Ccircle cx='6' cy='6' r='4.25' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M9.2 9.2 12.5 12.5' stroke='%23000' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") center / 14px 14px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Ccircle cx='6' cy='6' r='4.25' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M9.2 9.2 12.5 12.5' stroke='%23000' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") center / 14px 14px no-repeat;
  pointer-events: none;
}

/* Checkbox / Radio ----------------------------------------------------------- */
.check {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-8);
  min-height: var(--control-h-sm);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  cursor: pointer;
}

.check input[type="checkbox"],
.check input[type="radio"] {
  flex: none;
  width: 18px;
  height: 18px;
  margin: 1px 0 0;
  accent-color: var(--tint);
  cursor: pointer;
}

.check__text { min-width: 0; }
.check__hint { display: block; color: var(--text-muted); font-size: var(--fs-caption); }

/* Feldgruppe nebeneinander --------------------------------------------------- */
.field-row {
  display: flex;
  gap: var(--sp-12);
  align-items: flex-end;
  flex-wrap: wrap;
}

.field-row > .field { flex: 1 1 180px; }

/* ==========================================================================
   09  TABELLEN & LISTEN (§4)
   ========================================================================== */

/* Tabellen scrollen im eigenen Container, nie die Seite (§8) ------------------
   .table-scroll ist der sprechende Zweitname von .table-wrap: er sagt „diese
   Tabelle bleibt auch auf dem Handy eine Tabelle und scrollt hier drin“.
   Tabellen, die auf dem Handy zu Listenzeilen werden, tragen .table--stack. */
.table-wrap,
.table-scroll {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  background: var(--surface);
  border-radius: var(--radius-card);
}

.card .table-wrap,
.card .table-scroll,
.card--flush .table-wrap,
.card--flush .table-scroll { border: 0; border-radius: 0; }

.table-wrap--tall,
.table-scroll--tall { max-height: 560px; overflow-y: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body-sm);
}

.table th,
.table td {
  padding: var(--sp-12) var(--sp-16);
  text-align: left;
  vertical-align: middle;
}

/* --surface statt --fill: der Kopf ist die Oberkante der randlosen Karte und
   waere in --fill auf dem Gruppengrund (1.00:1) mit ihm verschmolzen. */
.table thead th {
  background: var(--surface);
  color: var(--text-muted);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  white-space: nowrap;
  border-bottom: 1px solid var(--separator);
}

.table-wrap--tall thead th,
.table-scroll--tall thead th { position: sticky; top: 0; z-index: 1; }

.table tbody tr { border-bottom: 1px solid var(--separator); }
.table tbody tr:last-child { border-bottom: 0; }
.table tbody tr:hover { background: var(--fill); }

.table tbody td { color: var(--text); }
/* Die Tonklassen verloren gegen die Zeile darueber (0,1,2 schlaegt 0,1,0):
   ein ueberzogenes Konto stand schwarz statt rot, eine Einnahme nicht gruen. */
.table tbody td.money-pos { color: var(--positive); }
.table tbody td.money-zero { color: var(--text-muted); }
.table tbody td.text-negative { color: var(--negative); }

/* Beträge immer in der letzten Spalte, rechtsbündig, tabellarisch (§4) -------- */
.table .num,
.table th.num,
.table td.num,
.table .money {
  text-align: right;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.table .col-shrink { width: 1%; white-space: nowrap; }
.table .col-date   { width: 1%; white-space: nowrap; color: var(--text-muted); font-variant-numeric: tabular-nums; }

.table tfoot td {
  background: var(--fill);
  font-weight: var(--fw-medium);
  border-top: 1px solid var(--separator);
}

.table--compact th,
.table--compact td { padding: var(--sp-8) var(--sp-12); }

.table__row-link { color: var(--text); text-decoration: none; font-weight: var(--fw-medium); }
.table__row-link:hover { color: var(--tint); text-decoration: none; }

.table__sub {
  display: block;
  font-size: var(--fs-caption);
  color: var(--text-muted);
}

/* Aktionen erst beim Hover/Fokus einer Zeile — bleiben tastaturerreichbar ----- */
/* flex-wrap: seit «Zaehlt nicht» stehen hier drei Knoepfe — auf einem schmalen
   Handy bricht die Zeile um, statt aus der Karte zu laufen. */
.table .row-actions { display: flex; flex-wrap: wrap; gap: var(--sp-4); justify-content: flex-end; opacity: 0; transition: opacity var(--t-fast); }
.table tbody tr:hover .row-actions,
.table tbody tr:focus-within .row-actions { opacity: 1; }
@media (hover: none) {
  .table .row-actions { opacity: 1; }
}

/* Liste — die mobile Entsprechung einer Tabelle ------------------------------ */
.list {
  background: var(--surface);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.card .list, .card--flush .list { border: 0; border-radius: 0; }

/* Trennlinie eingezogen wie in iOS-Listen: sie beginnt beim Text, nicht am
   Kartenrand. Als Pseudo-Element, weil ein Rand immer die ganze Breite nimmt. */
.list__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-12);
  padding: var(--sp-12) var(--sp-16);
  color: inherit;
  text-decoration: none;
}

.list__item + .list__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--sp-16);
  right: 0;
  height: 1px;
  background: var(--separator);
}
.list__item:hover { background: var(--fill); text-decoration: none; color: inherit; }

/* Zeilen in <li>: dieselbe eingezogene Trennlinie wie zwischen Geschwistern. */
.list > li { list-style: none; }
.list > li + li > .list__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: var(--sp-16);
  right: 0;
  height: 1px;
  background: var(--separator);
}

/* Chevron am Zeilenende: sagt «fuehrt weiter», wie in iOS in der ruhigsten
   Stufe. Rein dekorativ (aria-hidden), die Zeile ist ohnehin ein Link. */
.list__weiter {
  flex: none;
  width: 8px;
  height: 8px;
  margin-right: 3px;
  border-top: 2px solid var(--text-subtle);
  border-right: 2px solid var(--text-subtle);
  transform: rotate(45deg);
}

.list__main { min-width: 0; flex: 1; }

.list__title {
  /* block: ein <span> ist inline, und dort greift weder overflow noch
     text-overflow — ein langer Händlertext lief aus der Karte. */
  display: block;
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Titel, der umbrechen darf: fuer Saetze mit Betrag und Datum («Semestergebuehr:
   CHF 4'500 in 16 Tagen») oder Titel mit Badge dahinter. Die Ellipse oben ist
   fuer Haendlernamen gedacht, nicht fuer Aussagen — dort ginge die Zahl verloren. */
.list__title--wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4) var(--sp-8);
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.list__meta {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  font-size: var(--fs-caption);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.list__amount {
  flex: none;
  text-align: right;
  font-size: var(--fs-money);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
}

/* Definitionsliste für Detailangaben ---------------------------------------- */
.detail-list { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-8) var(--sp-16); }
.detail-list dt { font-size: var(--fs-label); text-transform: uppercase; color: var(--text-muted); font-weight: var(--fw-medium); align-self: center; }
.detail-list dd { font-size: var(--fs-body-sm); margin: 0; font-variant-numeric: tabular-nums; }

/* ==========================================================================
   10  BADGES & CHIPS (§4)
   ========================================================================== */

.badge,
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--badge-h);
  padding: 0 9px;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--text-muted);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  letter-spacing: 0;
  text-decoration: none;
  /* Lange Kategorienamen liefen bisher hart aus dem Chip heraus. */
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.badge--positive { background: var(--positive-weak); color: var(--positive); }
.badge--negative { background: var(--negative-weak); color: var(--negative); }
.badge--warning  { background: var(--warning-weak);  color: var(--warning); }
.badge--info     { background: var(--hint);          color: var(--text); }
.badge--accent   { background: var(--accent-weak);   color: var(--tint); }
.badge--outline  { background: transparent; border: 1px solid var(--separator); color: var(--text-muted); }

/* Kategorie-Chip: Kategoriefarbe zu 14 % als Fläche, abgedunkelt als Text ----- */
.chip--category {
  --chip: var(--text-muted);
  background: var(--fill);
  color: var(--text);
}

@supports (background: color-mix(in srgb, red 14%, white)) {
  .chip--category {
    background: color-mix(in srgb, var(--chip) 14%, var(--surface));
    /* 55 % ist der hoechste Mischanteil, bei dem alle 15 Kategoriefarben aus
       migration/003 4.5:1 auf der 14-%-Flaeche erreichen (schwaechste:
       Freizeit 4.56:1). Bei den frueheren 72 % fielen acht durch. Nicht
       erhoehen. Shopping hat dort keine Startfarbe und traegt den Rueckfall. */
    color: color-mix(in srgb, var(--chip) 55%, var(--text));
  }
}

.chip__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--chip, var(--text-subtle));
}

/* Entfernbarer Filter-Chip --------------------------------------------------- */
.chip--removable { padding-right: var(--sp-4); }

.chip__remove {
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  color: inherit;
  opacity: 0.6;
}

.chip__remove:hover { opacity: 1; background: var(--hover-tint); }

a.chip:hover,
button.chip:hover { text-decoration: none; filter: brightness(0.98); }

/* ==========================================================================
   11  STATS & MONEY (§3, §7)
   ========================================================================== */

.stat { display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }

.stat__label {
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--text-muted);
}

.stat__value {
  white-space: nowrap;
  font-size: var(--fs-money-lg);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  line-height: var(--lh-tight);
}

.stat__meta {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-muted);
}
/* Amber auf der Begruendung der Heldenzahl («vom Kontostand bis zum Lohn»):
   .text-warning allein verliert gegen die Farbe darueber, weil es frueher in
   der Datei steht. Die Zahl selbst bleibt in Textfarbe (DESIGN.md §2). */
.stat__meta.text-warning { color: var(--warning); }

/* Die eine Heldenzahl einer Seite (§7: „Lead every screen with one number“) --- */
.stat--hero .stat__value {
  font-size: var(--fs-display);
}

.stat-row {
  display: grid;
  /* 180px: «−CHF 3'328.44» in der grossen Geldschrift passt sonst nicht und
     bricht zwischen Währung und Zahl um (Budgets › Dieser Monat). */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--sp-24);
}

/* Beträge -------------------------------------------------------------------- */
.money {
  font-size: var(--fs-money);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.money-lg {
  font-size: var(--fs-money-lg);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  text-align: right;
  white-space: nowrap;
}

.money-display {
  font-size: var(--fs-display);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-tight);
  white-space: nowrap;
}

.money-pos { color: var(--positive); }
/* Ausgaben sind normal, kein Fehler (§9): .money-neg bleibt neutral. Rot gibt
   es nur ueber .text-negative, und das nur an echten Problemen — ueberzogen,
   ueberfaellig, Fehler. Vorher war jede Ausgabe brick-rot; damit trug dieselbe
   Farbe zwei Bedeutungen. */
.money-neg { color: var(--text); }
.money-zero { color: var(--text-muted); }

/* Zahlen tabellarisch (§3): Betraege und Kennzahlen laufen in der Textschrift
   mit gleich breiten Ziffern — sie stehen spaltenweise untereinander, ohne den
   Schreibmaschinen-Look der Systemmonospace, und brauchen weniger Breite.
   Entscheid vom 26.9.2026 (UI-Evaluation C1); Monospace bleibt nur fuer Code. */
.money,
.money-lg,
.money-display,
.num,
td.num,
.stat__value,
.detail-list dd,
.list__amount,
.progress__value,
.fw-ziel__stand {
  font-variant-numeric: tabular-nums;
}

/* Inline im Fliesstext soll nicht rechtsbündig wirken ------------------------ */
.money--inline { text-align: inherit; }

/* ==========================================================================
   11b  DIAGRAMM-CONTAINER

   Die Grafiken selbst kommen aus templates/partials/chart.php (.fw-chart…,
   .fw-hbar…). Hier steht nur der Rahmen drumherum: ein eigener Scrollbereich
   für breite Grafiken. Die kompakte Handy-Fassung .chart--mobile steht im
   Responsive-Teil (§19).
   ========================================================================== */

/* Breite Grafik? Dann scrollt sie hier drin — niemals die Seite (§8).
   Mindestbreite pro Einsatz setzen, Inline-Style ist erlaubt:
     <div class="chart-scroll" style="--chart-min-width: 640px"> … </div> */
.chart-scroll {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

.chart-scroll > * { min-width: var(--chart-min-width, 0); }

/* ==========================================================================
   12  PROGRESS — Budget- und Zielbalken
   ========================================================================== */

.progress {
  --progress: 0%;
  --marker: none;
  position: relative;
  height: 8px;
  background: var(--fill);
  border-radius: var(--radius-pill);
  overflow: hidden;
}

.progress__bar {
  display: block;
  height: 100%;
  width: var(--progress);
  max-width: 100%;
  background: var(--accent);
  border-radius: var(--radius-pill);
  transition: width var(--t-slow);
}

.progress--positive .progress__bar { background: var(--positive); }
.progress--warning  .progress__bar { background: var(--warning); }
.progress--negative .progress__bar { background: var(--negative); }
.progress--muted    .progress__bar { background: var(--border-strong); }

.progress--tall { height: 12px; }

/* Sollmarke (z. B. „so weit müsstest du heute sein“) ------------------------- */
.progress__marker {
  position: absolute;
  top: 0;
  bottom: 0;
  /* Die Bahn hat overflow: hidden — eine Marke bei 100 % faellt sonst ganz
     heraus. Das passiert regelmaessig, sobald die Quest-Marke ueber dem
     Tagesbudget liegt und der Balken auf sie skaliert. */
  left: min(var(--marker, 0%), calc(100% - 3px));
  /* 2px in --text-subtle bei 0.7 Deckkraft ergaben auf der Bahn effektiv
     1.75:1 — WCAG 1.4.11 verlangt 3:1 fuer bedeutungstragende Grafik, und
     diese Marke sagt "so weit muesstest du heute sein". Also breiter,
     dunkler und ohne Transparenz. */
  width: 3px;
  background: var(--text-muted);
}

/* Zweiter, schwaecherer Strich: liegt die Quest-Marke ueber dem Tagesbudget
   (Freitag 100 statt 64), skaliert der Balken auf die Quest und das Tagesbudget
   braucht seine eigene Marke. Keine zweite Farbe, nur eine ruhigere Linie. */
.progress__marker--schwach { width: 2px; background: var(--border-strong); left: min(var(--marker, 0%), calc(100% - 2px)); }

.progress-block { display: flex; flex-direction: column; gap: var(--sp-8); }

.progress__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-12);
}

.progress__name {
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.progress__value {
  font-size: var(--fs-body-sm);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--text-muted);
}

.progress__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-12);
  font-size: var(--fs-caption);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   13  SEGMENTED CONTROL (Filterumschalter)
   ========================================================================== */

.segmented {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  /* --separator statt --fill: auf dem Gruppengrund waere --fill mit 1.00:1
     unsichtbar. Die aktive Kapsel darin: hell weiss, dunkel eine Stufe heller
     als die Spur (iOS macht es ebenso). */
  --seg-aktiv: light-dark(var(--surface), color-mix(in srgb, var(--text) 25%, var(--surface)));
  background: var(--separator);
  border-radius: var(--radius-pill);
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.segmented::-webkit-scrollbar { display: none; }

.segmented__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--control-h-sm);
  padding: 0 var(--sp-12);
  border-radius: var(--radius-pill);
  /* --text wie iOS: --text-muted faende auf --separator nur 4.2:1, den
     Unterschied traegt die Kapsel. */
  color: var(--text);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast);
}

.segmented__item:hover { text-decoration: none; }

/* Ohne Schatten: die Kapsel hebt sich allein ueber die Flaeche von der Spur ab
   (Plan §6, der einzige Schatten in Ruhe sitzt an der Tab-Leiste). */
.segmented__item.is-active,
.segmented__item[aria-selected="true"],
.segmented__item[aria-current="true"],
.segmented__item[aria-current="page"] {
  background: var(--seg-aktiv);
  color: var(--text);
}

/* Auf dem Handy ueber die volle Breite und zu gleichen Teilen.
   Nach Inhalt bemessen sass "Alle" schmal links, "Kreditkarte" breit rechts —
   die Segmente wirkten dadurch wie verschieden wichtige Knoepfe, obwohl sie
   gleichwertige Filter sind. flex: 1 1 0 gibt jedem denselben Anteil,
   min-width: 0 laesst lange Beschriftungen notfalls kuerzen statt ueberlaufen. */
@media (max-width: 767.98px) {
  .segmented {
    display: flex;
    width: 100%;
    overflow-x: hidden;
  }
  /* Zeilenhoehe = Trefferfeld: das Feld ist auf dem Handy 44px hoch
     (--control-h-touch, Block H weiter unten). Mit 32px sass die Beschriftung
     oben und liess unter sich einen Streifen leeren Hintergrund stehen — bei
     der aktiven Pille sichtbar, weil sie sich von der Spur abhebt. */
  .segmented__item {
    flex: 1 1 0;
    min-width: 0;
    padding: 0 var(--sp-8);
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    line-height: var(--control-h-touch);
    text-align: center;
  }
}

.segmented__item:has(input:checked) {
  background: var(--seg-aktiv);
  color: var(--text);
}

.segmented__item:has(input:focus-visible) {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: var(--focus-offset);
}

.segmented--block { display: flex; width: 100%; }
.segmented--block .segmented__item { flex: 1; }

/* Mehr Kontrast: --separator wird dort dunkel, die Beschriftungen fielen auf
   der Spur unter 4.5:1. Spur auf --fill, die Linie zeigt sie. */
@media (prefers-contrast: more) {
  .segmented { background: var(--fill); border: 1px solid var(--separator); }
}

/* ==========================================================================
   14  FLASH / MELDUNGEN
   ========================================================================== */

.flash-stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-8);
  margin-bottom: var(--sp-24);
}

.flash {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-12);
  padding: var(--sp-12) var(--sp-16);
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
}

.flash--success { background: var(--positive-weak); border-color: transparent; color: var(--positive); }
.flash--error   { background: var(--negative-weak); border-color: transparent; color: var(--negative); }
.flash--warning { background: var(--warning-weak);  border-color: transparent; color: var(--warning); }
.flash--info    { background: var(--hint);          border-color: transparent; color: var(--text); }

.flash__body { flex: 1; min-width: 0; }
.flash__title {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  font-weight: var(--fw-semibold);
  white-space: nowrap;
}
/* Auf dem Handy unter den Text, sonst bleibt fuer die Meldung zu wenig Platz. */
@media (max-width: 767.98px) {
  .flash { flex-wrap: wrap; }
  .flash__title { width: 100%; }
}

.flash__close {
  flex: none;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 6px;
  color: currentColor;
  opacity: 0.6;
}

.flash__close:hover { opacity: 1; background: var(--hover-tint); }

.flash.is-leaving { opacity: 0; transition: opacity var(--t-slow); }

/* ==========================================================================
   15  EMPTY STATE (§4)
   ========================================================================== */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-12);
  max-width: 380px;
  margin: 0 auto;
  padding: var(--sp-40) var(--sp-16);
  text-align: center;
}

.empty-state__glyph {
  width: 24px;
  height: 24px;
  color: var(--text-subtle);
  font-size: var(--fs-money-lg);
  line-height: 1;
}

.empty-state__glyph svg { width: 24px; height: 24px; stroke: currentColor; fill: none; }

.empty-state__title { font-size: var(--fs-h3); font-weight: var(--fw-semibold); }

.empty-state__text {
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-muted);
}

.empty-state__action { margin-top: var(--sp-4); }

/* Kompakte Variante innerhalb einer Card/Tabelle ---------------------------- */
.empty-state--inline { padding: var(--sp-24) var(--sp-16); }

/* ==========================================================================
   16  MODAL & SHEET (§6 Level 3)
   ========================================================================== */

.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-24);
}

.modal[hidden] { display: none; }

.modal__backdrop {
  position: absolute;
  inset: 0;
  background: var(--backdrop);
  opacity: 0;
  transition: opacity var(--t-base);
}

.modal.is-open .modal__backdrop { opacity: 1; }

.modal__dialog {
  position: relative;
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - var(--sp-56));
  max-height: calc(100dvh - var(--sp-56));
  display: flex;
  flex-direction: column;
  background: var(--surface-elevated);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-3);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--t-base), transform var(--t-base);
}

.modal.is-open .modal__dialog { opacity: 1; transform: none; }

.modal__dialog--wide { max-width: 720px; }

.modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-12);
  padding: var(--sp-20) var(--sp-20) var(--sp-12);
}

.modal__title { font-size: var(--fs-h2); font-weight: var(--fw-semibold); }

.modal__subtitle {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
}

.modal__close {
  flex: none;
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  display: grid;
  place-items: center;
  border-radius: var(--radius-control);
  color: var(--text-muted);
}

.modal__close:hover { background: var(--fill); color: var(--text); text-decoration: none; }

.modal__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-4) var(--sp-20) var(--sp-20);
}

.modal__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-8);
  padding: var(--sp-12) var(--sp-20);
  border-top: 1px solid var(--separator);
}

.modal__footer--split { justify-content: space-between; }

body.is-modal-open { overflow: hidden; }

/* Geschlossen, aber noch im Ausblenden: faengt keine Tipps mehr ab. */
.modal:not(.is-open) { pointer-events: none; }

/* Ohne JavaScript oeffnet ein Anker auf die id das Modal per :target
   (⋯ in der Navigationsleiste); mit JavaScript uebernimmt FW.modal allein —
   sonst hielte :target ein Sheet offen, das FW.modal nicht schliessen kann. */
@media (scripting: none) {
  .modal:target { display: flex; pointer-events: auto; }
  .modal:target .modal__backdrop { opacity: 1; }
  .modal:target .modal__dialog { opacity: 1; transform: none; }
}

/* Sheet-Kopf (Plan §2): Griff 36×5, Titel mittig, «Fertig» rechts im Tint.
   Er sitzt auf der Sheet-Flaeche selbst — der Inhalt scrollt in .modal__body
   und nie unter ihn, Glas haette hier nichts zu zeigen. */
.sheet__kopf {
  position: relative;
  flex: none;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--sp-8);
  padding: var(--sp-16) var(--sp-16) var(--sp-4);
}

/* Die aelteren Dialoge mit .modal__header (× statt Abbrechen, wie iOS-Sheets
   mit Schliessknopf) tragen denselben Griff ueber ein ::before. */
.sheet__griff,
.modal__header::before {
  content: "";
  position: absolute;
  top: 6px;
  left: 50%;
  width: 36px;
  height: 5px;
  margin-left: -18px;
  border-radius: var(--radius-pill);
  background: var(--border-strong);
}

.sheet__titel {
  grid-column: 2;
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: 22px;
}

.sheet__fertig {
  grid-column: 3;
  justify-self: end;
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h-touch);
  padding: 0 var(--sp-4);
  color: var(--tint);
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
}
.sheet__fertig:hover { color: var(--tint); }

/* Erfassen-Sheet: links Abbrechen (regulaer), rechts Speichern als echter
   Absendeknopf in der Optik von «Fertig». */
.sheet__abbrechen {
  grid-column: 1;
  grid-row: 1;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h-touch);
  padding: 0 var(--sp-4);
  color: var(--tint);
  font-size: var(--fs-body);
}
.sheet__abbrechen:hover { color: var(--tint); }
button.sheet__fertig { grid-row: 1; border: 0; background: none; font-family: inherit; cursor: pointer; }
.sheet__kopf .sheet__titel { grid-row: 1; white-space: nowrap; }
/* Der Griff gehoert dem bodenbuendigen Sheet; im mittigen Dialog ab 768px
   verspraeche er ein Wegziehen, das es dort nicht gibt. */
@media (min-width: 768px) {
  .sheet__griff,
  .modal__header::before { display: none; }
}

/* ⋯-Sheet «Mehr»: gruppierte Liste wie in den iOS-Einstellungen. Hell sitzt
   sie auf dem Gruppengrund, dunkel eine Stufe heller als die Karten. */
.sheet-mehr .modal__dialog { max-width: 420px; background: light-dark(var(--bg), var(--surface)); }
.sheet-mehr .modal__body { padding: var(--sp-8) var(--sp-16) var(--sp-24); }

.sheet-mehr__gruppe {
  margin: 0 0 var(--sp-24);
  padding: 0;
  list-style: none;
  background: var(--surface-elevated);
}
.sheet-mehr__gruppe:last-child { margin-bottom: 0; }

.sheet-mehr .list__item {
  min-height: var(--control-h-touch);
  padding-block: var(--sp-8);
  font-size: var(--fs-body);
  color: var(--text);
}
/* Trennlinie ab dem Text, wie in iOS (16 + 28 Kachel + 12 Abstand). */
.sheet-mehr li + li .list__item::before {
  content: "";
  position: absolute;
  top: 0;
  left: 56px;
  right: 0;
  height: 1px;
  background: var(--separator);
}
.sheet-mehr [aria-current="page"] .list__main { color: var(--tint); font-weight: var(--fw-semibold); }

.sheet-mehr__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-tile);
  background: var(--accent);
  color: var(--on-accent);
}
.sheet-mehr__icon svg { width: 18px; height: 18px; }

.sheet-mehr__weiter { flex: none; display: grid; color: var(--text-subtle); }
.sheet-mehr__weiter svg { width: 16px; height: 16px; stroke-width: 2; }

/* Abmelden: eigene Gruppe, rot, mittig — die eine Zeile, die etwas beendet. */
.sheet-mehr .sheet-mehr__abmelden {
  width: 100%;
  justify-content: center;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--fs-body);
  color: var(--negative);
  cursor: pointer;
}
.sheet-mehr .sheet-mehr__abmelden:hover { color: var(--negative); background: var(--negative-weak); }

/* Rueckfrage (app.js §7): <dialog class="fw-alert">, Titel = data-confirm-
   Text, darunter Abbrechen und die bestaetigende Aktion (zerstoerend: rot).
   Werden die Beschriftungen zu lang, stapeln sie sich — Abbrechen unten. */
.fw-alert {
  width: min(320px, calc(100vw - var(--sp-32)));
  padding: 0;
  border: 0;
  border-radius: var(--radius-card);
  /* --surface statt --surface-elevated: dunkel waere die Karte sonst so hell
     wie ihre gefuellten Knoepfe (--fill) und diese verschwaenden. */
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-3);
  /* Dunkel traegt der Schatten nicht: eine Haarlinie zeichnet die Kante. */
  outline: 1px solid light-dark(transparent, var(--separator));
}
.fw-alert::backdrop { background: var(--backdrop, rgba(11, 10, 9, .40)); }
.fw-alert__inhalt { padding: var(--sp-20); }
.fw-alert__titel {
  margin: 0 0 var(--sp-20);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: 22px;
  text-align: center;
  overflow-wrap: anywhere;
}
.fw-alert__knoepfe { display: flex; flex-wrap: wrap-reverse; gap: var(--sp-8); }
.fw-alert__knoepfe .btn { flex: 1 1 120px; min-width: fit-content; padding-inline: var(--sp-8); white-space: normal; }
/* min-width: fit-content — passt ein Knopftext nicht neben Abbrechen, stapeln
   sich die Knoepfe (wrap-reverse: Aktion oben), statt einzeln umzubrechen;
   erst ein Text breiter als die Karte bricht im Knopf um. */
/* Wie iOS: Abbrechen und eine zerstoerende Aktion als gefuellte Kapseln,
   die zerstoerende mit roter Schrift; eine gewoehnliche Aktion in Navy. */
.fw-alert__knoepfe .btn-secondary,
.fw-alert__knoepfe .btn-danger { --btn-bg: var(--fill); --btn-border: transparent; }
.fw-alert__knoepfe .btn-danger:hover { --btn-bg: var(--negative-weak); }

/* ==========================================================================
   17  SPLIT-BUCHUNG
   ========================================================================== */

.split { display: flex; flex-direction: column; gap: var(--sp-12); }

.split__rows { display: flex; flex-direction: column; gap: var(--sp-8); }

.split-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 148px var(--control-h);
  align-items: center;
  gap: var(--sp-8);
}

.split-row__amount { min-width: 0; }

/* Automatisch gefüllte Zeile (der Restbetrag) — sichtbar, aber zurückhaltend -- */
.split-row.is-auto .input--amount {
  background: var(--fill);
  color: var(--text-muted);
  border-color: var(--separator);
}

.split-row.is-auto .input--amount:focus { background: var(--surface); color: var(--text); }

.split__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-12);
  flex-wrap: wrap;
}

.split-rest {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: var(--control-h-sm);
  padding: 0 var(--sp-12);
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition: background-color var(--t-fast), color var(--t-fast);
}

/* Summe stimmt exakt → ruhig grün */
.split-rest.is-balanced { background: var(--positive-weak); color: var(--positive); }
/* Es ist noch etwas offen → neutral, kein Alarm */
.split-rest.is-open { background: var(--fill); color: var(--text-muted); }
/* Die Teile übersteigen den Gesamtbetrag → gedämpftes Rot */
.split-rest.is-over { background: var(--negative-weak); color: var(--negative); }

.split-rest__hint { font-weight: var(--fw-regular); opacity: 0.85; }

button.split-rest { cursor: pointer; }
button.split-rest:hover { background: var(--accent-weak); color: var(--tint); }

/* ==========================================================================
   18  UTILITIES & ACCESSIBILITY
   ========================================================================== */

.sr-only {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.sr-only-focusable:focus,
.sr-only-focusable:focus-visible {
  position: static !important;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
}

.skip-link {
  position: absolute;
  left: var(--sp-12);
  top: var(--sp-12);
  z-index: 200;
  padding: var(--sp-8) var(--sp-12);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-control);
  color: var(--text);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  transform: translateY(calc(-100% - var(--sp-16)));
  transition: transform var(--t-fast);
}

.skip-link:focus { transform: none; text-decoration: none; }

.u-right   { text-align: right; }
.u-center  { text-align: center; }
.u-nowrap  { white-space: nowrap; }

/* Notausgang für alles, was breiter ist als der Schirm: scrollt hier drin,
   die Seite bleibt stehen (§8). */
.u-scroll-x {
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

.u-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.u-full    { width: 100%; }
.u-flex-1  { flex: 1 1 auto; min-width: 0; }

.mt-4  { margin-top: var(--sp-4); }
.mt-8  { margin-top: var(--sp-8); }
.mt-12 { margin-top: var(--sp-12); }
.mt-16 { margin-top: var(--sp-16); }
.mt-24 { margin-top: var(--sp-24); }
.mt-32 { margin-top: var(--sp-32); }
.mb-8  { margin-bottom: var(--sp-8); }
.mb-12 { margin-bottom: var(--sp-12); }
.mb-16 { margin-bottom: var(--sp-16); }
.mb-24 { margin-bottom: var(--sp-24); }

.u-hide { display: none !important; }

/* ==========================================================================
   19  RESPONSIVE (§8)
   ========================================================================== */

/* --- Tablet: 768–1099px — Sidebar auf Icons ------------------------------- */
@media (min-width: 768px) and (max-width: 1099.98px) {
  .app { grid-template-columns: var(--sidebar-w-rail) minmax(0, 1fr); }

  .sidebar { padding: var(--sp-20) var(--sp-8); align-items: center; }

  .sidebar__brand { justify-content: center; padding: 0; }
  .sidebar__brand-text { display: none; }
  .sidebar__group-label { display: none; }

  .sidebar__nav { width: 100%; }

  .nav-item {
    justify-content: center;
    padding: 0;
    width: 100%;
    min-height: var(--control-h-touch);
  }

  .nav-item__label,
  .nav-item__badge { display: none; }

  /* Ohne Beschriftung bliebe von den Reitern nur ein leerer Kasten. */
  .sidebar__group--children { display: none; }

  /* Abmelden als reines Symbol wie die Reiter darüber: mit Beschriftung ragte
     der Knopf links und rechts aus der 68px-Leiste (Romain, 25.9.2026). Den
     Namen trägt das aria-label am Knopf (templates/layout.php). */
  .sidebar__footer { width: 100%; }
  .sidebar__user { display: none; }
  .sidebar__logout .btn { justify-content: center; padding: 0; min-height: var(--control-h-touch); }
  .sidebar__logout .btn > span:not(.nav-item__icon) { display: none; }

  .content { padding: var(--sp-24) var(--sp-20) var(--sp-56); }

  .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Phone: < 768px — mobile Grundschicht (§8) -----------------------------
   Zielgerät: iPhone im Hochformat, 375–430px, einhändig. Alles Wichtige
   gehört in die untere Bildschirmhälfte, jedes Ziel misst mindestens 44px,
   Eingabefelder nie unter 16px (sonst zoomt iOS beim Fokus).

   Reihenfolge in diesem Block:
     A  Typografie        B  Gerüst & Abstände     C  Seitenkopf
     D  Karten & Raster   E  Tabellen              F  Formulare
     G  Diagramme         H  Touch-Ziele           I  Navigation & Sheet
     J  Utilities pro Gerät
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

  /* --- A  TYPOGRAFIE: Fliesstext 17 wie bei Apple (§3) ------------------- */
  /* Entscheid Romain (Apple-Stil, offene Entscheidung 1): body 17/22,
     Sekundaertext 15/20, Betraege 17. Hebt D3 (15px) ausdruecklich auf.
     Die uebrige Skala 44/34/22/17/13/12 gilt auf beiden Geraeten. */
  :root {
    --fs-body:     17px;
    --fs-body-sm:  15px;
    --fs-money:    17px;
    --lh-body:     1.3;
  }

  /* --- B  GERÜST & ABSTÄNDE ----------------------------------------------- */
  /* Zwei Zeilen: der Kopfbalken so hoch wie sein Inhalt, der Rest gehoert der
     Seite. Ohne grid-template-rows teilen sich beide Zeilen die Bildschirmhoehe
     und der Kopfbalken wird 200px hoch. */
  .app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  .sidebar { display: none; }

  /* Auf dem Handy traegt der Kopfbalken den Rueckweg — zwei waeren einer zu viel. */
  .fw-planen__weg { display: none; }

  /* Navigationsleiste (templates/layout.php): drei Spalten wie in iOS —
     Rueckweg | kompakter Titel | ⋯. In Ruhe traegt sie den Seitengrund und
     ist vom Inhalt nicht zu unterscheiden; erst wenn der grosse Titel darunter
     verschwindet (app.js: .is-kompakt), wird sie Glas mit Haarlinie und zeigt
     den Titel. Nur Farbe und Deckkraft wechseln — kein Layoutsprung. */
  .topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: grid;
    grid-template-columns: minmax(var(--control-h-touch), 1fr) auto minmax(var(--control-h-touch), 1fr);
    align-items: center;
    gap: var(--sp-8);
    min-height: var(--control-h-touch);
    /* Oben die Safe Area (Notch/Statusleiste), seitlich mindestens der Gutter */
    padding: max(var(--sp-8), env(safe-area-inset-top, 0px))
             max(var(--sp-16), env(safe-area-inset-right, 0px))
             var(--sp-8)
             max(var(--sp-16), env(safe-area-inset-left, 0px));
    background: var(--bg);
    border-bottom: 1px solid transparent;
    transition: background-color var(--t-fast), border-color var(--t-fast);
  }

  .topbar.is-kompakt {
    background: var(--glass);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    border-bottom-color: var(--separator);
  }

  .topbar__links { display: flex; justify-content: flex-start; min-width: 0; }
  .topbar__rechts { display: flex; justify-content: flex-end; min-width: 0; }

  .topbar__title {
    min-width: 0;
    max-width: 60vw;
    font-size: var(--fs-h3);
    font-weight: var(--fw-semibold);
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    opacity: 0;
    transition: opacity var(--t-fast);
  }
  .topbar.is-kompakt .topbar__title { opacity: 1; }

  /* Rueckweg und ⋯: volle 44er Tippziele, Symbol im Tint wie iOS-Leistenknoepfe.
     Auf Glas steht nie --text-muted (Plan §2). */
  .topbar__back,
  .topbar__action {
    flex: none;
    display: grid;
    place-items: center;
    width: var(--control-h-touch);
    height: var(--control-h-touch);
    border-radius: var(--radius-pill);
    color: var(--tint);
  }
  .topbar__back { margin-left: calc(var(--sp-12) * -1); }
  /* Nur das letzte: stehen «+» und ⋯ nebeneinander, ueberlappten sich sonst
     die Trefferfelder. */
  .topbar__action:last-child { margin-right: calc(var(--sp-8) * -1); }
  .topbar__back:hover,
  .topbar__action:hover { color: var(--tint); background: var(--hover-tint); text-decoration: none; }
  .topbar__back svg,
  .topbar__action svg { width: 24px; height: 24px; }

  /* 16px Gutter links/rechts, im Querformat mindestens bis zur Safe Area.
     Unten so viel Luft, dass die fixe Tab-Leiste nichts verdeckt. */
  /* Oben nur 4px: der grosse Titel schliesst direkt an die Leiste an. */
  .content {
    padding: var(--sp-4)
             max(var(--sp-16), env(safe-area-inset-right, 0px))
             calc(var(--tabbar-space) + var(--sp-16))
             max(var(--sp-16), env(safe-area-inset-left, 0px));
  }

  /* Abschnittsrhythmus rückt von 32px auf 24px zusammen (§5) */
  .section + .section { margin-top: var(--sp-24); }
  .section__header { margin-bottom: var(--sp-12); align-items: center; }

  /* «Alle Ziele», «Alle Buchungen» neben dem Abschnittstitel sind Tippziele —
     44px hoch, ohne dass der Titel deswegen springt. */
  .section__header > .link {
    display: inline-flex;
    align-items: center;
    min-height: var(--control-h-touch);
  }

  /* Werkzeugleisten dürfen schrumpfen statt die Seite breit zu machen */
  .toolbar { gap: var(--sp-8); margin-bottom: var(--sp-12); }
  .toolbar > * { min-width: 0; max-width: 100%; }

  .empty-state { padding: var(--sp-32) var(--sp-16); }

  /* --- C  SEITENKOPF: grosser Titel, Aktionen über die volle Breite ------- */
  .page-header {
    align-items: flex-start;
    gap: var(--sp-12);
    margin-bottom: var(--sp-16);
  }

  /* largeTitle 34/41. Scrollt er unter die Leiste, zeigt sie den kompakten
     Titel (app.js, IntersectionObserver). */
  .page-title { font-size: var(--fs-h1); line-height: 41px; }
  .page-subtitle { margin-top: 2px; }
  .page-header__text { flex: 1 1 100%; }
  .page-actions { width: 100%; gap: var(--sp-8); }
  .page-actions > .btn { flex: 1 1 auto; }
  .page-actions > .btn:only-child { width: 100%; }

  /* --- D  KARTEN & RASTER -------------------------------------------------- */
  /* Cards randlos im 16px-Gutter, kompakteres Innenmass (§4/§8) */
  .card { padding: var(--sp-16); }
  /* Nach der Zeile darueber, sonst bekaeme die buendige Karte die 16px zurueck. */
  .card--flush { padding: 0; }
  .card--flush > .card__header { padding: var(--sp-16) var(--sp-16) var(--sp-12); }
  .card--flush > .card__footer { padding: var(--sp-12) var(--sp-16); }
  .card__divider { margin-left: calc(var(--sp-16) * -1); margin-right: calc(var(--sp-16) * -1); }

  /* Linien statt Karten: Bloecke IN einer Karte (verschachtelte .card, .list,
     Tabellencontainer) tragen auf dem Handy keinen eigenen Rahmen, nur eine
     Linie oben. Die aeussere Karte — die mit der Heldenzahl — bleibt. Direkt
     nach einem .card__divider oder als erstes Kind entfaellt die Linie, sonst
     staenden zwei Striche uebereinander. */
  .card .card,
  .card .list,
  .card .table-wrap,
  .card .table-scroll {
    border: 0;
    border-top: 1px solid var(--separator);
    border-radius: 0;
    box-shadow: none;
    background: none;
  }
  .card .card { padding: var(--sp-12) 0 0; }
  .card > .card:first-child,
  .card > .list:first-child,
  .card > .table-wrap:first-child,
  .card > .table-scroll:first-child,
  .card__divider + .card,
  .card__divider + .list,
  .card__divider + .table-wrap,
  .card__divider + .table-scroll { border-top: 0; }
  .card__divider + .card { padding-top: 0; }

  /* Eine Spalte — untereinander lesen sich Karten am Handy am ruhigsten */
  .card-grid,
  .card-grid--wide,
  .pair { grid-template-columns: minmax(0, 1fr); }

  /* Kennzahlen: zwei statt vier nebeneinander. Die Heldenzahl darf die
     ganze Breite behalten (§7: eine Zahl führt die Seite an). */
  .stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-16); }
  .stat-row--single { grid-template-columns: minmax(0, 1fr); }
  .stat-row > .stat--hero { grid-column: 1 / -1; }

  /* Zwei Begriffe pro Zeile: Bezeichnung links, Wert rechts. Die Bezeichnung
     nimmt den Rest und bricht um; der Wert bekommt, was er braucht, aber nie
     mehr als 60 % — sonst drueckt ein langer Kontoname den Betrag ueber den
     Rand oder ein langer Wert die Bezeichnung auf null. */
  .detail-list { grid-template-columns: minmax(0, 1fr) fit-content(60%); gap: var(--sp-8) var(--sp-12); }
  .detail-list dt { overflow-wrap: anywhere; hyphens: auto; }
  .detail-list dd { text-align: right; }

  /* Budget-/Zielbalken: Name darf umbrechen, Kopf und Fuss brechen um statt
     abzuschneiden. Stand vorher seitenlokal in buy.php und dashboard.php. */
  .progress__head { flex-wrap: wrap; }
  .progress__name { white-space: normal; overflow: visible; }
  .progress__foot { flex-wrap: wrap; gap: var(--sp-4) var(--sp-12); }

  /* --- E  TABELLEN --------------------------------------------------------- */
  .table th, .table td { padding: var(--sp-12); }

  /* Listenzeilen sind auch Tippziele */
  .list__item { min-height: var(--control-h-touch); }

  /* E1  .table--stack — aus jeder Zeile wird eine Listenzeile (Plan §2/§3:
     gruppierte Inset-Liste statt Kartenstapel). tbody ist die Gruppe. Jede
     Zeile: Titel (.cell-title) links, Betrag (.cell-amount) rechts daneben,
     alle uebrigen Zellen als ruhige Unterzeile «Bezeichnung Wert», Formulare
     (.cell-form) darunter ueber die volle Breite, Aktionen (.cell-actions)
     rechts am Ende der Unterzeile.
     Voraussetzung im Markup: jede <td> trägt data-label="Spaltenname".
     Zellen ohne data-label zeigen nur ihren Wert.
     ZUGÄNGLICHKEIT: der display-Wechsel kostet die Tabellensemantik. Im
     Template deshalb role="table" / role="row" / role="cell" ergänzen (bei
     <thead>-Zellen role="columnheader"), sonst liest VoiceOver nur Fliesstext.
     Tabellen, die tabellarisch bleiben müssen, kommen in .table-scroll. */
  .table--stack {
    display: block;
    width: 100%;
    /* schlägt ein style="min-width: 44rem" im Template — sonst scrollt die
       Karte quer, obwohl gar keine Tabelle mehr da ist */
    min-width: 0 !important;
    font-size: var(--fs-body-sm);
  }

  /* Kopfzeile bleibt für Screenreader vorhanden, verschwindet nur optisch */
  .table--stack thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table--stack tbody {
    display: block;
    background: var(--surface);
    border-radius: var(--radius-card);
    overflow: hidden;
  }

  .table--stack tbody tr {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px var(--sp-12);
    padding: var(--sp-12) var(--sp-16);
    border: 0;
  }
  .table--stack tbody tr:hover { background: none; }

  /* Umbruch nach Titel und Betrag: ein leeres Flex-Element, das per order
     zwischen Kopf und Unterzeile rutscht. */
  .table--stack tbody tr::before { content: ""; order: 1; flex: 1 0 100%; height: 0; }

  /* Trennlinie eingezogen wie bei .list__item: sie beginnt beim Text. */
  .table--stack tbody tr + tr::after {
    content: "";
    position: absolute;
    top: 0;
    left: var(--sp-16);
    right: 0;
    height: 1px;
    background: var(--separator);
  }

  /* Unterzeile: Bezeichnung und Wert in einem ruhigen Satz */
  .table--stack tbody td {
    display: block;
    order: 2;
    flex: 0 1 auto;
    width: auto;
    min-width: 0;
    padding: 0;
    border: 0;
    font-size: var(--fs-body-sm);
    line-height: 20px;
    color: var(--text-muted);
    text-align: left;
    white-space: normal;
  }
  .table--stack tbody td::before { content: attr(data-label) " "; }
  .table--stack tbody td:not([data-label])::before { content: none; }
  .table--stack tbody td:empty { display: none; }
  /* .col-date/.col-shrink schrumpfen die Tabellenspalte auf 1 % — in der
     Zeile liefe der Wert sonst in den Nachbarn. */
  .table--stack tbody td.col-date,
  .table--stack tbody td.col-shrink { width: auto; }
  .table--stack tbody td.num,
  .table--stack tbody td.money { font-size: var(--fs-body-sm); font-weight: var(--fw-regular); }

  /* .cell-title — Titel der Zeile, 17 in Textfarbe (headline-Rolle der Liste) */
  .table--stack tbody td.cell-title {
    order: 0;
    flex: 1 1 0;
    font-size: var(--fs-body);
    line-height: 22px;
    color: var(--text);
    overflow-wrap: anywhere;
  }
  .table--stack tbody td.cell-title .table__sub { font-size: var(--fs-body-sm); line-height: 20px; }
  /* Symbol + Name: der Name füllt die Zeile neben dem Symbol, sonst rutscht
     ein langer Name unter das Symbol und es steht allein (Abos). */
  .table--stack tbody td.cell-title .cluster > .muted:first-child + span { flex: 1 1 calc(100% - 16px - var(--sp-8)); min-width: 0; }

  /* .cell-amount — der Betrag rechts neben dem Titel */
  .table--stack tbody td.cell-amount {
    order: 0;
    flex: none;
    font-size: var(--fs-money);
    line-height: 22px;
    font-weight: var(--fw-medium);
    color: var(--text);
    white-space: nowrap;
  }
  .table--stack tbody td.cell-amount.money-pos { color: var(--positive); }
  .table--stack tbody td.cell-amount.text-negative { color: var(--negative); }

  .table--stack tbody td.cell-title::before,
  .table--stack tbody td.cell-amount::before,
  .table--stack tbody td.cell-form::before,
  .table--stack tbody td.cell-actions::before { content: none; }

  /* .cell-form — Auswahl und Knopf unter der Unterzeile, volle Breite */
  .table--stack tbody td.cell-form { order: 3; flex: 1 1 100%; padding-top: var(--sp-8); color: var(--text); }

  /* .cell-actions — am Ende der Unterzeile, rechts, immer sichtbar */
  .table--stack tbody td.cell-actions { order: 2; margin-left: auto; align-self: center; }
  .table--stack .row-actions { opacity: 1; }

  /* .table--tippen — die eine Zeilenaktion (Bearbeiten) deckt die ganze Zeile
     ab und zeigt sich als Chevron wie jede Zeile, die weiterfuehrt. Nur fuer
     Tabellen ohne weitere Bedienelemente in der Zeile. Der Knopftext bleibt
     fuer VoiceOver im Baum, sichtbar ist nur der Chevron. */
  .table--tippen tbody tr { padding-right: calc(var(--sp-16) + 20px); }
  .table--tippen tbody tr:hover { background: var(--fill); }
  .table--tippen tbody td.cell-actions,
  .table--tippen tbody td.cell-actions .row-actions,
  .table--tippen tbody td.cell-actions .btn { position: absolute; inset: 0; margin: 0; }
  /* align-self: center aus E1 zentrierte die abgesetzte Zelle auf 0px Hoehe. */
  .table--tippen tbody td.cell-actions { align-self: stretch; }
  .table--tippen tbody td.cell-actions .btn {
    width: 100%;
    height: 100%;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    font-size: 0;
    color: transparent;
  }
  .table--tippen tbody td.cell-actions .btn::before {
    content: "";
    position: absolute;
    top: 50%;
    right: 19px;
    width: 8px;
    height: 8px;
    margin-top: -5px;
    border-top: 2px solid var(--text-subtle);
    border-right: 2px solid var(--text-subtle);
    transform: rotate(45deg);
  }

  /* Fusszeile (Summe) als eigene, ruhige Gruppe */
  .table--stack tfoot { display: block; }
  .table--stack tfoot tr {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-12);
    margin-top: var(--sp-8);
    padding: var(--sp-12) var(--sp-16);
    background: var(--fill);
    border-radius: var(--radius-card);
  }
  .table--stack tfoot td { display: block; padding: 0; border: 0; }

  /* Der umschliessende Container tritt zurück — jetzt trägt tbody die Gruppe.
     .table-wrap--stack ist die ausdrückliche Variante … */
  .table-wrap--stack {
    background: none;
    border: 0;
    border-radius: 0;
    overflow: visible;
  }

  /* … und dieselbe Regel automatisch, wo :has() unterstützt wird (Safari 15.4+).
     Bewusst als eigener Block: ein Browser ohne :has() würde sonst auch die
     Regel darüber verwerfen. */
  .table-wrap:has(> .table--stack),
  .table-scroll:has(> .table--stack) {
    background: none;
    border: 0;
    border-radius: 0;
    overflow: visible;
  }

  /* In einer Karte ist die Karte die Gruppe; mit Innenabstand (.card) laufen
     die Zeilen buendig mit dem uebrigen Inhalt. */
  .card .table--stack tbody { background: none; border-radius: 0; }
  .card:not(.card--flush) .table--stack tbody tr { padding-left: 0; padding-right: 0; }
  .card:not(.card--flush) .table--stack tbody tr + tr::after { left: 0; }
  /* Im Blatt ist das Blatt die Gruppe: die Zeilen stehen direkt darauf. */
  .modal .table--stack tbody { background: none; border-radius: 0; }
  .modal .table--stack tbody tr { padding-left: 0; padding-right: 0; }
  .modal .table--stack tbody tr + tr::after { left: 0; }

  /* --- F  FORMULARE -------------------------------------------------------- */
  /* Bezeichnung über dem Feld, Feld über die volle Breite (.field macht das
     schon), eine Spalte, Schriftgrösse 16px gegen den iOS-Zoom (§8). */
  .form { gap: var(--sp-16); }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .field-row > .field { flex: 1 1 100%; }

  /* Nie unter 16px, sonst zoomt iOS beim Fokus — mit 17 liegen sie darueber. */
  .input, .select, .textarea { font-size: var(--fs-body); height: var(--control-h-touch); }
  .textarea { height: auto; min-height: 112px; }
  .money-input__prefix { height: var(--control-h-touch); }
  .input--amount { font-size: var(--fs-money); }
  .input--narrow { width: 100%; max-width: none; }

  .check { min-height: var(--control-h-touch); align-items: center; }
  .check input[type="checkbox"],
  .check input[type="radio"] { width: 22px; height: 22px; margin: 0; }

  /* Aktionen untereinander, jede über die volle Breite. Keine Umkehrung mehr:
     sichtbare Reihenfolge = DOM-Reihenfolge, und der Primärknopf steht zuunterst,
     also dort, wo der Daumen ohnehin liegt. */
  .form-actions {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-8);
    margin-top: var(--sp-12);
  }
  .form-actions .btn { width: 100%; }

  /* .form-actions--sticky — die Aktionsleiste klebt über der Tab-Leiste.
     Für lange Formulare (Buchen, Budget anlegen): Speichern ist immer
     erreichbar, ohne ans Ende zu scrollen.
     Hintergrund per --sticky-bg anpassen, wenn die Leiste in einer Card sitzt:
       <div class="form-actions form-actions--sticky" style="--sticky-bg: var(--surface)"> */
  .form-actions--sticky {
    position: sticky;
    bottom: var(--tabbar-space);
    z-index: 30;
    margin-left: calc(var(--sp-16) * -1);
    margin-right: calc(var(--sp-16) * -1);
    padding: var(--sp-12) var(--sp-16);
    background: var(--sticky-bg, var(--bg));
    border-top: 1px solid var(--separator);
  }

  /* --- G  DIAGRAMME -------------------------------------------------------- */
  /* .chart--mobile auf die <figure> oder deren Hülle setzen. Die Höhe steht
     als Inline-Attribut im SVG (partials/chart.php) — nur !important kommt
     dagegen an; das ist hier die einzige Stelle mit !important-Höhe. */
  .chart--mobile .fw-chart__svg { height: var(--chart-h-phone) !important; }
  .chart--mobile .fw-chart { gap: var(--sp-4); }
  .chart--mobile .fw-chart__ticks { gap: var(--sp-4); }

  /* Ab 7 Säulen stehen die Beträge nicht mehr nebeneinander — sie stehen
     vollständig in der ausklappbaren Tabelle «Werte als Tabelle». */
  .chart--mobile .fw-chart__tick:nth-last-child(n+7):first-child .fw-chart__tick-value,
  .chart--mobile .fw-chart__tick:nth-last-child(n+7):first-child ~ .fw-chart__tick .fw-chart__tick-value {
    display: none;
  }

  /* Ab 10 Säulen zusätzlich nur noch jede zweite Beschriftung — der Platz
     bleibt erhalten, damit das Raster unter den Säulen nicht verrutscht. */
  .chart--mobile .fw-chart__tick:nth-last-child(n+10):first-child ~ .fw-chart__tick:nth-child(even) .fw-chart__tick-label {
    visibility: hidden;
  }

  /* Waagrechte Balken bleiben lesbar, brauchen aber weniger Luft */
  .chart--mobile .fw-hbars { gap: var(--sp-8); }

  /* --- H  TOUCH-ZIELE ≥ 44×44px (§8) --------------------------------------- */
  .btn--icon { width: var(--control-h-touch); }

  /* Kleine Knöpfe bleiben 34px — ihr 44er Trefferfeld steht schon bei .btn--sm. */

  .modal__close { position: relative; }
  .modal__close::after { content: ""; position: absolute; inset: -6px; }

  .flash__close { position: relative; }
  .flash__close::after { content: ""; position: absolute; inset: -10px; }

  .nav-item, .menu__item, .segmented__item,
  .tabbar__item, .topbar__action { min-height: var(--control-h-touch); }
  .segmented__item { height: var(--control-h); }

  /* --- I  NAVIGATION, SHEET & SPLIT ---------------------------------------- */
  .split-row { grid-template-columns: minmax(0, 1fr) var(--control-h-touch); grid-auto-rows: auto; }
  .split-row__category { grid-column: 1 / 2; }
  .split-row__amount { grid-column: 1 / 2; }
  .split-row__remove { grid-column: 2 / 3; grid-row: 1 / 3; align-self: center; }

  /* Modal wird zum bodenbündigen Sheet: faehrt in 350ms mit der iOS-Kurve
     von unten herein (Plan §2), der Scrim blendet gleich lang. */
  .modal { padding: 0; align-items: flex-end; }
  .modal__backdrop { transition: opacity var(--t-sheet); }

  .modal__dialog {
    max-width: none;
    max-height: 92dvh;
    border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
    opacity: 1;
    transform: translateY(100%);
    transition: transform var(--t-sheet);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .modal--sheet .modal__dialog,
  .sheet .modal__dialog { height: 100dvh; max-height: 100dvh; border-radius: 0; }
  /* Das ⋯-Sheet begrenzt seine Breite nur als Dialog — hier bodenbuendig. */
  .sheet-mehr .modal__dialog { max-width: none; }

  /* Tab-Leiste: schwebende Glas-Kapsel mit vier Zielen (Plan §3). Sie traegt
     den einzigen Schatten der Oberflaeche. Hoehe und Abstand stehen als
     --tabbar-h / --tabbar-unten in tokens.css, --tabbar-space rechnet sie
     zusammen — die Zahl wird nur dort gepflegt. */
  .tabbar {
    position: fixed;
    left: max(var(--sp-16), env(safe-area-inset-left, 0px));
    right: max(var(--sp-16), env(safe-area-inset-right, 0px));
    bottom: var(--tabbar-unten);
    z-index: 50;
    display: flex;
    align-items: stretch;
    height: var(--tabbar-h);
    padding: var(--sp-4);
    border-radius: var(--radius-pill);
    background: var(--glass);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    box-shadow: var(--shadow-tabbar);
  }

  /* Auf Glas nie --text-muted: ruhende Tabs stehen in --text, der aktive in
     --tint UND mit gefuelltem Symbol (layout.php, fw_icon «-voll») — Farbe
     allein truege die Aussage nicht. */
  .tabbar__item {
    flex: 1 1 0;
    min-width: 0;
    min-height: var(--control-h-touch);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    border-radius: var(--radius-pill);
    color: var(--text);
    text-decoration: none;
  }

  .tabbar__item:hover { text-decoration: none; color: var(--text); background: var(--hover-tint); }

  .tabbar__item.is-active,
  .tabbar__item.is-active:hover { color: var(--tint); }

  .tabbar__icon { display: grid; place-items: center; width: 26px; height: 26px; }
  .tabbar__icon svg { width: 24px; height: 24px; stroke: currentColor; fill: none; }

  .tabbar__label {
    font-size: var(--fs-caption);
    font-weight: var(--fw-medium);
    line-height: 14px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .tabbar__item.is-active .tabbar__label { font-weight: var(--fw-semibold); }
  /* Momo hat keine gefuellte Variante: aktiv traegt er einen Ring. */
  .tabbar__item.is-active .fw-panda--tab { border-radius: var(--radius-pill); box-shadow: 0 0 0 2px var(--tint); }

  /* --- J  UTILITIES PRO GERÄT ---------------------------------------------- */
  /* Inhalt nach Gerät gewichten — nie ganz entfernen: Was hier verschwindet,
     muss auf dem Handy an anderer Stelle erreichbar bleiben (z. B. hinter
     «Mehr» oder in einem <details>). */
  .u-hide-phone,
  .u-hide-sm { display: none !important; }

  /* Reihenfolge umsortieren, damit das Wichtigste zuerst (oder zuletzt,
     in Daumenreichweite) steht. Wirkt in Flex- und Grid-Containern. */
  .u-first-phone { order: -1; }
  .u-last-phone  { order: 99; }
}

/* --- Nur auf dem Desktop sichtbar ----------------------------------------- */
@media (min-width: 768px) {
  .u-hide-desktop,
  .u-hide-lg { display: none !important; }
}

/* Grobe Zeiger (Touch) — Inputs nie unter 16px, sonst zoomt iOS -------------- */
@media (pointer: coarse) {
  .input, .select, .textarea, textarea, select { font-size: max(16px, var(--fs-body)); }

  /* Ohne Hover gibt es kein Aufdecken: Zeilenaktionen stehen immer da. */
  .table .row-actions { opacity: 1; }
}

/* ==========================================================================
   19b  ZUM HOME-BILDSCHIRM HINZUGEFÜGT (standalone / PWA)

   Ohne Browserleiste ist die App das ganze Fenster. Hier nur Feinschliff —
   alles Übrige gilt aus dem Handy-Block darüber weiter.

   html.is-app (iOS-Huelle, templates/layout.php) bekommt dieselben Regeln:
   in WKWebView greift display-mode: standalone nicht. Eine Medienabfrage
   laesst sich nicht mit einer Klasse verodern, darum steht der Block zweimal —
   wer den einen aendert, aendert den anderen mit.
   ========================================================================== */

@media (display-mode: standalone) {
  /* Kein Gummiband-Effekt beim Überziehen: im Standalone-Modus sieht das
     wie ein Fehler aus, weil keine Adressleiste zurückfedert. */
  body { overscroll-behavior-y: none; }

  /* Navigationsflächen fühlen sich wie App-Knöpfe an: kein blaues
     Tipp-Aufblitzen, keine Textauswahl beim Halten. Der Fokusring (§4)
     bleibt davon unberührt. */
  .tabbar__item,
  .topbar__action,
  .nav-item,
  .btn {
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
  }

  @media (max-width: 767.98px) {
    /* Die Statusleiste liegt jetzt über dem Inhalt — Kopfzeile rückt nach.
       Die Hoehe zieht mit, sonst rechnet der Momo-Chat 4px daneben. */
    .topbar { padding-top: max(var(--sp-12), env(safe-area-inset-top, 0px)); }

    :root {
      --topbar-h: calc(var(--control-h-touch) + var(--sp-8) + 1px
                       + max(var(--sp-12), env(safe-area-inset-top, 0px)));
    }

    /* Ohne Browserleiste ist oben mehr Platz; das Sheet darf höher werden. */
    .modal__dialog { max-height: 96dvh; }
  }
}

.is-app body { overscroll-behavior-y: none; }

.is-app .tabbar__item,
.is-app .topbar__action,
.is-app .nav-item,
.is-app .btn {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

@media (max-width: 767.98px) {
  .is-app .topbar { padding-top: max(var(--sp-12), env(safe-area-inset-top, 0px)); }

  :root.is-app {
    --topbar-h: calc(var(--control-h-touch) + var(--sp-8) + 1px
                     + max(var(--sp-12), env(safe-area-inset-top, 0px)));
  }

  .is-app .modal__dialog { max-height: 96dvh; }
}

/* ==========================================================================
   20  REDUCED MOTION & PRINT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .btn:active { transform: none; }
  .modal__dialog { transform: none; }
}

@media print {
  .sidebar,
  .tabbar,
  .topbar,
  .page-actions,
  .row-actions,
  .btn { display: none !important; }

  .app { display: block; }
  .content { max-width: none; padding: 0; }
  .card, .table-wrap { border-color: var(--border-strong); break-inside: avoid; }
  body { background: var(--surface); }
}

/* ==========================================================================
   Nachtrag — Klassen, die die App-Shell (templates/layout.php) benoetigt.
   ========================================================================== */

/* Strichsymbole in Navigation und Knoepfen */
.icon { width: 20px; height: 20px; flex: 0 0 auto; display: block; }

/* Inhaltsspalte ohne Breitenbegrenzung (z. B. breite Tabellen) */
.content--wide { max-width: none; }

/* Fuss der Seitenleiste */
.sidebar__user {
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.sidebar__logout { margin: 0; }
.sidebar__logout .btn { width: 100%; justify-content: flex-start; gap: 8px; }

/* Markenzeichen mit Maskottchen */
.sidebar__mark { display: inline-flex; align-items: center; }

/* --- Seitenleiste: Reiter des offenen Bereichs, eingerueckt ---------------
   Nur der offene Bereich klappt seine Reiter aus — die Leiste bleibt kurz,
   und man sieht auf einen Blick, wo man steht. */
.sidebar__group--children {
  margin: var(--sp-4) 0 var(--sp-8) var(--sp-12);
  padding-left: var(--sp-12);
  border-left: 1px solid var(--separator);
}

.nav-item--child {
  min-height: var(--control-h-sm);
  font-size: var(--fs-caption);
}

/* --- Reiterleiste einer Seite (templates/partials/reiter.php) -------------
   Sie ist der Ersatz fuer die Seitenleiste dort, wo diese die Reiter nicht
   zeigt. Ab 1100px klappt die Seitenleiste die Reiter des offenen Bereichs
   eingerueckt auf und markiert den offenen mit der Pille — die Leiste auf der
   Seite waere dann derselbe Inhalt ein zweites Mal (DESIGN.md §9).

   Die Grenze ist 1100px und nicht 768px: zwischen 768 und 1099px ist die
   Seitenleiste eine Icon-Schiene, und `.sidebar__group--children` ist dort
   ausgeblendet (ohne Beschriftung bliebe von den Reitern ein leerer Kasten).
   Auf dem Tablet ist diese Leiste also der einzige Weg zwischen den Reitern. */
.fw-reiter { margin-bottom: var(--sp-16); }

/* Vier Reiter auf 375px: knapper Rand und die Schriftgroesse der Tab-Leiste,
   sonst steht dort «Auswert…». Reiterbeschriftungen sind Etiketten, keine
   Fliesstexte — 12px ist dafuer die dokumentierte Groesse (DESIGN.md §3). */
@media (max-width: 767.98px) {
  .fw-reiter .segmented__item { padding: 0 var(--sp-4); font-size: var(--fs-label); }
}

@media (min-width: 1100px) {
  .fw-reiter { display: none; }
}

/* --- Kennzahlen-Reihe: Zahlen duerfen sich nicht beruehren ------------------
   Auf 375px stiessen "−CHF 291'649.87" und "CHF 288'712.25" ohne Abstand
   aneinander und lasen sich wie eine einzige Zahl. Grosse Betraege brauchen
   entweder Platz oder eine eigene Zeile — mit auto-fit bekommt jede Kennzahl
   mindestens 9rem, sonst rutscht sie um. */
@media (max-width: 767.98px) {
  .stat-row {
    /* 11rem = 176px: zwei Spalten passen damit auf 375px NICHT mehr nebeneinander
       und die Kennzahlen stapeln sich. Die alte Grenze von 160px liess zwei
       Spalten zu, in die "−CHF 291'649.87" nicht hineinpasste — die Zahlen
       liefen ueber und beruehrten sich. */
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    row-gap: var(--sp-16);
  }
  .stat-row .stat__value {
    overflow-wrap: anywhere;
  }
}

/* --- Aufklapper -----------------------------------------------------------
   Ein Winkel vor jedem <summary>, auf jedem Gerät derselbe. Das Dreieck des
   Browsers verschwindet, sobald ein summary display:flex bekommt (auf dem Handy
   fast alle) — dann las sich «Was tun» wie eine leere Überschrift über den
   Knöpfen (UI-Evaluation C6). Zeigt nach rechts, offen nach unten. */
summary { cursor: pointer; list-style: none; }
summary::-webkit-details-marker { display: none; }
summary::before {
  content: "";
  display: inline-block;
  flex: none;
  width: 6px;
  height: 6px;
  margin-right: var(--sp-8);
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(-45deg);
  transition: transform var(--t-fast);
}
details[open] > summary::before { transform: translateY(-3px) rotate(45deg); }
/* Auf dem Handy ist jeder Aufklapper ein 44px-Ziel (§8). Knopf-Aufklapper
   (.btn) und eigene Koepfe (.fw-geplant__kopf) bringen ihr display selbst mit. */
@media (max-width: 767.98px) {
  summary { display: flex; align-items: center; min-height: var(--control-h-touch); }
  /* Kleiner Knopf bleibt 34px, sein Trefferfeld kommt aus .btn--sm::after. */
  summary.btn--sm { min-height: 0; }
}

/* Wird auf mehreren Seiten gebraucht (Übersicht, Abos). Der Zeiger und das
   Tippziel gehören deshalb hierher und nicht in eine <style>-Insel. */
.fw-fold > summary {
  cursor: pointer;
  color: var(--text-muted);
}
.fw-fold > summary:focus-visible {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: var(--focus-offset);
  border-radius: var(--radius-control);
}

/* --- Aus den Seiten-Styles hierher gezogen ---------------------------------
   .fw-stat-wide, die Diagramm-Aufklapper und die Fortschritts-Details standen
   wortgleich in dashboard.php, insights.php und buy.php. Drei Kopien einer
   Regel heisst: zwei davon veralten unbemerkt. */
.stat-row > .fw-stat-wide { grid-column: 1 / -1; }

@media (max-width: 767.98px) {
  /* Der Aufklapper unter jedem Diagramm: 44px hat jedes summary (oben). */
  .fw-chart__data > summary { padding: var(--sp-12) 0; }
}

/* Fliesstext-Links, die eine echte Aktion ausloesen, brauchen auf dem Handy
   ein 44px-Trefferfeld (DESIGN.md §8) — ohne die Zeilenhoehe zu sprengen. */
@media (max-width: 767.98px) {
  .fw-touch { position: relative; }
  .fw-touch::after {
    content: '';
    position: absolute;
    /* 15px: auch ein Link in Etikettengroesse (12px) kommt so auf 44px. */
    inset: -15px -8px;
  }
}

/* Lohnmonat als Segmentbalken: ein Segment je Tag. Die Vergangenheit ist eine
   Flaeche, die Zukunft ein Umriss — gruen heisst unter dem Tagesbudget, rot
   darueber, leer heisst Zukunft oder Tag ohne Beleg, der Rahmen heisst heute.
   Keine Zahl je Segment: das ist ein Muster, keine Kette. Auf 375 px bleiben
   rund 10 px je Segment — lesbar als Muster, nicht als Zahl.

   ROT IST HIER EINE AUSNAHME, und sie ist Romains ausdrueckliche Entscheidung
   («mach die Tage drueber rot statt braun, das ist intuitiver»). Der Vertrag
   laesst sie zu: DESIGN.md §9 nennt «a budget that is over» als echtes
   Problem. Dieselbe Bedeutung faerbt darum NICHT den Quest-Balken und nie die
   Heldenzahl — dort bleibt es grau bzw. amber, weil eine ueberschrittene
   Abmachung kein Problem ist, sondern eine verpasste Wette.

   Preis, bewusst bezahlt: --positive und --negative sind fast gleich hell
   (L 0,152 gegen 0,165, zueinander 1,06:1). Gegen die Karte stehen beide gut
   da (5,2:1 und 4,9:1), und der Farbton trennt sie klar — fuer ein rot-gruen-
   blindes Auge aber nicht. Vorher trennte die Helligkeit (--border-strong,
   3,15:1). Wer das zurueckwill, ohne das Rot aufzugeben, hellt --unter auf
   (--positive-weak gegen --negative sind 4,27:1); dann verschwindet allerdings
   der gruene Tag fast im Kartenweiss (1,14:1). Eine Loesung, die beides haelt,
   braucht ein zweites Merkmal statt einer dritten Farbe.

   DAS ZWEITE MERKMAL IST DIE HOEHE. Romains Rot bleibt unangetastet, die
   Segmente liegen stattdessen unterschiedlich hoch in einer gemeinsamen,
   vertikal zentrierten Spur: ein Tag UEBER dem Budget ist der auffaellige und
   damit der hoehere (11px), ein Tag darunter der ruhige (7px). Leere Tage
   (zukunft, keine) richten sich an der niedrigen Hoehe aus, damit sie nicht
   lauter sind als die guten. In Graustufen trennt die Hoehe, in Farbe der Ton
   — beide Wege tragen dieselbe Aussage. Das aria-label bleibt, wie es war. */
/* Seit dem Monatsgitter ist der Balken eine Tuer: der ganze Block ist ein Link
   nach /planen. Eine Tuer, die niemand sieht, ist keine Tuer — darum ein
   Tippziel von mindestens 44px (DESIGN.md §8), ein Fokusring wie bei jedem
   Link und rechts in der Achsenzeile das Wort «Planen ›» in --accent, wie die
   uebrigen Blockverweise auf Heute. Die HOEHE kommt aus der Polsterung, nicht
   aus dickeren Segmenten: das Hoehenverhaeltnis 7px/11px traegt die Aussage
   und bleibt unangetastet.
   position/z-index: das 44px-Trefferfeld von .fw-touch am Herleitungs-Link
   (inset -14px) reicht sonst in die oberste Zeile dieses Links hinein und
   faengt dort Tipps ab. */
.fw-monat {
  position: relative;
  z-index: 1;
  display: block;
  margin: var(--sp-4) calc(var(--sp-8) * -1) 0;
  padding: var(--sp-8) var(--sp-8) var(--sp-4);
  min-height: 44px;
  border-radius: var(--radius-control);
  color: inherit;
  text-decoration: none;
}
.fw-monat:hover { background: var(--fill); text-decoration: none; }
.fw-monat:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Derselbe Ton wie «Herleitung ›», «Verwalten ›», «Sparen ›». */
.fw-monat__mehr { color: var(--tint); }

/* Eingeplantes Geld unter dem Monatsbalken: was schon erfasst ist, aber erst
   noch abgeht. Ruhig — Etikettenfarbe, kein Amber, kein Rot. Dieselbe Zeile
   steht auf /planen unter dem Gitter (SavingAids::reserviert). */
.fw-reserviert {
  margin: var(--sp-8) 0 0;
  font-size: var(--fs-label);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* --monat-h-voll/--monat-h-klein stehen hier und nicht in tokens.css: sie
   gehoeren nur diesen beiden Darstellungen desselben Sachverhalts (Segmentbalken
   auf Heute, Gitterzelle auf /planen) und sind keine Systemgroesse. Sie stehen
   EINMAL: zwei Zahlen fuer eine Aussage liefen sonst auseinander, sobald jemand
   den Balken anfasst. */
:root {
  --monat-h-voll: 11px;
  --monat-h-klein: 7px;
}
.fw-monat__spur {
  display: flex;
  gap: 2px;
  /* Zentriert statt gestreckt — sonst waeren alle Segmente wieder gleich hoch. */
  align-items: center;
  /* Die Spur behaelt ihre Gesamthoehe, damit die Zeile nicht springt. */
  min-height: var(--monat-h-voll);
}
.fw-monat__tag { flex: 1 1 0; min-width: 0; height: var(--monat-h-klein); border-radius: 2px; background: transparent; border: 1px solid var(--separator); }
.fw-monat__tag--unter { background: var(--positive); border-color: var(--positive); }
.fw-monat__tag--drueber { height: var(--monat-h-voll); background: var(--negative); border-color: var(--negative); }
.fw-monat__tag--zukunft,
.fw-monat__tag--keine { background: transparent; border-color: var(--separator); }
.fw-monat__tag.is-today { border-color: var(--text); }
.fw-monat__achse { display: flex; justify-content: space-between; gap: var(--sp-8); margin-top: var(--sp-4); font-size: 12px; color: var(--text-muted); }

/* ==========================================================================
   MONATSGITTER (/planen)
   ==========================================================================
   Sieben Spalten, Montag bis Sonntag, ueber den LOHNMONAT — nicht ueber den
   Kalendermonat. Die Datumszahlen laufen darum ueber den Monatswechsel hinweg
   (25, 26 … 31, 1, 2 … 24): jede andere Zahl der App rechnet im Lohnmonat, ein
   Kalendergitter waere eine zweite Zeitrechnung.

   ZELLMASS: nachgerechnet bei 375px Geraetebreite — 375 minus 2x16 (.content)
   ergibt 343, minus 2x16 Kartenpolsterung und 2x1 Kartenrand bleiben 309. Sieben
   Spalten mit 4px Abstand waeren daraus nur 40,7px je Zelle, unter den 44px aus
   DESIGN.md §8 (und aspect-ratio kann min-height nicht ueberstimmen, die Zelle
   bliebe schmal statt quadratisch). Darum zieht der Handy-Block weiter unten das
   Netz aus der Kartenpolsterung heraus und halbiert den Abstand auf 2px: (341
   minus 12) / 7 = 47px. Ab 768px ist die Karte breit genug, dort bleibt es beim
   4px-Abstand.

   FARBEN UND HOEHEN kommen aus denselben Tokens wie der Segmentbalken auf
   Heute (--positive niedrig, --negative hoch, 7px/11px). Zwei Darstellungen
   desselben Sachverhalts duerfen nicht auseinanderlaufen. */

/* Der Rueckweg ab 768px — unter 768px traegt ihn der Pfeil im Kopfbalken. */
.fw-planen__weg { margin: 0 0 var(--sp-12); font-size: var(--fs-body-sm); }

.fw-gitter__kopf,
.fw-gitter__netz {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}
.fw-gitter__kopf { margin-bottom: var(--sp-4); }
.fw-gitter__wochentag {
  font-size: var(--fs-label);
  color: var(--text-muted);
  text-align: center;
}
/* Fuehrende und nachlaufende Leerzellen: kein Rand, kein Tippziel. */
.fw-gitter__leer { display: block; }

.fw-gitter__zelle {
  /* Die Hoehen --monat-h-voll/--monat-h-klein kommen von :root, aus demselben
     Grund wie im Segmentbalken: in Graustufen trennt die Hoehe, in Farbe der
     Ton. Hier steht darum keine eigene Zahl. */
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  min-height: 44px;
  padding: 0;
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
/* Kuenftige Tage sind eine Flaeche, keine Geschichte: --fill. */
.fw-gitter__zelle.is-zukunft { background: var(--fill); }
.fw-gitter__zelle.is-today { border-color: var(--text); }
/* Der offene Tag: derselbe Akzent wie ein aktiver Reiter. */
.fw-gitter__zelle.is-aktiv { border-color: var(--tint); background: var(--accent-weak); }
.fw-gitter__zelle:hover { border-color: var(--border-strong); }
.fw-gitter__zelle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fw-gitter__zahl {
  position: absolute;
  top: 3px;
  left: 5px;
  font-size: var(--fs-label);
  line-height: 1.2;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* Der Punkt: an diesem Tag geht Geld vom Konto, das NICHT aufs Tagesbudget
   zaehlt — also eine Rechnung. Grau fuer Vergangenes, Akzent fuer Geplantes. */
.fw-gitter__punkt {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--text-muted);
}
.fw-gitter__zelle.is-zukunft .fw-gitter__punkt { background: var(--accent); }

.fw-gitter__betrag {
  position: absolute;
  left: 2px;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
  text-align: center;
  font-size: var(--fs-label);
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  /* Auf sehr schmalen Geraeten (320px) klemmt «1'410» in der Zelle. Lieber
     abgeschnitten als ueber den Rand hinaus — die genaue Zahl steht im Blatt. */
  overflow: hidden;
}

.fw-gitter__balken {
  position: absolute;
  left: 5px;
  right: 5px;
  bottom: 4px;
  height: var(--monat-h-klein);
  border-radius: 2px;
  background: transparent;
  border: 1px solid var(--separator);
}
.fw-gitter__balken--unter { background: var(--positive); border-color: var(--positive); }
.fw-gitter__balken--drueber { height: var(--monat-h-voll); background: var(--negative); border-color: var(--negative); }
.fw-gitter__balken--zukunft,
.fw-gitter__balken--keine { background: transparent; border-color: var(--separator); }

.fw-gitter__achse {
  display: flex;
  /* Drei Teile, der letzte lang («Tagesbudget CHF 64.29»): bei 320px passt die
     Zeile nicht in die Karte. Umbrechen statt ausbrechen. */
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-8);
  row-gap: var(--sp-4);
  margin: var(--sp-8) 0 0;
  font-size: var(--fs-label);
  color: var(--text-muted);
}
/* Randnotizen: der erwartete Lohn und das eingeplante Geld. Beide ruhig —
   eine Einnahme ist kein Tageszustand, und Eingeplantes ist kein Problem. */
.fw-gitter__notiz {
  margin: var(--sp-8) 0 0;
  font-size: var(--fs-label);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ---- Tagesblatt ---------------------------------------------------------
   Kein Modal und kein Seitenwechsel: das Blatt steht unter dem Gitter. */
.fw-blatt__titel { margin: 0; font-size: var(--fs-h3); font-weight: var(--fw-semibold); }
.fw-blatt__einordnung { margin: var(--sp-4) 0 0; font-size: var(--fs-label); color: var(--text-muted); }
.fw-blatt__liste { list-style: none; margin: var(--sp-16) 0 0; padding: 0; }
.fw-blatt__zeile {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--sp-4) var(--sp-8);
  padding: var(--sp-8) 0;
  border-top: 1px solid var(--separator);
}
.fw-blatt__zeile:first-child { border-top: 0; }
/* Name und Betrag gehoeren auf EINE Zeile, das Etikett darunter — dieselbe
   Ordnung wie in der Buchungsliste (.table__sub). Ohne die festen Plaetze
   setzt die automatische Verteilung den Betrag hinter das ueber beide Spalten
   laufende Etikett und damit auf eine dritte Zeile. */
.fw-blatt__text { grid-column: 1; grid-row: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fw-blatt__chf { grid-column: 2; grid-row: 1; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
/* Eine Schaetzung darf leiser sein als eine Buchung: das Wort «erwartet» allein
   trennt die beiden sonst nur im Etikett. */
.fw-blatt__zeile.is-erwartet .fw-blatt__chf { color: var(--text-muted); }
.fw-blatt__etikett {
  grid-column: 1 / -1;
  grid-row: 2;
  font-size: var(--fs-label);
  color: var(--text-muted);
}
.fw-blatt__hinweis { color: var(--text-muted); }
.fw-blatt__leer { margin: var(--sp-12) 0 0; color: var(--text-muted); font-size: var(--fs-body-sm); }
.fw-blatt__stand {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-8);
  margin: var(--sp-12) 0 0;
  padding-top: var(--sp-12);
  border-top: 1px solid var(--separator);
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
}
.fw-blatt__aktion { margin: var(--sp-16) 0 0; }

/* Das Tippziel auf dem Handy: siehe die Rechnung im Kommentar oben. Das Netz
   tritt aus der Kartenpolsterung heraus (wie .card__divider es schon tut) und
   der Abstand halbiert sich — aus 40,7px werden 47px je Zelle, ueber den 44px
   aus DESIGN.md §8. Der Kopf mit den Wochentagen geht denselben Weg, sonst
   stuenden die Buchstaben nicht mehr ueber ihren Spalten. */
@media (max-width: 767.98px) {
  .fw-gitter__kopf,
  .fw-gitter__netz {
    gap: 2px;
    margin-left: calc(var(--sp-16) * -1);
    margin-right: calc(var(--sp-16) * -1);
  }
}

/* Zustandszeile unter der Heldenzahl: Zahlen statt Satz, auf beiden Geraeten
   sichtbar, darf umbrechen. Amber traegt sie nur als Ganzes (.text-warning),
   die Heldenzahl selbst nie. */
.fw-zustand {
  /* sp-16 statt sp-8: der Link «Herleitung ›» traegt auf dem Handy das
     44px-Trefferfeld von .fw-touch (inset -14px), das sonst in den
     Tagesbalken darueber ragen und dort Tipps abfangen wuerde. */
  margin: var(--sp-16) 0 0;
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
/* .text-warning/.text-negative stehen frueher in der Datei und verlieren bei
   gleicher Spezifitaet gegen .fw-zustand. Gleiches Muster und gleicher Grund
   wie bei .stat__meta.text-warning: die Heldenzahl bleibt neutral, die
   Zustandszeile traegt den Ton (DESIGN.md §«Die Heldenzahl»). */
.fw-zustand.text-warning  { color: var(--warning); }
.fw-zustand.text-negative { color: var(--negative); }
/* Auf Heute zwei Zeilen, je eine Aussage (UI-Evaluation A2). Der Ton sitzt
   auf der Zeile, die ihn begruendet, nicht auf dem ganzen Block. */
.fw-zustand > p + p { margin-top: var(--sp-4); }
/* Der Trenner «· » steht im Markup wie bei allen anderen Gliedern der Zeile,
   darum hier kein zusaetzlicher Abstand. */
.fw-zustand__link { white-space: nowrap; }

/* Naechstes Ziel: Name links, Stand rechts, darunter ein duenner Balken. */
.fw-ziel__kopf { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-4) var(--sp-12); align-items: baseline; margin-bottom: var(--sp-8); }
.fw-ziel__name { min-width: 0; }
.fw-ziel__stand { font-weight: var(--fw-semibold); white-space: nowrap; }
.fw-ziel .progress { height: 6px; }

/* Konten und Karte auf Heute: .detail-list setzt dt als Etikett (Versalien,
   gesperrt, --text-muted). Hier steht im dt aber ein Kontoname mit einer ganzen
   Zaehlerzeile — Fliesstext, wie auf jeder anderen Seite (DESIGN.md §3: ALL CAPS
   nur fuer den label-Stil; §9: dieselbe Sache sieht ueberall gleich aus). */
.fw-konten dt { font-size: var(--fs-body); letter-spacing: 0; text-transform: none; color: var(--text); font-weight: var(--fw-regular); }
.fw-konten .table__sub { text-transform: none; letter-spacing: 0; }
/* Saldo mindestens so gross wie der Kontoname — die Zahl ist die Heldin (§1).
   Rechtsbuendig auf jedem Geraet: auf dem Desktop stand die Betragsspalte
   sonst mitten in der Karte, gleich hinter dem laengsten Kontonamen (§4,
   UI-Evaluation C5). */
.fw-konten dd { font-size: var(--fs-body); }
.detail-list.fw-konten dd { text-align: right; }

/* Rueckhol-Frage in der Momo-Blase: Feld und zwei Knoepfe in einer Zeile, auf dem Handy umbrechend. */
.fw-reason { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.fw-reason .input { flex: 1 1 160px; min-width: 0; }
/* Bargeldbezug zuordnen: bei mehreren Bargeld-Konten steht die Bezugszeile
   ueber den Knoepfen — sonst reissen zwei Kontonamen auf dem Handy um. */
.fw-reason--bezug { align-items: center; }
.fw-reason--bezug .fw-reason__label { flex: 1 1 100%; }

/* Warteliste: zwei kleine Knoepfe neben dem Betrag. */
.fw-inline-actions { display: inline-flex; gap: 6px; margin-left: 8px; vertical-align: middle; }

/* Was zaehlt aufs Tagesbudget: ein Kontrollkaestchen je Kategorie, der Chip
   traegt ihre Farbe. Zwei Spalten muessen auf 375px passen: Gutter 2x16 und
   Kartenpolster 2x16 lassen 311px, zwei Spalten brauchen 2x136 + 12 = 284px.
   Darum 8.5rem und nicht mehr; min(100%, ...) haelt lange Namen in der Karte.
   Die Kaestchen behalten die Touch-Hoehe aus .check. */
.fw-budgetkat {
  list-style: none;
  margin: 0 0 var(--sp-12);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.5rem), 1fr));
  gap: var(--sp-4) var(--sp-12);
}
.fw-budgetkat .check { align-items: center; }
/* Die Gruppe traegt nur die Legende fuer Vorlesegeraete — sichtbar ist das
   Raster darin, also bekommt das <fieldset> weder Rahmen noch Polster. */
.fw-budgetkat-group { border: 0; margin: 0; padding: 0; min-width: 0; }

/* Prognose-Diagramme: Legende als ruhige Zeile, Prognosen gestrichelt. */
.fw-lines__legend { display: flex; flex-wrap: wrap; gap: 6px 14px; list-style: none; margin: 6px 0 0; padding: 0; font-size: 12px; color: var(--text-muted); }
.fw-lines__swatch { display: inline-block; width: 18px; height: 0; border-top: 2px solid var(--accent); vertical-align: middle; margin-right: 6px; }
.fw-lines__swatch--dashed { border-top-style: dashed; }
.fw-lines__axis { display: flex; justify-content: space-between; }

/* Handy knapp, Desktop ausfuehrlich: Erklaersaetze tragen .fw-desk, ihre
   Zahlen-Kurzform .fw-phone. Breakpoint wie ueberall: 768. */
@media (max-width: 767.98px) {
  .fw-desk { display: none !important; }
  /* Sprungmarken (heute /einstellungen#budget, #momo): der Kopfbalken klebt
     oben, also muss das Ziel darunter anhalten — sonst steht die Ueberschrift
     hinter dem Balken und die Erfolgsmeldung darueber ist gar nicht zu sehen. */
  .section[id],
  .card[id] { scroll-margin-top: calc(var(--topbar-h) + var(--sp-12)); }
}
@media (min-width: 768px) {
  .fw-phone { display: none !important; }
}

/* Sparhebel: der oberste als Karte mit Primaerknopf, die uebrigen als
   aufklappbare Zeilen einer Gruppe (Plan §3). Rang, Titel, Erwartung in einer
   Zeile; der Chevron am Ende zeigt offen nach unten wie bei den Zielen. */
.fw-hebel { margin-bottom: var(--sp-16); }
.fw-hebel__head { display: flex; align-items: flex-start; gap: 12px; }
/* «Platz 1» ist eine Nummer, kein Zustand. Der Kreis stand in --accent-weak mit
   --accent-Text und las sich dadurch als «ausgewaehlt/aktiv». */
.fw-hebel__rank { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 999px; background: var(--fill); color: var(--text); font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; }
.fw-hebel__title { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-body); line-height: 22px; }
.fw-hebel__name { color: var(--text); }
.fw-hebel__name--erst { font-weight: var(--fw-semibold); }
.fw-hebel__meta { font-size: var(--fs-body-sm); line-height: 20px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fw-hebel__expect { flex: 0 0 auto; font-size: var(--fs-money); line-height: 22px; font-variant-numeric: tabular-nums; font-weight: var(--fw-medium); }
.fw-hebel__tun { margin: var(--sp-12) 0 0; font-size: var(--fs-body-sm); line-height: 20px; }
.fw-hebel__actions { display: flex; gap: 8px; margin-top: var(--sp-12); }
.fw-hebelliste > li { position: relative; }
.fw-hebelliste > li + li::before { content: ""; position: absolute; top: 0; left: var(--sp-16); right: 0; height: 1px; background: var(--separator); }
.fw-hebelzeile > .fw-hebel__head { display: flex; align-items: flex-start; padding: var(--sp-12) var(--sp-16); color: inherit; }
.fw-hebelzeile > .fw-hebel__head::before { content: none; }
.fw-hebelzeile__winkel { align-self: center; transition: transform var(--t-fast); }
.fw-hebelzeile[open] .fw-hebelzeile__winkel { transform: translateY(-2px) rotate(135deg); }
.fw-hebelzeile__mehr { padding: 0 var(--sp-16) var(--sp-16) calc(var(--sp-16) + 38px); }
.fw-hebelzeile__mehr .fw-hebel__tun { margin-top: 0; }

/* Heute ab 1100px zwei Spalten (UI-Evaluation, optional): Konten und Ziel
   rechts neben Heldenkarte und Quests, der Verlauf ueber die ganze Breite —
   seine Zeichnung braucht die Breite (900 Einheiten, D1). Die Reihenfolge im
   HTML bleibt die des Handys; die Bereiche setzt nur dieses Raster. */
@media (min-width: 1100px) {
  .fw-heute {
    display: grid;
    grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
    grid-template-areas:
      "momo    momo"
      "held    rechts"
      "quests  rechts"
      "verlauf verlauf";
    /* Die Quest-Zeile ist flexibel: ist die rechte Spalte hoeher als Heldenkarte
       und Quests zusammen, waechst sie unter den Quests — nicht als Luecke
       zwischen Heldenkarte und Quests. */
    grid-template-rows: auto auto 1fr auto;
    gap: var(--sp-24);
    align-items: start;
  }
  .fw-heute > .fw-momo-zeile { grid-area: momo; margin: 0; }
  .fw-heute__held    { grid-area: held; }
  .fw-heute__quests  { grid-area: quests; }
  .fw-heute__verlauf { grid-area: verlauf; }
  .fw-heute__rechts  { grid-area: rechts; }
  .fw-heute > .section { margin-top: 0; }
  /* In der schmalen Spalte wie auf dem Handy: der Kontoname bricht um, der
     Saldo behaelt seinen Platz. Mit max-content schob die lange Unterzeile
     («Sparkonto · leer, Dauerauftrag am 10. · …») den Betrag aus der Karte. */
  .fw-heute__rechts .detail-list { grid-template-columns: minmax(0, 1fr) auto; }
  .fw-heute__rechts .detail-list dt { overflow-wrap: anywhere; }
  .fw-heute__rechts .detail-list dd { white-space: nowrap; }
}

/* Heldenkarte auf Heute (Plan §3): nur Etikett, Zahl, Balken, ein Satz. */
.fw-held .stat__value { line-height: 48px; }
.fw-held .progress { margin-top: var(--sp-12); }
.fw-held__satz { margin: var(--sp-12) 0 0; }

/* Woche, Lohnmonat, Reserviert, Herleitung: Zeilen mit Chevron unter der
   Heldenkarte. Links Titel und Unterzeile, rechts der Wert, darunter ueber
   die Textbreite die Grafik (Balken bzw. Segmentbalken). */
.fw-zeilen { margin: var(--sp-16) 0 0; padding: 0; }
.fw-zeile { min-height: 60px; }
.fw-zeile__inhalt {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 2px var(--sp-12);
}
.fw-zeile__titel { font-size: var(--fs-body); line-height: 22px; color: var(--text); }
.fw-zeile__wert { font-size: var(--fs-money); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; white-space: nowrap; text-align: right; }
.fw-zeile__wert.text-negative { color: var(--negative); }
.fw-zeile__unter { grid-column: 1 / -1; font-size: var(--fs-body-sm); line-height: 20px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fw-zeile__unter.text-warning { color: var(--warning); }
.fw-zeile__bild { grid-column: 1 / -1; margin-top: var(--sp-8); }
.fw-zeile__bild .progress { display: block; height: 6px; }
/* Gauge mit Statuswort rechts daneben: das Wort traegt die Farbe, der Balken
   allein nie (Amber und Rot nur zusammen mit einem Wort). */
.fw-zeile__spur { display: flex; align-items: center; gap: var(--sp-12); }
.fw-zeile__spur .progress { flex: 1; min-width: 0; }
.fw-zeile__wort { flex: none; font-size: var(--fs-body-sm); line-height: 20px; }
.fw-zeile__titel .chip__dot { display: inline-block; margin-right: var(--sp-8); vertical-align: 2px; }

/* Zeile als Knopf (oeffnet ein Blatt, z. B. ein Budget bearbeiten): sieht aus
   wie die verlinkte Zeile. */
button.list__item { width: 100%; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
/* Aktionszeile am Ende einer Gruppe («Budget hinzufügen»): Tint wie ein
   iOS-Textknopf, 17 wie jede Zeile. */
.list__item.fw-zeile--aktion { min-height: var(--control-h-touch); color: var(--tint); font-size: var(--fs-body); line-height: 22px; }
/* Zeilen ohne Ziel reagieren nicht auf den Zeiger. */
div.list__item:hover,
li.list__item:hover { background: none; }

/* Momo-Zeile ueber der Heldenzahl: Stimme, kein Block. Avatar links, ein Satz, Knoepfe darunter. */
/* Als Inset-Zeile (Plan §3): randlos auf dem Gruppengrund wie jede Karte,
   links die Momo-Kachel. Die Kachel ist in beiden Modi --momo-tile — Momos
   Farben werden im Dunkeln nie umdefiniert, er braucht seinen hellen Grund. */
.fw-momo-zeile { display: grid; grid-template-columns: 36px 1fr; gap: var(--sp-8) var(--sp-12); align-items: start; margin: 0 0 var(--sp-16); padding: var(--sp-12) var(--sp-16); border-radius: var(--radius-card); background: var(--surface); border: 1px solid transparent; }
/* Der Akzentrahmen gehoert der Frage, nicht dem Register: momo-zeile.php
   setzt --frage, sobald Antwort-Chips dastehen (kein :has(), Safari < 15.4
   laeuft in der PWA). */
.fw-momo-zeile--frage { border-color: var(--tint); }
.fw-momo-zeile__avatar { display: grid; place-items: center; width: 36px; height: 36px; border-radius: var(--radius-tile); background: var(--momo-tile); }
.fw-momo-zeile__body { min-width: 0; }
.fw-momo-zeile__text { margin: 0; padding-top: 7px; font-size: var(--fs-body); line-height: 22px; font-variant-numeric: tabular-nums; }
.fw-momo-zeile__chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.fw-momo-zeile__chips .btn { min-height: 40px; }
.fw-momo-zeile__more { display: inline-block; margin-top: var(--sp-4); font-size: var(--fs-body); }
/* Waehrend die Antwort unterwegs ist: die Zeile nimmt keinen zweiten Tipp an.
   Kein Spinner — der Tausch dauert einen Wimpernschlag (panda.js, drittes IIFE). */
.fw-momo-zeile.is-busy { opacity: 0.4; pointer-events: none; }

/* Quest-Zeile (partials/quest-zeile.php) und die Zeilen auf Sparen › Quests:
   eine .fw-zeile ohne Link — darum kein Hover. Unter der Unterzeile die
   lineare Kapazitaets-Gauge, rechts daneben das Statuswort («läuft», «Grenze
   erreicht», «geschafft ✓»). Nie rot, und ohne Balken, wenn er grau waere
   (UI-Evaluation A3); das Wort steht dann in der Unterzeile. */
.fw-quest.list__item:hover { background: none; }
.fw-quest__spur { display: flex; align-items: center; gap: var(--sp-12); }
.fw-quest__spur .progress { flex: 1; min-width: 0; }
.fw-quest__status { flex: none; font-size: var(--fs-body-sm); line-height: 20px; color: var(--text-muted); }
/* Direkt unter einem Abschnittskopf traegt der Kopf den Abstand. */
.section__header + .fw-zeilen { margin-top: 0; }

/* ==========================================================================
   NACHTRAG — Buchungsformular (Modal «+ Buchung» und Bearbeiten-Maske)
   --------------------------------------------------------------------------
   Stand bis P5 doppelt in den <style>-Inseln von templates/entry.php und
   templates/transactions.php. Seit die Erfassung im Modal auf der Liste lebt
   und das Bearbeiten dieselben Bausteine benutzt, gibt es zwei Orte fuer eine
   Optik — die Klassen gehoeren darum hierher. Nur Tokens aus DESIGN.md §2/§3/§5.
   ========================================================================== */

/* Betragsfeld: die erste und groesste Zahl des Formulars ------------------- */
.fw-amount__input {
  height: 72px;
  font-size: var(--fs-h1);
  font-weight: var(--fw-semibold);
  padding-left: var(--sp-72);
}

.fw-amount .money-input__prefix {
  height: 72px;
  font-size: var(--fs-body);
  left: var(--sp-16);
}

/* Richtungsumschalter: Radios in der .segmented-Optik ---------------------- */
.fw-dir { display: inline-flex; align-self: flex-start; max-width: 100%; }
.fw-dir .segmented__item { padding: 0 var(--sp-16); }
/* Auf dem Handy teilen sich drei Segmente die Breite; mit 16px Polster wurde
   «Umbuchung» bei 17px-Typo zu «Umbuchu…» gekappt. */
@media (max-width: 767.98px) {
  .fw-dir .segmented__item { padding: 0 var(--sp-4); }
}

/* Umbuchung im Erfassen-Modal: app.js (initRichtung) setzt hidden auf die
   Felder, die zur gewaehlten Art nicht passen. .field und .form-grid bringen
   eine eigene display-Regel mit, die das Attribut sonst ueberstimmte. */
[data-nur][hidden],
[data-umbuchung-gleich][hidden] { display: none; }

/* Kategorie-Raster: ein Tipp statt Dropdown-Suche -------------------------- */
.fw-catgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: var(--sp-8);
}

.fw-cat {
  --chip: var(--text-muted);
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  min-height: var(--control-h-touch);
  padding: var(--sp-8) var(--sp-12);
  border: 1px solid var(--separator);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body-sm);
  cursor: pointer;
  transition: border-color var(--t-fast), background-color var(--t-fast);
}

.fw-cat:hover { border-color: var(--border-strong); background: var(--fill); }

.fw-cat__dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--chip);
}

/* Kategorie-Punkte im Dunkeln: mit Weiss aufgehellt, dann liegen alle 15
   Startfarben bei mindestens 4.9:1. Die Chip-Formel (14 % / 55 %) bleibt.
   light-dark() statt @media: folgt der Einstellung Darstellung, nicht dem System. */
.chip__dot,
.fw-cat__dot {
  background: light-dark(var(--chip, var(--text-subtle)),
                         color-mix(in srgb, var(--chip, var(--text-subtle)) 75%, white));
}

.fw-cat__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.fw-cat input { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--tint); }

@supports selector(:has(*)) {
  /* Beide Radios verschwinden erst, wenn die Pille den Zustand tragen kann.
     Ohne :has() bliebe der Umschalter sonst zustandslos: weder Radio noch
     Pille zeigten, ob «Ausgabe» oder «Einnahme» gewaehlt ist. */
  .fw-dir input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
  .fw-cat input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
  .fw-cat:has(input:checked) {
    border-color: var(--tint);
    background: var(--accent-weak);
  }
  .fw-cat:has(input:focus-visible) {
    outline: var(--focus-width) solid var(--accent);
    outline-offset: var(--focus-offset);
  }

  /* Aufteilen-Umschalter blendet Einzelkategorie bzw. Positionen um.
     Ohne :has()-Unterstuetzung bleiben schlicht beide sichtbar — die
     Checkbox entscheidet ohnehin serverseitig. */
  .fw-choice:has(.fw-split-toggle:checked) .fw-choice__single { display: none; }
  .fw-choice:not(:has(.fw-split-toggle:checked)) .fw-choice__split { display: none; }
}

/* Beide Zweige des Umschalters stehen im selben Abstand zum Kasten darueber
   wie die uebrigen Felder des Formulars (.form gap: --sp-16). Ohne den Abstand
   klebte das Etikett «Kategorie» direkt am Hilfstext des Aufteilen-Kastens und
   las sich wie dessen Fortsetzung. */
.fw-choice__single,
.fw-choice__split { margin-top: var(--sp-16); }
/* WICHTIG: <noscript> hier NICHT auf display:contents setzen. Bei aktivem
   JavaScript ist sein Inhalt reiner Text — er wuerde als Quelltext sichtbar.
   Ohne JavaScript rendert der Browser die Zusatzzeilen ohnehin. */

.fw-splitcat { display: grid; gap: var(--sp-4); min-width: 0; }


@media (max-width: 767.98px) {

  /* Zwei Kacheln pro Zeile — jede ist ein 44px-Ziel. Schriftgroesse bleibt
     body-sm: bei 15px bricht «Restaurant & Café» um und die Reihe wird hoch. */
  .fw-catgrid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }

  /* Aufteilung: je Position eine Zeile (Kategorie, Bezeichnung, Betrag) und
     das × daneben — das Raster legt app.css oben, hier kommt der Fuss dazu. */
  .split__footer { flex-direction: column; align-items: stretch; gap: var(--sp-8); }
  .split__footer .btn { width: 100%; height: var(--control-h-touch); }

  /* Der Rest ist die wichtigste Zahl der Aufteilung: volle Breite, direkt
     ueber dem Speichern-Knopf. */
  .split-rest {
    display: flex;
    justify-content: space-between;
    align-items: center;
    min-height: var(--control-h-touch);
    padding: var(--sp-8) var(--sp-16);
    white-space: normal;
  }
}

/* ==========================================================================
   Verlauf (/planen/linie): der Kontostand Tag für Tag
   Reines Inline-SVG. Farbe trägt nie allein: grosse Abgänge sind gefüllte
   Kreise MIT Betrag, der Lohn ein Ring, Fristen Rauten auf der Achse, die
   Prognose gestrichelt.
   ========================================================================== */
.fw-linie__kopf { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-12); }
.fw-linie__pfeile { display: flex; gap: var(--sp-4); flex: 0 0 auto; }
.fw-linie__pfeil { display: inline-flex; align-items: center; justify-content: center; width: var(--control-h-touch); height: var(--control-h-touch); border: 1px solid var(--separator); border-radius: 999px; font-size: 22px; line-height: 1; color: var(--tint); text-decoration: none; background: var(--surface); }
.fw-linie__pfeil:hover { border-color: var(--border-strong); }
.fw-linie__pfeil.is-leer { color: var(--text-subtle); border-color: var(--separator); }
.fw-linie { display: block; width: 100%; height: auto; margin-top: var(--sp-16); }
.fw-linie__netz { stroke: var(--separator); stroke-width: 1; }
.fw-linie__null { stroke: var(--border-strong); stroke-dasharray: 4 3; }
.fw-linie__achse { fill: var(--text-muted); font-size: 14px; }
.fw-linie__marke { fill: var(--text); font-size: 14px; font-weight: var(--fw-medium); }
/* SVG-Schrift zaehlt in Einheiten der viewBox und schrumpft mit der Zeichnung:
   900 Einheiten auf 780px (1100px Fenster) machen aus 14 rund 12px, aus den
   frueheren 11 gut 9px (UI-Evaluation D1). Das Handy-Bild hat 360 Einheiten
   auf rund 390px, dort genuegen 12.
   ponytail: zwischen 768 und 1099px (Icon-Leiste) bleibt es bei 10–11px; eine
   eigene Tablet-Zeichnung, falls das stoert. */
.fw-linie__kurve { fill: none; stroke: var(--text); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.fw-linie__kurve--prognose { stroke-dasharray: 5 4; }
.fw-linie__gross { fill: var(--negative); stroke: var(--surface); stroke-width: 1.5; }
.fw-linie__lohn { fill: var(--surface); stroke: var(--accent); stroke-width: 2.5; }
.fw-linie__frist { fill: var(--warning); }
.fw-linie__heute { stroke: var(--accent); stroke-width: 1; }
.fw-linie__wahl { fill: var(--accent-weak); }
.fw-linie__ziel { fill: transparent; cursor: pointer; }
.fw-linie a:focus-visible .fw-linie__ziel { stroke: var(--accent); stroke-width: 2; }
.fw-linie__legende { display: flex; flex-wrap: wrap; gap: var(--sp-8) var(--sp-16); margin: var(--sp-8) 0 0; font-size: var(--fs-body-sm); color: var(--text-muted); }
.fw-linie__symbol { display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: 50%; vertical-align: -1px; }
.fw-linie__symbol--gross { background: var(--negative); }
.fw-linie__symbol--lohn { background: var(--surface); box-shadow: inset 0 0 0 2.5px var(--accent); }
.fw-linie__symbol--frist { background: var(--warning); border-radius: 1px; transform: rotate(45deg) scale(.85); }
.fw-linie__monate { display: flex; flex-wrap: wrap; gap: var(--sp-8); margin-top: var(--sp-16); }
.fw-linie__monat { position: relative; padding: 6px 12px; min-height: 32px; border: 1px solid var(--separator); border-radius: 999px; font-size: var(--fs-body-sm); color: var(--text); text-decoration: none; }
.fw-linie__monat.is-aktiv { background: var(--accent-weak); border-color: var(--tint); }
.fw-linie__punkt { display: inline-block; width: 6px; height: 6px; margin-left: 6px; border-radius: 50%; background: var(--negative); vertical-align: 2px; }
.fw-linie__fristzeile { margin: 0 0 var(--sp-8); color: var(--warning); font-size: var(--fs-body-sm); }
.fw-planen__verlauf { margin: 0 0 var(--sp-12); font-size: var(--fs-body-sm); text-align: right; }
/* Zwei Zeichnungen, je eine sichtbar: gross ab 768px, klein auf dem Handy.
   Auf dem Handy tritt die kleine aus der Kartenpolsterung heraus und nutzt die
   ganze Breite — Romain: «kein unnötiges Padding, kein Scrollen». */
.fw-linie--handy { display: none; }
@media (max-width: 767px) {
  .fw-linie--gross { display: none; }
  .fw-linie--handy { display: block; width: calc(100% + 2 * var(--sp-16)); margin-left: calc(var(--sp-16) * -1); margin-right: calc(var(--sp-16) * -1); }
  .fw-linie--handy .fw-linie__achse { font-size: 12px; }
  .fw-linie--handy .fw-linie__marke { font-size: 12px; }
  /* Dreizehn Monatsknöpfe in drei Reihen waren Lärm: eine Reihe, wischbar. */
  .fw-linie__monate { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: var(--sp-4); }
  .fw-linie__monat { flex: 0 0 auto; display: inline-flex; align-items: center; min-height: var(--control-h-touch); }
}
/* Der Verlauf als Baustein in der Heldenkarte auf Heute. */
.fw-verlauf { margin: 0; }
.fw-verlauf__tag { margin-top: var(--sp-16); padding-top: var(--sp-16); border-top: 1px solid var(--separator); }
.fw-verlauf__tabelle { margin-top: var(--sp-16); }
.fw-verlauf__tabelle > summary { cursor: pointer; font-size: var(--fs-body-sm); color: var(--text-muted); }

/* Monatsgitter auf dem Desktop: quadratische Zellen über die volle Breite
   wurden 130px gross und die Seite endlos. Ab 768px höchstens 640px breit. */
@media (min-width: 768px) {
  .fw-gitter, .fw-gitter__achse { max-width: 640px; }
}

/* ==========================================================================
   23  BUCHUNGSLISTE (/transaktionen)
   --------------------------------------------------------------------------
   Tagesgruppen, Inline-Zuordnung, die beiden Aufklapper (Filter, Sammelaktion)
   und die Kartenansicht auf dem Handy. Stand bis zum Apple-Stil als 300-Zeilen-
   Insel in templates/transactions.php.
   ========================================================================== */


/* --- Suche und Werkzeugzeile ---------------------------------------------
   Die Suche steht offen unter Titel und Reitern (Plan §3). Auf dem Gruppen-
   grund traegt sie --surface, sonst verschwaende sie mit 1.00:1. Darunter
   Textknoepfe im Tint (iOS «plain») statt dreier breiter Kapseln. */
.fw-suche .input--search { background-color: var(--surface); border-color: transparent; }
.fw-suche .input--search:hover { border-color: var(--separator); }

.fw-werkzeug {
  display: flex;
  flex-wrap: wrap;   /* 360px-Android mit «n aktiv» */
  align-items: center;
  gap: var(--sp-4);
  margin: var(--sp-4) calc(var(--sp-12) * -1) var(--sp-12);   /* Text buendig mit der Kante */
}
.fw-werkzeug__knopf { padding: 0 var(--sp-12); }
.fw-werkzeug__rechts { margin-left: auto; }

/* Das Kästchen selbst ist unsichtbar (sr-only) — der Fokus gehört sichtbar
   auf den Knopf, sonst tappt die Tastatur im Dunkeln. */
.fw-fold__switch:focus-visible ~ .fw-werkzeug .fw-fold__btn,
.fw-selectmode__switch:focus-visible ~ .fw-werkzeug .fw-selectmode__btn {
  outline: var(--focus-width) solid var(--accent);
  outline-offset: var(--focus-offset);
}

/* Aufklapper (Filter, Sammelaktion): die Kästchen tragen den Zustand, ganz
   ohne JavaScript — auf jedem Gerät gleich. «Auswählen» heisst offen «Fertig». */
.fw-fold__switch:not(:checked) ~ .fw-fold__panel,
.fw-selectmode__switch:not(:checked) ~ .fw-bulk,
.fw-selectmode__ein { display: none; }
.fw-selectmode__switch:checked ~ .fw-werkzeug .fw-selectmode__aus { display: none; }
.fw-selectmode__switch:checked ~ .fw-werkzeug .fw-selectmode__ein { display: inline; }

.fw-liste > .card { margin-bottom: var(--sp-16); }

.fw-filters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--sp-12);
  align-items: end;
}
.fw-filters__actions { display: flex; align-items: end; gap: var(--sp-8); }

.fw-bulk__hint { font-size: var(--fs-body-sm); color: var(--text-muted); }
.fw-bulk .fw-inline__select { width: auto; flex: 0 1 220px; }

/* --- Summen: eine Gruppe mit drei Zeilen, der Zeitraum als Sektionskopf --- */
.fw-totals__zeitraum {
  padding: var(--sp-8) var(--sp-16);
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--text-muted);
}
.fw-totals { margin-bottom: var(--sp-16); }
.fw-totals .list__item { justify-content: space-between; min-height: var(--control-h-touch); padding-block: var(--sp-8); }
.fw-totals__wert { font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Geplant: vordatierte Posten, eingeklappt über der Liste (UI-Evaluation A5).
   Der gestrichelte Rahmen sagt «noch nicht gebucht», ohne eine Farbe zu
   belegen — gestrichelt heisst in der App schon «Prognose» (Verlauf). */
.fw-geplant { border: 1px dashed var(--border-strong); }
.fw-geplant__kopf {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 2px var(--sp-8);
  padding: var(--sp-12) var(--sp-16);
  min-height: var(--control-h-touch);
}
.fw-geplant__kopf::before { margin: 0; }            /* der Winkel aus app.css */
.fw-geplant__meta { grid-column: 2; }
.fw-geplant__titel { font-weight: var(--fw-semibold); color: var(--text); }
.fw-geplant__meta { font-size: var(--fs-body-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fw-geplant[open] > .fw-geplant__kopf { border-bottom: 1px solid var(--separator); }
.fw-geplant > .table-wrap { margin-top: 0; }   /* .card > * + * gilt hier nicht */

.fw-modalform { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 0; }

/* --- Tagesköpfe ------------------------------------------------------------
   Halb --fill: in vollem --fill (= --bg) verlore die Karte an jedem Tageskopf
   ihre Seitenkanten. */
.fw-txtable .fw-day__head > * {
  position: relative;
  padding: var(--sp-12) var(--sp-16);
  background: color-mix(in srgb, var(--fill) 50%, var(--surface));
  border-top: 1px solid var(--separator);
  border-bottom: 1px solid var(--separator);
  text-align: left;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  color: var(--text-muted);
}

.fw-txtable .fw-day__head > .fw-day__sum { text-align: right; text-transform: none; }

/* --- Buchungszeile: Kachel 36, Titel, Unterzeile, Betrag rechts (Plan §3) --- */
.fw-tx__zelle { display: flex; align-items: center; gap: var(--sp-12); min-width: 0; }

/* Kategoriefarbe nach der Chip-Formel (14 % Fläche, 55 % Mischung im Symbol):
   dieselben geprüften Kontraste, hell wie dunkel. */
.fw-tx__kachel {
  --chip: var(--text-muted);
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-tile);
  background: color-mix(in srgb, var(--chip) 14%, var(--surface));
  color: color-mix(in srgb, var(--chip) 55%, var(--text));
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  line-height: 1;
}
.fw-tx__kachel--leer { background: var(--fill); color: var(--text-muted); }

.fw-tx__text { flex: 1 1 auto; min-width: 0; }
.fw-tx__titel,
.fw-tx__meta { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fw-tx__titel { font-size: var(--fs-body); font-weight: var(--fw-semibold); line-height: 22px; }
.fw-tx__meta { margin: 0; font-size: var(--fs-body-sm); line-height: 20px; }
/* Zweite Angabe ohne Alt-Text: Vorlesegeräte lesen sonst «Mittelpunkt». */
.fw-tx__meta > span + span::before { content: " · "; content: " · " / ""; }

.fw-txtable td.money { font-size: var(--fs-money); font-weight: var(--fw-medium); white-space: nowrap; }
/* .table tbody td setzt --text und wiegt mehr als .money-pos allein. */
.fw-txtable td.money-pos { color: var(--positive); }
.fw-txtable td.money-zero { color: var(--text-muted); }

.fw-inline { display: flex; align-items: center; gap: var(--sp-4); }
.fw-inline__select { min-width: 11em; }

/* Auswahl nur im Modus «Auswählen» — auf jedem Gerät. */
.fw-txtable .fw-col-select { display: none; }

/* --- Mehr laden ------------------------------------------------------------ */
.fw-mehr { display: flex; flex-direction: column; align-items: center; gap: var(--sp-8); margin-top: var(--sp-16); }
.fw-mehr__knopf { min-width: 240px; }
.fw-mehr__knopf[aria-busy="true"] { opacity: 0.6; pointer-events: none; }
.fw-mehr__info { font-size: var(--fs-body-sm); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.fw-neuere { margin: 0 calc(var(--sp-12) * -1) var(--sp-8); }   /* Textknopf buendig */

/* --------------------------------------------------------------------------
   Desktop: die Tabelle bleibt, mit Kategorie-Spalte und Aktionen beim Zeigen.
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  /* Die Aktionen in einer Zeile: umgebrochen machten sie jede Zeile 110px hoch.
     Dafuer gibt die Textspalte nach: max-width 0 laesst den langen Titel
     abschneiden, statt die Tabelle ueber die Karte hinaus zu dehnen. */
  .fw-txtable .row-actions { flex-wrap: nowrap; }
  .fw-txtable .fw-col-main { width: 100%; max-width: 0; }

  .fw-selectmode__switch:checked ~ .fw-selectmode__list .fw-txtable .fw-col-select { display: table-cell; }

  /* Die Kategorie-Auswahl liest sich wie Text, bis man auf die Zeile zeigt. */
  .fw-txtable .fw-inline__select { border-color: transparent; background-color: transparent; }
  .fw-txtable .fw-tx:hover .fw-inline__select,
  .fw-txtable .fw-inline__select:focus { border-color: var(--separator); background-color: var(--surface); }
}

/* Ab 1200px hat die Kategorie ihre eigene Spalte */
@media (min-width: 1200px) {
  .fw-tx__catchip { display: none; }
  .fw-tx__meta > .fw-tx__catchip + span::before { content: none; }
}

/* Zwischen 768 und 1199px (iPad hochkant, halbes Fenster) faellt «Bearbeiten»
   weg — der Titel fuehrt ohnehin zum Bearbeiten. Auch die Kategorie-Spalte
   faellt weg und steht wie auf dem Handy vorn in der Unterzeile (geaendert
   wird sie in der Buchung oder per Auswahl): mit ihr blieben dem Titel bei
   768px nur 115px, weil die Aktionsspalte ihre Breite auch unsichtbar haelt. */
@media (min-width: 768px) and (max-width: 1199.98px) {
  .fw-txtable .row-actions > a[href] { display: none; }
  .fw-txtable .fw-col-cat { display: none; }
}

/* --------------------------------------------------------------------------
   Handy: keine Tabelle mehr, sondern eingezogene Gruppen je Tag wie in iOS.
   Tageskopf auf dem Grund, darunter die Zeilen als Karte. Die ganze Zeile
   führt zum Bearbeiten.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {

  /* Sind alle Seitenaktionen Desktop-Knöpfe, bleibt kein leerer Streifen. */
  .page-actions:not(:has(> :not(.fw-desk))) { display: none; }

  /* Filtern und Zurücksetzen teilen sich die Zeile */
  .fw-filters__actions .btn { flex: 1 1 0; }

  /* --- Sammelaktion: die Auswahl über die volle Breite, die Knöpfe klein
     (34px, Trefferfeld 44 über .btn--sm::after) und umbrechend statt fünf
     breiter Zeilen untereinander. --- */
  .fw-bulk .fw-inline__select { flex: 1 1 100%; width: 100%; }
  .fw-bulk .cluster { row-gap: calc(var(--sp-8) + 2px); }   /* 44er Trefferfelder überlappen nicht */

  /* --- Liste als Gruppen -------------------------------------------------- */
  .fw-txtable,
  .fw-txtable tbody,
  .fw-txtable tr,
  .fw-txtable th,
  .fw-txtable td { display: block; }

  /* Kopfzeile bleibt für Vorlesegeräte da, verschwindet nur optisch */
  .fw-txtable thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Die Tagesliste selbst ist keine Karte mehr — jeder Tag ist eine. */
  .fw-tagesliste { background: none; border-radius: 0; overflow: visible; }

  /* Achtung Spezifität: die Regeln oben treffen mit .fw-txtable td/tr schon
     zwei Selektoren. Alles, was sie überschreiben soll, braucht mindestens
     dieselbe Gewichtung — darum überall .fw-txtable davor. */
  /* Kein gap: die leere Auswahlzelle im Auswahlmodus schöbe sonst das Datum. */
  .fw-txtable .fw-day__head {
    display: flex;
    align-items: baseline;
    padding: var(--sp-20) var(--sp-16) var(--sp-8);
  }
  .fw-txtable .fw-day__head > * { width: auto; padding: 0; background: none; border: 0; }
  .fw-txtable .fw-day__head > .fw-day__sum { margin-left: auto; padding-left: var(--sp-12); }
  .fw-tagesliste .fw-day:first-of-type .fw-day__head { padding-top: var(--sp-4); }

  .fw-txtable .fw-tx {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: var(--sp-12);
    min-height: 60px;
    padding: var(--sp-8) var(--sp-16);
    background: var(--surface);
  }
  .fw-txtable .fw-day__head + .fw-tx { border-top-left-radius: var(--radius-card); border-top-right-radius: var(--radius-card); }
  .fw-txtable .fw-tx:last-child { border-bottom-left-radius: var(--radius-card); border-bottom-right-radius: var(--radius-card); }
  .fw-txtable .fw-tx:active { background: var(--fill); }

  /* Die Zellen stehen in der Quellreihenfolge im Raster: Auswahl (nur im
     Auswahlmodus), Beschreibung, Betrag. Kategorie und Aktionen sind
     ausgeblendet und belegen deshalb keine Spalte. */
  .fw-txtable .fw-tx > td { width: auto; padding: 0; }

  /* Trennlinie eingezogen wie bei .list__item: sie beginnt beim Text, also
     hinter der Kachel (16 + 36 + 12). */
  .fw-txtable tbody tr.fw-tx,
  .fw-txtable tbody tr.fw-day__head { border-bottom: 0; }
  .fw-txtable .fw-tx + .fw-tx::before {
    content: "";
    position: absolute;
    top: 0;
    left: 64px;
    right: 0;
    height: 1px;
    background: var(--separator);
  }

  /* Die ganze Zeile ist das Tippziel */
  .fw-txtable .table__row-link::after { content: ""; position: absolute; inset: 0; }

  /* Kategorie ändern, bearbeiten und löschen stehen auf der Detailseite —
     ein Tipp auf die Zeile. Auf dem Handy bleibt die Liste ruhig. */
  .fw-txtable .fw-col-cat,
  .fw-txtable .fw-col-actions { display: none; }

  /* --- Auswahl ------------------------------------------------------------- */
  .fw-selectmode__switch:checked ~ .fw-selectmode__list .fw-txtable .fw-tx {
    grid-template-columns: var(--control-h-touch) minmax(0, 1fr) auto;
    column-gap: var(--sp-8);
    padding-left: var(--sp-4);
  }

  .fw-selectmode__switch:checked ~ .fw-selectmode__list .fw-txtable .fw-tx + .fw-tx::before { left: 104px; }

  .fw-selectmode__switch:checked ~ .fw-selectmode__list .fw-txtable .fw-col-select {
    display: block;
    position: relative;
    z-index: 1;                 /* über der Zeilen-Verlinkung */
  }

  /* 44×44 Trefferfeld mit rundem 22px-Kreis darin, wie in iOS-Listen */
  .fw-tx__check {
    -webkit-appearance: none;
    appearance: none;
    position: relative;
    display: block;
    width: var(--control-h-touch);
    height: var(--control-h-touch);
    margin: 0;
    background: none;
    border: 0;
    cursor: pointer;
  }
  .fw-tx__check::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 22px;
    height: 22px;
    margin: -11px 0 0 -11px;
    border: 1.5px solid var(--border-strong);
    border-radius: var(--radius-pill);
    background: var(--surface);
  }
  .fw-tx__check:checked::before { background: var(--tint); border-color: var(--tint); }
  .fw-tx__check:checked::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 10px;
    height: 5px;
    margin: -5px 0 0 -5px;
    border-left: 2px solid var(--surface);
    border-bottom: 2px solid var(--surface);
    transform: rotate(-45deg);
  }
  .fw-tx__check:focus-visible::before { outline: var(--focus-width) solid var(--accent); outline-offset: 2px; }

  .fw-mehr__knopf { width: 100%; }

}


/* ==========================================================================
   24  EINSTELLUNGEN (/einstellungen)
   --------------------------------------------------------------------------
   Alles unter .fw-einstellungen bzw. .fw-sprung, also nur auf dieser Seite.
   Stand bis zum Apple-Stil als Insel in templates/settings.php.
   ========================================================================== */

/* Prozentfeld mit nachgestellter Einheit — dasselbe Muster wie .money-input,
   nur auf der anderen Seite. */
.fw-einstellungen .fw-suffix { position: relative; display: block; }

.fw-einstellungen .fw-suffix__unit {
  position: absolute;
  top: 0;
  right: var(--sp-12);
  display: flex;
  align-items: center;
  height: var(--control-h);
  color: var(--text-muted);
  font-size: var(--fs-body-sm);
  pointer-events: none;
}

.fw-einstellungen .fw-suffix .input { padding-right: var(--sp-32); }

/* Kurze Einheiten wie «%» stehen im Feld. Eine ausgeschriebene wie
   «. des Monats» ist dafür zu breit: sie legte sich über die Zahl, weil der
   Platz rechts fest auf --sp-32 stand. Statt diese Reserve zu raten, tritt die
   Einheit aus dem Feld heraus und stellt sich daneben — so passt jede Länge. */
.fw-einstellungen .fw-suffix--wort { display: flex; align-items: center; gap: var(--sp-8); }

.fw-einstellungen .fw-suffix--wort .input {
  flex: 1 1 auto;
  min-width: 0;
  padding-right: var(--sp-12);
}

.fw-einstellungen .fw-suffix--wort .fw-suffix__unit {
  position: static;
  flex: 0 0 auto;
  height: auto;
  white-space: nowrap;
}

/* Befehle brechen um statt die Seite breit zu machen. */
.fw-einstellungen code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  overflow-wrap: anywhere;
}

/* Sprungmarken oben: eine Zeile, auf dem Handy wischbar, jede Marke ein
   44px-Ziel (DESIGN.md §8). */
.fw-sprung { display: flex; flex-wrap: wrap; gap: var(--sp-8); }
.fw-sprung__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-h-sm);
  padding: 0 var(--sp-12);
  border: 1px solid var(--separator);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-body-sm);
  text-decoration: none;
  white-space: nowrap;
}
.fw-sprung__link:hover { border-color: var(--border-strong); text-decoration: none; color: var(--text); }
@media (max-width: 767.98px) {
  .fw-sprung { flex-wrap: nowrap; overflow-x: auto; margin: 0 calc(var(--sp-16) * -1); padding: 0 var(--sp-16); scrollbar-width: none; }
  .fw-sprung__link { min-height: var(--control-h-touch); }
}

/* Download-Knöpfe stehen am Desktop links unter ihrem Feld. */
.fw-einstellungen .fw-actions--start { justify-content: flex-start; }

/* Abmelden als eigene Gruppe, rot und mittig — wie im ⋯-Blatt. */
.fw-einstellungen .fw-abmelden .btn {
  width: 100%;
  min-height: var(--control-h-touch);
  border-radius: var(--radius-card);
  background: var(--surface);
  color: var(--negative);
  font-size: var(--fs-body);
}
.fw-einstellungen .fw-abmelden .btn:hover { background: var(--negative-weak); color: var(--negative); }

/* Felder als Zeilen einer Gruppe (iOS-Einstellungen): Bezeichnung links in
   Textfarbe, Feld rechts, der Hinweis ueber die volle Breite darunter. */
.fw-einstellungen .fw-feldzeilen { display: block; }
.fw-einstellungen .fw-feldzeilen > .field {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 13rem);
  align-items: center;
  gap: var(--sp-4) var(--sp-12);
  margin: 0;
  padding: var(--sp-12) 0;
}
.fw-einstellungen .fw-feldzeilen > .field:first-of-type { padding-top: 0; }
.fw-einstellungen .fw-feldzeilen > .field + .field::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--separator);
}
.fw-einstellungen .fw-feldzeilen > .field > .field__label {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 22px;
  font-weight: var(--fw-regular);
  text-transform: none;
  letter-spacing: 0;
  color: var(--text);
}
.fw-einstellungen .fw-feldzeilen > .field > * { grid-column: 2; }
.fw-einstellungen .fw-feldzeilen > .field > .field__label { grid-column: 1; }
.fw-einstellungen .fw-feldzeilen > .field > .field__hint,
.fw-einstellungen .fw-feldzeilen > .field > .field__error { grid-column: 1 / -1; margin: 0; }
.fw-einstellungen .fw-feldzeilen > .form-actions,
.fw-einstellungen .fw-feldzeilen > .form-grid { margin-top: var(--sp-12); }
/* Das verschachtelte Raster (Passwort) setzt die Zeilen fort. */
.fw-einstellungen .fw-feldzeilen > .field + .form-grid > .field:first-of-type { padding-top: var(--sp-12); }
.fw-einstellungen .fw-feldzeilen > .field + .form-grid { margin-top: 0; }
.fw-einstellungen .fw-feldzeilen > .field + .form-grid > .field:first-of-type::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--separator);
}

/* Kennzahlen als Zeilen: Bezeichnung in Textfarbe, Wert gedaempft rechts. */
.fw-einstellungen .fw-werte { gap: 0; }
.fw-einstellungen .fw-werte dt,
.fw-einstellungen .fw-werte dd { padding: var(--sp-8) 0; border-top: 1px solid var(--separator); }
.fw-einstellungen .fw-werte dt:first-of-type,
.fw-einstellungen .fw-werte dd:first-of-type { border-top: 0; padding-top: 0; }
.fw-einstellungen .fw-werte dt { font-size: var(--fs-body); text-transform: none; letter-spacing: 0; font-weight: var(--fw-regular); color: var(--text); }
.fw-einstellungen .fw-werte dd { font-size: var(--fs-body); color: var(--text-muted); text-align: right; }

/* Termine: Zeilen buendig mit dem Karteninhalt. */
.fw-einstellungen .fw-termine .list__item { padding-left: 0; padding-right: 0; }
.fw-einstellungen .fw-termine .list__item + .list__item::before,
.fw-einstellungen .fw-termine > li + li > .list__item::before { left: 0; }
.fw-einstellungen .fw-termine .list__title { font-size: var(--fs-body); font-weight: var(--fw-regular); white-space: normal; }
.fw-einstellungen .fw-termine .list__meta { flex-wrap: wrap; font-size: var(--fs-body-sm); }

@media (max-width: 767.98px) {
  /* Am Handy ist das Prozentfeld 44px hoch — die Einheit zieht mit. */
  .fw-einstellungen .fw-suffix__unit { height: var(--control-h-touch); font-size: 16px; }

  /* Zeilen: das Feld nimmt auf dem Phone etwas mehr als die Hälfte. */
  .fw-einstellungen .fw-feldzeilen > .field { grid-template-columns: minmax(0, 1fr) minmax(0, 11rem); }
}
