﻿:root {
  /* Natives Steuerelement-Aussehen (Datumsfelder im Zeitraum-Sheet, Scrollbalken) folgt dem
     Theme – sonst blieben sie hell, waehrend die App dunkel ist. */
  color-scheme: light;
  --color-bg: #f4f6f3;
  --color-surface: #fff;
  --color-border: #dee5db;
  --color-text: #16211a;
  --color-text-muted: #5e6e60;
  --color-positive: #2e8b57;
  --color-negative: #b3492e;
  --color-accent: #1b4332;
  --color-accent-text: #256b4e;
  --color-accent-contrast: #fff;
  --color-chip-bg: #e7ede7;
  --color-pop-bg: #16211a;
  --color-pop-text: #f4f6f3;
  --color-pop-text-muted: #b6c2b6;
  --color-pop-rule: rgba(244, 246, 243, 0.16);
  --color-notice-text: #8a5a00;
  --color-notice-bg: #fbf1dd;
  --radius-md: 16px;
  --radius-sm: 10px;
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-7: #4a3aa7;
  --series-8: #e34948;
  --series-9: #0e93a3;
  --series-10: #a06a35;
  --series-other: #9aab97;
  --series-unassigned: #c3c9c1;
}

@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --color-bg: #10140f;
    --color-surface: #182018;
    --color-border: #253227;
    --color-text: #ecf2ea;
    --color-text-muted: #93a692;
    --color-positive: #6fd19b;
    --color-negative: #e4886a;
    --color-accent: #52a37e;
    --color-accent-text: #7ed1a8;
    --color-accent-contrast: #06140d;
    --color-chip-bg: #1e2a20;
    --color-pop-bg: #2b3a2e;
    --color-pop-text: #ecf2ea;
    --color-pop-text-muted: #a9baa8;
    --color-pop-rule: rgba(236, 242, 234, 0.16);
    --color-notice-text: #ffce7a;
    --color-notice-bg: #2c2210;
    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #008300;
    --series-7: #9085e9;
    --series-8: #e66767;
    --series-9: #22b4c5;
    --series-10: #c1854f;
    --series-other: #526354;
    --series-unassigned: #3a453c;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: #10140f;
  --color-surface: #182018;
  --color-border: #253227;
  --color-text: #ecf2ea;
  --color-text-muted: #93a692;
  --color-positive: #6fd19b;
  --color-negative: #e4886a;
  --color-accent: #52a37e;
  --color-accent-text: #7ed1a8;
  --color-accent-contrast: #06140d;
  --color-chip-bg: #1e2a20;
  --color-pop-bg: #2b3a2e;
  --color-pop-text: #ecf2ea;
  --color-pop-text-muted: #a9baa8;
  --color-pop-rule: rgba(236, 242, 234, 0.16);
  --color-notice-text: #ffce7a;
  --color-notice-bg: #2c2210;
  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-7: #9085e9;
  --series-8: #e66767;
  --series-9: #22b4c5;
  --series-10: #c1854f;
  --series-other: #526354;
  --series-unassigned: #3a453c;
}

:root[data-theme="light"] {
  color-scheme: light;
  --color-bg: #f4f6f3;
  --color-surface: #fff;
  --color-border: #dee5db;
  --color-text: #16211a;
  --color-text-muted: #5e6e60;
  --color-positive: #2e8b57;
  --color-negative: #b3492e;
  --color-accent: #1b4332;
  --color-accent-text: #256b4e;
  --color-accent-contrast: #fff;
  --color-chip-bg: #e7ede7;
  --color-pop-bg: #16211a;
  --color-pop-text: #f4f6f3;
  --color-pop-text-muted: #b6c2b6;
  --color-pop-rule: rgba(244, 246, 243, 0.16);
  --color-notice-text: #8a5a00;
  --color-notice-bg: #fbf1dd;
  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-7: #4a3aa7;
  --series-8: #e34948;
  --series-9: #0e93a3;
  --series-10: #a06a35;
  --series-other: #9aab97;
  --series-unassigned: #c3c9c1;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html, body {
  height: 100%;
}

body:has(dialog[open]) {
  overflow: hidden;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-variant-numeric: tabular-nums;
  background: var(--color-bg);
  color: var(--color-text);
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

button {
  font: inherit;
  cursor: pointer;
}

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 1rem 1.25rem;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.app-header h1 {
  font-size: 1.25rem;
  font-weight: 600;
}

/* Konto-Filter (globales Widget in der App-Header-Leiste) */

.account-filter {
  position: relative;
  flex-shrink: 0;
}

.account-filter-toggle {
  all: unset;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  padding: 0.35rem 0.65rem 0.35rem 0.55rem;
  color: var(--color-accent-contrast);
}

.account-filter-toggle svg {
  width: 14px;
  height: 14px;
  opacity: 0.9;
  flex-shrink: 0;
}

.account-filter-label {
  font-size: 0.74rem;
  font-weight: 600;
  white-space: nowrap;
  max-width: 8em;
  overflow: hidden;
  text-overflow: ellipsis;
}

.account-filter-popover {
  display: none;
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 210px;
  max-height: 280px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 16px 32px -12px rgba(0, 0, 0, 0.4);
  padding: 0.35rem;
  z-index: 50;
  color: var(--color-text);
}

.account-filter.is-open .account-filter-popover {
  display: block;
}

.account-filter-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.55rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.82rem;
}

.account-filter-row:hover {
  background: var(--color-chip-bg);
}

.account-filter-row input {
  accent-color: var(--color-accent-text);
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.account-filter-row-all {
  font-weight: 600;
  color: var(--color-accent-text);
  border-bottom: 1px solid var(--color-border);
  border-radius: 0;
  margin-bottom: 0.2rem;
  padding-bottom: 0.55rem;
}

.account-filter-row-archived {
  border-top: 1px solid var(--color-border);
  border-radius: 0;
  margin-top: 0.2rem;
  padding-top: 0.55rem;
  color: var(--color-text-muted);
}

.demo-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  padding: 0.45rem 1rem;
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.8rem;
  font-weight: 600;
}

.demo-banner svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.demo-banner[hidden] {
  display: none;
}

#view-container {
  /* Bezugsrahmen für den Ladeschleier (siehe .busy-overlay), der genau diese Fläche deckt. */
  position: relative;
  flex: 1;
  padding: 0.7rem;
  padding-bottom: 5rem; /* Platz für die fixe Bottom-Nav */
  max-width: 960px;
  width: 100%;
  margin: 0 auto;
}

.view[hidden] {
  display: none;
}

.app-nav {
  position: fixed;
  /* Über allem Listeninhalt (z. B. den sticky Gruppenköpfen der Verträge-Liste), aber unter dem
     Konto-Filter-Popover im Header (z-index: 50). */
  z-index: 30;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding-bottom: env(safe-area-inset-bottom, 0);
}

.nav-button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  border: none;
  background: none;
  padding: 0.6rem 0.5rem;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  min-height: 48px; /* touch-freundlich */
}

.nav-icon {
  width: 22px;
  height: 22px;
}

.nav-button.active {
  color: var(--color-accent-text);
  font-weight: 600;
}

@media (min-width: 768px) {
  .app-nav {
    justify-content: center;
    gap: 1rem;
  }

  .nav-button {
    flex: none;
    padding: 0.5rem 1.5rem;
  }
}

/* Hauptdashboard */

/* Die Zeitraumzeile (FB.PeriodNav). Bis 2026-08-30 gab es sie zweimal: hier als .month-nav und
   im Kategorie-Drilldown als .month-pill – identische Funktion, zwei Bausaetze. Sie steht jetzt
   in EINER Groesse an beiden Orten; eine kompakte Zweitfassung waere genau die Naht, an der die
   beiden wieder auseinanderlaufen. */

.period-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
}

.period-nav-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
  flex-shrink: 0;
  padding: 0;
}

.period-nav-arrow svg {
  width: 18px;
  height: 18px;
}

.period-nav-arrow:hover:not(:disabled) {
  color: var(--color-accent-text);
}

.period-nav-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}

/* Chip-Flaeche, Kalender und Caret sind kein Schmuck: vorher stand hier reiner gesperrter
   Versaltext, der wie eine Ueberschrift aussah – dass sich dahinter ein Zeitraum waehlen und
   frei festlegen laesst, war ihm nicht anzusehen. */
.period-nav-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: none;
  cursor: pointer;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  border-radius: 999px;
  padding: 0.42rem 0.7rem 0.42rem 0.75rem;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.period-nav-cal {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  opacity: 0.85;
}

.period-nav-caret {
  width: 13px;
  height: 13px;
  flex-shrink: 0;
  opacity: 0.7;
}

.period-nav-label:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 3px;
}

.hero-card {
  /* Bezugsrahmen für das Erklär-Popover: es gehört nicht mehr nur zum Tempo-Block, sondern
     erklärt auch die Rest-Zeile darunter. */
  position: relative;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1.25rem 1rem;
  margin-bottom: 0.75rem;
  text-align: center;
}

.hero-label {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin-bottom: 0.35rem;
}

/* Umschalter zwischen Ausgaben- und Einnahmenblick: der Kartenkopf der Hero-Karte selbst, also
   zwei Reiter anstelle des .hero-label. Bewusst leiser als ein Segment-Control – er wählt eine
   Ansichtsvariante und darf die Kennzahl darunter nicht überstrahlen. Er schaltet alles unter
   sich mit um (Kennzahl, Vergleich, Donut). */
.hero-card.has-flow-tabs {
  padding-top: 0.85rem;
}

.hero-flow-tabs {
  display: flex;
  justify-content: center;
  gap: 1.25rem;
  margin-bottom: 1.1rem;
}

/* In den Leerfällen gibt es keine Hero-Karte, die Reiterzeile steht dort für sich. */
.hero-flow-tabs.is-standalone {
  margin-bottom: 1.25rem;
}

.hero-flow-tabs button {
  border: none;
  background: transparent;
  font: inherit;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  padding: 0.2rem 0;
  cursor: pointer;
  position: relative;
  transition: color 0.15s ease;
}

.hero-flow-tabs button.is-active {
  color: var(--color-text);
  font-weight: 600;
}

.hero-flow-tabs button.is-active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-accent-text);
}

.hero-flow-tabs button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-accent-text);
  border-radius: var(--radius-sm);
}

.hero-amount {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.hero-delta {
  font-size: 0.85rem;
  color: var(--color-accent-text);
  margin-top: 0.35rem;
  margin-bottom: 1rem;
}

/* In der Reiter-Variante wandert der Abstand von unten nach oben: die Kennzahl bekommt mehr Luft
   zu den Reitern, die Karte bleibt dabei insgesamt gleich hoch. */
.hero-card.has-flow-tabs .hero-delta {
  margin-bottom: 0.45rem;
}

/* --- Tempo-Block der Hero-Karte (siehe paceHtml in js/ui/dashboard-view.js) ------------------- */

/* Der Tempo-Block ist kein Knopf mehr: angefasst werden die Balkenstücke und die beiden Zahlen
   der Hochrechnungszeile, jedes mit seiner eigenen Erklärung. Positioniert wird das Popover in
   .hero-card, nicht hier – siehe dort. */

/* Steht unter dem Balken: das kräftige Stück endet genau bei diesem Tag. */
.hero-pace-line {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin-top: 0.2rem;
}

/* Der Balken misst Geld: die volle Breite ist der größere Wert aus Hochrechnung und Ø-Monat.
   overflow bleibt sichtbar, weil die Ø-Marke oben und unten aus der Spur herausragt. */
/* Der Balken bleibt 8 px dünn, angefasst wird eine 34 px hohe Zone darüber – sonst trifft man
   die Stücke mit dem Daumen nicht. Die Trefferflächen liegen deshalb im Wrapper, nicht im Balken. */
.hero-pace-bar-wrap {
  position: relative;
  height: 34px;
  /* Die Trefferzone bringt oben und unten schon je 13 px mit – der zusätzliche Außenabstand
     bleibt deshalb klein, sonst steht der Balken wie abgetrennt zwischen den Zeilen. */
  margin: 0.1rem 0 0.05rem;
}

.hero-pace-bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 13px;
  height: 8px;
  border-radius: 999px;
  background: var(--color-chip-bg);
}

.hero-pace-hit {
  position: absolute;
  top: 0;
  bottom: 0;
  padding: 0;
  border: 0;
  background: none;
  border-radius: 999px;
  cursor: pointer;
}

.hero-pace-hit:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

/* Das gemeinte Stück tritt hervor, solange seine Erklärung offen ist – ohne das bliebe unklar,
   worauf sich der Text im Popover bezieht. */
.hero-card[data-pace-active="spent"] .hero-pace-bar-spent {
  filter: brightness(1.25);
}

.hero-card[data-pace-active="rest"] .hero-pace-bar-forecast {
  opacity: 0.5;
}

.hero-card[data-pace-active="average"] .hero-pace-bar-marker {
  width: 3px;
  background: var(--color-text);
}

/* Der Vergleichs-Balken (Zeitraeume ohne Tempo-Block) benutzt dieselben Stuecke, nur mit anderer
   Bedeutung: die Marke ist hier der gleich lange Zeitraum davor. */
.hero-card[data-pace-active="previous"] .hero-pace-bar-marker {
  width: 3px;
  background: var(--color-text);
}

.hero-pace-bar-forecast,
.hero-pace-bar-spent {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 999px;
  background: var(--color-accent);
}

/* Die hochgerechnete Fortsetzung liegt hinter dem bereits Ausgegebenen und ist nur angedeutet –
   sie ist eine Erwartung, keine gebuchte Zahl. */
.hero-pace-bar-forecast {
  opacity: 0.28;
}

.hero-pace-bar-marker {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  margin-left: -1px;
  border-radius: 2px;
  background: var(--color-text-muted);
}

/* Zwei eigenständige Zeilen: als inline-flex würden sie in der zentrierten Karte nebeneinander
   umbrechen, statt untereinander zu stehen. */
.hero-pace-forecast {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.15rem;
  font-size: 0.85rem;
  color: var(--color-text);
}

.hero-pace-forecast svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

/* Nur der Pfeil trägt die Bewertung. Der Satz daneben bleibt in Textfarbe – eine komplett
   eingefärbte Zeile läse sich als Warnung, gemeint ist eine Einordnung. */
.hero-pace-forecast.is-bad svg {
  color: var(--color-negative);
}

.hero-pace-forecast.is-good svg {
  color: var(--color-positive);
}

.hero-pace-forecast strong {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-weight: 600;
}

/* Der Ø-Monat steht als eigene, ruhigere Zeile direkt unter der großen Zahl: er ist der Maßstab,
   nicht die Aussage. Das kleine Strichzeichen davor ist dasselbe wie die Marke im Balken. */
.hero-pace-average {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.35rem;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.hero-pace-average-mark {
  width: 2px;
  height: 13px;
  flex-shrink: 0;
  border-radius: 2px;
  background: var(--color-text-muted);
}

.hero-pace-average strong {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-weight: 600;
  color: var(--color-text);
}

/* Hochrechnung und Ø-Monat tragen je eine eigene Rechnung und sind je ein eigenes Ziel. Sie
   bleiben dabei unmarkierter Text – erst beim Antippen hebt sich die angefasste Zahl ab. */
.hero-pace-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3rem;
  padding: 0.15rem 0.4rem;
  margin: -0.15rem -0.1rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.hero-pace-chip.is-active {
  background: var(--color-chip-bg);
}

.hero-pace-chip:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 1px;
}

.hero-pace-dot {
  color: var(--color-text-muted);
}

/* Das Popover liegt über der Karte und verschiebt deshalb nichts. Es zeigt mit seiner Spitze auf
   das gemeinte Stück; hängt es am Kartenrand fest, wandert nur die Spitze weiter
   (--pace-arrow-shift, von wirePace gesetzt). */
.hero-pace-pop {
  position: absolute;
  z-index: 3;
  transform: translate(-50%, -100%);
  width: max-content;
  max-width: 15rem;
  padding: 0.5rem 0.7rem;
  border-radius: var(--radius-sm);
  background: var(--color-pop-bg);
  color: var(--color-pop-text);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.22);
  text-align: left;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
}

.hero-pace-pop.is-open {
  opacity: 1;
}

.hero-pace-pop::after {
  content: "";
  position: absolute;
  left: calc(50% + var(--pace-arrow-shift, 0px));
  top: 100%;
  margin-left: -7px;
  border: 7px solid transparent;
  border-bottom: 0;
  border-top-color: var(--color-pop-bg);
}

.hero-pace-pop-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  font-size: 0.8rem;
  font-weight: 600;
}

.hero-pace-pop-title span:last-child {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  white-space: nowrap;
}

.hero-pace-pop-sub {
  font-size: 0.75rem;
  color: var(--color-pop-text-muted);
  margin-top: 0.1rem;
}

/* Der Rechenweg: je eine Zeile, Beschreibung links, Zahl rechts. */
.hero-pace-pop-rows {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin-top: 0.4rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--color-pop-rule);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.75rem;
  color: var(--color-pop-text-muted);
}

.hero-pace-pop-rows > span {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  white-space: nowrap;
}

/* Ab sieben Monaten (Kategorie-Detail, Zeitraum 12M) dieselben Zeilen in zwei Spalten: zwoelf
   untereinander waeren ein Turm, der die halbe Ansicht verdeckt. Die Rechnung bleibt dieselbe. */
.hero-pace-pop-rows.is-two-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 1.1rem;
}

@media (prefers-reduced-motion: reduce) {
  .hero-pace-pop {
    transition: none;
  }
}

/* Der Rest gilt unter beiden Reitern und sitzt deshalb abgesetzt unter einer Haarlinie, die über
   die volle Kartenbreite läuft (die Karte hat 1rem Innenabstand). */
.hero-net {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.5rem;
  margin: 0.9rem -1rem 0;
  padding: 0.7rem 1rem 0;
  border-top: 1px solid var(--color-border);
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

/* Wort und Zahl sind eine gemeinsame Trefferfläche (sonst hätte nur das Wort die Erklärung
   geöffnet); der Abstand bleibt dabei der der Zeile, nicht der engere der übrigen Chips. */
.hero-net .hero-pace-chip {
  gap: 0.5rem;
}

/* --- "Nicht zugeordnet" auf dem Dashboard ---------------------------------------------------- */

/* Bewusst im Hinweiston statt als weitere Kategorie-Zeile: das ist der einzige Handlungsaufruf
   des Dashboards und soll sich von der Auswertung darüber unterscheiden. */
.dashboard-unassigned {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  background: var(--color-notice-bg);
  border: 1px solid color-mix(in srgb, var(--color-notice-text) 25%, var(--color-notice-bg));
  border-radius: var(--radius-md);
  padding: 0.7rem 1rem;
  text-align: left;
  color: var(--color-text);
}

.dashboard-unassigned:hover,
.dashboard-unassigned:focus-visible {
  border-color: var(--color-notice-text);
}

/* Zahl-Anker: traegt die eigentliche Information. Feste Groesse statt Padding, damit ein- und
   zweistellige Zahlen denselben Kreis ergeben; ab drei Stellen darf er breiter werden. */
.dashboard-unassigned-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: 1.75rem;
  height: 1.75rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-notice-text) 18%, transparent);
  color: var(--color-notice-text);
  font-size: 0.9rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.dashboard-unassigned-label {
  flex: 1;
  min-width: 0;
  font-weight: 500;
}

.category-list-heading {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.category-row-chevron {
  width: 16px;
  height: 16px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Kategorien-Donut (Dashboard) */

.donut-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1.25rem 1rem;
  margin-bottom: 0.75rem;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1.25rem;
}

/* Der Donut liegt in einem eigenen Body-Wrapper, damit die Verträge-Ansicht darunter eine
   Fußzeile (Puffer-Zeile) in dieselbe Karte hängen kann, ohne dass diese ab 768px neben dem Ring
   statt darunter landet. Ohne Fußzeile ist der Wrapper wirkungslos – er erbt dieselbe Anordnung,
   die die Karte selbst hat. */
.donut-card-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1.25rem;
}

/* Höhere Spezifität als die .donut-card-Regel im 768px-Block darunter: die Karte selbst bleibt
   auch auf breiten Schirmen eine Spalte (Donut oben, Puffer unten), nur ihr Body wird zur Zeile. */
.donut-card.has-reserve-footer {
  flex-direction: column;
  align-items: stretch;
  gap: 1.1rem;
  padding-bottom: 0;
}

/* Trennt Donut und Puffer, und zieht sich bis an die Kartenkante (negativer Rand gegen das
   1rem-Innenmaß der Karte), damit Linie und Hover-Fläche die volle Breite haben. */
.donut-card-footer {
  margin: 0 -1rem;
  border-top: 1px solid var(--color-border);
}

@media (min-width: 768px) {
  .donut-card,
  .donut-card-body {
    flex-direction: row;
    align-items: center;
    gap: 2rem;
  }

  .donut-ring-wrap {
    flex-shrink: 0;
    width: 240px;
    height: 240px;
    margin: 0;
  }

  .donut-legend {
    flex: 1;
    min-width: 0;
  }
}

.donut-ring-wrap {
  position: relative;
  width: 300px;
  height: 300px;
  margin: 0 auto;
}

.donut-ring-wrap svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  display: block;
}

.donut-seg {
  fill: none;
  stroke-width: 18;
  cursor: pointer;
  transition: opacity 0.15s ease, stroke-width 0.15s ease;
}

.donut-seg.is-dimmed {
  opacity: 0.32;
}

/* Das gewählte Segment tritt aus dem Ring hervor, statt dass nur alle anderen abdunkeln. Der Platz
   dafür ist da: die viewBox ist deutlich größer als der Ring (siehe category-donut.js). */
.donut-seg.is-active {
  stroke-width: 23;
}

.donut-center {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.donut-center-inner {
  /* 46% ≈ Loch-Durchmesser / Ring-Box — verhindert, dass der Text über den Ring hinausläuft. */
  max-width: 46%;
  text-align: center;
}

.donut-center-label,
.donut-center-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.donut-center-label {
  font-size: 0.99rem;
  color: var(--color-text-muted);
  margin-bottom: 0.2rem;
}

.donut-center-value {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 1.3rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.donut-legend {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.donut-legend-row {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto auto;
  column-gap: 0.6rem;
  align-items: center;
  width: 100%;
  border: none;
  background: none;
  text-align: left;
  color: var(--color-text);
  padding: 0.4rem 0.55rem;
  /* Nur waagerecht ausbrechen, damit die Auswahlfläche bündig mit dem Karteninhalt beginnt;
     senkrecht ließ der negative Rand sie in die Nachbarzeilen hineinragen. */
  margin: 0 -0.55rem;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: opacity 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
}

/* 44-px-Touch-Ziel nur dort, wo wirklich getippt wird. Am Zeigegerät machte die Mindesthöhe die
   Auswahlfläche mehr als doppelt so hoch wie ihren rund 19 px hohen Inhalt. */
@media (pointer: coarse) {
  .donut-legend-row {
    min-height: 44px;
  }
}

.donut-legend-row.is-dimmed {
  opacity: 0.4;
}

/* Eingerückt wird nur der Inhalt, nicht die Fläche – so liegt die linke Kante aller
   Auswahlflächen auf einer Linie (0.55rem Grundpolster + 1.1rem Einzug). */
.donut-legend-row.is-indented {
  padding-left: 1.65rem;
}

.donut-group-label {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 0.5rem 0 0.15rem 0.3rem;
}

.donut-group-label:first-child {
  margin-top: 0;
}

.donut-legend-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: -2px;
}

/* Ausgewählt: 2-px-Kante in der Segmentfarbe plus eine Andeutung von Fläche. Die Kante nutzt die
   Farbe unvermischt – Unterkategorien sind über FB.Categories.getSubcategoryColorVar bereits gegen
   die Kartenfläche aufgehellt, eine reine Tönung wäre bei den hinteren Zeilen einer Gruppe kaum
   noch zu sehen. Gleiche Sprache wie .contract-cat-row und .contract-suggestion-card. */
.donut-legend-row.is-active {
  background: color-mix(in srgb, var(--cat-color) 7%, var(--color-surface));
  box-shadow: inset 2px 0 0 var(--cat-color);
}

.donut-legend-row.is-active .donut-legend-name {
  font-weight: 600;
}

/* Das Drüberfahren zeigt dieselbe Kante schon als Vorschau – passend dazu, dass auch die
   Vertragsliste beim Hover bereits mitzeichnet (siehe previewHighlight in vertraege-view.js).
   Vorschau und Auswahl unterscheiden sich damit bewusst nicht im Aussehen der Zeile, sondern
   darin, dass die Auswahl stehen bleibt, wenn die Maus weiterzieht, und zusätzlich das
   Ringsegment verdickt. Nur am Zeigegerät: auf Touch bliebe der Hover nach dem Tippen kleben. */
@media (hover: hover) {
  .donut-legend-row:hover {
    background: color-mix(in srgb, var(--cat-color) 7%, var(--color-surface));
    box-shadow: inset 2px 0 0 var(--cat-color);
  }

  .donut-legend-row:hover .donut-legend-name {
    font-weight: 600;
  }
}

.donut-legend-name {
  font-size: 0.86rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.donut-legend-amount {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.86rem;
  font-weight: 600;
  white-space: nowrap;
  text-align: right;
}

.donut-legend-share {
  font-size: 0.76rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  text-align: right;
  min-width: 2.6em;
}

/* Kategorie-Detail */

/* Kopf des Kategorie-Detail: bis 2026-08-20 vier gestapelte Bloecke (Subheader, Monats-Pill,
   Perioden-Leiste ueber die volle Breite, Hero-Karte). Die Karte ist aufgeloest – die Zahl steht
   direkt auf dem Hintergrund –, und seit 2026-08-22 traegt die Pille im Subheader den ganzen
   Zeitraum: der Umschalter 1M/3M/6M/12M neben der Zahl ist darin aufgegangen. */

.category-hero {
  margin-bottom: 1.25rem;
}

/* Betrag und Vergleichswert stehen mittig unter dem ebenfalls mittigen Kopf – die Kennzahl
   sitzt damit auf derselben Achse wie die Hero-Zahl des Dashboards. Das Balkenband darunter
   bleibt davon unberuehrt, es fuellt ohnehin die volle Breite. */
.category-hero.is-centered .category-hero-head {
  justify-content: center;
}

.category-hero.is-centered .category-hero-figure {
  text-align: center;
}

.category-hero-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.6rem;
}

.category-hero-figure {
  min-width: 0;
}

.category-hero-amount {
  font-size: 2.1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* Bezugsrahmen fuer das Popover des Vergleichswerts. Es steht mittig ueber dem Chip – seit der
   Chip selbst mittig sitzt (2026-08-30) laeuft es dort nicht mehr aus dem Bild, und die frueher
   noetige Verankerung am linken Rand samt versetzter Spitze ist entfallen. */
.category-hero-average {
  position: relative;
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

.category-hero-average strong {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-weight: 600;
  color: var(--color-text);
}

.category-average-pop {
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%);
}

.category-average-pop.is-wide {
  max-width: 21rem;
}

/* Balkenband: immer zwoelf Monate. Jeder Balken ist eine Schaltflaeche, die seinen Monat waehlt –
   die Trefferflaeche ist deshalb die volle Spaltenhoehe, nicht nur der sichtbare Balken. */
.category-trend {
  margin-top: 1rem;
}

.category-trend-bars {
  display: flex;
  align-items: stretch;
  gap: 3px;
  height: 52px;
}

.category-trend-col {
  flex: 1 1 0;
  display: flex;
  align-items: flex-end;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
}

.category-trend-bar {
  width: 100%;
  border-radius: 4px 4px 2px 2px;
  background: var(--color-chip-bg);
  transition: background-color 0.12s ease;
}

.category-trend-bar.is-selected {
  background: var(--color-accent-text);
}

.category-trend-col:hover .category-trend-bar {
  background: color-mix(in srgb, var(--color-accent-text) 55%, var(--color-chip-bg));
}

.category-trend-col:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: 4px;
}

.category-trend-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 0.3rem;
  font-size: 0.66rem;
  color: var(--color-text-muted);
}

/* Aufteilung nach Unterkategorie als *ein* gestapelter Balken. Drei einzelne Balken (bis
   2026-08-21) zeigten je einen Anteil am Ganzen, aber nie die Anteile zueinander. */
.category-split {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.85rem 0.95rem;
  margin-bottom: 1.5rem;
}

.category-split-bar {
  display: flex;
  gap: 2px;
  height: 12px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--color-chip-bg);
}

.category-split-piece {
  display: block;
  min-width: 3px;
}

.category-split-legend {
  display: flex;
  flex-direction: column;
  margin-top: 0.6rem;
}

.category-split-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.3rem 0;
  border: none;
  background: none;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  font-size: 0.88rem;
}

.category-split-row:hover .category-split-name,
.category-split-row:focus-visible .category-split-name {
  color: var(--color-accent-text);
}

.category-split-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.category-split-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.category-split-share {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  color: var(--color-text-muted);
  min-width: 2.8em;
  text-align: right;
}

.category-split-row .amount {
  font-size: 0.86rem;
}

.category-split-chevron {
  width: 14px;
  height: 14px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Top-Empfaenger als Rangliste statt als Karten: jede Zeile traegt nur drei Werte, ein
   Kartenrahmen darum waere reine Verpackung. */
.beneficiary-rank {
  display: flex;
  flex-direction: column;
  margin-bottom: 1.5rem;
}

.beneficiary-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.5rem 0.15rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: none;
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
}

.beneficiary-row:last-child {
  border-bottom: none;
}

.beneficiary-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.beneficiary-row.is-selected {
  background: color-mix(in srgb, var(--color-accent-text) 12%, transparent);
  border-radius: var(--radius-sm);
}

.beneficiary-bar {
  height: 3px;
  border-radius: 999px;
  background: var(--color-accent-text);
  flex-shrink: 0;
}

.beneficiary-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.88rem;
  font-weight: 500;
}

.beneficiary-count {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  color: var(--color-text-muted);
}

.beneficiary-row .amount {
  font-size: 0.86rem;
}

/* Die Buchungsliste liegt hinter diesem Schalter. Er steht bewusst *ueber* der Liste, damit er
   nach dem Aufklappen ohne Zurueckscrollen erreichbar bleibt. */
.transactions-disclosure {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.7rem;
  margin-bottom: 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-accent-text);
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
}

.transactions-disclosure:hover,
.transactions-disclosure:focus-visible {
  border-color: var(--color-accent-text);
}

.transactions-disclosure svg {
  width: 15px;
  height: 15px;
}

/* Transaktionen */

.import-status {
  font-size: 0.9rem;
  color: var(--color-text-muted);
  margin-bottom: 1rem;
}

.import-status:empty {
  display: none;
  margin: 0;
}

.visually-hidden-input {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  padding: 0;
  margin: -1px;
}

.empty-hint {
  color: var(--color-text-muted);
  padding: 1rem 0;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.5rem;
  padding: 3rem 1rem;
  color: var(--color-text-muted);
}

.empty-state-icon {
  font-size: 2.5rem;
  line-height: 1;
}

.empty-state-headline {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--color-text);
  margin: 0;
}

.empty-state-text {
  max-width: 24rem;
}

.empty-state-cta {
  display: inline-block;
  margin-top: 0.5rem;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: var(--radius-md);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
}

.empty-state-cta:active {
  opacity: 0.85;
}

.transaction-group {
  margin-bottom: 1.5rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  overflow: hidden;
}

.group-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.75rem 1rem;
  font-weight: 500;
}

.transaction-group[open] > .group-summary {
  border-bottom: 1px solid var(--color-border);
}

.group-summary::-webkit-details-marker {
  display: none;
}

.group-summary::marker {
  content: '';
}

.group-summary-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.chevron {
  display: inline-block;
  transition: transform 0.15s ease;
  color: var(--color-text-muted);
}

details[open] > .group-summary .chevron {
  transform: rotate(90deg);
}

.group-count {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-chip-bg);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}

.transaction-group .transaction-list {
  margin-top: 0;
  padding: 0.75rem 1rem 1rem;
}

.transaction-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Transaktionsliste: eine Liste mit Filter-Chips, Zeilen als randnahe Karten mit Datumsspalte */

.transaction-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.55rem 0.7rem;
  margin-bottom: 0.75rem;
  transition: border-color 0.12s ease;
}

.transaction-search:focus-within {
  border-color: var(--color-accent-text);
}

.transaction-search-icon {
  width: 17px;
  height: 17px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.transaction-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--color-text);
  font-family: inherit;
  font-size: 0.88rem;
  padding: 0;
}

.transaction-search-input:focus {
  outline: none;
}

.transaction-search-input::placeholder {
  color: var(--color-text-muted);
}

.transaction-search-clear {
  display: none;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 50%;
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  font-size: 0.75rem;
  line-height: 1;
  cursor: pointer;
}

.transaction-search.has-value .transaction-search-clear {
  display: inline-flex;
}

/* Zeitraum-Auslöser in der Transaktionsverwaltung. Er sitzt bewusst im Suchfeld und nicht in der
   Filterzeile darunter: dort müsste auch der leere Zustand Platz kosten, und mit dem gesetzten
   Chip daneben bräche die Zeile regelmäßig um. Gesetzt wird hier, angezeigt wird als
   .transaction-filter-period unten. */
.transaction-search-calendar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border: none;
  background: none;
  padding: 0.2rem;
  color: var(--color-text-muted);
  cursor: pointer;
}

.transaction-search-calendar svg {
  width: 17px;
  height: 17px;
  display: block;
}

.transaction-search-calendar.is-active {
  color: var(--color-accent-text);
}

.transaction-search-calendar:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: 999px;
}

.transaction-search-hint {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.78rem;
  font-weight: 600;
  line-height: 1.35;
  border-radius: var(--radius-sm);
}

.transaction-search-hint svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

.transaction-beneficiary mark,
.transaction-detail mark {
  background: color-mix(in srgb, var(--color-accent-text) 30%, transparent);
  color: var(--color-text);
  border-radius: 3px;
  padding: 0 1px;
}

/* Zwei unabhaengig schaltbare Filter-Chips (frueher zwei Reiter mit je eigenem Panel). Beide
   schraenken dieselbe Liste ein; ohne aktiven Chip sieht man alles. */

.transaction-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}

.transaction-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.transaction-filter svg {
  width: 0.72rem;
  height: 0.72rem;
}

.transaction-filter.is-active {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
}

.transaction-filter-count {
  font-size: 0.7rem;
  font-weight: 600;
  opacity: 0.75;
}

.transaction-filter:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

/* Der gesetzte Zeitraum, als Chip neben den beiden Filtern. Gleiche Höhe und gleicher Radius wie
   sie, aber durchgehend in Akzentfarbe statt als An/Aus-Schalter: er blendet nichts aus, er
   verschiebt den Ausschnitt. Angetippt öffnet er dasselbe Sheet wie das Kalender-Symbol im
   Suchfeld – das ist Absicht, der Chip ist die naheliegende Rückkehr zu dem eben Gesetzten. */
.transaction-filter-period {
  display: inline-flex;
  align-items: center;
  padding: 0 0.5rem 0 0.7rem;
  border: 1px solid var(--color-accent-text);
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  max-width: 100%;
}

/* Die Hülle trägt das Aussehen, die beiden Knöpfe darin nur ihre Trefferfläche. */
.transaction-filter-period-open,
.transaction-filter-period-clear {
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.transaction-filter-period-open {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0;
  min-width: 0;
}

.transaction-filter-period-open svg {
  width: 0.72rem;
  height: 0.72rem;
  flex-shrink: 0;
}

.transaction-filter-period-open .label {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Eigene Trefferfläche im Chip: das Kreuz hebt auf, der Rest öffnet das Sheet. */
.transaction-filter-period-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.35rem;
  height: 1.35rem;
  margin-left: 0.15rem;
  border-radius: 999px;
  font-size: 0.8rem;
  line-height: 1;
  opacity: 0.7;
}

.transaction-filter-period-open:focus-visible,
.transaction-filter-period-clear:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
  border-radius: 999px;
}

/* Die engere Zeilendichte der Verwaltung hing bisher am entfallenen .transaction-panel. */
#view-manage-transactions .transaction-list {
  gap: 0.5rem;
}

/* Ein Abschnitt je Monat (siehe rowsHtml in manage-transactions-view.js). content-visibility
   laesst den Browser Layout und Paint aller Monate ausserhalb des Viewports ueberspringen –
   ohne das war das Oeffnen der Ansicht bei einigen tausend Buchungen sekundenlang blockiert.
   contain-intrinsic-size haelt solange eine plausible Hoehe vor; den genauen Wert setzt
   rowsHtml je Abschnitt inline mit dem auto-Schluesselwort (Browser merkt sich dann die
   tatsaechliche Hoehe). Der Wert hier ist der Rueckfall fuer Browser ohne "auto" – ohne ihn
   fielen ausgelassene Abschnitte auf Hoehe 0 zusammen und die Scrollposition wuerde springen. */
.transaction-month {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  content-visibility: auto;
  contain-intrinsic-size: 600px;
}

/* .month-divider:first-child greift jetzt in jedem Abschnitt – der Abstand vor einem neuen Monat
   soll aber nur ganz oben entfallen. */
#view-manage-transactions .month-divider {
  padding-top: 0.15rem;
}

#view-manage-transactions .transaction-month:first-child .month-divider {
  padding-top: 0;
}

/* Notiz unter der Buchung – nur im Merkzeichen-Filter, siehe manage-transactions-view.js. */
.transaction-note-line {
  margin: -0.15rem 0 0.35rem 3.1rem;
  font-size: 0.78rem;
  font-style: italic;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.month-divider {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.15rem 0.15rem 0;
}

.month-divider:first-child {
  padding-top: 0;
}

.month-divider-label {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.month-divider-line {
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

.transaction-row {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  width: 100%;
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.65rem 0.85rem 0.6rem;
  color: var(--color-text);
}

.transaction-row.is-ignored {
  opacity: 0.5;
}

.transaction-row.is-actionable {
  flex-direction: row;
  align-items: center;
  height: auto;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition: border-color 0.12s ease;
}

.transaction-row.is-actionable:hover,
.transaction-row.is-actionable:focus-visible {
  border-color: var(--color-accent-text);
}

.transaction-row.is-actionable:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--color-accent-text) inset;
}

.transaction-row.is-actionable.is-highlighted {
  border-color: var(--color-accent-text);
  background: color-mix(in srgb, var(--color-accent-text) 10%, var(--color-surface));
}

.transaction-row.is-actionable.is-dimmed {
  opacity: 0.45;
}

.transaction-date {
  flex-shrink: 0;
  width: 2.3rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  margin-right: 0.6rem;
  padding-right: 0.55rem;
  border-right: 1px solid var(--color-border);
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}

.transaction-date-dow {
  font-size: 0.58rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.transaction-date-day {
  font-size: 0.98rem;
  font-weight: 700;
  line-height: 1.1;
}

.transaction-date-month {
  font-size: 0.58rem;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.transaction-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.28rem;
}

.transaction-beneficiary {
  flex: 1;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: break-word;
}

/* Der PayPal-Hinweis vor dem abgeleiteten Haendlernamen. Bewusst inline-block im selben
   Span wie der Name: als eigenes Flex-Kind haette es die Namen der PayPal-Zeilen gegenueber
   allen anderen eingerueckt, und die Liste haette unruhig gewirkt. */
.transaction-via {
  display: inline-block;
  margin-right: 0.35rem;
  padding: 0.05rem 0.3rem;
  border-radius: var(--radius-sm);
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: 0.05rem;
}

.transaction-row.is-actionable .transaction-beneficiary {
  font-size: 0.88rem;
  line-height: 1.3;
}

.transaction-detail {
  flex: 1;
  min-width: 0;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.transaction-row.is-actionable .transaction-detail {
  font-size: 0.8rem;
  line-height: 1.3;
}

.transaction-catline {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.3rem;
  min-width: 0;
}

.transaction-flag {
  display: flex;
  flex-shrink: 0;
  color: var(--color-notice-text);
}

.transaction-flag svg {
  width: 0.78rem;
  height: 0.78rem;
}

.transaction-side {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  padding-left: 0.6rem;
}

.transaction-row.is-actionable .amount {
  font-size: 0.92rem;
}

.amount {
  font-weight: 600;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
}

.amount.positive {
  color: var(--color-positive);
}

.amount.negative {
  color: var(--color-negative);
}

/* Kategorie-Pille in der Transaktionsliste */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  max-width: 100%;
  font-size: 0.78rem;
  font-weight: 500;
  padding: 0.22rem 0.6rem 0.22rem 0.4rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-text);
}

/* .pill ist meist ein <span>, wird für die antippbare Kategorie-Pille im Vertrags-Sheet aber
   auch als <button> verwendet – Browser-Default-Rand entfernen (Hintergrund/Padding kommen
   bereits von .pill selbst). */
button.pill {
  border: none;
}

.pill-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pill-unassigned {
  background: transparent;
  border: 1px dashed var(--color-border);
  color: var(--color-text-muted);
  padding: 0.2rem 0.6rem;
}

.transaction-catline .pill {
  max-width: 100%;
  font-size: 0.72rem;
  padding: 0.14rem 0.5rem 0.14rem 0.35rem;
}

.transaction-catline .pill-unassigned {
  font-size: 0.72rem;
  padding: 0.14rem 0.5rem;
}

.transaction-catline .cat-dot {
  --dot-size: 0.48rem;
}

/* Der Kategoriepunkt – eine Klasse fuer alle Stellen (Donut-Legende, Buchungszeile, Picker,
   Kategorie-Drilldown, Vertragsgruppen). Bis 2026-08-29 waren es vier Klassen in vier Groessen
   und zwei Formen (rund/eckig), ohne dass der Unterschied etwas bedeutet haette. Die Farbe kommt
   immer ueber --cat-color – entweder von der Zeile darueber oder vom Punkt selbst (FB.CategoryDot);
   --dot-size wird nur dort gesetzt, wo eine Zeile wirklich kompakter ist. */
.cat-dot {
  width: var(--dot-size, 0.55rem);
  height: var(--dot-size, 0.55rem);
  border-radius: 999px;
  flex-shrink: 0;
  background: var(--cat-color, var(--color-border));
}

/* Buchungs-Sheet (Übersicht → Kategorie → Unterkategorie → Regel-Konfiguration) */

.category-sheet-dialog {
  position: fixed;
  inset: auto 0 0 0;
  margin: 0 auto;
  border: none;
  border-top-left-radius: 1.25rem;
  border-top-right-radius: 1.25rem;
  padding: 1rem 1.1rem calc(1.2rem + env(safe-area-inset-bottom, 0));
  background: var(--color-surface);
  color: var(--color-text);
  width: 100%;
  max-width: 32rem;
  max-height: 85vh;
  overflow-y: auto;
}

@media (min-width: 768px) {
  .category-sheet-dialog {
    inset: 0;
    margin: auto;
    border-radius: var(--radius-md);
    padding: 1.25rem 1.25rem calc(1.25rem + env(safe-area-inset-bottom, 0));
    max-height: calc(100vh - 4rem);
  }
}

.category-sheet-dialog::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

/* REGEL FUER ALLE SHEETS: die oberste Zeile traegt den Titel.
   Frueher stand in dieser Zeile nur der Zurueck-Chevron und das Schliessen-X,
   und der Titel kam linksbuendig darunter – eine volle 44-px-Zeile fuer zwei
   Knoepfe, und der Titel dort, wo man ihn nicht sucht. Jetzt ist die Topbar ein
   Dreispalter: Zurueck links, Titel mittig, Schliessen rechts. Die beiden
   Aussenspalten sind fest gleich breit, damit der Titel unabhaengig davon
   mittig bleibt, ob ein Zurueck-Knopf da ist – nur so laesst sich der
   Zurueck-Knopf ergaenzen, ohne dass der Titel springt.
   Zwei Ausnahmen, jede mit eigener Begruendung an Ort und Stelle:
   .is-overview (Buchungs-Sheet) und das Vertrags-Sheet – dort ist der Kopf
   selbst der Inhalt (Empfaenger und Betrag, Vertragsname und Betrag), kein
   Screentitel, der in eine Knopfzeile passt. Diese behalten schwebende Knoepfe
   und .sheet-head-centered. */
.sheet-topbar {
  /* Die Zeilenhoehe kommt vom Titel, nicht von den Knoepfen. Ein .icon-button
     ist als Tippflaeche 44 px hoch – liesse man ihn die Zeile aufziehen, saesse
     der 22-px-Titel mittig darin und darunter blieben 11 px toter Raum, die bis
     zur Unterzeile durchschlagen. Und zwar je Sheet verschieden viel, weil mal
     zwei Knoepfe in der Zeile stehen, mal einer, mal keiner. */
  --kopf-zeile: 1.5rem;
  display: grid;
  grid-template-columns: 2rem 1fr 2rem;
  grid-auto-rows: var(--kopf-zeile);
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

/* Die Tippflaeche bleibt 44 px und ragt ueber die Zeile hinaus, statt sie zu
   dehnen: die negative Marge nimmt aus der Zeilenrechnung genau das heraus, was
   der Knopf hoeher ist als der Titel. */
.sheet-topbar > .sheet-back,
.sheet-topbar > .sheet-close {
  margin-block: calc((var(--kopf-zeile) - 44px) / 2);
}

.sheet-topbar > .sheet-back {
  grid-column: 1;
  justify-self: start;
}

.sheet-topbar > .sheet-close {
  grid-column: 3;
  justify-self: end;
}

/* Screens ohne eigenen Titel (Buchungs-Uebersicht) lassen ihn leer – dann darf
   er auch keine Zeilenhoehe beanspruchen. */
.sheet-topbar-title:empty {
  display: none;
}

.sheet-topbar-title {
  grid-column: 2;
  margin: 0;
  text-align: center;
  font-size: 1.05rem;
  line-height: var(--kopf-zeile);
  font-weight: 600;
  /* Ein langer Titel schiebt die Knoepfe nicht auseinander, er wird gekuerzt. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet-back {
  visibility: hidden;
}

/* Übersicht des Buchungs-Sheets: Hier ist der Kopf Inhalt (Empfänger, Betrag,
   Zweck) und kein Screentitel – er gehört gross und mehrzeilig nach oben, nicht
   gekürzt in eine Knopfzeile. Die Topbar hielte dann aber nur eine leere
   44px-Zeile frei; das Schließen-X wandert deshalb in die Ecke. */
.category-sheet-dialog.is-overview .sheet-topbar {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  margin-bottom: 0;
  /* Kein Dreispalter mehr: Hier haelt die Leiste nur noch das X, und die beiden
     leeren Aussenspalten wuerden es aus der Ecke schieben. */
  display: flex;
}

/* Frei schwebend gibt es keine Zeile, die der Knopf dehnen koennte – hier ist
   die Tippflaeche wieder ihre eigene Hoehe. */
.category-sheet-dialog.is-overview .sheet-topbar > .sheet-close {
  margin-block: 0;
}

/* Der Zurueck-Chevron ist in der Uebersicht nie erreichbar (es gibt keinen
   Screen davor) – hier verschwindet er ganz statt nur unsichtbar Platz zu
   halten, sonst schoebe er das X aus der Ecke. */
.category-sheet-dialog.is-overview .sheet-back {
  display: none;
}

.category-sheet-dialog.is-overview .tx-head {
  padding-top: 0;
}

.sheet-back.show {
  visibility: visible;
}

/* Fuer die beiden Sheets, deren Kopf Inhalt ist und deren Knoepfe deshalb
   schweben (.sheet-back-floating / .sheet-close-floating): der Kopf beginnt
   oben und spart sich die Ecken ueber seinen seitlichen Innenabstand aus,
   damit ein langer Titel nicht unter einen Knopf laeuft. */
.sheet-head-centered {
  text-align: center;
  /* Links und rechts dieselbe Aussparung: 44 px Chevron + Rand. */
  padding: 0 2.9rem;
}

/* Steht der Kopf dagegen unter einer normalen Topbar, tragen deren Spalten die
   Knoepfe bereits – die Aussparung waere dann nur eine unnoetige Verengung.
   Die negative Marge zieht ihn ausserdem an den Titel heran: .sheet-inner setzt
   seine Abstaende ueber gap, und der volle gap zwischen Titel und der
   dazugehoerenden Unterzeile ist zu viel. */
.sheet-head-centered.is-under-topbar {
  padding: 0;
  /* Wie .sheet-sub.is-lead, nur gegen den gap von .sheet-inner gerechnet. */
  margin-top: calc(0.25rem - 0.75rem);
}

.sheet-title {
  font-size: 1.05rem;
  font-weight: 600;
  margin-bottom: 0.1rem;
}

.sheet-sub {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin-bottom: 1rem;
}

/* Unterzeile direkt unter dem Topbar-Titel: sie gehoert zum Kopf – sie steht
   deshalb mittig wie er und rueckt dicht an ihn heran. Die negative Marge hebt
   die Untermarge der Topbar auf (beide kollabieren durch den randlosen
   .sheet-body hindurch); ohne sie klafft zwischen Titel und Unterzeile eine
   Luecke, die groesser ist als der Abstand zum Inhalt darunter. */
.sheet-sub.is-lead {
  text-align: center;
  /* Die Topbar traegt 0.6rem Untermarge fuer den Fall "Titel, dann Inhalt".
     Zur eigenen Unterzeile sollen davon 0.25rem bleiben – die Margen
     kollabieren durch den randlosen .sheet-body hindurch. */
  margin-top: calc(0.25rem - 0.6rem);
}

/* Übersichts-Screen des Buchungs-Sheets: Kopf, Kategorie-Zeile, Aktionsliste. Drei Ebenen, mehr
   nicht – Notiz und Merkzeichen sind bewusst Zeilen der Aktionsliste und keine eigenen Karten. */

.tx-head {
  text-align: center;
  padding: 0.2rem 0 1rem;
}

.tx-head-name {
  font-size: 1.02rem;
  font-weight: 700;
}

.tx-head-amount {
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin-top: 0.15rem;
}

.tx-head-meta {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  margin-top: 0.35rem;
}

.tx-head-purpose {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin-top: 0.15rem;
  opacity: 0.85;
  overflow-wrap: anywhere;
}

/* Nur im Onboarding-"Drei Buchungen"-Schritt: "Kommt 12x im Jahr vor · 1.068 € gesamt". */
.tx-head-hint {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin-top: 0.5rem;
}

/* Fortschritts-Eyebrow ("Buchung 2 von 3") über dem jeweils aktiven Screen, nur im
   Onboarding-Ablauf (siehe FB.CategorySheet.open, fortschritt-Parameter). */
.sheet-progress-label {
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--color-text-muted);
  margin: 0 0 0.6rem;
}

.sheet-progress-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1.1rem;
}

/* Ohne "Kategorie"-Label: Punkt, Titel und Chevron sagen bereits, worum es geht. */
.tx-catrow {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-chip-bg);
  color: var(--color-text);
  text-align: left;
}

.tx-catrow.is-changed {
  border-color: var(--color-accent-text);
}

.tx-catrow.is-empty .tx-catrow-value {
  color: var(--color-text-muted);
}

.tx-catrow-value {
  flex: 1;
  min-width: 0;
  font-size: 0.92rem;
  font-weight: 600;
}

.tx-catrow-chevron {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.cat-dot--empty {
  background: transparent;
  border: 1px solid var(--color-text-muted);
}

/* Regel-Angebot: erscheint nur nach einer tatsächlichen Kategorie-Änderung. Die Kategorie ist zu
   diesem Zeitpunkt bereits gespeichert – hier geht es nur noch um die Regel. */
.rule-offer {
  margin-top: 0.8rem;
  padding: 0.78rem 0.85rem;
  border-radius: var(--radius-md);
  background: var(--color-notice-bg);
}

.rule-offer-text {
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-notice-text);
}

.rule-offer-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.65rem;
}

.rule-offer-btn {
  flex: 1;
  padding: 0.45rem 0.5rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 0.82rem;
  font-weight: 600;
}

.rule-offer-btn.primary {
  border-color: transparent;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.tx-actions {
  margin-top: 1rem;
  border-top: 1px solid var(--color-border);
}

.tx-action {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  width: 100%;
  padding: 0.78rem 0.1rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: none;
  color: var(--color-text);
  font-size: 0.88rem;
  text-align: left;
}

.tx-actions > :last-child {
  border-bottom: none;
}

.tx-action > svg {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  margin-top: 0.08rem;
  color: var(--color-text-muted);
}

.tx-action > svg.is-flagged {
  color: var(--color-notice-text);
}

.tx-action-body {
  flex: 1;
  min-width: 0;
}

.tx-action-hint {
  color: var(--color-text-muted);
}

.tx-action-note {
  display: block;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.tx-action--danger,
.tx-action--danger > svg {
  color: var(--color-negative);
}

.tx-action--editing {
  align-items: flex-start;
}

.tx-note-input {
  flex: 1;
  min-width: 0;
  resize: vertical;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 0.86rem;
  line-height: 1.45;
}

.tx-note-input:focus-visible {
  outline: none;
  border-color: var(--color-accent-text);
}

.tx-switch {
  width: 40px;
  height: 23px;
  flex-shrink: 0;
  align-self: center;
  position: relative;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-chip-bg);
}

.tx-switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: var(--color-text-muted);
  transition: left 0.15s ease;
}

.tx-switch.is-on {
  border-color: transparent;
  background: var(--color-accent-text);
}

.tx-switch.is-on::after {
  left: 20px;
  top: 3px;
  background: var(--color-accent-contrast);
}

.receipt-card {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin-bottom: 1rem;
  padding: 0.65rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-bg);
}

.receipt-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.9rem;
  font-size: 0.82rem;
}

.receipt-row + .receipt-row {
  padding-top: 0.45rem;
  border-top: 1px dashed var(--color-border);
}

.receipt-label {
  flex: none;
  color: var(--color-text-muted);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.receipt-value {
  text-align: right;
  color: var(--color-text);
  line-height: 1.4;
  min-width: 0;
  overflow-wrap: break-word;
}

.receipt-value--muted {
  color: var(--color-text-muted);
}

.receipt-value--link {
  color: var(--color-accent-text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-accent-text) 40%, transparent);
  text-underline-offset: 0.15em;
}

.receipt-value--link:hover,
.receipt-value--link:focus-visible {
  text-decoration-color: var(--color-accent-text);
}

.receipt-value--amount {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.receipt-value--amount.positive {
  color: var(--color-positive);
}

.receipt-value--amount.negative {
  color: var(--color-negative);
}

.chip-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.chip-opt {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  font-size: 0.9rem;
  background: var(--color-bg);
  /* Die meisten .chip-opt sind <div> und erben die Textfarbe – die Erinnerungs-Chips im
     Vertrags-Sheet sind <button> und fielen ohne diese Zeile auf die dunkle System-Buttonfarbe
     zurück (im Dark Mode praktisch unlesbar). */
  color: var(--color-text);
}

.chip-opt.selected {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-weight: 500;
}

.skip-link,
.ignore-link {
  cursor: pointer;
  text-align: center;
  font-size: 0.85rem;
  color: var(--color-text-muted);
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

.ignore-link {
  border-top: 1px solid var(--color-border);
  margin-top: 0.5rem;
  padding-top: 0.75rem;
}

.ignore-link svg {
  width: 16px;
  height: 16px;
}

/* Zwei Aktionen in einer .ignore-link-Zeile (statt einer einzelnen klickbaren Zeile) – je eigener
   Button, damit beide per Tastatur fokussierbar und unabhängig antippbar sind. */
.link-action {
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  padding: 0.3rem 0.15rem;
}

.link-action:hover,
.link-action:focus-visible {
  color: var(--color-accent-text);
}

.link-action:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--color-accent-text);
  border-radius: 4px;
}

.link-sep {
  color: var(--color-border);
}

/* Zweiter Footer-Link (Vertrag zuordnen) direkt unter "ignorieren" – teilt sich dessen Trenner */
.contract-link {
  border-top: none;
  margin-top: 0;
  padding-top: 0;
}

/* Kategorie und Unterkategorie, auf die die Regel zielt. Sie gehoeren zum Kopf
   des Regel-Screens und stehen deshalb mittig unter dem Topbar-Titel – wie die
   Unterzeile der anderen Screens (.sheet-sub.is-lead), inklusive der negativen
   Marge, die die Untermarge der Topbar aufhebt. */
.confirm-pill-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  margin-top: calc(0.25rem - 0.6rem);
  margin-bottom: 1rem;
  flex-wrap: wrap;
}

.confirm-arrow {
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.confirm-text {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--color-text);
  margin-bottom: 1.25rem;
}

.sheet-btn {
  /* Ein Teil der .sheet-btn sind <div> (siehe category-sheet.js) und erben den Zeiger deshalb
     nicht aus der globalen button-Regel. */
  cursor: pointer;
  width: 100%;
  min-height: 44px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  font-size: 0.9rem;
  font-weight: 500;
  border: 1px solid transparent;
}

.sheet-btn.primary {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.sheet-btn.secondary {
  background: transparent;
  color: var(--color-text-muted);
  margin-top: 0.5rem;
}

.sheet-btn svg {
  width: 16px;
  height: 16px;
}

.field-label {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin-bottom: 0.5rem;
}

.field-options {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.1rem;
}

.field-opt {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.6rem 0.75rem;
}

.field-opt.selected {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
}

.field-opt-radio {
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 999px;
  border: 1.5px solid var(--color-border);
  flex-shrink: 0;
  position: relative;
}

.field-opt.selected .field-opt-radio {
  border-color: var(--color-accent-text);
}

.field-opt.selected .field-opt-radio::after {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 999px;
  background: var(--color-accent-text);
}

.field-opt-body {
  flex: 1;
  min-width: 0;
}

.field-opt-label {
  font-size: 0.85rem;
  font-weight: 500;
}

.field-opt-value {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 0.1rem;
}

.field-pattern-input {
  width: 100%;
  font: inherit;
  font-size: 0.8rem;
  color: var(--color-text);
  background: transparent;
  border: none;
  border-bottom: 1px dashed var(--color-border);
  padding: 0.1rem 0;
  margin-top: 0.15rem;
}

.field-pattern-input:focus-visible {
  outline: none;
  border-bottom-color: var(--color-accent-text);
}

.field-opt-count {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border-radius: 999px;
  padding: 0.15rem 0.55rem;
  flex-shrink: 0;
  white-space: nowrap;
}

.field-opt.selected .field-opt-count {
  color: var(--color-accent-text);
}

/* Trefferliste im Regel-Screen des Buchungs-Sheets (seit 2026-08-29). Sie ist hier nicht nur
   Vorschau, sondern das Bedienelement für die Betragsbedingung: der Umschalter oben verengt die
   Regel auf den Betrag der angetippten Buchung, was herausfällt bleibt durchgestrichen stehen.
   Entwurf: Notizen/Mockups/regel-betrag-im-buchungssheet.html, Variante D. */
.rule-hits {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  margin-bottom: 1rem;
  overflow: hidden;
}

.rule-hits-head {
  display: flex;
  gap: 0.4rem;
  padding: 0.55rem 0.6rem;
  border-bottom: 1px solid var(--color-border);
}

.rule-hits-head button {
  flex: 1;
  min-height: 34px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}

.rule-hits-head button.selected {
  background: var(--color-chip-bg);
  border-color: var(--color-accent-text);
  color: var(--color-accent-text);
  font-weight: 600;
}

/* Ab etwa fünf Zeilen scrollt die Liste in sich statt das ganze Sheet zu verlängern – der
   Speichern-Knopf muss ohne Scrollen erreichbar bleiben. */
.rule-hits-list {
  max-height: 216px;
  overflow-y: auto;
}

.rule-hit-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.6rem;
  font-size: 0.8rem;
  border-bottom: 1px solid var(--color-border);
}

.rule-hit-row:last-child {
  border-bottom: none;
}

.rule-hit-body {
  flex: 1;
  min-width: 0;
}

.rule-hit-name,
.rule-hit-date {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rule-hit-date {
  font-size: 0.72rem;
  color: var(--color-text-muted);
}

.rule-hit-amount {
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

/* Herausfallende Zeilen bleiben sichtbar statt zu verschwinden: erst der Vergleich macht
   deutlich, was der Umschalter gerade abschneidet. */
.rule-hit-row.is-out {
  color: var(--color-text-muted);
}

.rule-hit-row.is-out .rule-hit-name {
  text-decoration: line-through;
}

.rule-hits-foot,
.rule-hits-empty {
  padding: 0.45rem 0.6rem;
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

.rule-hits-foot {
  border-top: 1px solid var(--color-border);
}

/* Statistiken */


.stats-section-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin-bottom: 0.75rem;
}

/* Mehr / Einstellungen */

.settings-section {
  margin-bottom: 1.5rem;
}

.settings-section-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin-bottom: 0.6rem;
}

.settings-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.settings-list {
  display: flex;
  flex-direction: column;
}

.settings-list-item {
  /* Die Datei-Ausloeser der Liste sind <label for> statt <button> (WebKit weist einen
     programmatischen Klick auf ein Datei-Feld ab, siehe more-view.js) und erben den Zeiger
     deshalb nicht aus der globalen button-Regel. Ueberschrieben wird das weiter unten von
     [disabled], .is-busy und .settings-list-item--static. */
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 56px;
  padding: 0.75rem 1rem;
  border: none;
  background: none;
  text-align: left;
  color: var(--color-text);
}

.settings-list-item + .settings-list-item {
  border-top: 1px solid var(--color-border);
}

/* Im Demo-Modus gesperrte Einträge (siehe more-view.js): bewusst sichtbar statt ausgeblendet,
   damit die Liste nicht je nach Modus die Höhe wechselt. */
.settings-list-item[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

.settings-list-item-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-sm);
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  flex-shrink: 0;
}

.settings-list-item-icon svg {
  width: 18px;
  height: 18px;
}

.settings-list-item-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.settings-list-item-title {
  font-size: 0.9rem;
  font-weight: 500;
}

.settings-list-item-hint {
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--color-text-muted);
}

.settings-list-item-chevron {
  display: flex;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.settings-list-item-chevron svg {
  width: 16px;
  height: 16px;
}

.settings-list-item-icon.is-danger,
.settings-list-item-title.is-danger {
  color: var(--color-negative);
}

.settings-list-item-icon.is-notice {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

/* Steuerelemente am rechten Rand einer Listenzeile (Theme-Umschalter, Demo-Schalter) duerfen
   nicht schrumpfen -- sonst quetscht ein langer Hinweistext sie zusammen. */
.settings-list-item > .theme-switcher,
.settings-list-item > .switch {
  flex-shrink: 0;
}

/* Kontokarte (Kopf der Mehr-Ansicht)
   -----------------------------------
   Eigene Karte statt Listenzeile, weil sie als Einzige auf diesem Screen einen Zustand zeigt,
   der sich ohne Zutun des Nutzers aendert: Klemmt der Abgleich, faerbt sich die Karte im
   Hinweiston, statt als graue Unterzeile mitzulaufen. */
.account-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 0.85rem 1rem;
  margin-bottom: 1.5rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  text-align: left;
  color: var(--color-text);
}

.account-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-size: 0.95rem;
  font-weight: 600;
  flex-shrink: 0;
}

.account-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  min-width: 0;
}

/* Lange Adressen brechen die Karte sonst auf oder schieben das Chevron aus dem Bild. */
.account-mail {
  font-size: 0.9rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-sync {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.account-sync-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-text-muted);
  flex-shrink: 0;
}

.account-card.is-ok .account-sync-dot {
  background: var(--color-positive);
}

.account-card.is-warn {
  background: var(--color-notice-bg);
  border-color: var(--color-notice-text);
}

.account-card.is-warn .account-sync {
  color: var(--color-notice-text);
  font-weight: 500;
}

.account-card.is-warn .account-sync-dot {
  background: var(--color-notice-text);
}

/* Daten löschen */

.delete-option-checkbox {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1.5px solid var(--color-border);
  color: transparent;
  flex-shrink: 0;
}

.delete-option-checkbox svg {
  width: 14px;
  height: 14px;
}

.delete-option.is-checked .delete-option-checkbox {
  background: var(--color-negative);
  border-color: var(--color-negative);
  color: #fff;
}

.delete-options-card {
  margin-bottom: 1.5rem;
}

.settings-card-danger {
  border-color: var(--color-negative);
}

.delete-action-bar {
  position: sticky;
  bottom: 0;
  margin-top: 1.5rem;
  padding-top: 0.85rem;
  padding-bottom: 0.85rem;
  background: var(--color-bg);
  border-top: 1px solid var(--color-border);
}

.delete-action-button {
  width: 100%;
  min-height: 48px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--color-negative);
  color: #fff;
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
}

.delete-action-button:disabled {
  opacity: 0.35;
  cursor: default;
}

/* Unterseiten (z.B. Transaktionen verwalten) */

.view-subheader {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.view-subheader-title {
  flex: 1;
  font-size: 1.1rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Mittig gesetzter Kopf (Kategorie-Drilldown). Der Zurueck-Chevron kann dafuer nicht in der
   Zeile bleiben – er schoebe den Titel um seine eigene Breite nach rechts, und "mittig" waere
   sichtbar daneben. Er schwebt deshalb links in der Ecke, und der Titel spart ihn beidseitig
   aus, damit ein langer Name nicht darunter laeuft. Gleiche Ueberlegung wie bei
   .sheet-head-centered in den Sheets, deren Kopf Inhalt ist. */
.view-subheader.is-centered {
  position: relative;
  justify-content: center;
  min-height: 44px;
}

.view-subheader.is-centered .icon-button {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
}

.view-subheader.is-centered .view-subheader-title {
  flex: 0 1 auto;
  padding: 0 44px;
  text-align: center;
}

.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: none;
  background: none;
  color: var(--color-accent-text);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.icon-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.toolbar-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: none;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

/* Im Demo-Modus gesperrter Import (siehe manage-transactions-view.js) – wie .icon-button:disabled. */
.toolbar-button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.theme-switcher {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  background: var(--color-chip-bg);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  width: fit-content;
}

.theme-option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.theme-option-label {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.theme-option-icon {
  width: 16px;
  height: 16px;
}

.theme-option input:checked + .theme-option-label {
  background: var(--color-surface);
  color: var(--color-accent-text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.theme-option input:focus-visible + .theme-option-label {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  padding: 0;
  margin: -1px;
}

/* Regel-Dialog */

.rule-dialog {
  position: fixed;
  inset: 0;
  margin: auto;
  border: none;
  border-radius: var(--radius-md);
  padding: 0;
  background: var(--color-surface);
  color: var(--color-text);
  width: min(28rem, calc(100vw - 2rem));
  /* dvh statt vh: Mit offener Bildschirmtastatur schrumpft auf dem Handy nur der sichtbare
     Bereich, 100vh bleibt die volle Bildschirmhöhe – der Dialog wäre also höher als das, was
     man sieht, und alles unterhalb des Eingabefelds läge hinter der Tastatur. vh bleibt als
     Rückfallwert für Browser ohne dvh stehen. */
  max-height: calc(100vh - 4rem);
  max-height: calc(100dvh - 4rem);
}

.rule-dialog::backdrop {
  background: rgba(0, 0, 0, 0.4);
}

.rule-dialog-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem;
  overflow-y: auto;
}

.rule-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.rule-dialog-title {
  font-size: 1.1rem;
  font-weight: 600;
}

.rule-dialog-field-group {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.rule-dialog-field-group[hidden] {
  display: none;
}

.rule-dialog-field-group label {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.rule-dialog-field-hint {
  font-size: 0.74rem;
  color: var(--color-text-muted);
}

/* Ankreuzfelder sind hier bewusst ausgenommen: Das Textfeld-Styling (44px Mindesthöhe,
   Innenabstand, Rahmen) macht aus einem Radio einen hohen Kasten, in dem der Punkt weit
   unter der ersten Textzeile sitzt. */
.rule-dialog-field-group input:not([type="radio"]):not([type="checkbox"]),
.rule-dialog-field-group select,
.rule-amount-input input {
  min-height: 44px;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  transition: border-color 0.12s ease, box-shadow 0.12s ease, border-radius 0.15s ease;
}

.rule-dialog-field-group input:not([type="radio"]):not([type="checkbox"]):focus-visible,
.rule-dialog-field-group select:focus-visible,
.rule-amount-input input:focus-visible {
  outline: none;
  border-color: var(--color-accent-text);
  box-shadow: 0 0 0 1px var(--color-accent-text) inset;
}

.rule-dialog-field-group select:focus-visible {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.rule-dialog-field-group select.opens-upward:focus-visible {
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* Betrag-Feld ohne Spinner-Pfeile – bei einem Geldbetrag klickt niemand einzelne Cent hoch/runter */
.rule-dialog-field-group input[type="number"] {
  -moz-appearance: textfield;
}

.rule-dialog-field-group input[type="number"]::-webkit-outer-spin-button,
.rule-dialog-field-group input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Betrag als Zusatzbedingung im Regel-Dialog (seit 2026-08-28, an Stelle des entfallenen
   Regeltyps "IBAN ist genau"). Der eigene Rahmen zeigt, dass Schalter und Felder zusammen
   eine Bedingung sind und dem Textkriterium darüber untergeordnet bleiben.
   Entwurf: Notizen/Mockups/regel-betrag-statt-iban.html, Variante A. */
.rule-extra-block {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.15rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

/* Zugeklappt ist der Block nur eine Schalterzeile – volle 44px Zeilenhöhe plus Innenabstand
   ließen ihn wie einen eigenen Abschnitt wirken. Die Höhe steckt deshalb in der Zeile selbst,
   und der untere Abstand hängt am aufklappbaren Teil: so ist er weg, solange der es auch ist. */
.rule-extra-block .switch-row {
  padding: 0;
  min-height: 38px;
}

.rule-extra-body {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  padding-bottom: 0.45rem;
}

.rule-extra-body[hidden] {
  display: none;
}

/* Zwei Vergleichsarten rechtfertigen kein Auswahlfeld – ein Chip-Paar zeigt beide auf einen
   Blick und ist mit dem Daumen in einem Tipp erreichbar. */
.rule-amount-mode {
  display: flex;
  gap: 0.4rem;
}

.rule-amount-mode button {
  flex: 1;
  min-height: 38px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}

.rule-amount-mode button.selected {
  background: var(--color-chip-bg);
  border-color: var(--color-accent-text);
  color: var(--color-accent-text);
  font-weight: 600;
}

.rule-amount-inputs {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Das Euro-Zeichen steht im Feld statt im Label: der Nutzer tippt eine Zahl, die Einheit ist
   keine Beschriftung. Deshalb liegt es als ::after auf dem Wrapper, nicht im Eingabewert. */
.rule-amount-input {
  position: relative;
  flex: 1;
  min-width: 0;
}

.rule-amount-input input {
  width: 100%;
  padding-right: 2rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.rule-amount-input::after {
  content: "€";
  position: absolute;
  right: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--color-text-muted);
  font-size: 0.9rem;
  pointer-events: none;
}

.rule-amount-input[hidden] {
  display: none;
}

.rule-amount-sep {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.rule-amount-sep[hidden] {
  display: none;
}

/* Betragsbedingung in der Regelliste (siehe js/ui/manage-rules-view.js) – ohne sie sähen zwei
   Regeln auf denselben Empfänger mit verschiedenen Beträgen identisch aus. */
.rule-b-amount {
  font-variant-numeric: tabular-nums;
  color: var(--color-accent-text);
}

.rule-dialog-target {
  font-size: 0.9rem;
  color: var(--color-text-muted);
}

.rule-dialog-preview {
  background: var(--color-chip-bg);
  border-radius: var(--radius-sm);
  padding: 0.75rem;
}

.rule-match-count {
  font-weight: 600;
  font-size: 0.9rem;
}

.rule-dialog-preview summary {
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--color-accent-text);
  margin-top: 0.35rem;
}

.rule-match-list {
  list-style: none;
  margin-top: 0.5rem;
  max-height: 8rem;
  overflow-y: auto;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-height: 44px;
}

.switch-row label {
  font-size: 0.9rem;
}

.switch {
  position: relative;
  display: inline-flex;
  width: 40px;
  height: 24px;
  flex-shrink: 0;
}

.switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
  z-index: 1;
}

.switch-track {
  position: absolute;
  inset: 0;
  background: var(--color-border);
  border-radius: 999px;
  transition: background-color 0.15s ease;
}

.switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-surface);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
  transition: transform 0.15s ease;
}

.switch input:checked ~ .switch-track {
  background: var(--color-accent);
}

.switch input:checked ~ .switch-thumb {
  transform: translateX(16px);
}

.switch input:focus-visible ~ .switch-track {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

.rule-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.rule-dialog-button {
  min-height: 44px;
  padding: 0.5rem 1.25rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

.rule-dialog-button svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.rule-dialog-button-primary {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.rule-dialog-button:disabled {
  opacity: 0.4;
  cursor: default;
}

.button-spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: button-spinner-spin 0.6s linear infinite;
}

@keyframes button-spinner-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Ladeanzeige für die zwei Wartezeiten ohne auslösenden Knopf (siehe FB.BusyOverlay): der Start
   nach dem Umschalten des Demo-Modus und das Fenster zwischen Nav.show() und fertigem Render.
   Erscheint erst nach einer kurzen Verzögerung — die sitzt im JS, nicht hier. */
.busy-overlay {
  position: absolute;
  inset: 0;
  /* Über dem Ansichtsinhalt inklusive der sticky Gruppenköpfe, aber unter der Bottom-Nav (30):
     die bleibt bedienbar, damit ein Fehlgriff sofort korrigierbar ist. */
  z-index: 20;
  background: color-mix(in srgb, var(--color-bg) 82%, transparent);
  backdrop-filter: blur(2px);
  animation: busy-overlay-in 0.18s ease-out;
}

@keyframes busy-overlay-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Hält Ring und Text im sichtbaren Fenster, auch wenn die darunterliegende (noch alte) Ansicht
   seitenlang ist: die Fläche deckt die ganze Ansicht, der Inhalt klebt am Bildausschnitt. */
.busy-overlay-inner {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
}

/* Der Start hat nichts zu verdecken und deshalb auch nichts durchscheinen zu lassen — deckend,
   über allem, auch über dem Konto-Filter-Popover (50). */
.busy-overlay.is-boot {
  position: fixed;
  z-index: 60;
  background: var(--color-bg);
  backdrop-filter: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.85rem;
}

/* Nach .is-boot, sonst gewinnt dessen display:flex gegen das hidden-Attribut. */
.busy-overlay[hidden] {
  display: none;
}

.busy-overlay-ring {
  width: 34px;
  height: 34px;
  border: 2.5px solid color-mix(in srgb, var(--color-accent-text) 25%, transparent);
  border-top-color: var(--color-accent-text);
  border-radius: 50%;
  animation: button-spinner-spin 0.9s linear infinite;
}

.busy-overlay-brand {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--color-text);
}

.busy-overlay-text {
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  text-align: center;
  padding: 0 2rem;
}

/* Die Fläche und der Text bleiben, nur die Bewegung geht — dieselbe Abwägung wie bei
   .sync-ring.is-running weiter unten. */
@media (prefers-reduced-motion: reduce) {
  .busy-overlay {
    animation: none;
  }

  .busy-overlay-ring {
    animation: none;
  }
}

/* Läuft gerade eine Aktion (siehe FB.Busy): sichtbar zurückgenommen und nicht noch einmal
   auslösbar. Bewusst über eine Klasse statt über [disabled] — ein <label> auf ein Datei-Feld
   kennt kein disabled, wäre sonst aber weiter anklickbar. */
.is-busy {
  opacity: 0.6;
  pointer-events: none;
  cursor: default;
}

/* Der Spinner, den FB.Busy.aufZeile rechts an eine settings-card-Zeile hängt. Steht an der Stelle
   des Chevrons, das solange verdeckt wird — sonst stünden beide nebeneinander. */
.settings-list-item-busy {
  display: flex;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.settings-list-item.is-busy .settings-list-item-chevron {
  display: none;
}

.rule-dialog-button-danger {
  border-color: var(--color-negative);
  color: var(--color-negative);
}

/* Bank-Mapping-Dialog */

.bank-mapping-dialog {
  width: min(36rem, calc(100vw - 2rem));
}

.mapping-preview-wrapper {
  overflow-x: auto;
}

/* Aufklapper im Zuordnungs-Screen: "Weitere Angaben" (IBAN, Konto, Kategorie …) und
   "Alle Spalten anzeigen". Beides bleibt zugeklappt, statt die Liste zu überladen. */
.mapping-more-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: none;
  border: none;
  color: var(--color-accent-text);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.3rem 0;
  margin: 0.4rem 0 0.6rem;
  cursor: pointer;
}

.mapping-more-toggle svg {
  width: 14px;
  height: 14px;
  transition: transform 0.15s ease;
}

.mapping-more-toggle.is-open svg {
  transform: rotate(45deg);
}

.rule-dialog-target.is-attention {
  color: var(--color-negative);
  font-weight: 600;
}

/* Zusätzliche Absicherung für kurze Viewports (z. B. Querformat): Der "Weiter"-Button bleibt
   sichtbar, auch wenn Titel/Vorschau/Liste zusammen doch mal die 40vh-Grenze der Liste
   übersteigen und .rule-dialog-content dadurch selbst scrollen muss. Nur für diesen Dialog –
   andere Dialoge mit .rule-dialog-actions bleiben unangetastet. */
#bank-mapping-dialog .rule-dialog-actions {
  position: sticky;
  bottom: 0;
  background: var(--color-surface);
  padding-top: 0.5rem;
  margin-top: 0.25rem;
  border-top: 1px solid var(--color-border);
}

/* Am PC ist der Dialog nicht an ein Handy-Display gebunden – dort darf er den Platz nutzen.
   Die Dateiansicht ("Ganze Datei ansehen") bekommt am meisten, weil man dort alle Spalten
   nebeneinander und möglichst viele Zeilen sehen will; der Zuordnungs-Screen bleibt schmaler,
   damit die Zeilen lesbar bleiben. Unterhalb des Breakpoints ändert sich nichts. */
@media (min-width: 768px) {
  .bank-mapping-dialog {
    width: min(44rem, calc(100vw - 4rem));
  }

  .bank-mapping-dialog:has(.mapping-screen-file) {
    width: min(80rem, calc(100vw - 3rem));
    max-height: calc(100vh - 3rem);
    max-height: calc(100dvh - 3rem);
  }

  .bank-mapping-dialog:has(.mapping-screen-file) .file-table-wrap {
    max-height: 70vh;
  }
}

/* ---------------------------------------------------------------------------
   Zuordnungs- und Dateiansicht (Entwurf 31.08.2026, Mockups import-zuordnung-
   aendern-spaltenname.html und import-datei-ansehen.html).

   Durchgehende Regel: Der Spaltenname der Bank wird technisch gesetzt (Monospace,
   gedämpft), der Wert daneben in der normalen Schrift. Das trennt das Zitat aus der
   fremden Datei von unseren eigenen Beschriftungen – und erst beide zusammen
   verraten, welcher Wert der richtige ist.
   --------------------------------------------------------------------------- */

.mapping-topbar-spacer {
  flex: 1;
}

.map-col-name {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.map-col-value {
  font-size: 0.86rem;
  color: var(--color-text);
  overflow-wrap: anywhere;
}

.map-field-sep {
  color: var(--color-text-muted);
  margin: 0 0.3rem;
}

/* Blätterleiste über der Feldliste. Ein einzelner Datensatz beweist nie, dass zwei
   Datumsspalten auseinanderlaufen – deshalb wechselt sie ALLE Werte des Screens.
   Bewusst als Chip-Leiste und nicht als Knopfpaar: sie ist Navigation, keine Aktion,
   und darf neben "Übernehmen" nicht um Gewicht konkurrieren. */
.map-record-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  background: var(--color-chip-bg);
  border-radius: 999px;
  padding: 0.25rem 0.35rem;
  margin-bottom: 0.6rem;
}

.map-record-nav button {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.map-record-nav button[disabled] {
  opacity: 0.4;
  cursor: default;
}

.map-record-nav button svg {
  width: 14px;
  height: 14px;
}

.map-record-nav > span {
  font-size: 0.76rem;
  color: var(--color-text-muted);
  font-weight: 500;
}

.map-field-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.map-field {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  overflow: hidden;
}

.map-field.is-open {
  border-color: var(--color-accent-text);
}

.map-field-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 44px;
  padding: 0.55rem 0.7rem;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.map-field-grow {
  flex: 1;
  min-width: 0;
}

.map-field-label {
  display: block;
  font-size: 0.82rem;
  font-weight: 500;
}

.map-field-summary {
  display: block;
}

.map-field-empty {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  font-style: italic;
}

.map-field-caret {
  display: flex;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.map-field-caret svg {
  width: 14px;
  height: 14px;
}

.map-field-body {
  border-top: 1px solid var(--color-border);
  padding: 0.5rem 0.55rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  /* Eigenes Scrollen statt den ganzen Dialoginhalt mitzuziehen, damit die Aktionen
     bei vielen Spalten sichtbar bleiben. */
  max-height: 44vh;
  overflow-y: auto;
}

/* Die Rollenwahl ("Wofür nehmen wir diese Spalte?") ist ein eigener Bildschirm und
   steht nicht in einer aufgeklappten Zeile – dort wäre der Rahmen oben zu viel. */
.map-field-body.is-flat {
  border-top: none;
  padding: 0;
  max-height: none;
}

/* Radio versteckt, .map-cand-mark zeichnet den Kreis – dieselbe Versteck-Technik
   wie bei .switch input. */
.map-cand {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  min-height: 44px;
  padding: 0.5rem 0.55rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.map-cand.is-active {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
}

.map-cand input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.map-cand-mark {
  position: relative;
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  margin-top: 0.15rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
}

.map-cand.is-active .map-cand-mark {
  border-color: var(--color-accent-text);
  background: var(--color-accent-text);
}

.map-cand.is-active .map-cand-mark::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 2px;
  width: 4px;
  height: 8px;
  border: solid var(--color-surface);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.map-cand-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.map-cand-note {
  font-size: 0.72rem;
  color: var(--color-notice-text);
}

/* Dateiansicht: die Tabelle scrollt waagerecht UND senkrecht in sich. Sie darf den
   Dialog nicht auseinanderdrücken, und weder 9 Spalten noch 800 Zeilen passen hinein. */
.file-table-wrap {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  overflow: auto;
  max-height: 52vh;
}

.file-table {
  border-collapse: collapse;
  font-size: 0.74rem;
}

.file-table th,
.file-table td {
  text-align: left;
  padding: 0.4rem 0.55rem;
  border-bottom: 1px solid var(--color-border);
  white-space: nowrap;
}

.file-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  vertical-align: top;
  padding: 0;
  background: var(--color-surface);
}

.file-table th.file-col-mapped {
  background: var(--color-chip-bg);
}

.file-table th + th,
.file-table td + td {
  border-left: 1px solid var(--color-border);
}

.file-table td {
  color: var(--color-text-muted);
}

.file-table td.file-col-mapped {
  background: var(--color-chip-bg);
  color: var(--color-text);
}

/* Die Spaltenüberschrift IST der Schalter – Ansehen und Zuordnen fallen hier zusammen.
   Der Caret am Etikett sagt, dass sich etwas aufmachen lässt. */
.file-th {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  width: 100%;
  padding: 0.4rem 0.55rem;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.file-th-name {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.68rem;
  color: var(--color-text-muted);
}

.role-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.12rem 0.4rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  white-space: nowrap;
}

.file-col-mapped .role-chip {
  background: var(--color-surface);
}

.role-chip.is-unused {
  background: transparent;
  color: var(--color-text-muted);
  border: 1px dashed var(--color-border);
  font-weight: 500;
}

.role-chip svg {
  width: 11px;
  height: 11px;
}

.file-row {
  cursor: pointer;
}

.file-row.is-current td {
  box-shadow: inset 0 0 0 1px var(--color-accent-text);
}

.file-foot {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  margin: 0.4rem 0 0;
}

/* Bestätigen-Vorschau: eigene Tabelle statt .mapping-preview-table – die soll pro Zeile drei
   gestapelte Zeilen (Name/Datum/Zweck) statt der generischen einzeiligen Zellen-Kürzung. */
.mapping-confirm-table {
  width: 100%;
  border-collapse: collapse;
}

.mapping-confirm-row {
  cursor: pointer;
}

.mapping-confirm-row td {
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}

.mapping-confirm-row:last-child td {
  border-bottom: none;
}

.mapping-confirm-who {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.mapping-confirm-name {
  font-size: 0.88rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mapping-confirm-date {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.mapping-confirm-purpose {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mapping-confirm-row.is-expanded .mapping-confirm-purpose {
  white-space: normal;
}

/* Zusatzfelder wie IBAN/Konto/Kategorie – nur sichtbar, wenn im Dialog auch zugeordnet,
   damit sich die Zuordnung vor dem Import wirklich kontrollieren lässt. */
.mapping-confirm-extra {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  margin-top: 0.2rem;
}

.mapping-confirm-extra-item {
  font-size: 0.7rem;
  color: var(--color-text-muted);
}

.mapping-confirm-extra-item b {
  color: var(--color-text);
  font-weight: 600;
}

.mapping-confirm-amount {
  text-align: right;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-left: 0.6rem;
}

.mapping-confirm-amount.is-neg {
  color: var(--color-negative);
}

.mapping-confirm-amount.is-pos {
  color: var(--color-positive);
}

.icon-button-danger {
  color: var(--color-text-muted);
}

.icon-button-danger:hover,
.icon-button-danger:focus-visible {
  color: var(--color-negative);
  background: var(--color-chip-bg);
}

/* Regel-Übersicht */

.rule-b {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cat-color, var(--color-accent));
  border-radius: var(--radius-md);
  padding: 0.75rem 0.9rem;
  margin-bottom: 0.75rem;
}

.rule-b.is-inactive {
  border-left-color: var(--color-border);
}

.rule-b.is-inactive .rule-b-target-name {
  color: var(--color-text-muted);
}

.rule-b-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.6rem;
  margin-bottom: 0.4rem;
}

.rule-b-target-name {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--color-text);
}

.rule-b-target-sub {
  font-weight: 400;
  color: var(--color-text-muted);
}

.rule-b-body {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  margin-bottom: 0.6rem;
}

.rule-b-pattern {
  color: var(--color-text);
  font-weight: 500;
}

.rule-b-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--color-border);
}

.rule-b-tag {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

.rule-b-actions {
  display: flex;
  align-items: center;
  gap: 0.1rem;
}

.rule-reorder {
  display: flex;
  gap: 0.15rem;
}

.group-summary-actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.group-summary.is-inactive .group-summary-label,
.group-summary.is-inactive .group-count {
  opacity: 0.5;
}

/* Profile verwalten (Listen-Übersicht) */

.profile-card {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.65rem;
  margin-bottom: 0.6rem;
}


.profile-card-hint {
  font-size: 0.78rem;
  color: var(--color-text-muted);
  margin-top: 0.1rem;
}


.profile-card-actions {
  position: relative;
  flex-shrink: 0;
}

.profile-card-actions-list {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  min-width: 11rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.16);
  padding: 0.25rem;
  display: flex;
  flex-direction: column;
  z-index: 20;
}

.profile-card-actions-item {
  min-height: 44px;
  padding: 0.5rem 0.75rem;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.profile-card-actions-item:hover {
  background: var(--color-chip-bg);
}

.profile-card-actions-item:disabled {
  opacity: 0.4;
  cursor: default;
}

.profile-card-color-item,
.profile-card-toggle-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  cursor: pointer;
}

/* Das Menü hat nur eine Mindestbreite, wächst also mit: ohne das bräche "Zählt zum Alltag"
   neben dem Schalter auf zwei Zeilen um. */
.profile-card-toggle-item {
  white-space: nowrap;
}

.category-color-input {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
}

.category-color-input::-webkit-color-swatch-wrapper {
  padding: 2px;
}

.category-color-input::-webkit-color-swatch {
  border: none;
  border-radius: calc(var(--radius-sm) - 2px);
}

/* Umbuchungs-Ziel (Kategorie-Auswahl für die automatische Umbuchungs-Erkennung) */

#transfer-target-section {
  margin-bottom: 0.9rem;
}

/* Profil-Pillen (Umschalter oberhalb der Kategorienliste) */

.profile-pill-row {
  display: flex;
  gap: 0.4rem;
  overflow-x: auto;
  padding-bottom: 0.2rem;
  margin-bottom: 0.9rem;
}

.profile-pill {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  min-height: 36px;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  border: none;
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  white-space: nowrap;
}

.profile-pill.is-selected {
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.profile-pill-star {
  font-size: 0.75rem;
}

.profile-pill-add {
  background: none;
  border: 1px dashed var(--color-border);
  color: var(--color-text-muted);
}

.view-subheader-actions {
  position: relative;
  flex-shrink: 0;
}

/* Kategorien-Detailansicht eines Profils */

.category-count {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-chip-bg);
  border-radius: 999px;
  padding: 0.1rem 0.55rem;
  flex-shrink: 0;
}

/* Kategorien, die nicht zum Alltag zählen und deshalb nicht hochgerechnet werden (siehe
   FB.Categories.countsAsEveryday). Bewusst dieselbe leise Pille wie die Zähl-Anzeige daneben:
   es ist ein Vermerk, keine Warnung – und ohne ihn wäre die Einstellung nur im Menü sichtbar. */
.category-flat-flag {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  background: var(--color-chip-bg);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  flex-shrink: 0;
}

.category-flat-item {
  margin-bottom: 0.75rem;
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cat-color, var(--color-accent));
  border-radius: var(--radius-md);
  background: var(--color-surface);
  padding: 0.5rem 0.75rem 0.75rem;
}

.category-flat-header {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  min-height: 44px;
}

.category-reorder,
.sub-chip-reorder {
  display: flex;
  gap: 0.05rem;
  flex-shrink: 0;
}

.mini-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: none;
  color: var(--color-text-muted);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
}

.mini-icon-button:disabled {
  opacity: 0.3;
}

.mini-icon-button svg {
  width: 14px;
  height: 14px;
}

.category-title {
  /* Ein Klick auf den Titel benennt um (startInlineRename in manage-profiles-view.js). */
  cursor: pointer;
  flex: 1;
  min-width: 0;
  font-weight: 600;
  color: var(--cat-color, var(--color-text));
  padding: 0.35rem 0.5rem;
  border-radius: var(--radius-sm);
}

.category-title:hover {
  background: var(--color-chip-bg);
}

.sub-chip-row {
  display: flex;
  flex-direction: column;
  margin-top: 0.4rem;
  margin-left: 1.4rem;
  border-left: 1px solid var(--color-border);
}

.sub-chip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.1rem;
  min-height: 34px;
  padding: 0.2rem 0.2rem 0.2rem 0.75rem;
  font-size: 0.82rem;
  border-bottom: 1px solid var(--color-border);
}

.sub-chip:last-of-type {
  border-bottom: none;
}

.sub-chip-label {
  /* Wie .category-title: ein Klick benennt um. */
  cursor: pointer;
  flex: 1;
  min-width: 0;
  border-radius: var(--radius-sm);
  padding: 0.1rem 0.2rem;
}

/* Aktionsmenü einer Unterkategorie ("Verschieben" / "Löschen"). Ersetzt das frühere "×", das
   Löschen als einzige Aktion zeigte – siehe subChipMenuHtml in manage-profiles-view.js.
   Eigene Wrapper-Klasse statt .profile-card-actions, damit der Klick-außerhalb-Handler die beiden
   Menüs auseinanderhalten kann (Kategorie-Menü vs. Unterkategorie-Menü). */
.sub-chip-menu {
  position: relative;
  flex-shrink: 0;
}

.sub-chip-menu-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Überschreibt .nav-icon (22px) aus dem geteilten Punkte-Icon – in der schmalen Chip-Zeile
   säße es sonst zu breit neben den 14px-Pfeilen. */
.sub-chip-menu-trigger svg {
  width: 15px;
  height: 15px;
}

.sub-chip-menu-list {
  min-width: 9.5rem;
}

.sub-chip-menu-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0.45rem 0.65rem;
  border: none;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text);
  font: inherit;
  font-size: 0.82rem;
  text-align: left;
}

.sub-chip-menu-item svg {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.sub-chip-menu-item:hover {
  background: var(--color-chip-bg);
}

.sub-chip-menu-item.is-danger {
  color: var(--color-negative);
}

/* Ziel-Liste im Verschieben-Sheet (move-subcategory-sheet.js). Bewusst eine Zeile je Kategorie
   statt der .chip-opt-Pillen des Kategorie-Pickers: Hier stehen alle Kategorien eines Profils
   untereinander (schnell ein Dutzend und mehr), und Pillen bräuchen dafür mehrere Umbruchzeilen. */
.move-target-list {
  display: flex;
  flex-direction: column;
}

.move-target-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 48px;
  padding: 0.3rem 0.2rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.move-target-row:last-child {
  border-bottom: none;
}

.move-target-row-title {
  flex: 1;
  min-width: 0;
}

.move-target-row.is-current {
  color: var(--color-text-muted);
}

.move-target-row-current-label {
  font-size: 0.76rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.sub-chip-add {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  border: none;
  background: none;
  color: var(--color-accent-text);
  font-weight: 600;
  padding: 0.4rem 0.2rem 0.4rem 0.4rem;
  min-height: 34px;
  font-size: 0.82rem;
  text-align: left;
}

.sub-chip-add-input {
  min-height: 36px;
  border-radius: 999px;
  border: 1px solid var(--color-accent-text);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 0.82rem;
  padding: 0.3rem 0.75rem;
  width: 9rem;
}

.category-add-row {
  padding: 0.25rem 0;
}


.category-add-input,
.category-title-input {
  min-height: 44px;
  width: 100%;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
}

.category-add-input:focus-visible,
.category-title-input:focus-visible {
  outline: none;
  border-color: var(--color-accent-text);
  box-shadow: 0 0 0 1px var(--color-accent-text) inset;
}

/* Verträge */

.contracts-section {
  margin-bottom: 1.5rem;
}

.contracts-add-wrap {
  display: flex;
  justify-content: center;
  margin-top: 0.25rem;
}

.contracts-add-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px dashed var(--color-border);
  background: none;
  color: var(--color-accent-text);
  border-radius: 999px;
  padding: 0.6rem 1.15rem;
  font-size: 0.85rem;
  font-weight: 600;
}

.contracts-add-pill:hover,
.contracts-add-pill:focus-visible {
  border-color: var(--color-accent-text);
}

.contracts-add-pill .nav-icon {
  width: 18px;
  height: 18px;
}

.section-title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.6rem;
}

.section-title-row .category-list-heading {
  margin: 0;
}

/* Die Donut-Überschrift trägt seit dem Anteils-Umschalter ebenfalls eine .section-title-row; ihr
   eigener Abstand nach unten würde sich sonst zu dem der Zeile addieren. */
.section-title-row .stats-section-title {
  margin: 0;
  align-self: center;
}

/* Umschalter für die Gliederungsebene der Vertragsliste (Ober-/Unterkategorie). Segment-Control
   auf Chip-Grund, das aktive Segment hebt sich über die Oberflächenfarbe ab – bewusst leiser als
   ein Button, da es eine Ansichtsvariante wählt und keine Aktion auslöst. */
.contracts-grouping-toggle {
  display: inline-flex;
  align-self: center;
  gap: 2px;
  padding: 2px;
  background: var(--color-chip-bg);
  border-radius: 999px;
  flex-shrink: 0;
}

.contracts-grouping-toggle button {
  border: none;
  background: transparent;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  padding: 0.2rem 0.7rem;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.contracts-grouping-toggle button.is-active {
  background: var(--color-surface);
  color: var(--color-text);
}

.contracts-grouping-toggle button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-accent-text);
}

.suggestion-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.contract-suggestion-card {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-notice-text);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.75rem;
  cursor: pointer;
}

.contract-suggestion-card:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: 2px;
}

.contract-suggestion-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.contract-suggestion-name {
  margin: 0;
  font-size: 0.92rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.contract-suggestion-evidence {
  margin: 0;
  font-size: 0.73rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.contract-suggestion-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
  flex-shrink: 0;
}

.contract-suggestion-amount {
  font-size: 0.92rem;
}

.row-actions {
  display: flex;
  gap: 0.15rem;
  flex-shrink: 0;
}

.row-actions .icon-button {
  width: 26px;
  height: 26px;
}

.row-actions .icon-button .nav-icon {
  width: 16px;
  height: 16px;
}

.icon-button.accept {
  color: var(--color-positive);
}

.icon-button-muted {
  color: var(--color-text-muted);
}

/* Leer-Karte für "Aktive/Archivierte Verträge" ohne Einträge – gleicher Rahmen/Radius wie die
   Vorschlagskarten, aber gestrichelt statt Akzentfarbe, damit sie als "nichts zu tun" statt als
   "hier gibt's was" gelesen wird. */
.contract-empty-card {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.85rem 0.9rem;
  color: var(--color-text-muted);
  font-size: 0.85rem;
}

.contract-empty-icon {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--color-chip-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.contract-empty-icon svg {
  width: 15px;
  height: 15px;
  color: var(--color-text-muted);
}

/* Die Vertragsliste ist seit 2026-08-22 EINE Karte, deren Zeilen nur durch Haarlinien getrennt
   sind – vorher war jede Zeile eine eigene Karte mit Rahmen, Rundung und 0,5 rem Lücke. Kein
   overflow: hidden, weil das die Karte zum Scroll-Container machen und damit den klebenden
   Gruppenkopf darin außer Kraft setzen würde; die Ecken runden stattdessen erstes und letztes
   Kind ab. */
.contract-list {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin-bottom: 1.25rem;
}

.contract-list > :first-child {
  border-top-left-radius: calc(var(--radius-md) - 1px);
  border-top-right-radius: calc(var(--radius-md) - 1px);
}

.contract-list > :last-child {
  border-bottom-left-radius: calc(var(--radius-md) - 1px);
  border-bottom-right-radius: calc(var(--radius-md) - 1px);
}

/* Das Archiv steckt bereits in der Karte des <details> (.transaction-group) – dort trägt die
   Liste nur die Zeilen, ohne zweiten Rahmen. */
.contract-archive-list {
  border-top: 1px solid var(--color-border);
}

/* Gruppenkopf statt des früheren .category-divider (Label + Linie): klebt beim Scrollen oben
   fest, damit immer ablesbar bleibt, in welcher Kategorie man liest. Der eingefärbte Grund
   ersetzt die Linie – er trennt und benennt in einem Zug und kommt mit halber Höhe aus. */
.contract-group-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.42rem 0.85rem 0.38rem 0.75rem;
  background: color-mix(in srgb, var(--cat-color, var(--color-border)) 9%, var(--color-surface));
  border-bottom: 1px solid var(--color-border);
}

.contract-group-label {
  font-size: 0.67rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cat-color, var(--color-text-muted));
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.contract-group-sum {
  margin-left: auto;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--color-text-muted);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  white-space: nowrap;
}

/* Eine Zeile je Vertrag, einzeilig. Der Farbstreifen links bleibt (gleicher Farbcode wie in der
   Regel-Übersicht, .rule-b) und wirkt lückenlos untereinander stärker als zuvor mit Rahmen und
   Abstand dazwischen. min-height hält die Tippfläche bei 44 px, auch wenn die Zeile nur aus Name
   und Betrag besteht. */
.contract-line {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  min-height: 44px;
  /* Rechts knapper als links: dort steht mit Betrag und Turnus die schmalste, klar begrenzte
     Spalte der Zeile, links dagegen Text, der Luft zum Farbstreifen braucht. Jeder Millimeter
     hier ist Platz, den Name und Status vor dem Umbruch gewinnen. */
  padding: 0.6rem 0.5rem 0.6rem 0.72rem;
  background: transparent;
  border: none;
  border-top: 1px solid var(--color-border);
  border-left: 3px solid var(--cat-color, var(--color-border));
  text-align: left;
  font: inherit;
  color: var(--color-text);
  cursor: pointer;
  transition: opacity 0.15s ease, background-color 0.15s ease;
}

/* Nach einem Gruppenkopf trägt schon dessen Unterkante die Trennung. */
.contract-group-head + .contract-line,
.contract-list > .contract-line:first-child,
.contract-archive-list > .contract-line:first-child {
  border-top: none;
}

.contract-line:hover,
.contract-line:focus-visible {
  background: color-mix(in srgb, var(--cat-color, var(--color-accent-text)) 7%, var(--color-surface));
  outline: none;
}

/* --contract-highlight-color setzt die Verträge-Ansicht beim Donut-Klick je Zeile auf die Farbe
   des gewählten Segments (siehe highlightContractsFor). Ohne Auswahl greift die Akzentfarbe.
   Getönt statt gerahmt: einen eigenen Rahmen hat die Zeile nicht mehr. */
.contract-line.is-highlighted {
  background: color-mix(in srgb, var(--contract-highlight-color, var(--color-accent-text)) 12%, var(--color-surface));
}

.contract-line.is-dimmed {
  opacity: 0.45;
}

/* Linker Textblock: Name und Statuszeile stehen nebeneinander, solange sie nebeneinander passen –
   erst wenn nicht, rutscht der Status unter den Namen (flex-wrap). Keine feste Zeilenzahl also,
   sondern so wenige Zeilen wie möglich: ein kurzer Name behält seinen Status neben sich, ein
   langer bekommt ihn darunter, und ein Vertrag ohne Status bleibt einzeilig bei 44 px.

   Der Name schrumpft dabei zuerst (flex-shrink), aber nur bis zur Umbruchgrenze – reicht auch die
   volle Breite nicht, kürzt er mit Ellipse ab. */
.contract-line-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.1rem 0.4rem;
}

.contract-line-name {
  min-width: 0;
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Status: Teiler und Mindestlaufzeit als Icon plus Kurzwert. Farbe trägt hier nur der
   Warnzustand (.pill-pending, gesetzt von statusItemHtml) – in einer sonst durchgehend
   gedämpften Zeile ist ein einziger farbiger Chip Signal genug.

   Bleibt als Ganzes zusammen (flex-shrink: 0, nowrap): er umbricht lieber komplett unter den
   Namen, als seine zwei Angaben auf zwei Zeilen zu verteilen. */
.contract-line-status {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  font-size: 0.72rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.contract-line-status-item {
  display: inline-flex;
  align-items: center;
  gap: 0.22rem;
}

/* Der Warnzustand kommt als .pill herein und bringt deren Maße mit – hier auf die Statuszeile
   heruntergesetzt, mit etwas mehr Luft links, damit das Icon nicht an der Rundung klebt. */
.contract-line-status-item.pill {
  gap: 0.22rem;
  font-size: 0.72rem;
  padding: 0.08rem 0.45rem 0.08rem 0.35rem;
}

.contract-line-status-sep::before {
  content: "·";
  margin: 0 0.3rem;
  opacity: 0.6;
}

/* Betrag in der Ticker-Monospace, die in der App ohnehin jede Zahl trägt. .amount bringt die
   Farbe mit, hier zählen nur Schnitt und Größe. */
.contract-line-amount {
  margin-left: auto;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.88rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
  flex-shrink: 0;
}

/* Turnus-Kürzel hinter dem Betrag. Eigene Spalte fester Mindestbreite, die auch leer mitläuft –
   nur so bleiben die Beträge untereinander bündig, egal ob in der Zeile ein Kürzel steht. Die
   Breite ist auf den längsten Regelfall "/HJ" gerechnet und nicht großzügiger: sie wird in jeder
   Zeile reserviert, also auch in den vielen, in denen gar nichts drinsteht, und fehlt dort dem
   Namen. Längere Custom-Werte ("/128T") dürfen die Spalte ausnahmsweise aufweiten.
   Das negative margin nimmt den Zeilen-gap auf den engeren Abstand zurück, den die Zahl und ihr
   Suffix als Einheit brauchen. */
.contract-line-freq {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  flex-shrink: 0;
  display: inline-block;
  min-width: 1.35rem;
  margin-left: -0.15rem;
  text-align: left;
}

.contract-line-icon {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

.contract-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.75rem 0.9rem;
  text-align: left;
  color: var(--color-text);
  transition: opacity 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.contract-row:hover,
.contract-row:focus-visible {
  border-color: var(--color-accent-text);
}

/* Nur noch vom Vertrag-Zuordnen-Dialog verwendet – in der Verträge-Liste selbst trägt der
   Farbstreifen die Zuordnung, ein zusätzlicher Punkt davor wäre doppelt gemoppelt. */
.contract-row-freq-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-accent-text);
  flex-shrink: 0;
}

.contract-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.contract-row-name {
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.contract-row-meta {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

/* Kleine Pillen-Variante für enge Zeilen (Vertrags-Sheet). Hieß bis 2026-08-20
   .contract-row-end-pill, als die Vertragszeile selbst noch Pillen trug. */
.pill-sm {
  font-size: 0.68rem;
  padding: 0.08rem 0.4rem;
}

.contract-row-right {
  text-align: right;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
}

.pill-pending {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

/* --- "Vertrag zuordnen" (ui/contract-picker-dialog.js) ---------------------
   Entwurf: Notizen/Mockups/vertrag-zuordnen-angleichung.html, Variante A.
   Bis 2026-08-30 war das ein mittiger .rule-dialog mit .receipt-card
   ("EMPFÄNGER / BETRAG / DATUM"), einer .settings-list-item-Zeile, einem
   "oder"-Teiler und einem zweiten Schritt für die eigentliche Liste – vier
   Formen, die es im Vertrags-Bereich sonst nirgends mehr gibt. Jetzt: ein
   Bottom-Sheet wie Anlegen/Bearbeiten/Vorschlag prüfen, mit der Liste sofort. */

/* Die Buchung als EINE gedämpfte Zeile unter dem Titel statt als eigener
   Kasten. Sie ist hier Kontext und nicht der Gegenstand – der Gegenstand ist
   die Frage, zu welchem Vertrag sie gehört. Zwei Zeilen darf sie werden
   (langer Empfängername), mehr nicht. */
.assign-sub {
  font-size: 0.82rem;
  color: var(--color-text-muted);
  line-height: 1.35;
  margin-bottom: 0.9rem;
  overflow-wrap: anywhere;
}

.assign-sub b {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

/* Ab etwa sechs Zeilen scrollt die LISTE, nicht das Sheet – nur so bleibt
   "Neuen Vertrag anlegen" darunter erreichbar, ohne erst an vierzig Verträgen
   vorbeizuscrollen. Weicher Auslauf statt Systemscrollleiste, dieselbe
   Überlegung wie beim aufgeklappten Kategorieblock im Anlegen-Dialog. */
.assign-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-height: 17rem;
  overflow-y: auto;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 1.6rem), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 1.6rem), transparent 100%);
  padding-bottom: 0.6rem;
  margin-bottom: 0.4rem;
}

/* Passt die Liste ohnehin ganz ins Sheet, wäre der Auslauf eine Andeutung von
   etwas, das es nicht gibt. */
.assign-list.is-short {
  -webkit-mask-image: none;
  mask-image: none;
  padding-bottom: 0;
  margin-bottom: 0.9rem;
}

.assign-list .contract-row {
  padding: 0.65rem 0.85rem;
}

.assign-chev {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

/* Erscheint erst ab ASSIGN_SEARCH_THRESHOLD Verträgen – darunter wäre es ein
   Bedienelement für vier Zeilen. */
.assign-filter {
  margin-bottom: 0.6rem;
}

/* Die zuzuordnende Buchung im Bestätigungs-Screen: dieselbe Zeile wie in der
   Trefferliste des Such-Screens, nur ohne Auswahl – sie ist hier eine Auskunft
   und kein Bedienelement. Der Rahmen darf deshalb auch beim Darüberfahren nicht
   aufleuchten, sonst verspricht er einen Klick. */
.contract-match-row.is-static {
  cursor: default;
}

.contract-match-row.is-static:hover {
  border-color: var(--color-border);
}

/* Der Zurueck-Chevron schwebt in der Ecke – dieselbe Ueberlegung wie
   .sheet-close-floating, nur spiegelbildlich links. Er steht nur da, wo es
   wirklich einen Rueckweg gibt (Vertrags-Sheet aus dem Buchungs-Sheet heraus,
   Bestaetigung aus dem Zuordnen-Sheet heraus); sonst traegt die Ecke das X. */
.sheet-back-floating {
  position: absolute;
  top: 0.4rem;
  left: 0.6rem;
  width: 32px;
  height: 32px;
  z-index: 1;
}

.sheet-tx-list {
  display: flex;
  flex-direction: column;
  margin-bottom: 1rem;
  max-height: 13.75rem; /* ~5 Zeilen à .sheet-tx-row, danach scrollt die Liste statt das ganze Sheet */
  overflow-y: auto;
}

.sheet-tx-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: 100%;
  padding: 0.55rem 0;
  border: none;
  border-bottom: 1px solid var(--color-border);
  border-radius: 0;
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.sheet-tx-row:last-child {
  border-bottom: none;
}

.sheet-tx-row:hover .sheet-tx-date,
.sheet-tx-row:focus-visible .sheet-tx-date {
  color: var(--color-accent-text);
}

.sheet-tx-row:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--color-accent-text) inset;
}

.sheet-tx-date {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

/* Kategorie-Zeile im Vertrags-Sheet: eigene Karte mit Farbakzent (analog .rule-b), damit auf
   einen Blick klar ist, dass es sich um die Kategorie-Zuordnung handelt statt einer beliebigen Pille. */
.contract-cat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--cat-color, var(--color-border));
  border-radius: var(--radius-sm);
  padding: 0.65rem 0.8rem;
}

.contract-cat-row.is-unassigned {
  border-left-style: dashed;
  border-left-color: var(--color-border);
}

.contract-cat-row-name {
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--cat-color, var(--color-text-muted));
}

.contract-cat-row.is-unassigned .contract-cat-row-name {
  font-weight: 500;
  color: var(--color-text-muted);
}

.contract-cat-row-sub {
  font-weight: 400;
  color: var(--color-text-muted);
}

.contract-cat-row-chevron {
  color: var(--color-text-muted);
  flex-shrink: 0;
  display: flex;
}

.contract-cat-row-chevron svg {
  width: 16px;
  height: 16px;
}

/* "Verknüpfte/Erkannte Buchungen" liegen in der Treffer-Vorschau (.rule-dialog-preview, gleiches
   Muster wie die Regel-Dialoge) – .sheet-tx-list bringt eigenes margin/max-height mit, das hier
   stört, weil die Vorschau ihren Innenabstand bereits selbst setzt. */
.rule-dialog-preview .sheet-tx-list {
  margin-bottom: 0;
}

/* Im Vertrags-Sheet folgt direkt unter der Treffer-Vorschau der Speichern-Button – ohne Abstand
   kleben beide Blöcke aneinander. Nur hier, im Regel-Dialog trägt der Actions-Bereich den
   Abstand bereits selbst. */
.sheet-body .rule-dialog-preview {
  margin-bottom: 1rem;
}

.contract-schedule-input {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  font: inherit;
  font-size: 0.9rem;
  padding: 0.45rem 0.6rem;
  width: 100%;
}

.contract-schedule-input:focus-visible {
  outline: none;
  border-color: var(--color-accent-text);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent-text) 20%, transparent);
}

.contract-schedule-hint {
  font-size: 0.74rem;
  color: var(--color-text-muted);
}

/* Zwischenüberschrift innerhalb eines aufgeklappten Blocks ("Erinnerung") – gliedert einen
   mehrteiligen Editor, ohne dafür eine zweite Zeile in der Feldliste zu verbrauchen. */
.editor-sublabel {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.match-count {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-text-muted);
}


/* Vertrags-Hinweis auf dem Dashboard: gleiche Warnfarbe wie die Vorschlagskarten, sitzt über der
   Monatsnavigation, weil er sich auf heute bezieht und nicht auf den betrachteten Monat.
   Wegwischbar per Swipe (Transform aus dem JS) oder ✕ für Maus/Tastatur. */
.contract-alert {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.7rem;
  transition: transform 0.2s ease, opacity 0.2s ease;
  touch-action: pan-y;
}

.contract-alert-main {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  padding: 0;
  border-radius: var(--radius-sm);
}

.contract-alert-icon {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  flex-shrink: 0;
  background: color-mix(in srgb, var(--color-notice-text) 20%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.contract-alert-icon svg {
  width: 14px;
  height: 14px;
}

.contract-alert-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.contract-alert-title {
  font-size: 0.86rem;
  font-weight: 600;
}

.contract-alert-sub {
  font-size: 0.74rem;
  opacity: 0.85;
}


.contract-alert-dismiss {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: inherit;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  opacity: 0.7;
}

.contract-alert-dismiss:hover,
.contract-alert-dismiss:focus-visible {
  opacity: 1;
  background: color-mix(in srgb, var(--color-notice-text) 15%, transparent);
}

.contract-alert-dismiss svg {
  width: 14px;
  height: 14px;
}

.contract-alert-main:focus-visible,
.contract-alert-dismiss:focus-visible {
  outline: 2px solid var(--color-notice-text);
  outline-offset: 1px;
}

@media (prefers-reduced-motion: reduce) {
  .contract-alert {
    transition: none;
  }
}

/* Konten verwalten (Liste + Aktions-Sheet) */

.account-list {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.account-row,
.account-sub-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 60px;
  padding: 0.65rem 0.9rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.account-list > :last-child {
  border-bottom: none;
}

.account-row:hover,
.account-sub-row:hover {
  background: color-mix(in srgb, var(--account-color, var(--color-text-muted)) 8%, var(--color-surface));
}

.account-row:focus-visible,
.account-sub-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: -2px;
}

/* Zusammengeführtes Vorgänger-Konto: eingerückt unter dem Konto, zu dem es heute gehört. */
.account-sub-row {
  background: var(--color-bg);
  padding-left: 1.9rem;
  min-height: 50px;
}

/* Initialen-Badge: einzige Farbe der Liste. --account-color setzt die View je Zeile stabil aus
   dem Rohnamen (siehe FB.Accounts.colorVarFor) – ausgeblendete Konten lassen es weg und bleiben
   damit im Grau des Fallbacks. */
.account-badge {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--account-color, var(--color-text-muted)) 18%, var(--color-surface));
  border: 1px solid color-mix(in srgb, var(--account-color, var(--color-text-muted)) 35%, transparent);
  color: var(--account-color, var(--color-text-muted));
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.account-row.is-muted .account-badge {
  background: var(--color-chip-bg);
  border-color: var(--color-border);
}

/* Vorgänger-Konto: gleiches Badge, kleiner und zurückgenommen. */
.account-badge-sm {
  width: 26px;
  height: 26px;
  border-radius: 9px;
  font-size: 0.66rem;
  opacity: 0.65;
}

.account-row-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.account-row-title {
  font-weight: 600;
  font-size: 0.95rem;
  overflow-wrap: anywhere;
}

.account-row.is-muted .account-row-title {
  color: var(--color-text-muted);
}

.account-sub-row-title {
  font-size: 0.88rem;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.account-row-meta {
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.account-row-chevron {
  flex-shrink: 0;
  color: var(--color-text-muted);
  display: flex;
}

.account-row-chevron svg {
  width: 18px;
  height: 18px;
}

.account-row-pill {
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  padding: 0.15rem 0.55rem;
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.account-sheet-origin {
  font-size: 0.82rem;
  color: var(--color-text-muted);
  margin: -0.6rem 0 0.9rem;
}

.account-action-list {
  display: flex;
  flex-direction: column;
}

.account-action {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 52px;
  padding: 0.7rem 0.2rem;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.account-action-list > :last-child {
  border-bottom: none;
}

.account-action:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: -2px;
  border-radius: var(--radius-sm);
}

.account-action-icon {
  flex-shrink: 0;
  color: var(--color-accent-text);
  display: flex;
}

.account-action-icon svg {
  width: 18px;
  height: 18px;
}

.account-action-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.account-action-title {
  font-size: 0.92rem;
}

.account-action-hint {
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.account-action-chevron {
  flex-shrink: 0;
  color: var(--color-text-muted);
  display: flex;
}

.account-action-chevron svg {
  width: 18px;
  height: 18px;
}

/* Rücklage: Puffer-Zeile in der Verträge-Ansicht + Unteransicht mit Verlaufskurve */

.reserve-bar {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  background: var(--color-surface);
  border: 1px solid var(--color-accent-text);
  border-radius: var(--radius-md);
  padding: 0.75rem 0.9rem;
  margin-bottom: 1rem;
  text-align: left;
  cursor: pointer;
  color: var(--color-text);
}

.reserve-bar:hover,
.reserve-bar:focus-visible {
  background: var(--color-chip-bg);
  outline: none;
}

/* Als Fußzeile der Donut-Karte braucht die Zeile keinen eigenen Rahmen und keine eigene Fläche –
   beides stellt die Karte. Übrig bleibt die Zeile selbst: Beschriftung und Chevron. */
.donut-card-footer .reserve-bar {
  background: none;
  border: none;
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  margin: 0;
  padding: 0.85rem 1rem;
}

.donut-card-footer .reserve-bar:hover,
.donut-card-footer .reserve-bar:focus-visible {
  background: var(--color-chip-bg);
}

/* Einzige Textzeile der Puffer-Zeile und damit kein Untertitel mehr, sondern eine Zeilen-
   Beschriftung wie .contract-row-name in der Liste direkt darunter – gleiche Größe, gleiches
   Gewicht, volle Textfarbe. */
.reserve-bar-label {
  flex: 1;
  min-width: 0;
  font-weight: 500;
  color: var(--color-text);
}

.reserve-bar-chevron {
  width: 15px;
  height: 15px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Eine Karte für alles: Diagramm, Monatsaufschlüsselung und Puffer-Zeile. Früher waren das zwei
   Karten – die zweite trug nach dem Wegfall von Monatsrate und teuerstem Monat aber nur noch eine
   einzige Zeile und stand als eigener Block nicht mehr für sich. */
.reserve-chart-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 0.85rem 0.85rem 0.35rem;
  margin-bottom: 1.25rem;
}

.reserve-chart-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 1.15rem;
}

.reserve-chart-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.reserve-chart-meta {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-text-muted);
}

/* Zeichenfläche. Das SVG ist rein grafisch, jede Beschriftung liegt als HTML darüber bzw. darunter:
   das viewBox skaliert mit der Kartenbreite, und damit skalierte früher auch jede SVG-Schrift mit –
   auf einem 900px breiten Fenster wurde aus font-size 8.5 optisch über 20px, in der System-Sans
   statt in der Monospace, die sonst jede Zahl der App trägt. */
.reserve-plot {
  position: relative;
}

.reserve-curve {
  display: block;
  width: 100%;
  height: auto;
}

/* Beschriftung des fokussierten Monats: nennt beide Zahlen nebeneinander (Rücklagenstand und
   Fixkosten). Bewusst eine gemeinsame Pille statt zweier freistehender Beschriftungen – Kurvenpunkt
   und Säulenoberkante liegen in manchen Monaten fast übereinander und würden sich überlagern. */
.reserve-tag {
  position: absolute;
  transform: translate(-50%, -100%);
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  white-space: nowrap;
  pointer-events: none;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
}

/* Am ersten und letzten Monat würde die zentrierte Pille aus der Karte laufen. */
.reserve-tag.is-start {
  transform: translate(-6%, -100%);
}

.reserve-tag.is-end {
  transform: translate(-94%, -100%);
}

.reserve-tag .is-balance {
  color: var(--color-accent-text);
}

.reserve-tag .is-due {
  color: var(--color-negative);
}

.reserve-tag .is-none {
  color: var(--color-text-muted);
  font-weight: 600;
}

/* Monatsachse als HTML-Raster statt SVG-Text – dieselben Spalten wie die Trefferflächen im SVG,
   damit Beschriftung und antippbare Spalte deckungsgleich sind. */
.reserve-axis {
  display: flex;
  margin-top: 0.15rem;
}

/* Die Spaltenbreite kommt inline aus der Diagramm-Geometrie (siehe axisHtml). */
.reserve-axis button {
  border: none;
  background: transparent;
  font: inherit;
  font-size: 0.68rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  min-width: 0;
  padding: 0.4rem 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.reserve-axis button.is-active {
  color: var(--color-text);
  font-weight: 600;
}

.reserve-axis button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--color-accent-text);
}

.reserve-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.9rem;
  font-size: 0.72rem;
  color: var(--color-text-muted);
  padding: 0.5rem 0.25rem 0.15rem;
}

.reserve-legend span {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.reserve-legend-swatch {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex-shrink: 0;
}

.reserve-legend-swatch.is-balance {
  background: var(--color-accent-text);
}

.reserve-legend-swatch.is-due {
  background: var(--color-negative);
}

/* Kopfkarte. Trägt seit 2026-08-20 die Antwort, auf die die ganze Rechnung hinausläuft – bis dahin
   stand sie als schmale Fußzeile ("Puffer auf dem Konto") unter dem Diagramm, also erst nach der
   Grafik, die sie eigentlich erklärt. Die Zahl steht groß in derselben Monospace wie jede andere
   Kennzahl der App (siehe Dashboard). */
.reserve-hero {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1rem 0.95rem 0.35rem;
  margin-bottom: 0.75rem;
}

.reserve-hero-eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.reserve-hero-value {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 2.4rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin-top: 0.35rem;
}

/* Sagt in einem Satz, was die Zahl darüber bedeutet – ohne ihn liest man sie als Kontostand. */
.reserve-hero-caption {
  font-size: 0.82rem;
  color: var(--color-text-muted);
  line-height: 1.45;
  margin-top: 0.2rem;
}

/* Zwei Zeilen unter der großen Zahl: die erste nennt die Monatsrate, die zweite führt ins
   Puffer-Sheet. Nur die zweite ist ein Button, deshalb tragen beide dieselbe Geometrie, aber nur
   button.reserve-hero-row bekommt Hover und Mindesthöhe.

   Bewusst Grid statt Flex: die dritte Spalte gehört dem Chevron und ist in der Raten-Zeile leer
   (leeres <span> im Markup). Mit Flex hing das Chevron rechts *am* Betrag und schob allein die
   Betrags-Kante der Button-Zeile nach links – die beiden Zahlen standen dann versetzt. */
.reserve-hero-rows {
  margin-top: 0.85rem;
  border-top: 1px solid var(--color-border);
}

.reserve-hero-row {
  display: grid;
  grid-template-columns: 1fr auto 14px;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.6rem 0.15rem;
  text-align: left;
}

.reserve-hero-row + .reserve-hero-row {
  border-top: 1px solid var(--color-border);
}

/* Bewusst ohne eigene min-height: die Zeile trug bis 2026-08-22 48px "touch-freundlich" und war
   damit sichtbar höher als die Raten-Zeile darüber, die nur ihr Padding hochhält. Zwei Zeilen
   derselben Liste dürfen nicht unterschiedlich hoch sein, nur weil eine davon anklickbar ist –
   das Padding allein ergibt bereits gut 40px Trefferfläche. */
/* Ebenso ohne border-radius: die Trennlinie zwischen den Zeilen ist ein border-top auf genau
   diesem Element, und eine Rahmenkante folgt der Rundung – die Linie bog sich an beiden Enden
   nach unten weg und verriet so, dass hier ein Button liegt. Die Hover-Fläche ist deshalb ein
   glattes Rechteck, wie bei jeder anderen Listenzeile der App. */
button.reserve-hero-row {
  border: none;
  background: transparent;
  font: inherit;
  color: var(--color-text);
  cursor: pointer;
}

button.reserve-hero-row:hover,
button.reserve-hero-row:focus-visible {
  background: var(--color-chip-bg);
  outline: none;
}

.reserve-hero-label {
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

/* tabular-nums, damit die Ziffern beider Zeilen auch untereinander in denselben Spalten sitzen
   und nicht nur die rechten Kanten fluchten. */
.reserve-hero-amount {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 1rem;
  font-weight: 700;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.reserve-chevron {
  width: 14px;
  height: 14px;
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Einordnungssatz zwischen Kopfkarte und Diagramm. Bewusst ohne Karte und ohne Rahmen: er ist
   Fließtext, keine Kennzahl, und soll die Ansicht nicht um einen dritten Block verlängern. */
.reserve-intro {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  line-height: 1.55;
  padding: 0 0.25rem;
  margin-bottom: 1rem;
}

.reserve-intro strong {
  color: var(--color-text);
  font-weight: 600;
}

/* Räumt den größten Denkfehler der Grafik aus: die Kurve ist durch den Offset in
   FB.Reserve.compute kein Kontoguthaben, sondern nur der reservierte Anteil. */
.reserve-disclaimer {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  line-height: 1.45;
  padding: 0.15rem 0.25rem 0.35rem;
}

/* Herleitung als natives <details>, zugeklappt. Der Marker wird ersetzt, weil die Browser-Vorgabe
   (Dreieck links) sonst als einziges Element der App links vor der Schrift säße. */
.reserve-how {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  margin-bottom: 1.25rem;
  overflow: hidden;
}

.reserve-how summary {
  list-style: none;
  cursor: pointer;
  padding: 0.7rem 0.9rem;
  min-height: 48px; /* touch-freundlich */
  font-size: 0.82rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.reserve-how summary::-webkit-details-marker {
  display: none;
}

.reserve-how summary:focus-visible {
  outline: none;
  background: var(--color-chip-bg);
}

/* Chevron aus zwei Rahmenkanten statt SVG – summary trägt kein eigenes Markup. */
.reserve-how summary::after {
  content: '';
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--color-text-muted);
  border-bottom: 2px solid var(--color-text-muted);
  transform: rotate(45deg);
  margin-right: 3px;
  transition: transform 0.15s ease;
}

.reserve-how[open] summary::after {
  transform: rotate(-135deg);
}

.reserve-how-body {
  padding: 0 0.9rem 0.85rem;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  line-height: 1.6;
}

.reserve-step {
  display: flex;
  gap: 0.6rem;
  padding: 0.35rem 0;
}

.reserve-step-n {
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-text);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.7rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.reserve-step b {
  color: var(--color-text);
  font-weight: 600;
}

/* Puffer-Sheet: Aufschlüsselung des laufenden Monats */

.buffer-sum {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.7rem 0.75rem;
  border-radius: var(--radius-sm);
  background: var(--color-chip-bg);
  margin-bottom: 1rem;
}

.buffer-sum-label {
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

.buffer-sum-value {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 1.5rem;
  font-weight: 700;
}

.buffer-group-title {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin: 0 0 0.4rem 0.15rem;
}

.buffer-list {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  margin-bottom: 1rem;
}

.buffer-empty {
  font-size: 0.85rem;
  color: var(--color-text-muted);
  padding: 0.75rem;
}

.buffer-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  min-height: 48px; /* touch-freundlich */
  padding: 0.6rem 0.7rem;
  border: none;
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.buffer-row + .buffer-row {
  border-top: 1px solid var(--color-border);
}

.buffer-row:hover,
.buffer-row:focus-visible {
  background: var(--color-chip-bg);
  outline: none;
}

.buffer-check {
  width: 20px;
  height: 20px;
  border-radius: 999px;
  border: 2px solid var(--color-border);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: transparent;
}

.buffer-check svg {
  width: 12px;
  height: 12px;
}

.buffer-row.is-paid .buffer-check {
  background: var(--color-accent-text);
  border-color: var(--color-accent-text);
  color: var(--color-accent-contrast);
}

.buffer-row-main {
  flex: 1;
  min-width: 0;
}

.buffer-row-name {
  display: block;
  font-size: 0.88rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Umbruch erlaubt: seit der zweiten Pille ("Buchung vorhanden") passt die Zeile auf schmalen
   Handys nicht mehr zwingend in eine Zeile. */
.buffer-row-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
  font-size: 0.73rem;
  color: var(--color-text-muted);
  margin-top: 0.1rem;
}

.buffer-row-amount {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.9rem;
  font-weight: 600;
  flex-shrink: 0;
}

/* Abgebuchtes ist erledigt: es zählt nicht mehr in den Puffer und tritt deshalb optisch zurück. */
.buffer-row.is-paid .buffer-row-name,
.buffer-row.is-paid .buffer-row-amount {
  color: var(--color-text-muted);
}

.buffer-row-pill {
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.1rem 0.4rem;
}

/* Offene Posten kosten noch Geld und tragen deshalb die Hinweisfarbe; Abgebuchtes ist erledigt
   und tritt neutral zurück – dieselbe Gewichtung wie bei Name und Betrag der Zeile. */
.buffer-row-pill.is-open {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

.buffer-row-pill.is-paid {
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
}

/* "Buchung vorhanden" nennt eine Tatsache aus den Daten, keinen Zustand, den man umstellen kann –
   deshalb bewusst als Umriss statt gefüllt: neben der gefüllten Zustands-Pille bleibt so auf
   einen Blick klar, welche der beiden die schaltbare ist. */
.buffer-row-pill.is-detected {
  background: transparent;
  color: var(--color-text-muted);
  box-shadow: inset 0 0 0 1px var(--color-border);
}

/* Antippbare Monatsspalten der Rücklagen-Kurve */

/* Reine Zeigerfläche ohne Tastaturfokus – bedienbar ist über die Tastatur die Monatsachse
   (.reserve-axis button), die dieselben Spalten trägt. */
.reserve-hit {
  cursor: pointer;
}

.reserve-band {
  fill: var(--color-accent-text);
  fill-opacity: 0.07;
}

/* Fixkosten-Säulen im Rücklagenverlauf. Bewusst schwach getönt: sie sind der Hintergrund, vor dem
   die Rücklagenkurve gelesen wird, nicht die Hauptaussage. Im Dunkelmodus etwas kräftiger, weil
   die gleiche Deckkraft auf dunklem Grund deutlich weniger hergibt. */
.reserve-due-bar {
  fill: var(--color-negative);
  fill-opacity: 0.18;
}

/* Der angetippte Monat: dieselbe Farbe, nur kräftig gefüllt. Das Auswahl-Band hebt die Spalte
   hervor, die Säule den Betrag, um den es beim Antippen geht. */
.reserve-due-bar.is-focus {
  fill-opacity: 0.5;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .reserve-due-bar {
    fill-opacity: 0.28;
  }

  :root:not([data-theme='light']) .reserve-due-bar.is-focus {
    fill-opacity: 0.65;
  }
}

:root[data-theme='dark'] .reserve-due-bar {
  fill-opacity: 0.28;
}

:root[data-theme='dark'] .reserve-due-bar.is-focus {
  fill-opacity: 0.65;
}

/* Bewusst nicht kursiv – Kursivschrift kommt sonst nirgends in der App vor. */
.reserve-legend-hint {
  margin-left: auto;
}

/* Aufschlüsselung des fokussierten Monats – steht immer unter Kurve und Legende in derselben
   Karte, im Startzustand für den laufenden Monat. */
.reserve-month-panel {
  border-top: 1px solid var(--color-border);
  margin-top: 0.55rem;
  padding-top: 0.6rem;
}

.reserve-month-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.45rem;
}

.reserve-month-title {
  font-size: 0.85rem;
  font-weight: 600;
}

.reserve-month-total {
  flex: 1;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.78rem;
  color: var(--color-text-muted);
  text-align: right;
}

.reserve-month-list {
  display: flex;
  flex-direction: column;
}

.reserve-month-row {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  padding: 0.35rem 0.15rem;
}

.reserve-month-row + .reserve-month-row {
  border-top: 1px solid var(--color-border);
}

.reserve-month-date {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.72rem;
  color: var(--color-text-muted);
  flex-shrink: 0;
  width: 5.5ch;
}

.reserve-month-name {
  flex: 1;
  min-width: 0;
  font-size: 0.85rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.reserve-month-freq {
  font-size: 0.72rem;
  color: var(--color-text-muted);
  margin-left: 0.35rem;
}

.reserve-month-amount {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.85rem;
  font-weight: 600;
  flex-shrink: 0;
}

.reserve-month-empty {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  line-height: 1.45;
  padding: 0.15rem;
}


/* --- Zeitraum-Sheet (FB.PeriodSheet) -------------------------------------------------------
   Presets oben, darunter der eigene Zeitraum. Bewusst zwei getrennte Bloecke: ein Preset wirkt
   sofort beim Antippen, der eigene Zeitraum braucht zwei Eingaben und deshalb einen Abschluss. */

.period-preset-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.45rem;
  margin: 0.75rem 0 1.1rem;
}

.period-preset {
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}

.period-preset:hover {
  border-color: var(--color-accent-text);
}

.period-preset.is-active {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-weight: 600;
}

.period-custom {
  border-top: 1px solid var(--color-border);
  padding-top: 0.9rem;
}

.period-custom-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin-bottom: 0.5rem;
}

.period-custom.is-active .period-custom-label {
  color: var(--color-accent-text);
}

.period-custom-fields {
  display: flex;
  gap: 0.5rem;
}

.period-field {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.6rem;
  min-width: 0;
}

.period-field:focus-within {
  border-color: var(--color-accent-text);
}

.period-field span {
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.period-field input {
  border: none;
  background: none;
  color: var(--color-text);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.9rem;
  padding: 0;
  width: 100%;
  min-width: 0;
}

.period-field input::-webkit-calendar-picker-indicator {
  opacity: 0.6;
}

.period-custom-hint {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  color: var(--color-negative);
}

.period-apply {
  margin-top: 0.75rem;
  width: 100%;
  padding: 0.65rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
}

.period-apply:hover {
  opacity: 0.92;
}

/* Konto & Sync (siehe js/ui/manage-account-view.js) */

/* Fehlermeldungen heben sich vom neutralen Statustext ab, nutzen aber dieselbe Zeile. */
.import-status-error {
  color: var(--color-negative);
}

/* Eine Zeile in einer settings-card, die kein Knopf ist -- gleiche Optik, kein Hover. */
.settings-list-item--static {
  cursor: default;
}

/* Der Wiederherstellungs-Code wird von Hand abgeschrieben: monospace, gross, mit Luft zwischen
   den Zeichen, und umbrechbar, damit er auf schmalen Displays vollstaendig sichtbar bleibt. */
.recovery-code {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  font-size: 1.05rem;
  letter-spacing: 0.08em;
  line-height: 1.7;
  text-align: center;
  overflow-wrap: anywhere;
  padding: 0.9rem 0.6rem;
  margin: 0.25rem 0 0.75rem;
  border-radius: var(--radius-md);
  background: var(--color-chip-bg);
  color: var(--color-text);
}


/* Band für den Abgleich (siehe FB.SyncBanner). Erscheint nur, wenn etwas klemmt – deshalb darf
   es auffallen, ohne zu schreien: warme Warnfarbe, eine Zeile, volle Breite, anklickbar. */
#sync-banner-mount[hidden] {
  display: none;
}

.sync-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 10px 16px;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}

.sync-banner-text {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.sync-banner-text::before {
  content: '';
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-negative);
}

.sync-banner-action {
  flex: none;
  color: var(--color-accent-text);
  font-weight: 600;
}


/* Eine Aktionszeile für einen einzelnen, langen Knopf: Er bekommt die volle Breite, statt sich
   rechtsbündig bis an den Kartenrand zu drängen (siehe "Serverstand ersetzen"). */
.rule-dialog-actions-block {
  justify-content: stretch;
}

.rule-dialog-actions-block .rule-dialog-button {
  width: 100%;
  text-align: center;
}

/* ===========================================================================
   Admin-Bereich: Ereignisprotokoll und Einladungscodes
   (js/ui/admin-log-view.js, js/ui/admin-invites-view.js)

   Nur für Konten mit is_admin = 1 überhaupt erreichbar. Die Bausteine folgen den
   vorhandenen Mustern der App – Karte auf --color-surface, Filterchips wie in
   "Transaktionen verwalten", Bottom-Sheet wie beim Buchungs-Sheet.
   =========================================================================== */

/* Gemeinsames Innenleben der beiden Admin-Sheets. Das umgebende <dialog> trägt
   bereits .category-sheet-dialog (Rundung, Polsterung, Hintergrund). */
.sheet-inner {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Nur noch in den beiden Admin-Sheets. Aus den Vertrags-Sheets ist er raus: Er
   verspricht eine Ziehgeste, die es bei einem nativen <dialog> nicht gibt, und
   ueber einer .sheet-topbar schob er die Titelzeile nach unten. */
.sheet-grip {
  width: 34px;
  height: 4px;
  border-radius: 2px;
  background: var(--color-border);
  margin: 0 auto;
  flex-shrink: 0;
}

/* Die Ereignisart ("login.fail") ist ein technischer Bezeichner und wird als
   solcher gesetzt – man sucht danach, man liest ihn nicht. */
.sheet-sub.is-mono {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.8rem;
}

.sheet-inner .sheet-title,
.sheet-inner .sheet-sub {
  margin-bottom: 0;
}

/* .sheet-inner setzt die Abstaende ueber gap – die eigene Untermarge der Topbar
   kaeme dort obendrauf. */
.sheet-inner > .sheet-topbar {
  margin-bottom: 0;
}

/* --- Protokoll: Kennzahlen der letzten 24 Stunden ------------------------- */

.log-summary {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  margin: 0 0 0.85rem;
  overflow: hidden;
}

.log-summary > div {
  padding: 0.6rem 0.7rem;
}

.log-summary > div + div {
  border-left: 1px solid var(--color-border);
}

.log-summary dt {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin-bottom: 0.15rem;
}

.log-summary dd {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 600;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  letter-spacing: -0.02em;
}

.log-summary dd.is-negative {
  color: var(--color-negative);
}

/* --- Protokoll: Liste ---------------------------------------------------- */

.log-daygroup {
  margin-bottom: 0.8rem;
}

.log-dayhead {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  padding: 0 0.2rem 0.4rem;
}

.log-list {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* Den Zustand trägt der Streifen links, nicht die Textfarbe: Beim Überfliegen
   sucht man die roten Kanten, nicht rote Wörter. */
.log-row {
  display: grid;
  grid-template-columns: 3px 1fr auto;
  gap: 0 0.7rem;
  align-items: start;
  width: 100%;
  padding: 0.55rem 0.8rem 0.55rem 0;
  border: none;
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.log-row + .log-row {
  border-top: 1px solid var(--color-border);
}

.log-row::before {
  content: "";
  align-self: stretch;
  background: var(--color-border);
  border-radius: 0 3px 3px 0;
}

.log-row.is-ok::before { background: var(--color-positive); }
.log-row.is-warn::before { background: var(--color-notice-text); }
.log-row.is-bad::before { background: var(--color-negative); }

.log-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: -2px;
}

.log-row-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding-left: 0.75rem;
}

.log-row-title {
  font-size: 0.87rem;
  font-weight: 500;
}

.log-row-repeats {
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.log-row-meta {
  font-size: 0.74rem;
  color: var(--color-text-muted);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.log-row-time {
  font-size: 0.75rem;
  color: var(--color-text-muted);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  padding-top: 0.1rem;
}

/* Web oder App – bewusst kein User-Agent, sondern die Herkunft der Anfrage. */
.client-tag {
  display: inline-block;
  margin-right: 0.35rem;
  padding: 0.05rem 0.3rem;
  border-radius: 5px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-family: inherit;
  font-size: 0.64rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.load-more {
  width: 100%;
  margin-top: 0.6rem;
  padding: 0.55rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
}

.load-more:disabled {
  opacity: 0.6;
}

/* --- Ereignis-Detail ------------------------------------------------------ */

.kv {
  display: grid;
  grid-template-columns: 8rem 1fr;
  gap: 0.35rem 0.6rem;
  margin: 0;
  font-size: 0.83rem;
}

.kv dt {
  color: var(--color-text-muted);
}

.kv dd {
  margin: 0;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.79rem;
  word-break: break-word;
}

/* Das rohe detail-JSON. Steht bewusst so da, wie es in der Datenbank liegt –
   und ausschließlich als Text (siehe Kopf von admin-log-view.js). */
.detail-json {
  margin: 0;
  padding: 0.6rem 0.7rem;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.73rem;
  color: var(--color-text-muted);
  overflow-x: auto;
  white-space: pre;
}

.hint-box {
  display: flex;
  gap: 0.5rem;
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius-sm);
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.77rem;
  line-height: 1.4;
}

/* --- Einladungscodes ------------------------------------------------------ */

/* Der aktive Einladungslink: das Kopfobjekt des Screens. Akzentrand statt Standardrand, damit
   er sich von der Historie darunter absetzt, ohne eine farbige Flaeche zu werden. */
.invite-hero {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0.9rem;
  margin-bottom: 1.25rem;
  background: var(--color-surface);
  border: 1px solid var(--color-accent-text);
  border-radius: var(--radius-md);
}

/* Historienzeile: Einmalcodes und abgeschaltete Links. Kein Kartenrand -- die Historie ist
   Nachschlagewerk, keine Handlungsflaeche. */
.invite-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--color-border);
}

.invite-row-text {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  /* Ohne das wachsen lange Mailadressen ueber die Zeile hinaus, statt zu kuerzen. */
  min-width: 0;
}

.invite-row .invite-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Abschnittsueberschrift zwischen zwei Listen. Wie .field-label, aber mit Luft darueber. */
.invite-section {
  margin-top: 1.4rem;
}

.invite-code {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.06em;
}

.invite-code.is-spent {
  color: var(--color-text-muted);
  text-decoration: line-through;
}

.invite-link {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.82rem;
  font-weight: 500;
  line-height: 1.45;
  /* Ein Link hat keine Wortgrenzen, an denen er von selbst umbrechen wuerde. */
  overflow-wrap: anywhere;
}

.invite-row .invite-link {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.status-pill {
  padding: 0.12rem 0.5rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 0.7rem;
  font-weight: 600;
  white-space: nowrap;
}

.status-pill.is-offen {
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  border-color: var(--color-accent-text);
}

.status-pill.is-eingeloest {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}

.status-pill.is-abgelaufen {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

/* Gedaempft wie "eingeloest", aber ohne Durchstreichen: Abgeschaltet ist umkehrbar,
   durchgestrichen sieht endgueltig aus. */
.status-pill.is-deaktiviert {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}

.invite-meta {
  font-size: 0.76rem;
  color: var(--color-text-muted);
}

/* --- Wer hat sich ueber den Link angemeldet ------------------------------- */

/* Der Ausloeser sitzt an der Stelle der Meta-Zeile und soll auch so aussehen: kein Knopf,
   sondern der Text, der schon dort stand, plus ein Chevron. Ein zweiter Knopf neben "Link
   kopieren" waere in der Hero-Karte eine zweite Hauptaktion, die es nicht ist. */
.invite-disclosure {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  max-width: 100%;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-size: 0.76rem;
  color: var(--color-text-muted);
  text-align: left;
  cursor: pointer;
}

.invite-disclosure > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.invite-disclosure:hover {
  color: var(--color-text);
}

/* Die Meta-Zeile der Hero-Karte: "Gueltig bis ..." bleibt Text, nur die Zahl der Konten ist
   klickbar. Umbrechen darf sie, ein Datum und eine Zahl passen nicht immer nebeneinander. */
.invite-meta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
}

.invite-chevron {
  width: 0.85rem;
  height: 0.85rem;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}

.invite-disclosure[aria-expanded="true"] .invite-chevron {
  transform: rotate(180deg);
}

/* Eingerueckt und mit Linie an der linken Kante: Die Namen gehoeren zu der Zeile darueber,
   nicht in die Liste der Einladungen. */
.invite-uses {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin: 0.1rem 0 0.5rem 0.2rem;
  padding: 0.45rem 0 0.15rem 0.7rem;
  border-left: 2px solid var(--color-border);
}

.invite-use {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
}

.invite-use-name {
  font-size: 0.82rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Ein geloeschtes Konto hat keine Adresse mehr -- der Platzhalter soll nicht wie eine aussehen. */
.invite-use-name.is-gone {
  color: var(--color-text-muted);
  font-style: italic;
}

/* Nur das Datum in einer Namenszeile darf nicht umbrechen -- die Meldungen der Liste
   ("Wird geladen ...", ein Fehler) sollen es sehr wohl. */
.invite-use .invite-meta {
  white-space: nowrap;
  flex-shrink: 0;
}

/* .empty-hint ist fuer eine leere Ansicht gemacht und bringt dafuer Luft mit; in einer
   aufgeklappten Zeile ist es nur eine Zeile Text neben zwei anderen. */
.invite-uses .empty-hint {
  padding: 0;
  font-size: 0.82rem;
}

.ghost-button {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.42rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text);
  font: inherit;
  font-size: 0.8rem;
  font-weight: 500;
}

.ghost-button svg {
  width: 14px;
  height: 14px;
}

.ghost-button.is-danger {
  color: var(--color-negative);
}

/* Im Einladungs-Sheet folgen Anzeige, Knopf, Hinweis und Abschluss unmittelbar aufeinander --
   ohne diesen Abstand kleben sie aneinander. Die Chip-Reihen bringen ihren eigenen mit. */
.invite-sheet > .code-reveal,
.invite-sheet > .primary-button,
.invite-sheet > .ghost-button {
  margin-top: 0.75rem;
}

/* Eine Notiz in Notice-Farben: nennt eine Bedingung oder einen Fehlschlag, ist also kein
   Beiwerk, aber auch kein Fehler. Entstand fuer den Hinweis aufs Domain-Passwort im
   "Link erstellt"-Sheet; der ist mit der Basic Auth am 2026-09-02 entfallen, die Klasse traegt
   seither die Meldungen ueber den Admin-Listen (Variante .is-top unten). */
.invite-note {
  margin-top: 0.75rem;
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-sm);
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.77rem;
  line-height: 1.45;
}

/* Dieselbe Notiz ueber der Liste statt unter einem Knopf: eine Aktion ist gescheitert, der
   Inhalt darunter stimmt aber weiterhin. */
.invite-note.is-top {
  margin-top: 0;
  margin-bottom: 1rem;
}

.primary-button {
  width: 100%;
  padding: 0.7rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
}

/* Der frisch erzeugte Code. Gestrichelter Rand, weil er noch nirgends hingehört –
   er wartet darauf, kopiert zu werden. */
.code-reveal {
  padding: 0.8rem;
  border: 1px dashed var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  text-align: center;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 1.2rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

/* Ein Link statt eines Codes: kleiner, ohne Sperrung und umbruchfaehig -- gesperrte Schrift
   hilft beim Abtippen, und ein Link wird nicht abgetippt. */
.code-reveal.is-link {
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
   Nutzerverwaltung (Mehr -> Administration -> Nutzer, siehe js/ui/admin-users-view.js)

   ACHTUNG, Namensraum: .account-row/.account-list/.account-badge weiter oben gehoeren den
   BANKKONTEN ("Mehr -> Konten verwalten"). In Finanzblick ist ein "Konto" das Girokonto --
   die Zugaenge zur App heissen hier durchgaengig .user-*, und der Screen heisst "Nutzer".
   --------------------------------------------------------------------------- */

.user-list {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.user-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 56px;
  padding: 0.6rem 0.8rem;
  border: none;
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
}

.user-row + .user-row {
  border-top: 1px solid var(--color-border);
}

.user-row:focus-visible {
  outline: 2px solid var(--color-accent-text);
  outline-offset: -2px;
}

/* Ohne min-width: 0 schiebt eine lange Mailadresse die Statuspille aus der Zeile, statt selbst
   zu kuerzen -- flex-Kinder duerfen von sich aus nicht unter ihre Inhaltsbreite. */
.user-row-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.user-row-mail {
  font-size: 0.87rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Zwei Angaben, nicht drei: Datensatzzahl (wird der Zugang ueberhaupt benutzt) und der Zustand,
   der gerade zaehlt. Mehr passt in 390 px nicht daneben und steht im Steckbrief. */
.user-row-meta {
  font-size: 0.74rem;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Abgeschaltete und gesperrte Zugaenge bleiben lesbar, treten aber zurueck -- sie sind der
   Ausnahmefall, nicht der Fehlerfall. */
.user-row.is-inaktiv .user-row-mail {
  color: var(--color-text-muted);
}

.user-row-chevron {
  color: var(--color-text-muted);
  flex-shrink: 0;
}

/* Admin ist ein Merkmal, kein Zustand -- deshalb keine zweite Pille neben der rechten, sondern
   das erste Glied der Metazeile. Und bewusst kein Kaestchen wie .client-tag: ein inline-block in
   einer Zeile mit text-overflow wird beim Kuerzen angeschnitten statt weggelassen, und die Zeile
   sieht dann kaputt aus statt gekuerzt. */
.user-badge {
  color: var(--color-accent-text);
  font-weight: 600;
}

/* Zwei Zustaende neben den .status-pill-Varianten der Einladungen weiter oben. "Aus" nutzt die
   bestehende .is-deaktiviert. */
.status-pill.is-aktiv {
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  border-color: var(--color-accent-text);
}

.status-pill.is-gesperrt {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

/* Abschnittsueberschrift im Steckbrief. Wie .field-label, aber mit Luft darueber -- sie trennt
   zwei Bloecke, statt ein Eingabefeld zu beschriften. */
.section-label {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  margin: 1.1rem 0.2rem 0.4rem;
}

/* Roter Rand statt roter Flaeche: Eine Flaeche zoege den Blick auf den Abschluss des Screens,
   obwohl hier fast nie etwas zu tun ist. Der Rand markiert, ohne zu rufen. */
.danger-zone {
  margin-top: 1.25rem;
  padding: 0.9rem;
  border: 1px solid var(--color-negative);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.danger-zone-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-negative);
}

.danger-zone-hint {
  font-size: 0.76rem;
  color: var(--color-text-muted);
  line-height: 1.4;
}

.danger-button {
  width: 100%;
  min-height: 44px;
  border: 1px solid var(--color-negative);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-negative);
  font: inherit;
  font-size: 0.9rem;
  font-weight: 500;
}

.danger-button:focus-visible {
  outline: 2px solid var(--color-negative);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   Anmelde-Screen (siehe js/ui/login-view.js)

   Er liegt nicht im View-Container, sondern daneben: Solange er steht, gibt es weder Datenbank
   noch Router. Deshalb schaltet er die App per data-gate am body komplett weg statt sie nur zu
   überdecken – eine halb sichtbare, leere App im Hintergrund sähe aus wie ein Ladefehler.

   Dunkler Kopf, helle Karte: derselbe Kontrast wie bei den Pop-Flächen der App
   (--color-pop-bg), damit der erste Moment nach Finanzblick aussieht und nicht nach Formular.
   --------------------------------------------------------------------------- */

/* Drei Werte, ein Verhalten: "login" und "onboarding" gehören ihrem Screen, "start" steht von
   Anfang an im Markup (siehe index.html) und liegt, bis feststeht, welcher der drei Fälle gilt;
   weggenommen wird er in js/app.js. Der <noscript>-Hinweis steht bewusst NICHT in dieser Liste –
   ohne JavaScript bleibt er das Einzige, was zu sehen ist. */
body[data-gate="start"] .app-header,
body[data-gate="start"] .app-nav,
body[data-gate="start"] #view-container,
body[data-gate="start"] .demo-banner,
body[data-gate="start"] #erste-schritte-streifen-mount,
body[data-gate="start"] #sync-banner-mount,
body[data-gate="login"] .app-header,
body[data-gate="login"] .app-nav,
body[data-gate="login"] #view-container,
body[data-gate="login"] .demo-banner,
body[data-gate="login"] #erste-schritte-streifen-mount,
body[data-gate="login"] #sync-banner-mount,
body[data-gate="onboarding"] .app-header,
body[data-gate="onboarding"] .app-nav,
body[data-gate="onboarding"] #view-container,
body[data-gate="onboarding"] .demo-banner,
body[data-gate="onboarding"] #erste-schritte-streifen-mount,
body[data-gate="onboarding"] #sync-banner-mount {
  display: none;
}

/* Kein eigener Screen, nur ein Satz: Ohne JavaScript gibt es nichts zu bedienen. Trägt seine
   Farben selbst, weil zu diesem Zeitpunkt kein Skript ein Theme gesetzt hat – die Tokens greifen
   trotzdem, sie stehen in :root und in der prefers-color-scheme-Abfrage. */
.noscript-hinweis {
  display: block;
  margin: 24px;
  padding: 16px;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  text-align: center;
}

.login-screen {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  background: var(--color-pop-bg);
  color: var(--color-pop-text);
}

.login-screen[hidden] {
  display: none;
}

.login-hero {
  flex: 0 0 auto;
  padding: 4.5rem 1.5rem 2rem;
}

.login-brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
}

.login-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--radius-sm);
  background: var(--color-pop-text);
  color: var(--color-pop-bg);
}

.login-mark svg {
  width: 1.3rem;
  height: 1.3rem;
}

.login-name {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.login-claim {
  margin: 1.6rem 0 0;
  font-size: 1.8rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.login-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 0 1.1rem 2.5rem;
}

.login-card {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 1.1rem;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}

.login-card-lead {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
}

.login-hint {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--color-text-muted);
}

.login-status {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* Auf Formular-Ebene, zwischen letztem Feld und Knopf – und ohne rot gefärbtes Feld: Der Server
   sagt bewusst nicht, welcher der beiden Werte falsch ist (siehe api/login.php). Ein markiertes
   Passwortfeld würde etwas behaupten, das die App nicht weiß. */
.login-error {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--color-negative);
}

.login-error svg {
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  margin-top: 0.08rem;
}

/* Der Lagebericht über der Karte ("Diese Sitzung wurde beendet") – keine Eingabeprüfung, und
   deshalb bewusst außerhalb des Formulars. */
.login-notice {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 0;
  padding: 0.8rem 0.9rem;
  border-radius: var(--radius-sm);
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.85rem;
  line-height: 1.4;
}

.login-notice svg {
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  margin-top: 0.08rem;
}

.login-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
}

.login-button-primary {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
}

.login-button:disabled {
  opacity: 0.6;
  cursor: default;
}

.login-button-quiet {
  min-height: 2.4rem;
  border: 0;
  background: none;
  color: var(--color-accent-text);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
}

.login-foot {
  margin: 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--color-pop-text-muted);
}

.login-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-pop-text);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
}

@media (min-width: 640px) {
  .login-hero,
  .login-body {
    width: 100%;
    max-width: 26rem;
    margin: 0 auto;
  }
}

/* ---------------------------------------------------------------------------
   Onboarding-Ablauf (siehe js/ui/onboarding-view.js)

   Läuft wie #login-screen außerhalb des Routers, aber erst NACH FB.Storage.init()/FB.Nav.init() –
   das (leere) Dashboard steht zu diesem Zeitpunkt schon dahinter, FB.Onboarding blendet es beim
   Abschluss nur wieder ein (FB.Nav.refreshCurrent), statt neu zu laden. Anders als der
   Anmelde-Screen bewusst OHNE den dunklen "Pop"-Kontrast: der Ablauf soll sich wie ein Teil der
   App anfühlen, nicht wie ein vorgeschaltetes Formular.

   DREI FESTE ZONEN, und daran hängt alles Weitere (Entwurf: Notizen/Mockups/onboarding-rahmen.html,
   2026-08-28). Der Screen besteht immer aus .onboarding-kopf (44px, auch leer), .onboarding-inhalt
   (wächst, scrollt bei Bedarf INNEN) und .onboarding-fuss (die Aktionen). Vorher regelten das
   .onboarding-spacer-Elemente, die jeder Screen anders setzte – Titel und Knöpfe wanderten dadurch
   bei jedem Schritt an eine andere Stelle. Es gibt deshalb keinen Spacer mehr: wer einen einführt,
   holt sich das Springen zurück.

   Zweiter Grund für eigene Klassen statt geliehener: Die Kopfzeile benutzte .sheet-topbar und
   .mapping-step-label aus dem Bank-Zuordnungs-Dialog, die Zentrierung galt aber .onboarding-topbar
   – eine Klasse, die im Markup nirgends stand. Der Fortschrittsbalken klebte am Fensterrand,
   während der Inhalt mittig saß. Kopf, Inhalt und Fuß teilen sich jetzt dieselbe max-width.

   Ausrichtung ist eine Regel, keine Laune: mittig steht, was man ansieht (Willkommen, Bilanz –
   .onboarding-mitte), linksbündig, was man tut (Bank, Anleitung, Datei).
   --------------------------------------------------------------------------- */

.onboarding-screen {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  /* hidden, nicht auto: gescrollt wird innerhalb von .onboarding-inhalt, sonst wandert die
     Fußzone aus dem Bild. */
  overflow: hidden;
  background: var(--color-bg);
  color: var(--color-text);
}

.onboarding-screen[hidden] {
  display: none;
}

/* ---- Zone 1: Kopf ---- */

.onboarding-kopf {
  flex: 0 0 auto;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 0.4rem;
}

.onboarding-kopf-knopf {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: none;
  color: var(--color-text);
  cursor: pointer;
}

.onboarding-kopf-knopf.leise {
  color: var(--color-text-muted);
}

/* Nicht display:none – der Platz muss stehen bleiben, sonst rutschen die Punkte aus der Mitte. */
.onboarding-kopf-knopf.unsichtbar {
  visibility: hidden;
}

.onboarding-kopf-knopf svg {
  width: 22px;
  height: 22px;
}

/* Drei Punkte statt Balken plus Textzeile "Schritt 1 von 3": der aktive wird zur Pille. Sie
   erscheinen nur auf den drei Sammel-Schritten – Willkommen ist der Umschlag, die Bilanz das
   Ergebnis. Sonst stünde der Balken bei Schritt 3 auf 100 %, obwohl noch zwei Screens folgen. */
.onboarding-dots {
  display: flex;
  align-items: center;
  gap: 0.36rem;
}

.onboarding-dots i {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--color-border);
  transition: width 0.18s ease;
}

.onboarding-dots i.on {
  width: 20px;
  background: var(--color-accent-text);
}

/* ---- Zone 2: Inhalt ---- */

.onboarding-inhalt {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  padding: 0.5rem 1.25rem 0;
}

/* ---- Zone 3: Fuß ---- */

.onboarding-fuss {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.7rem 1.25rem 1.6rem;
}

@media (min-width: 640px) {
  .onboarding-kopf,
  .onboarding-inhalt,
  .onboarding-fuss {
    width: 100%;
    max-width: 30rem;
    margin: 0 auto;
  }
}

/* ---- Gemeinsame Bausteine ---- */

/* Der Block sitzt senkrecht mittig zwischen Kopf und Fuß (Willkommen und Bilanz). Bewusst
   `margin: auto 0` statt `justify-content: center` am Elternteil: Wird der Inhalt höher als
   der Platz, schneidet die zentrierende Variante oben ab, statt scrollbar zu bleiben. */
.onboarding-block {
  display: flex;
  flex-direction: column;
  margin: auto 0;
}

/* Überschrift und Vorspann stehen in einem mittigen Block mittig – die Inhalte darunter
   (Schritte, Punkte, Bilanzzeilen) bleiben linksbündig, damit ihre Icons untereinander stehen. */
.onboarding-block > .onboarding-title,
.onboarding-block > .onboarding-lead {
  text-align: center;
}

.onboarding-title {
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0 0 0.5rem;
  text-align: left;
}

.onboarding-lead {
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--color-text-muted);
  margin: 0 0 1.6rem;
  text-align: left;
}

.onboarding-mitte,
.onboarding-mitte .onboarding-title,
.onboarding-mitte .onboarding-lead {
  text-align: center;
}

/* ---- Screen 1: Willkommen ---- */

.onboarding-hero-icon {
  display: flex;
  justify-content: center;
  margin: 0 0 1.3rem;
  color: var(--color-accent-text);
}

.onboarding-hero-icon svg {
  width: 2.9rem;
  height: 2.9rem;
}

/* Drei einzeilige Versprechen. Die frühere Fassung hatte je Zeile noch einen Untertitel – das war
   der größte Textblock des ganzen Ablaufs, für den Screen, der am wenigsten zu sagen hat. */
.onboarding-punkte {
  display: flex;
  flex-direction: column;
  gap: 1.15rem;
  max-width: 20rem;
  margin-inline: auto;
  text-align: left;
}

.onboarding-punkt {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  font-size: 0.95rem;
  font-weight: 500;
}

.onboarding-punkt-icon {
  flex: 0 0 auto;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: var(--radius-sm);
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  display: flex;
  align-items: center;
  justify-content: center;
}

.onboarding-punkt-icon svg {
  width: 1.1rem;
  height: 1.1rem;
}

/* ---- Screen 2: Bankauswahl ---- */

.onboarding-suche {
  width: 100%;
  height: 2.8rem;
  flex: 0 0 auto;
  padding: 0 0.8rem;
  margin-bottom: 0.7rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-size: 0.9rem;
}

/* Die Liste scrollt in sich, damit der Screen selbst stillsteht. */
.onboarding-bankliste {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.onboarding-bank-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  height: 3.3rem;
  padding: 0 0.8rem;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  background: none;
  color: var(--color-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.onboarding-bank-row:last-child {
  border-bottom: none;
}

.onboarding-bank-mono {
  flex: 0 0 auto;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.62rem;
  font-weight: 700;
}

.onboarding-bank-name {
  flex: 1;
  min-width: 0;
  font-size: 0.95rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.onboarding-bank-chevron {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  color: var(--color-text-muted);
}

.onboarding-leer {
  padding: 1.4rem 1rem;
  text-align: center;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--color-text-muted);
}

/* ---- Screen 3: Anleitung ---- */

/* Das Bank-Zeichen steht ÜBER dem Titel, nicht daneben: daneben blieben dem Titel ~250px, er
   brach zweizeilig um und sah aus wie ein Satzfehler. */
.onboarding-anleitung-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  margin-bottom: 0.7rem;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--color-text-muted);
}

.onboarding-anleitung-head .onboarding-bank-mono {
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 0.5rem;
  font-size: 0.55rem;
}

.onboarding-schritte {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 20rem;
  margin-inline: auto;
}

.onboarding-schritt {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
}

.onboarding-schritt-nr {
  flex: 0 0 auto;
  width: 1.7rem;
  height: 1.7rem;
  margin-top: 0.05rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.78rem;
  font-weight: 700;
}

.onboarding-schritt-text {
  font-size: 0.92rem;
  line-height: 1.5;
}

/* Fußnote, keine Warnung – deshalb eine leise Zeile statt einer eingefärbten Karte. */
.onboarding-hinweis {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  max-width: 20rem;
  margin-inline: auto;
  margin-top: 1.4rem;
  font-size: 0.84rem;
  line-height: 1.45;
  color: var(--color-text-muted);
}

.onboarding-hinweis svg {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  margin-top: 0.15rem;
}

/* ---- Screen 4: Datei ---- */

.onboarding-dropzone {
  flex: 0 0 auto;
  height: 14.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  border: 1.5px dashed var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.onboarding-dropzone.is-dragover {
  border-color: var(--color-accent-text);
  background: var(--color-chip-bg);
}

.onboarding-dropzone > svg {
  width: 2rem;
  height: 2rem;
  margin-bottom: 0.45rem;
  color: var(--color-accent-text);
}

.onboarding-dropzone-titel {
  font-size: 0.98rem;
  font-weight: 600;
}

.onboarding-dropzone-sub {
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.onboarding-dropzone-formate {
  margin-top: 0.7rem;
  padding: 0.22rem 0.6rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.68rem;
  font-weight: 600;
}

/* Zentriert, obwohl der Screen sonst linksbündig ist: die Fußnote gehört zur Dropzone, und die
   ist ein mittiges Objekt. Linksbündig darunter hinge sie in der Luft. */
.onboarding-fussnote {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1rem;
  font-size: 0.84rem;
  color: var(--color-text-muted);
}

.onboarding-fussnote svg {
  flex: 0 0 auto;
  width: 0.95rem;
  height: 0.95rem;
}

.onboarding-status {
  margin-top: 1rem;
  text-align: center;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.onboarding-fehler {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: 1rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--color-negative);
}

.onboarding-fehler svg {
  flex: 0 0 auto;
  width: 1rem;
  height: 1rem;
  margin-top: 0.1rem;
}

/* ---- Screen 5: Bilanz ---- */

.onboarding-ergebnis {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin: 0 0 1.3rem;
}

.onboarding-ergebnis > svg {
  width: 6.5rem;
  height: 6.5rem;
  margin-bottom: 0.5rem;
}

.onboarding-ergebnis .onboarding-title {
  font-size: 1.3rem;
  text-align: center;
  margin-bottom: 0.35rem;
}

.onboarding-ergebnis .onboarding-lead {
  text-align: center;
  margin-bottom: 0;
}

/* Die Zeilen bleiben linksbündig, damit die Icons untereinander stehen; mittig wirkt der
   Block über die schmale, zentrierte Liste. */
.onboarding-bilanz-liste {
  max-width: 20rem;
  margin-inline: auto;
}

.onboarding-bilanz-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  min-height: 3.4rem;
  padding: 0.5rem 0.1rem;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.95rem;
  font-weight: 500;
}

.onboarding-bilanz-row:last-child {
  border-bottom: none;
}

/* Geräteliste unter "Konto & Sync". Das eigene Gerät bekommt keinen Knopf, sondern ein
   Merkzeichen – wer sich selbst abmeldet, hat sich vertan, nicht entschieden. */
.device-chip {
  flex: 0 0 auto;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-text-muted);
  font-size: 0.72rem;
  font-weight: 600;
  white-space: nowrap;
}

.device-action {
  flex: 0 0 auto;
  padding: 0.35rem 0.6rem;
  border: 0;
  background: none;
  color: var(--color-negative);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}

.device-action:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ---------------------------------------------------------------------------
   Konto & Sync (js/ui/manage-account-view.js)

   Der Screen berichtet vor allem: oben, wer man ist, darunter, wie es um den Abgleich steht.
   Alles Seltene liegt eine Ebene tiefer hinter einem Chevron. Die Bausteine hier sind genau
   die, die es dafuer zusaetzlich braucht -- Zeilen, Karten und Knoepfe kommen unveraendert aus
   dem Settings-Baukasten weiter oben.
   --------------------------------------------------------------------------- */

/* Freier Inhalt in einer settings-card -- Formularfelder, Absaetze. Ohne diesen Rahmen liegen
   sie buendig am Kartenrand, weil .settings-card selbst keinen Innenabstand hat (ihre Zeilen
   bringen ihren eigenen mit). */
.settings-card-body {
  padding: 0.9rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Der erklaerende Satz schliesst die Karte ab, statt sie in der Mitte zu teilen. */
.settings-card-foot {
  padding: 0.7rem 1rem 0.8rem;
  border-top: 1px solid var(--color-border);
  font-size: 0.75rem;
  color: var(--color-text-muted);
}

/* Knoepfe ueber die volle Kartenbreite, abgesetzt durch eine Trennlinie. Untereinander statt
   nebeneinander: Auf einem Handy passen zwei Beschriftungen wie "Serverstand ersetzen" nicht in
   eine Zeile, ohne umzubrechen. */
.settings-card-action {
  padding: 0.75rem 1rem 0.85rem;
  border-top: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.settings-card-action .rule-dialog-button {
  width: 100%;
}

/* Rechtsbuendiger Wert in einer Listenzeile (Geraetezahl). */
.settings-list-item-value {
  flex: 0 0 auto;
  font-size: 0.82rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- Identitaetskopf --- */

.account-identity {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  padding: 1rem;
}

.account-avatar {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.account-identity-text {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.account-identity-mail {
  font-size: 0.9rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-pill {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-size: 0.7rem;
  font-weight: 500;
}

.account-pill svg {
  width: 11px;
  height: 11px;
  flex-shrink: 0;
}

/* --- Abgleich-Karte --- */

.sync-card {
  padding: 1.05rem 1rem 0.95rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.sync-card-top {
  display: flex;
  align-items: center;
  gap: 0.8rem;
}

/* Der Zustand als Form, nicht nur als Satz: gruen nur, wenn wirklich alles uebertragen ist. */
.sync-ring {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--color-positive) 16%, transparent);
  color: var(--color-positive);
}

.sync-ring svg {
  width: 22px;
  height: 22px;
}

/* Ein Zustand, der weder gut noch schlecht ist: Es wartet etwas, das von allein weggeht.
   Gruen waere gelogen, Warnfarbe uebertrieben. */
.sync-ring.is-quiet {
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
}

.sync-ring.is-notice {
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
}

.sync-ring.is-danger {
  background: color-mix(in srgb, var(--color-negative) 15%, transparent);
  color: var(--color-negative);
}

.sync-ring.is-running svg {
  animation: button-spinner-spin 1.4s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .sync-ring.is-running svg {
    animation: none;
  }
}

.sync-card-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.sync-head {
  font-size: 1rem;
  font-weight: 600;
}

.sync-sub {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* Drei Kennzahlen unter dem Zustand. Sie beantworten die Frage, die der Satz darueber offen
   laesst: wie viel haengt eigentlich daran? */
.sync-meta {
  display: flex;
  border-top: 1px solid var(--color-border);
  padding-top: 0.75rem;
}

.sync-meta-cell {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  min-width: 0;
}

.sync-meta-cell + .sync-meta-cell {
  border-left: 1px solid var(--color-border);
  padding-left: 0.75rem;
}

.sync-meta-key {
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
}

.sync-meta-value {
  font-size: 0.86rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* Waehrend eines langen Durchlaufs an der Stelle der Kennzahlen. Nur beim Senden gefuellt --
   beim Abrufen nennt der Server keine Gesamtzahl, dort bleibt es bei der laufenden Zahl im
   Untertitel (siehe FB.Sync.status().fortschritt). */
.sync-progress {
  height: 4px;
  border-radius: 999px;
  background: var(--color-chip-bg);
  overflow: hidden;
}

.sync-progress span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--color-accent);
  transition: width 0.3s ease;
}

/* Erste Schritte (siehe js/ui/erste-schritte-view.js)
   ---------------------------------------------------
   Zwei Orte: der STREIFEN unter dem App-Header und der Screen unter "Mehr -> Erste Schritte".
   Es steht immer genau EIN Punkt im Fokus, mit Grund und Weg; ein Antippen oeffnet dessen Guide.
   (Entwuerfe: Notizen/Mockups/erste-schritte-guide*.html, erste-schritte-sichtbarkeit.html)

   Bis 2026-08-31 stand statt des Streifens eine KARTE im Dashboard, zwischen Hero-Karte und
   Donut. Sie ist ersatzlos entfallen, weil sie genau das Material der uebrigen Dashboard-Karten
   trug -- --color-surface, --radius-md, dieselbe Polsterung, dazu ein Akzentrand als einziger
   Unterschied -- und dadurch als "noch eine Karte" gelesen wurde statt als Fuehrung. Zwei Folgen
   davon, beide Absicht:

     - Der Streifen liegt AUSSERHALB jeder View, auf der Ebene von Demo- und Sync-Banner. Er kann
       damit nicht mehr mit den Karten einer Ansicht verwechselt werden -- und er steht in JEDEM
       Screen, auch in "Vertraege" und "Mehr", wohin die Haelfte der Punkte fuehrt.
     - Er ist EINE Zeile und bleibt es. Der Aufgabentext kuerzt lieber, als den Streifen
       zweizeilig werden zu lassen; eine zweite Zeile waere wieder eine kleine Karte. */

.es-streifen {
  display: flex;
  align-items: center;
  /* Mittig statt linksbuendig: Der Streifen liegt auf der Ebene von Demo- und Sync-Banner,
     und das Demo-Banner darueber zentriert ebenso. Auf einem breiten Fenster klebte der Text
     sonst am linken Rand, waehrend das Chevron am rechten stand -- zwei Enden ohne sichtbaren
     Zusammenhang. Zentriert wird die GRUPPE aus Punkten, Text und Chevron, nicht der Text
     allein: Die drei gehoeren zusammen und behalten so einen gemeinsamen Bezugspunkt. Auf dem
     Handy aendert das nichts, dort fuellt die Gruppe die Zeile ohnehin aus. */
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-chip-bg);
  color: var(--color-text);
  text-align: left;
  font: inherit;
  padding: 0.55rem 1.25rem;
  min-height: 44px;
  cursor: pointer;
}

.es-streifen:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* Fortschritt als Punktreihe, nicht als Ring: Der Streifen ist 44 px hoch und traegt links
   ohnehin schon eine Marke -- ein Ring mit Bruch daneben braeuchte die doppelte Breite. */
.es-punkte {
  display: inline-flex;
  gap: 3px;
  flex: 0 0 auto;
}

.es-punkt {
  width: 5px;
  height: 5px;
  border-radius: 999px;
  /* Offene Punkte trugen bis 2026-08-31 --color-border und verschwanden damit auf dem
     --color-chip-bg des Streifens fast vollstaendig: Sichtbar blieben nur die gruenen, die
     Reihe las sich als zusammenhanglose Luecke statt als "2 von 6". Der gedaempfte Textton
     traegt genug Kontrast, um die Gesamtzahl zu zeigen, ohne mit den erledigten zu
     konkurrieren. */
  background: color-mix(in srgb, var(--color-text-muted) 45%, transparent);
}

.es-punkt.is-erledigt {
  background: var(--color-accent);
}

.es-punkt.is-aktiv {
  background: var(--color-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 22%, transparent);
}

/* Wartet der Punkt auf eine Voraussetzung (Ruecklage ohne bestaetigte Vertraege), verliert der
   aktive Punkt seinen Akzent: Was auf etwas anderes wartet, ist keine Aufforderung. */
.es-streifen.is-wartend .es-punkt.is-aktiv {
  background: var(--color-text-muted);
  box-shadow: none;
}

.es-streifen.is-wartend .es-streifen-marke {
  color: var(--color-text-muted);
}

.es-streifen-text {
  /* Nicht flex: 1 -- der Text soll nur so breit sein, wie er ist, damit die Gruppe als Ganzes
     in der Mitte steht. Schrumpfen (und damit kuerzen) darf er weiterhin. */
  flex: 0 1 auto;
  min-width: 0;
  font-size: 0.83rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.es-streifen-marke {
  color: var(--color-accent-text);
  font-weight: 600;
}

.es-streifen > svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

/* --- Fortschritt im Screen ----------------------------------------------------------------- */

.es-fortschritt {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.es-zaehler {
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
  font-weight: 500;
}

.es-balken {
  height: 5px;
  border-radius: 999px;
  background: var(--color-chip-bg);
  overflow: hidden;
  margin: 0.5rem 0 1rem;
}

.es-balken i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--color-accent);
  transition: width 0.3s ease;
}

/* --- Der Guide im Screen -------------------------------------------------------------------- */

.es-fokus {
  background: var(--color-surface);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  padding: 0.9rem 0.95rem 1rem;
  margin-bottom: 1rem;
}

/* Erledigt und wartend brauchen keinen Akzent: Beides ist kein offener Auftrag. */
.es-fokus.is-erledigt,
.es-fokus.is-wartend {
  border-color: var(--color-border);
}

.es-fokus-eyebrow {
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin-bottom: 0.25rem;
}

.es-fokus-stand {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-positive);
  margin-bottom: 0.25rem;
}

.es-fokus-stand svg {
  width: 13px;
  height: 13px;
}

.es-fokus-titel {
  font-size: 1.05rem;
  font-weight: 600;
  margin-bottom: 0.7rem;
}

.es-guide-warum {
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--color-text);
  margin-bottom: 0.9rem;
}

.es-fokus.is-erledigt .es-guide-warum {
  color: var(--color-text-muted);
}

/* Nummernkreise per CSS-Counter statt getippter Ziffern: Faellt ein Schritt weg oder kommt einer
   dazu, stimmt die Nummerierung ohne Zutun. */
.es-guide-schritte {
  list-style: none;
  counter-reset: es-schritt;
  margin-bottom: 0.9rem;
}

.es-guide-schritte li {
  counter-increment: es-schritt;
  position: relative;
  padding: 0 0 0 1.85rem;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--color-text-muted);
}

.es-guide-schritte li + li {
  margin-top: 0.6rem;
}

.es-guide-schritte li::before {
  content: counter(es-schritt);
  position: absolute;
  left: 0;
  top: 0.05rem;
  width: 1.25rem;
  height: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 0.7rem;
  font-weight: 600;
}

.es-guide-schritte strong,
.es-guide-warum strong {
  color: var(--color-text);
  font-weight: 500;
}

.es-guide-aktion {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  min-height: 46px;
  padding: 0 0.8rem;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-accent-contrast);
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
}

.es-guide-aktion svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

/* Erledigt wird aus dem Auftrag ein Angebot -- also ein Chip statt der vollen Flaeche. */
.es-guide-nachlegen {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: none;
  border-radius: 999px;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.45rem 0.85rem;
  min-height: 40px;
  cursor: pointer;
}

.es-guide-nachlegen svg {
  width: 14px;
  height: 14px;
}

/* Das Abhaken von Hand: bewusst zurueckgenommen und unter einer Haarlinie. Es ist die Ausnahme
   fuer Punkte, die zu jemandem nicht passen -- frueher lag es auf der Zeile selbst und damit auf
   der naheliegendsten Geste. */
.es-guide-manuell {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  margin-top: 0.85rem;
  padding-top: 0.8rem;
  border: none;
  border-top: 1px solid var(--color-border);
  background: none;
  font: inherit;
  font-size: 0.8rem;
  color: var(--color-text-muted);
  text-align: left;
  cursor: pointer;
  min-height: 44px;
}

.es-guide-manuell svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
}

/* --- Die uebrigen Punkte --------------------------------------------------------------------- */

.es-rest-titel {
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin: 0 0 0.15rem 0.1rem;
}

.es-liste {
  list-style: none;
}

.es-zeile {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: 100%;
  padding: 0.7rem 0.1rem;
  border: none;
  background: none;
  color: inherit;
  text-align: left;
  font: inherit;
  font-size: 0.88rem;
  line-height: 1.4;
  cursor: pointer;
  min-height: 48px;
  border-radius: var(--radius-sm);
}

.es-liste li + li .es-zeile {
  border-top: 1px solid var(--color-border);
  border-radius: 0;
}

.es-zeile:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* Der Punkt, dessen Guide gerade oben im Fokus steht. Bewusst nur ein schmaler Balken und etwas
   mehr Gewicht statt einer gefüllten Fläche -- die Liste soll ruhig bleiben und nicht mit der
   Fokus-Karte darüber um Aufmerksamkeit ringen. */
.es-zeile.is-aktiv {
  box-shadow: inset 2px 0 0 var(--color-accent);
  padding-left: 0.6rem;
}

.es-zeile.is-aktiv .es-titel {
  font-weight: 600;
  color: var(--color-text);
}

.es-box {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 19px;
  height: 19px;
  border: 1.5px solid var(--color-border);
  border-radius: 6px;
  color: var(--color-accent-contrast);
}

.es-box.is-erledigt {
  background: var(--color-positive);
  border-color: var(--color-positive);
}

.es-box svg {
  width: 12px;
  height: 12px;
}

.es-text {
  flex: 1;
  min-width: 0;
}

.es-titel {
  display: block;
}

.es-box.is-erledigt + .es-text .es-titel {
  color: var(--color-text-muted);
  text-decoration: line-through;
  text-decoration-color: var(--color-border);
  text-decoration-thickness: 1.5px;
}

.es-chevron {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.es-schalter {
  margin-top: 1rem;
}

.es-fussnote {
  margin-bottom: 1rem;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--color-text-muted);
}

/* Trefferliste im "Vertrag anlegen"-Dialog (js/ui/contract-form-dialog.js)
   -----------------------------------------------------------------------------------------
   Eigene, bewusst schmale Zeile statt der Buchungszeile der App: Datums-Chip und Auswahlring
   nebeneinander kosteten auf einem Handy so viel Breite, dass von Empfänger und Zweck kaum
   etwas übrig blieb. Der Zweck muss hier lesbar sein – bei über PayPal bezahlten Verträgen
   steht im Empfänger nur "PayPal", und 300 Zeilen sähen sonst identisch aus.

   Ausgewählt wird ohne Ankreuzfeld: die Karte selbst ist der Schalter (aria-pressed), der
   ausgewählte Zustand ist derselbe grüne Rahmen, den .is-highlighted in der
   Kategorie-Detailansicht schon für die Empfängerauswahl verwendet. */

.contract-match-count {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.7rem 0 0.4rem;
  font-size: 0.78rem;
  color: var(--color-text-muted);
}

.contract-match-count b {
  font-weight: 600;
  color: var(--color-text);
}

.contract-match-list {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-height: min(20rem, 45vh);
  overflow-y: auto;
}

/* Eine Zeile: links Name über Datum/Zweck, rechts Betrag über Auswahlhaken. Betrag und Haken
   stehen übereinander statt nebeneinander, weil sie sonst zusammen mit dem Datums-Chip eine
   dritte Spalte aufmachen und dem Text auf einem Handy die Breite nehmen. */
.contract-match-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  text-align: left;
  padding: 0.45rem 0.6rem;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  transition: border-color 0.12s ease;
}

.contract-match-row:hover,
.contract-match-row:focus-visible {
  border-color: var(--color-accent-text);
}

.contract-match-row:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--color-accent-text) inset;
}

/* Ein Treffer, der schon zu einem anderen Vertrag gehoert. Er bleibt sichtbar –
   ihn wegzufiltern hiesse, dem Nutzer "keine Buchung gefunden" zu sagen, waehrend
   zwoelf davon existieren – tritt aber deutlich zurueck und laesst sich nicht
   anhaken (TRANSACTION_CONTRACTS.transactionId ist eindeutig). Der leere Ring
   bleibt stehen statt zu verschwinden, sonst verrutschte die Zeile gegenueber
   ihren Nachbarn. */
.contract-match-row:disabled {
  background: transparent;
  border-style: dashed;
  color: var(--color-text-muted);
}

.contract-match-row:disabled .contract-match-name {
  font-weight: 500;
  color: var(--color-text-muted);
}

.contract-match-row:disabled .amount {
  color: var(--color-text-muted);
}

.contract-match-row:disabled .contract-match-mark {
  opacity: 0.4;
}

.contract-match-row.is-picked {
  border-color: var(--color-accent-text);
  background: color-mix(in srgb, var(--color-accent-text) 10%, var(--color-surface));
}

.contract-match-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.contract-match-name {
  font-size: 0.86rem;
  line-height: 1.25;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Nicht ausgewählte Treffer treten zurück, ohne unlesbar zu werden (kein opacity auf die
   ganze Zeile – der Betrag muss vergleichbar bleiben, um überhaupt auswählen zu können). */
.contract-match-row:not(.is-picked) .contract-match-name {
  font-weight: 500;
}

/* Datum und Verwendungszweck teilen sich eine einzige Zeile. Der Zweck ist der Grund, warum
   die Buchung überhaupt dasteht (bei PayPal der einzige Ort, an dem der Händler steht) – über
   zwei Zeilen umbrechend machte er die Liste aber so hoch, dass kaum drei Treffer gleichzeitig
   zu sehen waren. Wer mehr braucht, tippt die Buchung ohnehin nicht hier an. */
/* Flex-Zeile, weil links eine Pille stehen kann (siehe .contract-match-reason). Das Kuerzen
   uebernimmt deshalb .contract-match-rest und nicht mehr dieses Element selbst. */
.contract-match-meta {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  font-size: 0.76rem;
  line-height: 1.3;
  color: var(--color-text-muted);
}

/* min-width:0 ist Pflicht: Ein Flex-Kind schrumpft sonst nicht unter seine Textbreite und
   schiebt die Zeile aus der Karte heraus, statt zu kuerzen. */
.contract-match-rest {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Warum eine Buchung nicht ins erkannte Muster passt ("Betrag weicht ab", "ausser der Reihe").
   Notice-Farbe statt --color-negative: Rot heisst in dieser App "Ausgabe" und ueberall sonst
   "Fehler" – hier ist beides falsch. Die Buchung ist in Ordnung, sie passt nur nicht ins Muster;
   es ist eine Auskunft, keine Warnung.

   Die Pille steht VOR Datum und Zweck und verdraengt sie nicht: Bei einer ueber PayPal bezahlten
   Buchung ist der Zweck der einzige Ort, an dem der echte Haendler steht – ausgerechnet die
   erklaerungsbeduerftige Zeile darf ihn nicht verlieren. Sie schrumpft deshalb auch nicht mit. */
.contract-match-reason {
  flex-shrink: 0;
  padding: 0.08rem 0.4rem;
  border-radius: 999px;
  background: var(--color-notice-bg);
  color: var(--color-notice-text);
  font-size: 0.68rem;
  font-weight: 600;
}

.contract-match-side {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
}

.contract-match-side .amount {
  font-size: 0.86rem;
}

/* Der Haken. Im nicht ausgewählten Zustand bleibt der leere Ring stehen, statt zu
   verschwinden – sonst verrutschte die ganze Zeile bei jedem Antippen. */
.contract-match-mark {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  color: transparent;
}

.contract-match-mark svg {
  width: 0.62rem;
  height: 0.62rem;
}

.is-picked .contract-match-mark {
  border-color: var(--color-accent-text);
  background: var(--color-accent-text);
  color: var(--color-surface);
}

/* ===========================================================================
   Vertrag anlegen — zweischrittiges Bottom-Sheet (js/ui/contract-form-dialog.js)
   Entwurf: Notizen/Mockups/vertrag-anlegen-b-final.html. Das umgebende <dialog>
   trägt .category-sheet-dialog (Rundung, Polsterung, von unten hochfahrend) und
   scrollt selbst; die Bausteine hier sitzen darin.
   =========================================================================== */

.contract-sheet-sub {
  margin-bottom: 0.7rem;
}

/* Der Primärknopf steht direkt unter der Liste bzw. den Treffern und braucht
   etwas Luft nach oben — .sheet-btn selbst bringt keine mit. */
.contract-sheet-primary {
  margin-top: 1rem;
}

.sheet-btn.primary[disabled] {
  opacity: 0.45;
}

/* --- Schritt 1: das eine Feld für Name und Erkennungsmuster ---------------- */

/* Mittig wie der Kopf von Schritt 2 – ohne dessen seitliche Aussparung, da hier
   kein Zurück-Chevron in der Ecke schwebt, den ein langer Titel treffen könnte. */
.contract-step1-head {
  text-align: center;
}

.contract-seek {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 0.7rem;
  background: var(--color-chip-bg);
  border-radius: var(--radius-sm);
}

.contract-seek svg {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.contract-seek input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  color: var(--color-text);
  font: inherit;
  font-size: 0.95rem;
  outline: none;
}

.contract-seek input::placeholder {
  color: var(--color-text-muted);
}

/* --- Schritt 2: der Vertrag als Zeilenliste ------------------------------- */

/* Nutzt .sheet-head-centered (siehe dort) – hier nur die Feinabstimmung der
   Abstaende nach unten. */
.contract-step2-head {
  padding-bottom: 0.2rem;
}

.contract-step2-head .sheet-title {
  margin-bottom: 0.15rem;
}

.contract-step2-head .sheet-sub {
  margin-bottom: 0.75rem;
}

.contract-facts {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* Label links, Wert rechts, Chevron als einziges Versprechen "hier geht was
   auf" – dieselbe Anmutung wie die Aktionsliste im Buchungs-Sheet. */
.contract-fact {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 46px;
  padding: 0.4rem 0.8rem;
  text-align: left;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  font: inherit;
  font-size: 0.9rem;
}

.contract-fact:last-child {
  border-bottom: none;
}

.contract-fact-label {
  flex-shrink: 0;
  font-size: 0.82rem;
  color: var(--color-text-muted);
}

.contract-fact-value {
  flex: 1;
  text-align: right;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.contract-fact-value.is-mono {
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-variant-numeric: tabular-nums;
}

/* Leer, aber in Ordnung (Kategorie, Buchungen, "Geteilt mit"). */
.contract-fact-value.is-empty {
  color: var(--color-text-muted);
  font-weight: 400;
}

/* Leer und noch offen – nur Name und Betrag. Kursiv statt farbig: eine Farbe
   wäre hier eine Fehlermeldung, und es ist kein Fehler, sondern unfertig. */
.contract-fact-value.is-required {
  color: var(--color-text-muted);
  font-weight: 400;
  font-style: italic;
}

.contract-fact-chev {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--color-text-muted);
}

.contract-fact-chev.is-open {
  transform: rotate(90deg);
}

.contract-fact .pill {
  flex-shrink: 0;
  max-width: 100%;
}

/* Die Zeile, in der gerade getippt wird: Sie verlässt die Liste nicht, sie
   bekommt nur einen Rahmen in der Akzentfarbe – damit klar ist, wo die
   Tastatur hinschreibt. */
/* 1.5px, nicht 1px: Eine 1px-Linie erreicht auf dem 15px-Bogen der Ecke nur die
   halbe Deckkraft – reine Kantenglättung, in border, outline und box-shadow
   gleichermaßen. Die Ecken sähen dann blasser aus als die geraden Kanten und die
   Linie wirkte unterbrochen. 1.5px ist das gemessene Minimum, ab dem die Ecke voll
   deckt (1.25px reicht noch nicht); 2px wäre schon eine sichtbar dickere Linie. */
.contract-fact.is-editing {
  background: color-mix(in srgb, var(--color-accent-text) 7%, var(--color-surface));
  box-shadow: inset 0 0 0 1.5px var(--color-accent-text);
}

/* Das Eingabefeld sitzt genau dort, wo eben der Wert stand – gleiche Schrift,
   gleiche Ausrichtung, kein springender Text beim Antippen. */
.contract-fact-input {
  flex: 1;
  min-width: 0;
  text-align: right;
  border: none;
  background: transparent;
  outline: none;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-text);
}

/* Ticker-Ziffern nur fuer den Betrag – ein Name in Monospace saehe aus wie ein
   technischer Bezeichner. */
.contract-fact-input.is-mono {
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  font-variant-numeric: tabular-nums;
}

.contract-fact-unit {
  flex-shrink: 0;
  font-size: 0.9rem;
  color: var(--color-text-muted);
}

/* Die Zeile, die sich vergrößert (Turnus, Kategorie, Geteilt mit): Der Block
   ersetzt die Zeile nicht, er wächst aus ihr heraus – oben bleibt dieselbe
   Beschriftung stehen, darunter erscheint die Auswahl. */
.contract-fact-expand {
  border-bottom: 1px solid var(--color-border);
  background: color-mix(in srgb, var(--color-accent-text) 7%, var(--color-surface));
  /* 1.5px: siehe .contract-fact.is-editing – auf dem Bogen deckt 1px nur halb. */
  box-shadow: inset 0 0 0 1.5px var(--color-accent-text);
}

.contract-fact-expand:last-child {
  border-bottom: none;
}

/* Der Akzentring des aufgeklappten Blocks ist eckig, .contract-facts rundet
   aber. Berührt der Block ein Ende der Liste – im Regel-Dialog ist er sogar der
   einzige Eintrag –, liefe die grüne Linie sonst gerade in die Ecke und würde
   vom runden Beschnitt abgeschnitten, während der Kartenrand daneben eine Kurve
   zieht. Das "- 1px" ist der Kartenrahmen: damit laufen beide Kurven
   konzentrisch. Ein Block mitten in der Liste bleibt eckig, dort ist es
   richtig so. */
.contract-fact-expand:first-child {
  border-top-left-radius: calc(var(--radius-md) - 1px);
  border-top-right-radius: calc(var(--radius-md) - 1px);
}

.contract-fact-expand:last-child {
  border-bottom-left-radius: calc(var(--radius-md) - 1px);
  border-bottom-right-radius: calc(var(--radius-md) - 1px);
}

/* Füllt der aufgeklappte Block die ganze Karte (im Regel-Dialog ist die Kategorie
   die einzige Zeile), lägen Kartenrand und Akzentring als zwei Linien direkt
   nebeneinander – in den Ecken sieht das aus wie ein Zeichenfehler. Dann
   übernimmt der Ring die Umrandung. In einer längeren Liste bleibt der Rand
   stehen: dort umrandet er tatsächlich mehr als den Block. */
.contract-facts:has(> .contract-fact-expand:only-child) {
  border-color: transparent;
}

.contract-fact-expand .contract-fact {
  border-bottom: none;
  background: transparent;
}

.contract-fact-expand-body {
  padding: 0 0.8rem 0.7rem;
}

/* Bewusst KEINE max-height auf dem aufgeklappten Block: Sie schnitt die letzte
   Chipreihe mittendurch ab und legte eine Systemscrollleiste darüber – das
   liest sich wie ein Fehler, nicht wie "hier geht es weiter". Die zehn
   Standardkategorien stehen vollständig da, und das Sheet selbst scrollt
   ohnehin (.category-sheet-dialog, max-height: 85vh). */

/* Kompakte Chipform für Turnus, Kategorie und "Geteilt mit". Kleiner als die
   44-px-.chip-opt des Kategorie-Pickers: Hier stehen bis zu zehn Kategorien in
   einem Block, der zwischen zwei Zeilen aufgeht. */
.chip-choice {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.chip-choice button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 36px;
  padding: 0.2rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  /* Nicht --color-bg wie .chip-opt: Die Chips stehen hier auf der eingefärbten
     Fläche des offenen Blocks und verschwänden darin. */
  background: var(--color-surface);
  color: var(--color-text-muted);
  font: inherit;
  font-size: 0.82rem;
}

.chip-choice button.is-active {
  border-color: transparent;
  background: var(--color-chip-bg);
  color: var(--color-accent-text);
  font-weight: 600;
}

/* Die zwei Auswege unter den Unterkategorien. .skip-link ist in der App ein
   <div>; hier sind es <button>, damit beide per Tastatur erreichbar sind.
   Auch im Kopf-Block des Vertrags-Screens (.contract-hero-expand), seit die
   Kategorie dorthin gezogen ist – sonst stehen dort zwei graue Kästen. */
.contract-fact-expand-body button.skip-link,
.contract-hero-expand button.skip-link {
  width: 100%;
  min-height: 36px;
  padding: 0;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}

/* "individuell" ist der einzige Wert mit Zusatzangabe. Das Tagefeld steht
   deshalb NEBEN den Chips, nicht darunter: Es gehört zum gewählten Chip. */
.contract-interval-inline {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
  font-size: 0.85rem;
  color: var(--color-text-muted);
}

.contract-interval-inline input {
  width: 4.2rem;
  padding: 0.35rem 0.5rem;
  text-align: right;
  border: 1px solid var(--color-accent-text);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  font-family: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
  outline: none;
}

.contract-inline-done {
  margin-left: auto;
  min-height: 36px;
  padding: 0 0.4rem;
  border: none;
  background: transparent;
  color: var(--color-accent-text);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 600;
}

/* Inhalte des aufgeklappten Blocks, die keine Chips sind: die Datumsfelder der
   Mindestlaufzeit und der erklärende Halbsatz unter den Kriterien-Chips. Sie
   stehen als <span>/<input> direkt im Block und brauchen deshalb ihre eigene
   Zeilenbildung. */
.contract-fact-expand-body .editor-sublabel {
  display: block;
  margin: 0.7rem 0 0.3rem;
}

.contract-fact-expand-body .contract-schedule-input {
  margin-top: 0.1rem;
}

.contract-fact-expand-body .contract-schedule-hint {
  display: block;
  margin-top: 0.4rem;
}

/* Sagt, was die zwei Kriterien bewirken – ohne den Satz ist "Betrag ±15 %" eine
   Einstellung ohne erkennbare Folge. */
.contract-fact-note {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--color-text-muted);
}

/* Was dem Anlegen noch fehlt – zwischen letzter Zeile und Knopf, wie überall in
   der App. Kein rotes Feld: Es ist nichts schiefgegangen, es ist unfertig. */
.contract-blocker-hint {
  margin: 0.9rem 0 0.4rem;
  font-size: 0.8rem;
  text-align: center;
  color: var(--color-text-muted);
}

/* --- Vertrags-Sheet: der Kopf, in dem bearbeitet wird ---------------------- */

/* Seit 2026-08-29 gibt es nur noch EINEN Vertrags-Screen (Entwurf:
   Notizen/Mockups/vertrag-ansehen-bearbeiten-zusammen-final.html). Name, Betrag
   und Kategorie stehen im Kopf und werden DORT geaendert; die Zeilenliste
   darunter traegt den Rest. Zwei Festlegungen stecken in diesen Regeln:
   · Der Hero traegt KEINE Einheit mehr ("/ Monat"). Die Einheit ist der Turnus,
     und der wird in der Liste gesetzt – ein Wert im Kopf, den man nur unten
     aendern kann, war genau die Uneindeutigkeit, die der Umbau abschafft.
   · Die gepunktete Unterlinie ist das einzige Versprechen "hier laesst sich
     tippen". Ein Chevron machte aus dem Kopf eine Werkzeugleiste, und die
     Kategorie traegt ihre Pille ohnehin schon als Bedienzeichen. */
.contract-hero {
  text-align: center;
  /* Links und rechts dieselbe Aussparung wie .sheet-head-centered: das
     Schliessen-X schwebt in der Ecke, ein langer Name laeuft nicht darunter. */
  padding: 0 2.9rem 0.2rem;
}

.contract-hero-name,
.contract-hero-amount {
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  padding: 0.1rem 0.2rem;
  border-bottom: 1px dashed var(--color-border);
}

.contract-hero-name {
  font-size: 1.05rem;
  font-weight: 600;
  max-width: 100%;
  overflow-wrap: break-word;
}

/* Gleiche monospace-Kennzahl wie .hero-amount auf Dashboard und Verträge-
   Uebersicht, eine Stufe kleiner – sie sitzt in einem Sheet. */
.contract-hero-amount {
  display: inline-block;
  margin: 0.5rem 0 0.15rem;
  font-family: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;
  font-size: 1.9rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--color-negative);
}

.contract-hero-amount.positive {
  color: var(--color-positive);
}

/* Im Tippen: gleiche Groesse, gleiche Stelle, nur der Akzentrahmen – dieselbe
   Sprache wie .contract-fact.is-editing in der Liste. */
.contract-hero-name.is-editing,
.contract-hero-amount.is-editing {
  border: none;
  border-radius: var(--radius-sm);
  text-align: center;
  background: color-mix(in srgb, var(--color-accent-text) 7%, var(--color-surface));
  box-shadow: inset 0 0 0 1px var(--color-accent-text);
  outline: none;
}

.contract-hero-name.is-editing {
  width: 100%;
}

.contract-hero-amount.is-editing {
  width: 8.5ch;
}

.contract-hero-unit {
  margin-left: 0.35rem;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--color-text-muted);
}

.contract-hero-cat {
  background: none;
  border: none;
  padding: 0.15rem;
  font: inherit;
}

.contract-hero-cat .pill {
  max-width: 100%;
}

/* Die Kategorie-Chips klappen unter dem Kopf auf, nicht in einem Sheet
   obendrauf – sonst waere es doch wieder ein zweiter Screen. Gleiche Fuellung
   und Umrandung wie .contract-fact-expand, damit beide Ebenen gleich sprechen. */
.contract-hero-expand {
  margin-top: 0.6rem;
  padding: 0.7rem 0.8rem;
  background: color-mix(in srgb, var(--color-accent-text) 7%, var(--color-surface));
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 1px var(--color-accent-text);
  text-align: left;
}

/* Die Speicherleiste gibt es nur, solange der Entwurf vom gespeicherten Vertrag
   abweicht; ohne Aenderung gibt es nichts zu speichern und nichts zu verwerfen,
   und ein dauerhafter Speichern-Knopf machte aus dem Lese-Screen ein Formular.
   Sie steht an derselben Stelle wie sonst "Kein Vertrag · Archivieren" und
   ersetzt die Zeile, solange sie da ist. */
.contract-savebar {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.9rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--color-border);
}

.contract-savebar .sheet-btn {
  margin: 0;
  flex: 1;
}

.contract-savebar .sheet-btn.primary {
  flex: 1.4;
}

/* Das Schliessen-X schwebt in der Ecke: Diese Sheets tragen oben keinen
   Screentitel, sondern Inhalt (Vertragsname und Betrag) – ueber dem Kopf soll
   deshalb kein toter Raum stehen. Gegenstueck ist .sheet-back-floating links. */
.sheet-close-floating {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  width: 32px;
  height: 32px;
  z-index: 1;
}
