/* ═══════════════════════════════════════════════════════
   THEMES — 7 Farbschemen mit vollständigen Design-Tokens
═══════════════════════════════════════════════════════ */
/* Optionale lokale Schriften: liegen Dateien unter public/fonts/, werden sie
   genutzt; sonst System-Schriften. Früher als Inline-<style> in index.html –
   die CSP erlaubt keine Inline-Style-Blöcke mehr (style-src-elem 'self'). */
@font-face { font-family: "Fraunces"; src: local("Fraunces"), url("../fonts/Fraunces.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Outfit"; src: local("Outfit"), url("../fonts/Outfit.woff2") format("woff2"); font-display: swap; }
/* Native Formularelemente (Checkbox, Radio, Datums-/Zeit-Picker, Scrollbar,
   Select-Popup) rendern ohne color-scheme immer nach der HELLEN System-
   voreinstellung – unabhängig vom gewählten App-Theme. Das macht z. B.
   unmarkierte Checkboxen in den dunklen Themes zu grellen weißen Quadraten.
   color-scheme sagt dem Browser, welche native Optik zum Theme passt. */
:root, html[data-theme="warm"], html[data-theme="dunkel"], html[data-theme="wald"], html[data-theme="meer"] { color-scheme: dark; }
html[data-theme="hell"], html[data-theme="rose"] { color-scheme: light; }

/* ─── Spacing-Tokens (Audit 4.1/4.3) ─────────────────────────────────────────
   Kodifizieren die faktisch verwendete 2-px-Skala der App – themenunabhängig.
   Für margin/padding/gap gelten NUR diese Werte; krumme Zwischenwerte
   (3/5/7/9/11/13px) wurden im Zuge des Audits auf den nächsten Skalenwert
   umgestellt und werden durch test/spacing-skala.test.js abgewiesen.
   Neue Stellen bitte die Variablen verwenden statt roher px-Werte. */
:root {
  --sp-2: 2px;    /* Haarlinie/Feinjustage */
  --sp-4: 4px;    /* mini: Chip-/Icon-Abstände */
  --sp-6: 6px;    /* xs: enge Gaps (Toasts, Buttons klein) */
  --sp-8: 8px;    /* s: Zeilen-Gaps, Checkzeilen */
  --sp-10: 10px;  /* m: Standard-Innenabstand klein, Modal-Button-Gap */
  --sp-12: 12px;  /* m+: Zellen-Padding, Listen */
  --sp-14: 14px;  /* l: Feldabstände, Karten-Zwischenräume klein */
  --sp-16: 16px;  /* xl: Grid-Gap, Karten-Zwischenräume */
  --sp-18: 18px;  /* xxl: Button-Padding horizontal */
  --sp-20: 20px;  /* Abschnitt: Modal-Fußzeile, Blockabstände */
  --sp-22: 22px;  /* Fläche: Card-/Modal-Innenraum */
}

:root, html[data-theme="warm"] {
  --bg: #13100e; --bg-2: #1b1710; --panel: #211c16; --panel-2: #2a231b;
  --line: #38302a; --ink: #f5eddf; --ink-soft: #c9bda8; --muted: #978970;
  --accent: #d98b3b; --accent-2: #e8b96a; --accent-ink: #150f06;
  --green: #7dbb6c; --red: #d96959;
  --shadow-sm: 0 2px 8px rgba(0,0,0,.35);
  --shadow: 0 12px 32px rgba(0,0,0,.45);
  --shadow-lg: 0 24px 56px rgba(0,0,0,.55);
  --radius-sm: 10px; --radius: 16px; --radius-lg: 22px;
  --display: "Fraunces", Georgia, serif; --body: "Outfit", system-ui, sans-serif;
  --sidebar-w: 230px; --topbar-h: 56px; --transition: .16s ease;
  --bg-grad-1: rgba(217,139,59,.12); --bg-grad-2: rgba(123,184,107,.07);
  --input-bg: #18140f; --btn-from: #e0962e; --btn-to: #c97620;
}
html[data-theme="dunkel"] {
  --bg: #0f1114; --bg-2: #161921; --panel: #1b2028; --panel-2: #222832;
  --line: #303848; --ink: #eaeff5; --ink-soft: #b4bcc9; --muted: #848f9e;
  --accent: #5b9dd9; --accent-2: #82bdf0; --accent-ink: #060e18;
  --green: #6fbf73; --red: #e07d6e;
  --shadow-sm: 0 2px 8px rgba(0,0,0,.4); --shadow: 0 12px 32px rgba(0,0,0,.5); --shadow-lg: 0 24px 56px rgba(0,0,0,.6);
  --radius-sm: 10px; --radius: 16px; --radius-lg: 22px;
  --display: "Fraunces", Georgia, serif; --body: "Outfit", system-ui, sans-serif;
  --sidebar-w: 230px; --topbar-h: 56px; --transition: .16s ease;
  --bg-grad-1: rgba(91,157,217,.10); --bg-grad-2: rgba(111,191,115,.06);
  --input-bg: #131720; --btn-from: #6aaae2; --btn-to: #4a8fc8;
}
html[data-theme="hell"] {
  --bg: #f5f1ea; --bg-2: #fefcf8; --panel: #fefcf9; --panel-2: #f2ece0;
  --line: #dfd5c2; --ink: #28211a; --ink-soft: #58503f; --muted: #756a57;
  --accent: #b96d1c; --accent-2: #cf8936; --accent-ink: #fff;
  --green: #3d7d39; --red: #b3452e;
  --shadow-sm: 0 2px 6px rgba(100,80,50,.12); --shadow: 0 10px 28px rgba(100,80,50,.18); --shadow-lg: 0 20px 48px rgba(100,80,50,.22);
  --radius-sm: 10px; --radius: 16px; --radius-lg: 22px;
  --display: "Fraunces", Georgia, serif; --body: "Outfit", system-ui, sans-serif;
  --sidebar-w: 230px; --topbar-h: 56px; --transition: .16s ease;
  --bg-grad-1: rgba(185,109,28,.07); --bg-grad-2: rgba(61,125,57,.04);
  --input-bg: #faf7f0; --btn-from: #c77620; --btn-to: #a86018;
}
html[data-theme="wald"] {
  --bg:#0e1411; --bg-2:#151f1a; --panel:#192519; --panel-2:#202d23; --line:#2f4234;
  --ink:#e8f0e9; --ink-soft:#b9d0bc; --muted:#7f9682; --accent:#5fa873; --accent-2:#86c997;
  --accent-ink:#081209; --green:#7bc47f; --red:#e07d6e;
  --shadow-sm:0 2px 8px rgba(0,0,0,.35); --shadow:0 12px 32px rgba(0,0,0,.45); --shadow-lg:0 24px 56px rgba(0,0,0,.55);
  --radius-sm:10px; --radius:16px; --radius-lg:22px;
  --display:"Fraunces",Georgia,serif; --body:"Outfit",system-ui,sans-serif;
  --sidebar-w:230px; --topbar-h:56px; --transition:.16s ease;
  --bg-grad-1:rgba(95,168,115,.12); --bg-grad-2:rgba(95,168,115,.05);
  --input-bg:#121a14; --btn-from:#6ab87f; --btn-to:#4e9e65;
}
html[data-theme="meer"] {
  --bg:#0b1316; --bg-2:#101d22; --panel:#122229; --panel-2:#182d35; --line:#28424d;
  --ink:#e4f0f3; --ink-soft:#afccd2; --muted:#78969a; --accent:#2e9db0; --accent-2:#5cc3d4;
  --accent-ink:#041418; --green:#5fc0a0; --red:#e07d6e;
  --shadow-sm:0 2px 8px rgba(0,0,0,.4); --shadow:0 12px 32px rgba(0,0,0,.5); --shadow-lg:0 24px 56px rgba(0,0,0,.6);
  --radius-sm:10px; --radius:16px; --radius-lg:22px;
  --display:"Fraunces",Georgia,serif; --body:"Outfit",system-ui,sans-serif;
  --sidebar-w:230px; --topbar-h:56px; --transition:.16s ease;
  --bg-grad-1:rgba(46,157,176,.12); --bg-grad-2:rgba(92,195,212,.05);
  --input-bg:#0d1c22; --btn-from:#39adc2; --btn-to:#268da0;
}
html[data-theme="rose"] {
  --bg:#faf0f0; --bg-2:#fff8f8; --panel:#fffafb; --panel-2:#f5e6e6; --line:#ead2d2;
  --ink:#381f22; --ink-soft:#6a4a4d; --muted:#806264; --accent:#c0566b; --accent-2:#d97d8e;
  --accent-ink:#fff; --green:#4d8752; --red:#be3c2e;
  --shadow-sm:0 2px 6px rgba(140,80,90,.12); --shadow:0 10px 28px rgba(140,80,90,.18); --shadow-lg:0 20px 48px rgba(140,80,90,.22);
  --radius-sm:10px; --radius:16px; --radius-lg:22px;
  --display:"Fraunces",Georgia,serif; --body:"Outfit",system-ui,sans-serif;
  --sidebar-w:230px; --topbar-h:56px; --transition:.16s ease;
  --bg-grad-1:rgba(192,86,107,.08); --bg-grad-2:rgba(77,135,82,.04);
  --input-bg:#fff2f3; --btn-from:#cd6278; --btn-to:#b04d62;
}

/* ═══ BASE — Reset, Typografie, Farb-Utilities ═══ */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* Höhe der Notch/Statusleiste (iOS Standalone, status-bar-style "black-
   translucent" lässt den Seiteninhalt unter die Notch reichen) – wird zur
   Topbar-Höhe addiert, damit App-Inhalt nicht von der Notch verdeckt wird. */
:root { --safe-top: env(safe-area-inset-top, 0px); }
/* Höhe eines optionalen Banners GANZ oben, noch vor der Topbar (aktuell nur
   die Admin-Gruppen-Rechte-Vorschau, s. settings.js showGruppenPreviewBanner)
   – 0px, solange keins sichtbar ist. Wird per JS (Element.offsetHeight)
   gesetzt, damit Topbar/Sidebar/Scrim nicht darunter verschwinden. */
:root { --preview-h: 0px; }
/* iOS erlaubt für "black-translucent" nur eine feste (weiße) Symbolfarbe für
   Uhrzeit/Akku/Empfang in der Statusleiste – unabhängig vom aktuellen Theme.
   Bei den hellen Themes (hell, rosé) wäre der Kontrast dadurch zu schwach.
   Daher: schmaler, dauerhaft dunkler Streifen exakt in Notch-Höhe, nur bei
   diesen beiden Themes, rein optisch (pointer-events: none). */
html[data-theme="hell"]::before,
html[data-theme="rose"]::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--safe-top);
  background: rgba(20, 16, 10, .55);
  z-index: 200;
  pointer-events: none;
}
body {
  background:
    radial-gradient(1200px 700px at 80% -8%, var(--bg-grad-1), transparent 60%),
    radial-gradient(800px 500px at -5% 108%, var(--bg-grad-2), transparent 55%),
    var(--bg);
  color: var(--ink); font-family: var(--body); font-size: 16px;
  line-height: var(--user-line, 1.6); min-height: 100vh; -webkit-font-smoothing: antialiased;
  letter-spacing: var(--user-letter, normal); word-spacing: var(--user-word, normal);
}
a { color: var(--accent-2); }

/* Überschriften, Feld-Beschriftungen, Buttons, Chips/Badges und die
   Navigation sind reine UI-Beschriftung, keine Inhalte zum Kopieren. Ohne
   diese Regel interpretiert iOS Safari einen Scroll-Touch, der auf so einem
   Text beginnt (z. B. eine Formular-Überschrift oder ein Feld-Label), leicht
   als Beginn einer Textauswahl statt als Scrollen – die blauen
   Auswahl-Anfasser erscheinen dann mitten im Scrollen. Freitext-Inhalte
   (Beschreibungen, IBAN, Beträge, Formularfelder) bleiben bewusst auswählbar,
   falls jemand sie kopieren möchte. */
h1, h2, h3, label, button, .btn, .btn-ghost, .btn-sm,
.chip, .badge, .section-head, nav.side a, .topbar {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
h1, h2, h3 { font-family: var(--display); font-weight: 600; letter-spacing: -.015em; margin: 0; line-height: 1.25; }
.muted { color: var(--muted); }
.soft  { color: var(--ink-soft); }
.pos   { color: var(--green); }
.neg   { color: var(--red); }
.hidden { display: none !important; }

/* ─── Reduzierte Bewegung ────────────────────────────────────────────────
   Respektiert die Systemeinstellung "Bewegung reduzieren": Animationen und
   Übergänge werden praktisch abgeschaltet (Wert > 0 statt 0, da manche
   Skripte transitionend abwarten). Die Klasse .reduced-motion setzt das
   App-intern erzwungen, unabhängig von der Systemeinstellung.
   nav.side (inkl. aller Kindelemente), .scrim und .modal-back sind komplett
   ausgenommen: ihre transform/opacity-Übergänge öffnen/schließen das mobile
   Menü bzw. Modale. Eine auf .001ms gekürzte Transition kann hier dazu
   führen, dass das Element in einem Zwischenzustand "einfriert" (Menü
   bleibt offen, dunkler Hintergrund bleibt stehen, App nicht mehr
   bedienbar) – insbesondere beim Wechsel zwischen reduzierter und normaler
   Bewegung, wenn die Übergangsdauer sich während einer laufenden
   Transition ändert. */
@media (prefers-reduced-motion: reduce) {
  :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *),
  :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *)::before,
  :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *)::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
html.reduced-motion :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *),
html.reduced-motion :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *)::before,
html.reduced-motion :where(*):not(nav.side, nav.side *, .scrim, .modal-back, .modal-back *)::after {
  animation-duration: .001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: .001ms !important;
  scroll-behavior: auto !important;
}

/* ─── Reduzierte Ansicht ────────────────────────────────────────────────
   Optionaler Modus für weniger Reizüberflutung: größere Klickflächen, mehr
   Abstand zwischen Elementen, weniger Tabellenspalten in großen Tabellen. */
html.reduced-view { font-size: 17px; }
html.reduced-view button, html.reduced-view .btn {
  padding: var(--sp-12) var(--sp-20); font-size: 15px; min-height: 46px;
}
html.reduced-view input, html.reduced-view select, html.reduced-view textarea {
  padding: var(--sp-12) var(--sp-14); font-size: 16px; min-height: 46px;
}
html.reduced-view input[type="checkbox"], html.reduced-view input[type="radio"] {
  width: 22px; height: 22px;
}
html.reduced-view .card  { padding: 28px; }
html.reduced-view .row   { gap: var(--sp-18); }
html.reduced-view .field { margin-bottom: var(--sp-18); }
html.reduced-view .grid  { gap: var(--sp-22); }
html.reduced-view nav.side a { padding: var(--sp-12) var(--sp-12); gap: var(--sp-12); }
/* Weniger wichtige Spalten ausblenden: Soll/Ist bei Mitgliedern (Saldo zeigt
   das Wesentliche), Typ in der Buchungsübersicht. */
html.reduced-view #memTable th:nth-child(3), html.reduced-view #memTable td:nth-child(3),
html.reduced-view #memTable th:nth-child(4), html.reduced-view #memTable td:nth-child(4),
html.reduced-view #buchTable th:nth-child(2), html.reduced-view #buchTable td:nth-child(2) {
  display: none;
}

/* ─── Ruhe-Modus ────────────────────────────────────────────────────────────
   Opt-in (Standard aus), serverseitig je Nutzer gespeichert (ME.calmMode). Senkt
   die visuelle Reizlast: Hintergrund-Verläufe, Unschärfe (backdrop-filter) und
   tiefe Schatten weichen ruhigen, flachen Flächen. Bewegung/Animation bleibt
   bewusst unberührt – dafür ist „Animationen reduzieren" zuständig. Bewusst nur
   auf Flächen/Effekte beschränkt; funktionale Indikatoren (aktiver Menüpunkt,
   Fokus-Ring, Statuspunkte) bleiben unverändert erhalten. */
html.calm {
  --shadow-sm: 0 0 0 1px var(--line);
  --shadow:    0 0 0 1px var(--line);
  --shadow-lg: 0 0 0 1px var(--line);
}
html.calm body { background: var(--bg); }
html.calm .card { background: var(--panel); }
html.calm .stat::before { display: none; }
html.calm .topbar {
  background: var(--bg);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
html.calm .modal-back {
  background: rgba(8, 6, 4, .82);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
