/*
 * Design-System "Stille Klarheit", Nutzerentscheidung 2026-10-03 (Schritt 4,
 * Schrift): Noto Sans (Google Fonts, OFL-lizenziert), lokal vendort unter
 * css/fonts/ -- NICHT ueber die Google-Fonts-CDN nachgeladen. Grund: die App
 * ist Offline-first (PWA mit Service-Worker-Precache, file://-Start ohne
 * Netzwerk) -- ein Nachladezwang zu einem externen Host wuerde beides
 * brechen UND eine neue externe Abhaengigkeit ausserhalb der bestehenden
 * CSP/Netzwerk-Allowlist einfuehren (server/security-helpers.js
 * STATIC_DIRECTORIES erlaubt ".woff2" bereits gezielt unter "/css/" --
 * dieser Pfad wird hier zum ersten Mal tatsaechlich genutzt).
 *
 * 4 Teilbereiche (Latin/Latin-Ext/Griechisch/Kyrillisch -- Entscheidung
 * 2026-10-02: KEIN Kyrillisch-Ext/Devanagari/Griechisch-Ext/Vietnamesisch/
 * CJK/Arabisch), echte Groessen gemessen (nicht geschaetzt):
 * latin=35.820B, latin-ext=167.960B, greek=21.776B, cyrillic=20.080B,
 * zusammen 245.636 Byte (~240 KB). unicode-range je Subset direkt aus
 * Google Fonts' eigener css2-API uebernommen (fonts.googleapis.com,
 * modernes Chrome-UA fuer WOFF2 statt TTF abgefragt) -- der Browser laedt
 * dadurch pro Seite nur die Subset-Datei(en), deren Zeichen tatsaechlich
 * vorkommen, nie alle 4 auf einmal. Lizenz/Herkunft: FONT_LICENSES.md.
 *
 * Variable Schriftschnitt-Datei (wght 100-900 in einer Datei, daher
 * font-weight als Bereich statt Einzelwert) -- deckt alle im Projekt
 * verwendeten Schriftstaerken ab (400/500/600/700, siehe font-weight-
 * Fundstellen in dieser Datei) ohne weitere Dateien.
 *
 * font-display: swap -- Text bleibt mit dem Fallback-Stack sofort lesbar,
 * tauscht non-blocking, sobald die Datei geladen ist. Kompatibilitaet hat
 * Vorrang (Nutzer-Vorgabe): fehlt eine Datei (404, Dateisystem-Zugriff
 * blockiert o.ae.), faellt die Schrift automatisch auf den weiter unten im
 * Basis-Selektor definierten font-family-System-Stack zurueck -- kein
 * zusaetzlicher Code noetig, das ist eingebautes CSS-Verhalten. Siehe
 * tests/guard.font-noto-sans.test.js fuer den expliziten Beleg (Fallback-
 * Kette vorhanden, Dateien existieren mit den oben genannten exakten
 * Groessen, CSP erlaubt den Ladeweg).
 */
@font-face {
  font-family: "Noto Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/noto-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Noto Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/noto-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Noto Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/noto-sans-greek.woff2") format("woff2");
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: "Noto Sans";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/noto-sans-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

:root {
  --bg: #f4f7fb;
  --surface: #ffffff;
  --surface-muted: #f8fafc;
  --surface-strong: #eef3f8;
  --text: #152033;
  --text-muted: #5d6c82;
  --border: #d9e1eb;
  --border-strong: #b9c7d8;

  --primary: #185bb9;
  --primary-hover: #0e4a9d;
  --primary-soft: #e7f0ff;

  --success: #157348;
  --success-soft: #e6f6ed;

  --warning: #a75d00;
  --warning-soft: #fff3dc;

  --danger: #b42318;
  --danger-hover: #8d1b12;
  --danger-soft: #feeceb;

  /*
   * Status-Center-Avatar-Badge (Nutzerauftrag 2026-10-01): dritte, eigene
   * Stufe "Info" (gelb) neben --warning (orange) und --danger (rot) --
   * eigener Ton statt Wiederverwendung von --warning, damit alle drei
   * Prioritaetsstufen auf einen Blick unterscheidbar sind. #8a6d00 auf
   * Weiss: 4,92:1 (AA).
   */
  --info: #8a6d00;
  --info-soft: #fdf6da;

  /*
   * AP7b-1 (2026-08-30): CSS-Custom-Properties fuer Diagrammfarben, die
   * bisher als reine Hex-Literale in Chart-Klassen unten bzw. als
   * JS-Konstanten (js/settings/activity-categories.js) hartcodiert waren
   * -- dadurch unveraendert im Dark-Theme (z.B. war --chart-af im Light-
   * Modus zufaellig identisch zu --primary, blieb im Dark-Modus aber die
   * dunkle Light-Variante und damit kaum lesbar vor dunklem Hintergrund).
   * Namensschema bewusst zweigeteilt, damit AP7b-2 (Band-Layer, noch
   * NICHT umgesetzt) sauber andocken kann, ohne umzubauen: --chart-* =
   * Linien-/Punkt-/Marker-Vordergrundfarben (diese Runde), --band-* =
   * reservierter, noch NICHT befuellter Namensraum fuer die spaeteren
   * Tag/Nacht-/Aktivitaetsphasen-/Medikationsfenster-Hintergrundflaechen.
   */
  /*
   * Nutzerauftrag 2026-10-01 ("Beschriftungen/Farben bei allen Diagrammen
   * fuer alle Channels pruefen und optimieren"): komplette Neuvergabe aller
   * 11 --chart-*-Werte, systematisch generiert (fixer Hue pro Kanal,
   * HSL->Hex, WCAG-Kontrast gegen --bg je Theme nachjustiert, siehe
   * PROJECT_STATUS.md Abschnitt "Diagramm-Farbpalette 2026-10-01" fuer das
   * Erzeugungsskript). Feste Zuordnung je Kanal, EIN Hue pro Kanal ueber
   * ALLE 5 Themes hinweg (nur Lightness/Saturation passen sich dem Theme-
   * Hintergrund an) -- das ist die Umsetzung von "unabhaengig vom Theme".
   * Pflichtvorgabe: HR=rot (hue 5), Atmung/AF=blau (hue 215), in jedem der
   * 5 Themes unten identisch eingehalten. Alle Werte >=4.5:1 Kontrast
   * gegen --bg (ikyru-a11y >=7:1). Vorherige Kollision --chart-hrv ==
   * --chart-ratio im Dark-Theme (beide #b79aec) ist mit dieser Neuvergabe
   * behoben (siehe PROJECT_STATUS.md).
   */
  --chart-hr: #ab2c21;
  --chart-af: #215aab;
  --chart-ratio: #6621ab;
  --chart-weight: #188144;
  /*
   * Gesundheits-Stammdaten-Konzept, Commit C (2026-09-11): fuer den
   * neuen "height"-Channel (exakt analog "weight" aufgebaut, siehe
   * channel-registry.js), damit dessen automatisch abgeleitetes
   * cssColorVar (--chart-height) nicht ins Leere zeigt -- sonst
   * unsichtbare Linie/Markierung, sobald der Channel je gechartet wird.
   */
  --chart-height: #7b7324;
  --chart-barking: #9e4a2e;
  --chart-measurement: #ab21ab;
  --chart-stool: #634a2c;
  /*
   * Sprint 13 (2026-09-14): fuer die drei neuen Fitbit-Vital-Kanaele
   * (resting_heartrate/spo2/hrv, channel-registry.js) -- gleicher Grund
   * wie beim --chart-height-Kommentar oben.
   */
  --chart-resting-heartrate: #ab2172;
  --chart-spo2: #167474;
  --chart-hrv: #2121ab;

  /*
   * Nutzerauftrag 2026-10-01 (Fortsetzung der Diagramm-Farbpruefung):
   * BEFUND -- die Marker-Ereigniskanaele (diagnosis/vet_appointment/
   * symptom_episode, js/core/channel-registry.js) hatten GAR KEINE
   * Fuellfarbe (chart-renderer.js appendMarkerChannelRow() setzt die
   * Klasse chart-marker-<id>, aber es gab keine CSS-Regel dafuer --
   * Raute blieb auf Browser-Default-Fuellung statt einer bewussten
   * Farbe), und die Legende kannte nur 4 von 9 Marker-Kanaelen
   * (renderChartLegend(), ui-charts.js). Generischer Fix: JEDER Marker-
   * Kanal bekommt jetzt sein eigenes --chart-<id>-Token -- die bereits
   * bestehenden 6 nutzen es als blossen ALIAS auf ihren semantischen Ton
   * (unveraendertes Aussehen, EINE Quelle statt zwei), die 3 bisher
   * ungefaerbten bekommen neue, kontrastgepruefte Farben (>=4,5:1 gegen
   * --bg, ikyru-a11y >=7:1). renderChartLegend() liest jetzt fuer ALLE
   * Kanaele (Linie UND Marker) einheitlich channel.cssColorVar --
   * keine manuell nachgepflegte CSS-Klasse pro Kanal mehr noetig.
   */
  --chart-medication_administration: var(--success);
  --chart-medication_planned: var(--text-muted);
  --chart-medication_plan_change: var(--danger);
  --chart-observation: var(--warning);
  --chart-context_event: var(--primary);
  --chart-nutrition_event: var(--chart-measurement);
  --chart-diagnosis: #3b8118;
  --chart-vet_appointment: #4f21ab;
  --chart-symptom_episode: #ab2138;

  /*
   * Nutzerauftrag 2026-09-24 (medizinische Diagramm-Zusatzoptionen, Prioritaet 4
   * "Vergleichszeitraum"): vorgebaute, aber noch nicht aktivierte Farbdaempfungs-
   * Option fuer die Vorperiode-Linie (.chart-line-comparison) -- siehe dortiger
   * Kommentar. 1 = keine Daempfung (aktueller Stand, Nutzerentscheidung).
   */
  --chart-comparison-overlay-opacity: 1;

  /*
   * Nutzer-Auftrag "Daten-Uebersicht" (2026-09-14): kleine, feste
   * Palette fuer die neue profilweite Abdeckungs-/Luecken-Zeitleiste
   * (App.UI.openDataCoverageDialog(), ui-overview.js) -- EIN Farbton
   * je unterschiedlicher Datenquelle (zyklisch durchlaufen, nicht
   * kanalgebunden wie --chart-hr/--chart-af oben), plus ein eigener,
   * bewusst deutlich abweichender Farbton fuer Luecken-Abschnitte.
   */
  --coverage-source-1: #2f8f5b;
  --coverage-source-2: #185bb9;
  --coverage-source-3: #b8760a;
  --coverage-source-4: #7b4acb;
  --coverage-source-5: #1f8f8c;
  --coverage-gap: #c33a32;

  /*
   * Reine Namens-Aliase auf bereits theme-fähige Tokens (keine neue
   * Farbe) -- damit alle vier in dieser Runde geforderten Bereiche
   * (HR/AF/Aktivitaets-Codes/Findings) unter demselben --chart-*-/--act-*-
   * Schema auffindbar sind. Nur in :root definiert (nicht im
   * Dark-Block) -- var(--danger) etc. loest bereits am Verwendungsort
   * auf die dort aktive Theme-Variante auf, eine Dark-Redefinition
   * dieser Aliase waere reine Duplikation.
   */
  --chart-finding-high: var(--danger);
  --chart-finding-medium: var(--warning);
  --chart-finding-low: var(--text-muted);

  /*
   * Korb E, Paket E1.1 (SVG-Sprite-Icon-System, 2026-09-16): reiner
   * Namens-Alias auf --text-muted (kein neuer Farbwert) -- Icons sind
   * standardmaessig dezent/sekundaer, dieselbe Logik wie die
   * --chart-finding-*-Aliase oben. Nur in :root definiert, kein
   * Dark-Block-Gegenstueck noetig (var(--text-muted) loest bereits am
   * Verwendungsort theme-richtig auf). Ein Icon mit eigener Bedeutung
   * (z.B. Severity-Icons) ueberschreibt die Farbe gezielt am
   * Verwendungsort, nicht hier global.
   */
  --icon-color: var(--text-muted);

  /*
   * Aktivitaets-Codes: feste Farbe pro bekanntem Default-Code
   * (js/settings/activity-categories.js KNOWN_CODE_COLORS), benannt
   * nach dem jeweiligen Klartext-Label.
   */
  --act-code-unknown: #8a94a3;
  --act-code-standing: #f2c94c;
  --act-code-resting: #5cb3ae;
  --act-code-sleep: #0f4d49;
  --act-code-walking: #f2a541;
  --act-code-running: #a8331f;

  /*
   * Fallback-Palette pro Klassifizierung
   * (FALLBACK_PALETTE_BY_CLASSIFICATION) fuer unbekannte/
   * benutzerdefinierte Aktivitaets-Codes.
   */
  --act-resting-1: #5cb3ae;
  --act-resting-2: #0f4d49;
  --act-active-1: #f0c04b;
  --act-active-2: #8a4508;
  --act-light-1: #f5cd7a;
  --act-light-2: #c98a1f;
  --act-unknown-1: #aab1bd;
  --act-unknown-2: #6b7280;
  --act-unknown-3: #545b66;

  /*
   * AP7b-2a (Band-Layer): befuellt den in AP7b-1 reservierten
   * band-Namensraum. --band-night faerbt sowohl das dezente
   * Hintergrundband als auch (spaeter, AP7b-2b) die Tag/Nacht-Spur --
   * Aktivitaetsphasen nutzen bewusst die bereits vorhandenen act-
   * Tokens ueber App.ActivityCategories.getClassificationColor()
   * statt eigener band-Aktivitaets-Farben (keine zweite Palette fuer
   * dieselbe Bedeutung). Medikationsphasen (PRE_DOSE/PEAK/MID_CYCLE/
   * WEARING_OFF, App.ContextClustering.medPhase) bekommen eine eigene,
   * vierteilige Skala.
   * Nachtrag (2026-08-31, Usertest-Finding 6): --band-morning/-day/
   * -evening ergaenzt -- resolveBandColor()/resolveBandValueLabel()
   * (js/ui/chart-renderer.js) faellen fuer bandType "dayNight" vorher
   * fuer JEDE Klassifizierung (NACHT/MORGEN/TAG/ABEND) auf --band-night/
   * "Nacht" zurueck, jetzt vier eigene Werte je Tageszeit.
   */
  --band-night: #1f3a63;
  --band-morning: #d98a3f;
  --band-day: #4a90c9;
  --band-evening: #8a4a7a;
  --band-medphase-pre-dose: #9aa8c9;
  --band-medphase-peak: #2f8f5b;
  --band-medphase-mid-cycle: #5cb3ae;
  --band-medphase-wearing-off: #c98a1f;

  --shadow: 0 12px 35px rgba(24, 52, 82, 0.08);
  --radius: 14px;
  --radius-small: 9px;

  color-scheme: light;
  /*
   * "Inter" -> "Noto Sans" (2026-10-03, s.o.): "Inter" war nie per
   * @font-face eingebunden, loeste also auf jedem System ohne lokal
   * installiertes Inter ohnehin sofort auf ui-sans-serif/system-ui/...
   * durch. "Noto Sans" ist jetzt der erste Name, der tatsaechlich auf
   * eine (lokal vendorte) Schriftdatei verweist -- der gesamte
   * restliche Fallback-Stack bleibt unveraendert und greift unveraendert,
   * falls die Dateien fehlen oder nicht laden.
   */
  font-family:
    "Noto Sans",
    ui-sans-serif,
    system-ui,
    -apple-system,
    BlinkMacSystemFont,
    "Segoe UI",
    sans-serif;
}

:root[data-theme="dark"] {
  --bg: #0d1521;
  --surface: #152131;
  --surface-muted: #19283a;
  --surface-strong: #213248;
  --text: #edf4ff;
  --text-muted: #b4c3d7;
  --border: #30445d;
  --border-strong: #46617f;

  --primary: #77adff;
  --primary-hover: #a2c8ff;
  --primary-soft: #1c3863;

  --success: #62d59b;
  --success-soft: #173c2c;

  --warning: #f7bb58;
  --warning-soft: #483413;

  --danger: #ff968d;
  --danger-hover: #ffb5af;
  --danger-soft: #542525;

  /* Dark-Gegenstueck zum --info-Token oben (Status-Center-Avatar-Badge). */
  --info: #e8d44a;
  --info-soft: #463f16;

  /*
   * Dark-Gegenstuecke zu den --chart-*-/--act-*-Tokens oben -- hellere/
   * entsaettigtere Toene DESSELBEN Hues wie im Light-Theme (Nutzerauftrag
   * 2026-10-01, siehe Kommentar in :root oben), nur Lightness/Saturation
   * an den dunklen Hintergrund angepasst. HR bleibt rot, AF bleibt blau.
   * Vorherige Kollision behoben: --chart-af war hier bisher faelschlich
   * `var(--primary)` statt einer eigenen Farbe, und --chart-hrv war mit
   * --chart-ratio identisch (beide #b79aec) -- beides mit dieser
   * Neuvergabe korrigiert.
   */
  --chart-hr: #dd867e;
  --chart-af: #7ea6dd;
  --chart-ratio: #ad7edd;
  --chart-weight: #7edda6;
  --chart-height: #d5ce86;
  --chart-barking: #d59a86;
  --chart-measurement: #dd7edd;
  --chart-stool: #b3926b;
  --chart-resting-heartrate: #dd7eb5;
  --chart-spo2: #7edddd;
  --chart-hrv: #7e7edd;

  /* Marker-Kanal-Aliase/-Farben, gleicher Grund wie im :root-Block oben. */
  --chart-medication_administration: var(--success);
  --chart-medication_planned: var(--text-muted);
  --chart-medication_plan_change: var(--danger);
  --chart-observation: var(--warning);
  --chart-context_event: var(--primary);
  --chart-nutrition_event: var(--chart-measurement);
  --chart-diagnosis: #9edd7e;
  --chart-vet_appointment: #9e7edd;
  --chart-symptom_episode: #dd7e8e;

  /* Dark-Gegenstuecke zu den --coverage-*-Tokens oben, gleiches Prinzip. */
  --coverage-source-1: #57c98a;
  --coverage-source-2: var(--primary);
  --coverage-source-3: #e0a83e;
  --coverage-source-4: #b295e8;
  --coverage-source-5: #5fcac6;
  --coverage-gap: #ff7a6e;

  --act-code-unknown: #aab4c2;
  --act-code-standing: #f5d873;
  --act-code-resting: #7fd1cb;
  --act-code-sleep: #3f8f88;
  --act-code-walking: #f5b866;
  --act-code-running: #d9634b;

  --act-resting-1: #7fd1cb;
  --act-resting-2: #3f8f88;
  --act-active-1: #f3cd73;
  --act-active-2: #c07a2e;
  --act-light-1: #f7d998;
  --act-light-2: #dba64a;
  --act-unknown-1: #c2c9d4;
  --act-unknown-2: #8b93a1;
  --act-unknown-3: #6b7280;

  /* Dark-Gegenstuecke zu den band-Tokens oben, gleiches Kontrast-Prinzip. */
  --band-night: #6b8fd6;
  --band-morning: #f0b06a;
  --band-day: #7ab8e0;
  --band-evening: #b06aa0;
  --band-medphase-pre-dose: #b7c2de;
  --band-medphase-peak: #57c98a;
  --band-medphase-mid-cycle: #7fd1cb;
  --band-medphase-wearing-off: #dba64a;

  --shadow: 0 12px 35px rgba(0, 0, 0, 0.26);

  color-scheme: dark;
}

/*
 * Phase E5 (WCAG-2.2-Audit, 2026-09-15): .button.primary/.button.danger
 * setzen `color: #ffffff` fest (siehe unten) -- im Dark-Theme sind
 * --primary/--danger aber deutlich aufgehellte Akzenttoene (fuer
 * Lesbarkeit von TEXT vor dunklem Hintergrund gedacht), nicht fuer
 * weissen Text auf sich selbst. Weiss-auf-Hellblau/-Lachs lag bei
 * ~2,1-2,3:1, weit unter AA 4,5:1. Dunkler Text (--bg) statt Weiss
 * behebt das in beiden Faellen (Hover-Hintergruende sind noch heller,
 * bleiben also ebenfalls konform).
 */
:root[data-theme="dark"] .button.primary,
:root[data-theme="dark"] .button.danger {
  color: var(--bg);
}

/*
 * Ikyru Zen-Theme (Nutzerauftrag 2026-09-24): drei zusaetzliche, eigene
 * Theme-Werte -- "light"/"dark" oben bleiben VOLLSTAENDIG unveraendert,
 * nichts wird ersetzt (ausdrueckliche Leitplanke). Naming bewusst
 * "ikyru-light"/"ikyru-dark"/"ikyru-a11y" statt einer Wiederverwendung von
 * "light"/"dark": diese Werte sind bereits vergeben (siehe :root oben und
 * :root[data-theme="dark"]), eine Wiederverwendung wuerde sie ueberschreiben
 * statt sie zu ergaenzen (Konzeptvorschlag, Chat 2026-09-24, Punkt 6 --
 * vom Nutzer bestaetigt).
 *
 * Farbwelt (Nutzer-Vorgabe): Tinte/Papier-Basis, EIN Akzent (Siegellack-
 * Rot #B4453A Light / #C85A4D Dark) statt bunter Kategoriefarben --
 * Datentrennung in Diagrammen laeuft ueber Linienstil (stroke-dasharray je
 * Kanal, siehe .chart-line-* Regeln unten und guard.ikyru-theme-wiring.
 * test.js), nicht ueber Farbvielfalt: alle --chart-*-Tokens zeigen daher
 * unten auf denselben --primary-Akzent. --coverage-*, --act-* und --band-*
 * bleiben bewusst unterscheidbare (aber gedaempfte) Toene -- diese Bereiche
 * zeigen mehrere KATEGORIEN GLEICHZEITIG nebeneinander (z.B. die
 * Abdeckungs-Zeitleiste mehrerer Datenquellen auf einmal), fuer die
 * Linienstil keine uebertragbare Unterscheidungstechnik ist (keine Linien,
 * sondern gefuellte Flaechen) -- das waere ausserhalb dessen, was der
 * Nutzerauftrag mit "Diagrammfarben" (Vitalwert-Kanaele) meinte.
 */
:root[data-theme="ikyru-light"] {
  --bg: #f7f5f0;
  --surface: #fcfaf6;
  --surface-muted: #f2efe8;
  --surface-strong: #eae5d9;
  --text: #20262a;
  --text-muted: #5b6368;
  --border: #dcd6c9;
  --border-strong: #9aa6a0;

  /*
   * Design-System "Stille Klarheit", Nutzerentscheidung 2026-10-03
   * (Token-Konsolidierung + Farbentscheidung 1): Hauptakzent jetzt aus dem
   * Logo-Blau abgeleitet (icons/icon.svg, #185bb9, HSL h:215/s:77/l:41 --
   * "Ai-iro"/Indigo), auf grossen Flaechen gedaempft (s:60 statt 77).
   * ABLOESUNG, keine Fortfuehrung: der bisherige Ton #b4453a ("Siegellack-
   * Rot") war NICHT das Logo-Blau -- eine fruehere Analyse (Migrationsplan-
   * Entwurf, Abschnitt 3.1) hat das faelschlich behauptet, indem sie den
   * falschen/laengst abgeloesten CSS-Block (bare :root, Alt-Theme) statt
   * dieses aktiven ikyru-light-Blocks verglichen hat. #2d65b4 (h:215/s:60/
   * l:44) erreicht 5,31:1 auf --bg, 5,55:1 auf --surface (AA 4,5:1).
   */
  --primary: #2d65b4;
  --primary-hover: #255393;
  /* Akzent-Text (#2d65b4) auf diesem Pill-/Badge-Hintergrund: 5,08:1. */
  --primary-soft: #e9f1fb;

  /*
   * Zweitfarbe "Jade" (Nutzerentscheidung 2026-10-03): bewusst nicht der
   * gleiche Gruenton wie --success (h:154, sehr blass, s:7 -- siehe
   * darunter) -- Jade liegt auf h:178 (Richtung Tuerkis/Teal statt
   * Gelbgruen) UND deutlich saettigungsstaerker (s:55), damit sich beide
   * Token-Paare klar unterscheiden, nicht nur im Hex-Wert. Eigener
   * Kontrasttest: tests/guard.ikyru-theme-wiring.test.js.
   */
  --accent-2: #217370;
  --accent-2-hover: #1a5b59;
  /* Akzent-Text (#217370) auf diesem Pill-/Badge-Hintergrund: 5,19:1. */
  --accent-2-soft: #ebf9f9;

  --success: #5f6d67;
  /*
   * s.o.: von #e7eae6 auf #f5f6f4 aufgehellt -- Alt-Ton erreichte nur
   * 4,47:1 (unter AA 4,5:1). Neu: 5,01:1.
   */
  --success-soft: #f5f6f4;

  /*
   * Nutzerauftrag 2026-09-24 (Nachbesserung nach Live-Kontrast-Audit,
   * ECHTER Bug, keine Grenzwertfrage): der urspruengliche Ton #a67c3d
   * erreichte nur 3,46:1 auf --bg / 3,62:1 auf --surface UND 3,07:1 auf
   * --warning-soft -- alle drei unter AA 4,5:1, unabhaengig vom Hintergrund
   * (auch reines Weiss reicht fuer #a67c3d nicht: 3,77:1). Abgedunkelt auf
   * #7e5e2e (gleiche Ocker-Familie) -- neu: 5,46:1 auf --bg, 5,71:1 auf
   * --surface, 4,85:1 auf --warning-soft (--warning-soft selbst bleibt
   * unveraendert, reicht mit dem dunkleren Text bereits).
   */
  --warning: #7e5e2e;
  --warning-soft: #f1e7d4;

  --danger: #7a2e24;
  --danger-hover: #5f241c;
  --danger-soft: #eedbd7;

  /* Ikyru-Gegenstueck zum --info-Token oben (Status-Center-Avatar-Badge). */
  --info: #8a7a1f;
  --info-soft: #f3efd9;

  /*
   * ABGELOEST durch Nutzerauftrag 2026-10-01 (siehe ausfuehrlicher
   * Kommentar bei den --chart-*-Tokens in :root oben): die Nutzer-Vorgabe
   * 2026-09-24 "Ein Akzent statt Kategoriefarben, Kanaele nur per
   * stroke-dasharray unterscheiden" wird NICHT mehr befolgt -- echte
   * Kanalfarben sind jetzt Pflicht (HR=rot, AF=blau, feste Hues je Kanal
   * ueber alle Themes). Die stroke-dasharray-Regeln weiter unten
   * (".chart-line-hr" etc.) bleiben als ZUSAETZLICHE, redundante
   * Kodierung bestehen (hilft z.B. bei Farbfehlsichtigkeit) --
   * Dokumentation der Abloesung: PROJECT_STATUS.md, Abschnitt
   * "Diagramm-Farbpalette 2026-10-01".
   */
  --chart-hr: #8d3c34;
  --chart-af: #34598d;
  --chart-ratio: #61348d;
  --chart-weight: #276842;
  --chart-height: #716b33;
  --chart-barking: #864e3c;
  --chart-measurement: #8d348d;
  --chart-stool: #514434;
  --chart-resting-heartrate: #8d3468;
  --chart-spo2: #276868;
  --chart-hrv: #34348d;

  /* Marker-Kanal-Aliase/-Farben, gleicher Grund wie im :root-Block oben. */
  --chart-medication_administration: var(--success);
  --chart-medication_planned: var(--text-muted);
  --chart-medication_plan_change: var(--danger);
  --chart-observation: var(--warning);
  --chart-context_event: var(--primary);
  --chart-nutrition_event: var(--chart-measurement);
  --chart-diagnosis: #3c6827;
  --chart-vet_appointment: #52348d;
  --chart-symptom_episode: #8d3443;

  --coverage-source-1: #5f6d67;
  --coverage-source-2: #b4453a;
  --coverage-source-3: #a67c3d;
  --coverage-source-4: #7c8a7f;
  --coverage-source-5: #9aa6a0;
  --coverage-gap: #c9c2b2;

  --act-code-unknown: #b3ada0;
  --act-code-standing: #a67c3d;
  --act-code-resting: #9aa6a0;
  --act-code-sleep: #5f6d67;
  --act-code-walking: #96654a;
  --act-code-running: #b4453a;

  --act-resting-1: #9aa6a0;
  --act-resting-2: #5f6d67;
  --act-active-1: #c99a5c;
  --act-active-2: #96654a;
  --act-light-1: #d9c8a8;
  --act-light-2: #a67c3d;
  --act-unknown-1: #c9c2b2;
  --act-unknown-2: #b3ada0;
  --act-unknown-3: #8a8578;

  --band-night: #5f6d67;
  --band-morning: #c99a5c;
  --band-day: #9aa6a0;
  --band-evening: #96654a;
  --band-medphase-pre-dose: #c9c2b2;
  --band-medphase-peak: #5f6d67;
  --band-medphase-mid-cycle: #9aa6a0;
  --band-medphase-wearing-off: #a67c3d;

  --shadow: 0 12px 30px rgba(32, 38, 42, 0.08);

  color-scheme: light;
}

:root[data-theme="ikyru-dark"] {
  --bg: #20262a;
  --surface: #262d31;
  --surface-muted: #2b3236;
  --surface-strong: #333b3f;
  --text: #f7f5f0;
  --text-muted: #b9c0bc;
  --border: #454d48;
  --border-strong: #6c7871;

  /*
   * Design-System "Stille Klarheit", Nutzerentscheidung 2026-10-03
   * (Token-Konsolidierung + Farbentscheidung 1): Hauptakzent aus dem
   * Logo-Blau (#185bb9) abgeleitet, fuer das Dark-Theme wie gewohnt
   * aufgehellt (gleiches Prinzip wie zuvor beim Siegellack-Rot -- der
   * dunkle Logo-Ton selbst waere auf dunklem Grund zu kontrastarm). #719bd6
   * (h:215/s:55/l:64) erreicht 5,37:1 auf --bg, 4,90:1 auf --surface (AA
   * 4,5:1). Als Knopf-Hintergrund mit weissem Text waere das zu hell
   * (2,85:1) -- Knopf-Textfarbe daher unten weiterhin gezielt auf --bg
   * umgeschaltet (5,37:1 mit dunkler Tinte), exakt das bereits bestehende
   * Muster von :root[data-theme="dark"] oben (dort fuer denselben Grund bei
   * .button.primary/.button.danger) -- bleibt unveraendert gueltig, da die
   * Regel nicht an einen bestimmten Farbwert gebunden ist.
   */
  --primary: #719bd6;
  --primary-hover: #88abdd;
  /* Akzent-Text (#719bd6) auf diesem Pill-/Badge-Hintergrund: 5,06:1. */
  --primary-soft: #152a47;

  /*
   * Zweitfarbe "Jade" (s.o., gleiche Nutzerentscheidung): h:178/s:50,
   * deutlich von --success (h:150, s:6 -- fast Graugruen) unterschieden.
   */
  --accent-2: #5bc8c5;
  --accent-2-hover: #71d0cd;
  /* Akzent-Text (#5bc8c5) auf diesem Pill-/Badge-Hintergrund: 5,67:1. */
  --accent-2-soft: #1c403f;

  --success: #9aa6a0;
  --success-soft: #2b322e;

  --warning: #c79a5c;
  --warning-soft: #3a2f1e;

  /*
   * --danger #e08a7a statt derselben Akzentfarbe -- Weiss-auf-#e08a7a waere
   * bei nur 2,60:1 zu niedrig; die Knopf-Textfarbe wird daher unten gezielt
   * auf --bg umgeschaltet (5,89:1), exakt das bereits bestehende Muster von
   * :root[data-theme="dark"] oben.
   */
  --danger: #e08a7a;
  --danger-hover: #eaa695;
  --danger-soft: #3d2620;

  /* Ikyru-Dark-Gegenstueck zum --info-Token oben (Status-Center-Avatar-Badge). */
  --info: #d4c468;
  --info-soft: #3a351c;

  /* Abgeloest 2026-10-01, gleicher Grund wie bei :root[data-theme="ikyru-light"] oben. */
  --chart-hr: #cb8b86;
  --chart-af: #86a3cb;
  --chart-ratio: #a886cb;
  --chart-weight: #86cba3;
  --chart-height: #c4bf8d;
  --chart-barking: #c49a8d;
  --chart-measurement: #cb86cb;
  --chart-stool: #9c8c77;
  --chart-resting-heartrate: #cb86ae;
  --chart-spo2: #86cbcb;
  --chart-hrv: #8686cb;

  /* Marker-Kanal-Aliase/-Farben, gleicher Grund wie im :root-Block oben. */
  --chart-medication_administration: var(--success);
  --chart-medication_planned: var(--text-muted);
  --chart-medication_plan_change: var(--danger);
  --chart-observation: var(--warning);
  --chart-context_event: var(--primary);
  --chart-nutrition_event: var(--chart-measurement);
  --chart-diagnosis: #9dcb86;
  --chart-vet_appointment: #9d86cb;
  --chart-symptom_episode: #cb8691;

  --coverage-source-1: #9aa6a0;
  --coverage-source-2: #c85a4d;
  --coverage-source-3: #c79a5c;
  --coverage-source-4: #7c8a7f;
  --coverage-source-5: #6c7871;
  --coverage-gap: #454d48;

  --act-code-unknown: #7c8a7f;
  --act-code-standing: #c79a5c;
  --act-code-resting: #9aa6a0;
  --act-code-sleep: #6c7871;
  --act-code-walking: #c99a72;
  --act-code-running: #c85a4d;

  --act-resting-1: #9aa6a0;
  --act-resting-2: #6c7871;
  --act-active-1: #c79a5c;
  --act-active-2: #96654a;
  --act-light-1: #d9c8a8;
  --act-light-2: #a67c3d;
  --act-unknown-1: #7c8a7f;
  --act-unknown-2: #6c7871;
  --act-unknown-3: #454d48;

  --band-night: #454d48;
  --band-morning: #c79a5c;
  --band-day: #6c7871;
  --band-evening: #96654a;
  --band-medphase-pre-dose: #7c8a7f;
  --band-medphase-peak: #9aa6a0;
  --band-medphase-mid-cycle: #6c7871;
  --band-medphase-wearing-off: #c79a5c;

  --shadow: 0 12px 35px rgba(0, 0, 0, 0.4);

  color-scheme: dark;
}

:root[data-theme="ikyru-dark"] .button.primary,
:root[data-theme="ikyru-dark"] .button.danger {
  color: var(--bg);
}

/*
 * Ikyru a11y-Variante: KEIN drittes "huebsches" Theme, sondern maximal
 * simplifiziert -- Funktion vor Aesthetik (Nutzer-Vorgabe). Kontrast
 * >=7:1 (WCAG AAA) rechnerisch geprueft (WCAG-Relativluminanz-Formel,
 * nicht nur geschaetzt), siehe Werte in den Kommentaren je Token. Eigene,
 * VOLLE Token-Kaskade (wie :root[data-theme="dark"] oben auch keine
 * "nur Overrides" ist) -- ein Kontrast-Modus kann keine Werte des
 * dekorativen Basisthemes erben, die selbst nicht AAA-geprueft sind.
 */
:root[data-theme="ikyru-a11y"] {
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-muted: #f2f2f2;
  --surface-strong: #e8e8e8;
  --text: #111111;
  --text-muted: #333333;
  --border: #333333;
  --border-strong: #000000;

  /* #111 auf #fff: 18,88:1. */
  /*
   * Design-System "Stille Klarheit", Nutzerentscheidung 2026-10-03
   * (Token-Konsolidierung + Farbentscheidung 1): Hauptakzent aus dem
   * Logo-Blau abgeleitet, fuer den a11y-Modus auf AAA (>=7:1) abgedunkelt.
   * #1c519c auf #fff: 7,76:1.
   */
  --primary: #1c519c;
  --primary-hover: #153f79;
  /* Akzent-Text (#1c519c) auf diesem Pill-/Badge-Hintergrund: 7,22:1. */
  --primary-soft: #f4f7fa;

  /*
   * Zweitfarbe "Jade" (s.o.), ebenfalls auf AAA abgedunkelt, h:178 (Teal)
   * statt --success' h:140 -- klar unterscheidbar. #105b59 auf #fff: 7,89:1.
   */
  --accent-2: #105b59;
  --accent-2-hover: #0d4a48;
  /* Akzent-Text (#105b59) auf diesem Pill-/Badge-Hintergrund: 7,30:1. */
  --accent-2-soft: #ebf9f9;

  /* #1e5631 auf #fff: 8,64:1. Auf --success-soft (#e3ece6): 7,16:1 -- bereits AAA, unveraendert. */
  --success: #1e5631;
  --success-soft: #e3ece6;

  /*
   * s.o.: von #efe6d3 auf #f5f0e4 aufgehellt -- Alt-Ton erreichte nur
   * 6,70:1 (unter AAA 7:1). Neu: 7,31:1.
   */
  --warning: #6b4700;
  --warning-soft: #f5f0e4;

  /*
   * s.o.: von #f0ddd6 auf #f9f2ef aufgehellt -- Alt-Ton erreichte nur
   * 6,19:1 (unter AAA 7:1). Neu: 7,34:1.
   */
  --danger: #8a3419;
  --danger-hover: #6e2913;
  --danger-soft: #f9f2ef;

  /*
   * a11y-Gegenstueck zum --info-Token oben (Status-Center-Avatar-Badge),
   * AAA-geprueft: #5c5400 auf Weiss: 7,71:1, auf --info-soft: 7,09:1.
   */
  --info: #5c5400;
  --info-soft: #f8f6e6;

  /*
   * Abgeloest 2026-10-01, gleicher Grund wie bei :root[data-theme=
   * "ikyru-light"] oben -- hier zusaetzlich auf AAA (>=7:1 statt >=4,5:1)
   * nachjustiert, da ikyru-a11y durchgehend AAA-Kontrast einhaelt.
   */
  --chart-hr: #7b1d14;
  --chart-af: #143f7b;
  --chart-ratio: #47147b;
  --chart-weight: #0d4f28;
  --chart-height: #595318;
  --chart-barking: #71331e;
  --chart-measurement: #7b147b;
  --chart-stool: #3a2b18;
  --chart-resting-heartrate: #7b1450;
  --chart-spo2: #0d4f4f;
  --chart-hrv: #14147b;

  /* Marker-Kanal-Aliase/-Farben, gleicher Grund wie im :root-Block oben. */
  --chart-medication_administration: var(--success);
  --chart-medication_planned: var(--text-muted);
  --chart-medication_plan_change: var(--danger);
  --chart-observation: var(--warning);
  --chart-context_event: var(--primary);
  --chart-nutrition_event: var(--chart-measurement);
  --chart-diagnosis: #234f0d;
  --chart-vet_appointment: #36147b;
  --chart-symptom_episode: #7b1425;

  --coverage-source-1: #1e5631;
  --coverage-source-2: #8b2e24;
  --coverage-source-3: #6b4700;
  --coverage-source-4: #333333;
  --coverage-source-5: #000000;
  --coverage-gap: #999999;

  --act-code-unknown: #666666;
  --act-code-standing: #6b4700;
  --act-code-resting: #1e5631;
  --act-code-sleep: #000000;
  --act-code-walking: #6e241c;
  --act-code-running: #8a3419;

  --act-resting-1: #1e5631;
  --act-resting-2: #000000;
  --act-active-1: #6b4700;
  --act-active-2: #333333;
  --act-light-1: #999999;
  --act-light-2: #6b4700;
  --act-unknown-1: #999999;
  --act-unknown-2: #666666;
  --act-unknown-3: #333333;

  --band-night: #000000;
  --band-morning: #6b4700;
  --band-day: #333333;
  --band-evening: #6e241c;
  --band-medphase-pre-dose: #999999;
  --band-medphase-peak: #1e5631;
  --band-medphase-mid-cycle: #333333;
  --band-medphase-wearing-off: #6b4700;

  --shadow: none;

  color-scheme: light;

  /*
   * Nutzer-Vorgabe: Basis-Schriftgroesse >=18px, Zeilenhoehe 1.6, dicke
   * farbige Fokus-Ringe. font-size auf :root (nicht body) wirkt auf jedes
   * rem-basierte Mass im ganzen Dokument, ohne jede Komponente einzeln
   * anzufassen.
   */
  font-size: 18px;
  line-height: 1.6;
}

:root[data-theme="ikyru-a11y"] :focus-visible {
  outline: 3px solid var(--primary);
  outline-offset: 2px;
}

/*
 * Nutzer-Vorgabe: "alle rein dekorativen Meridian-/Enso-SVG-Elemente
 * ausgeblendet" im a11y-Modus -- Funktion vor Aesthetik. Jedes rein
 * dekorative Grafikelement (Hero-Banner, Kiesgarten-Hintergrund, siehe
 * .ikyru-hero/.ikyru-decorative unten) traegt dafuer die Klasse
 * "ikyru-decorative"; ein Screenreader ueberspringt sie ohnehin
 * (aria-hidden="true", siehe Markup), dieser Block entfernt sie zusaetzlich
 * optisch, damit sie im a11y-Modus keine Aufmerksamkeit/Kontrast-Flaeche
 * beanspruchen, die dem eigentlichen Inhalt fehlen wuerde.
 */
:root[data-theme="ikyru-a11y"] .ikyru-decorative {
  display: none !important;
}

/*
 * Ikyru Zen-Theme: Hero-Banner (Willkommen-Bildschirm) -- standardmaessig
 * UNSICHTBAR (display:none), fuer light/dark/auto also null zusaetzliches
 * Markup-Gewicht sichtbar. Nur bei aktivem Ikyru-Theme eingeblendet.
 * "currentColor" auf den Pfaden faerbt sich automatisch mit dem jeweiligen
 * Theme-Token um (siehe index.html-Kommentar an derselben Stelle) -- keine
 * zweite Datei fuer ikyru-light/-dark noetig.
 */
.ikyru-hero {
  display: none;
}

:root[data-theme^="ikyru"] .ikyru-hero {
  display: block;
  margin: 0 0 20px;
}

/*
 * "Ueber Ikyru"-Seite (Nutzerauftrag 2026-10-03): dieselbe Hero-Grafik, aber bewusst in JEDEM
 * Theme sichtbar (nicht nur bei aktivem Ikyru-Zen-Theme wie die Willkommen-Variante oben) --
 * die Grafik ist hier der Seiteninhalt selbst ("huebsche Grafiken"), nicht ein optionales
 * Theme-Flourish. Hoehere Spezifitaet (zwei Klassen) gewinnt gegen die display:none-Grundregel;
 * die a11y-Theme-Regel oben (.ikyru-decorative, !important) blendet sie dort weiterhin aus.
 */
.about-hero.ikyru-hero {
  display: block;
  margin: 0 0 20px;
}

/*
 * Wortmarke-Icon (Topbar, links vom Markennamen): Nutzer-Vorgabe
 * (2026-09-27) -- gehoert fest zur Marke, nicht mehr an das Ikyru-Zen-
 * Theme gekoppelt wie zuvor. Immer sichtbar (ausser im a11y-Theme, siehe
 * .ikyru-decorative-Regel oben), "currentColor" faerbt sich automatisch
 * mit dem jeweiligen Theme-Token um.
 */
.ikyru-wordmark-icon {
  display: inline-block;
  width: 26px;
  height: 26px;
  vertical-align: middle;
  margin-right: 6px;
  color: var(--primary);
}

.ikyru-hero-svg {
  display: block;
  width: 100%;
  max-width: 320px;
  height: auto;
}

.ikyru-hero-enso {
  color: var(--primary);
}

.ikyru-hero-meridian {
  color: var(--text-muted);
  opacity: 0.35;
}

.ikyru-hero-pulse {
  color: var(--primary);
}

/*
 * Nutzerauftrag 2026-09-24/26: reichhaltigere Recraft.ai-Tuschezeichnung als Ersatz fuer
 * .ikyru-hero-simple, NUR bei ikyru-light (helle Flaeche noetig, siehe Kommentar in index.html).
 * .ikyru-hero-rich ist standardmaessig ausgeblendet -- fuer ikyru-dark/base/a11y also kein
 * zusaetzliches Rendergewicht sichtbar, nur das (bereits vorhandene) Markup liegt im DOM.
 */
.ikyru-hero-rich {
  display: none;
}

:root[data-theme="ikyru-light"] .ikyru-hero-simple {
  display: none;
}

:root[data-theme="ikyru-light"] .ikyru-hero-rich {
  display: block;
}

/*
 * "Ueber Ikyru"-Seite (Nutzerauftrag 2026-10-03): nutzt bewusst NUR die leichte .ikyru-hero-simple-
 * Variante (keine zweite Kopie der sehr grossen .ikyru-hero-rich-Tuschezeichnung hier noetig) --
 * diese Regel gewinnt gegen die ikyru-light-Austauschregel direkt darueber (eine Klasse mehr auf
 * dem Wrapper), damit die einfache Linien-Grafik hier in JEDEM Theme sichtbar bleibt.
 */
:root[data-theme="ikyru-light"] .about-hero .ikyru-hero-simple {
  display: block;
}

/*
 * Wortmarke "Ikyru" (Recraft.ai) unter dem Hero-Grafikelement -- fuer ikyru-light UND ikyru-dark,
 * currentColor faerbt sich automatisch mit dem Theme-Akzent. Ergaenzt, ersetzt nicht, den
 * textbasierten Markennamen (bleibt fuer Screenreader/Suche unveraendert bestehen).
 */
.ikyru-hero-wordmark {
  display: block;
  width: 100%;
  max-width: 220px;
  height: auto;
  margin: 14px auto 0;
  color: var(--primary);
}

/*
 * Kopfleisten-Banner (Nutzerauftrag 2026-09-27): anders als .ikyru-hero IMMER sichtbar (jede
 * Ansicht, jedes Theme -- nicht an data-theme^="ikyru" gekoppelt), deshalb zurueckhaltend gestaltet:
 * geringe Hoehe, keine Animation (Nutzer-Vorgabe "ruhig"). .ikyru-decorative blendet ihn im
 * a11y-Theme aus wie jedes andere rein dekorative Element (siehe Regel weiter oben).
 *
 * Live-Fund (Nutzerauftrag 2026-09-28, "Grafiken sind immernoch nicht zu sehen"): "--border" war als
 * Farbe zu subtil -- dieses Token ist auf Trennlinien-Kontrast ausgelegt (z.B. #dcd6c9 auf #f7f5f0
 * im hellen Theme, kaum messbarer Helligkeitsunterschied), zusaetzlich mit 0,45-0,7 Deckkraft
 * multipliziert praktisch unsichtbar. "--text-muted" ist das Token, das .ikyru-hero bereits
 * erfolgreich fuer denselben Zweck nutzt (gedaempft, aber lesbar) -- hier uebernommen, Deckkraft
 * angehoben, damit das Banner tatsaechlich wahrnehmbar ist, ohne laut zu wirken.
 *
 * Umbau (Nutzerauftrag 2026-09-28, "nicht unter Produktname/Profilbild, sondern in dieselbe Zeile
 * dahinter/in den Hintergrund"): war ein eigener Block UNTER .topbar (voller Breite, eigene Zeile) --
 * jetzt absolut positionierter Hintergrund INNERHALB von .topbar (siehe index.html: erstes Kind vor
 * .brand), hinter .brand/.topbar-actions liegend. .topbar bekommt dafuer eine eigene
 * Stapelkontext-Ebene (position:relative + z-index), .brand/.topbar-actions werden explizit
 * darueber gelegt -- kein "aus dem Fluss geschoben"/uebersprungenes Layout, nur eine Ebene tiefer.
 * pointer-events:none, damit die rein dekorative Grafik keine Klicks auf Markenname/Profilbild
 * abfaengt.
 */
.topbar {
  position: relative;
  z-index: 0;
}

.brand,
.topbar-actions {
  position: relative;
  z-index: 1;
}

/*
 * Live-Fund (Nutzerauftrag 2026-09-28, "Kopfzeile sieht schlecht aus"): .topbar ist flex-wrap --
 * bei schmaler Breite faellt .topbar-actions (Profilbild) unter .brand (Markenname) in eine zweite
 * Zeile, aber .ikyru-header-banner spannte bisher IMMER die volle (dann hoehere) .topbar-Hoehe auf
 * und zentrierte sich darin -- die Linien/der Enso-Kreis landeten dadurch in der LEEREN LUECKE
 * zwischen den beiden umgebrochenen Zeilen, statt hinter Text/Bild zu liegen (wirkte wie ein
 * abgerissenes, zufaelliges Element statt wie Gestaltung). Fix: fest auf die Hoehe EINER Zeile
 * (oben) gepinnt, statt sich ueber die ganze, variable Topbar-Hoehe zu strecken -- liegt dadurch
 * bei breiter Ansicht (Marke+Bild nebeneinander) hinter beiden, bei schmaler (umgebrochener)
 * Ansicht sauber nur hinter der Markenzeile, nie mehr in einer Luecke.
 */
.ikyru-header-banner {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.ikyru-header-banner-svg {
  display: block;
  width: 100%;
  height: 22px;
  color: var(--text-muted);
}

.ikyru-header-banner-enso {
  opacity: 0.85;
}

.ikyru-header-banner-meridian {
  opacity: 0.7;
}

.ikyru-header-banner-pulse {
  opacity: 0.55;
}

* {
  box-sizing: border-box;
}

html {
  min-height: 100%;
  background: var(--bg);
  /*
   * Phase E5 (WCAG-2.2-Audit, 2026-09-15, SC 2.4.11 "Focus Not
   * Obscured" -- neu in WCAG 2.2): .app-sticky-header (Topbar) ist
   * `position: sticky; top: 0`, der Scroll-Kontext ist der Viewport
   * selbst (kein eigener overflow-Container, siehe Kommentar bei
   * .app-content-column). Ohne scroll-padding-top konnte ein per Tab
   * fokussiertes Element direkt unter der Topbar teilweise/ganz
   * dahinter verschwinden. 5rem ist eine bewusste Naeherung an die
   * typische Topbar-Hoehe (Padding + Inhalt, variiert leicht durch
   * flex-wrap/Safe-Area) -- etwas Luft ist unkritisch, zu wenig waere
   * es nicht.
   */
  scroll-padding-top: 5rem;
}

body {
  min-width: 320px;
  min-height: 100vh;
  margin: 0;
  background:
    radial-gradient(
      circle at 0 0,
      color-mix(in srgb, var(--primary) 9%, transparent),
      transparent 30rem
    ),
    var(--bg);

  color: var(--text);
  line-height: 1.5;
  /*
   * AP12 Thread M1: Basis-Typografie-Skala fluid gemacht (gleiche
   * clamp(min, preferred-vw, max)-Formel-Konvention wie h1/h2/Padding
   * an den bereits bestehenden 5 clamp()-Stellen dieser Datei). Wirkt
   * nur auf tatsaechlich gerenderten Text (line-height/font-size),
   * NICHT auf rem-basierte Layout-/Padding-Masse (die bleiben an
   * :root gebunden, unveraendert).
   */
  font-size: clamp(0.95rem, 0.3vw + 0.9rem, 1rem);
}

button,
input,
select,
textarea {
  font: inherit;
}

button,
select,
input,
textarea {
  border-radius: var(--radius-small);
}

button {
  cursor: pointer;
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}

input,
select,
textarea {
  width: 100%;
  padding: 0.7rem 0.8rem;
  /*
   * Phase E5 (WCAG-2.2-Audit, 2026-09-15): --border allein lag im
   * Ruhezustand unter 3:1 (Non-text-Kontrast, SC 1.4.11) gegen
   * --surface in beiden Themes -- --border-strong verwendet, das
   * andernorts im Projekt bereits fuer genau diesen Zweck existiert
   * (z.B. .button.secondary-Rahmen).
   */
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  outline: none;
}

/*
 * AP11 Thread C: ersetzt die einzige Inline-style="width: 5em"-Stelle
 * im gesamten index.html (Periodenvergleich-Anzahl-Feld) -- Voraussetzung
 * fuer eine CSP ohne style-src 'unsafe-inline'.
 */
.input-width-narrow {
  width: 5em;
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/*
 * Phase E5 (WCAG-2.2-Audit, 2026-09-15, SC 3.3.1): visuelles
 * Gegenstueck zu App.UI.showFieldError() (ui-core.js) -- Feld-Rahmen
 * markiert den Fehler zusaetzlich zur programmatischen aria-invalid/
 * aria-describedby-Verknuepfung, nicht nur der danebenstehende Text.
 */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger);
}

.field-error {
  display: block;
  color: var(--danger);
  font-size: 0.78rem;
  font-weight: 600;
}

/*
 * Phase E5 (WCAG-2.2-Audit, 2026-09-15, SC 3.3.2): sichtbares
 * Pflichtfeld-Signal zusaetzlich zum (bereits vorhandenen, aber rein
 * programmatischen) `required`-Attribut -- `aria-hidden`, da
 * Screenreader `required` ohnehin automatisch ansagen; ein zusaetzlich
 * vorgelesenes "*" waere Doppelinformation.
 */
.required-marker {
  color: var(--danger);
}

/*
 * AP12 Thread M6: generische, sichtbare Fokus-Ring-Regel fuer alle
 * interaktiven Elemente, die bisher nur auf den unzuverlaessigen
 * Browser-Default angewiesen waren (`<button>`/`<a>`/`[role="button"]`/
 * jedes `[tabindex]`-Element, z.B. Profilbild-Button, klickbare Karten ohne
 * eigene .clickable-row-Klasse). Nutzt die bestehende --primary-Variable,
 * kein neuer Farbwert. Bewusst additiv/als Sicherheitsnetz gedacht --
 * bereits bestehende, speziellere Regeln (.clickable-row:focus-visible
 * in analysis-drilldown.css, .toggle-chip/.segmented-option ueber
 * :has(input:focus-visible)) bleiben unangetastet und gewinnen dort
 * weiterhin (gleiche oder hoehere Spezifitaet, spaeter geladen).
 */
a:focus-visible,
button:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

textarea {
  min-height: 5rem;
  resize: vertical;
}

h1,
h2,
h3,
p {
  margin-top: 0;
}

h1 {
  margin-bottom: 0;
  font-size: clamp(1.2rem, 2vw, 1.55rem);
  letter-spacing: 0.04em;
}

h2 {
  margin-bottom: 0.35rem;
  font-size: clamp(1.45rem, 3vw, 2rem);
}

h3 {
  margin-bottom: 0.3rem;
  font-size: clamp(1rem, 0.3vw + 0.95rem, 1.1rem);
}

small {
  color: var(--text-muted);
}

.hidden,
[hidden] {
  display: none !important;
}

/*
 * Korb E, Paket E1.1 (SVG-Sprite-Icon-System, 2026-09-16): einzige
 * Styling-Stelle fuer Sprite-Icons -- App.UI.renderIcon() (ui-core.js)
 * setzt diese Klasse auf jedes erzeugte <svg>. `fill="currentColor"`
 * in den Symbol-Pfaden (Pflicht, siehe ICON_LICENSES.md/E1.7-Pruefung)
 * + `color: var(--icon-color)` hier macht Icons theme-faehig, ohne
 * dass ein Icon selbst Farbwerte enthalten darf. Groesse ist bewusst
 * NICHT hier fest verdrahtet (24px Navigation, 16px Tabellen/Listen
 * laut E1.1) -- App.UI.renderIcon()s `sizePx`-Option setzt width/
 * height direkt am Element, `flex-shrink: 0` verhindert nur ein
 * Stauchen in Flex-Kontexten (Buttons/Listenzeilen).
 */
.ds-icon {
  display: inline-block;
  flex-shrink: 0;
  color: var(--icon-color);
  fill: currentColor;
  vertical-align: middle;
}

.muted,
.hint {
  color: var(--text-muted);
}

/*
 * AP10 (Thread H): Groessenlimit-Hinweis fuer den Export-Dialog --
 * nicht blockierend, gleiche Warnfarb-Konvention wie ueberall sonst.
 */
.hint.warning {
  color: var(--warning);
  background: var(--warning-soft);
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-sm, 6px);
}

/*
 * AP42b-Nachtrag (Onboarding-Overlay-Deadlock-Fix, 2026-09-11):
 * gleiche Struktur wie .hint.warning, nur fuer echte Fehlschlaege
 * (z.B. #profileGateStatusMessage nach einer fehlgeschlagenen
 * Backup-Wiederherstellung) statt blosser Warnungen.
 */
.hint.danger {
  color: var(--danger);
  background: var(--danger-soft);
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-sm, 6px);
}

/*
 * AP49 UI-Wiring-Plan (docs/ap49/04-ui-wiring-plan.md, Frage 1):
 * gleiche Struktur wie .hint.warning/.hint.danger, aber neutraler Ton
 * (--primary statt --warning/--danger) -- eine Chart-Empfehlung ist
 * kein Warn-/Fehlerzustand.
 */
.hint.info {
  color: var(--primary);
  background: var(--primary-soft);
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius-sm, 6px);
}

/*
 * AP52/53 (KI-Integration Phase B, 2026-09-19, ENTWURF): Consent-
 * Vorschau-Inhalt (js/ui/ui-ai-panel.js buildConsentContent()) -- inline
 * im Panel UND im Consent-Dialog wiederverwendet. Bewusst schlicht
 * (keine Karten/Grids), da es sich um eine feldgenaue Text-Vorschau
 * handelt, kein visuelles Feature.
 */
.ki-consent-preview,
#kiConsentDialogBody {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  padding: 0.75rem 1rem;
  margin-top: 0.75rem;
}

.ki-consent-section-heading {
  font-weight: 600;
  margin: 0.75rem 0 0.25rem;
}

.ki-consent-section-heading:first-child {
  margin-top: 0;
}

.ki-consent-field {
  margin: 0.15rem 0;
}

.ki-consent-question {
  font-style: italic;
}

/* Kontextpaket v2: Ebene 2 der Einwilligung (aufklappbarer Volltext) und Modellwahl je Anfrage. */
.ki-consent-details {
  margin: 0.75rem 0;
  text-align: left;
}

.ki-consent-package {
  max-height: 16rem;
  overflow: auto;
  margin: 0.5rem 0 0;
  padding: 0.5rem;
  font-size: 0.75rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  border: 1px solid var(--border, #cbd5e1);
  border-radius: 6px;
}

.ki-consent-model-choice {
  display: block;
  margin: 0.5rem 0;
}

/*
 * KI-Gesamtkonzept Abschnitt 1.2 Punkt 2 / 3.6 (2026-09-19):
 * "dauerhaft sichtbares Badge 'KI-Interpretation'" -- erste
 * `.ai-generated-badge`-Klasse im Projekt (vorher 0 Treffer, siehe
 * docs/concepts/konzept-ki-integration.md Abschnitt 5). Bewusst
 * kontrastreich (--primary statt eines neutralen Grautons), damit ein
 * KI-generierter Text nie mit einem regelbasierten Systemtext
 * verwechselt wird.
 */
/*
 * KI-04 (docs/concepts/ki-gesamtkonzept.md Abschnitt 2.4, 2026-09-19):
 * Vorlagen-Buttons vor dem Fragefeld -- einfacher Zeilenumbruch-Fluss,
 * kein festes Grid (Anzahl/Textlaenge der Vorlagen kann sich aendern).
 */
.ki-template-questions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.ai-generated-badge {
  display: inline-block;
  background: var(--primary);
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.15rem 0.5rem;
  border-radius: var(--radius-sm, 6px);
}

/*
 * AP-Account Phase 1.3 (2026-09-13): Wiederherstellungsschluessel-
 * Anzeige bei der Konto-Ersteinrichtung -- monospace fuer eindeutige
 * Zeichenerkennung (0/O, 1/I sind ohnehin per Alphabet ausgeschlossen,
 * siehe crypto-wrapper.js, aber Monospace bleibt fuer generelle
 * Abschreib-Genauigkeit sinnvoll), grosszuegiger Zeilenabstand.
 */
.recovery-key-display {
  font-family: ui-monospace, "Courier New", monospace;
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  background: var(--surface-alt, var(--warning-soft));
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  padding: 0.75rem 1rem;
  text-align: center;
  user-select: all;
}

.chart-recommendation-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

.chart-recommendation-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

/*
 * AP11 Thread I: persistenter Export-Datenschutzhinweis -- dezent
 * abgesetzt (Border statt Warnfarbe, da kein Fehlerzustand, nur ein
 * staendiger Hinweis), gleiche Token-Basis wie .hint.warning.
 */
.export-privacy-hint {
  padding: 0.4rem 0.6rem;
  border-left: 3px solid var(--border);
  border-radius: var(--radius-sm, 6px);
}

.eyebrow {
  margin-bottom: 0.25rem;
  color: var(--primary);
  font-size: 0.7rem;
  font-weight: 750;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/*
 * AP46-Nachtrag (Branding, 2026-09-11): eigener Klassenname statt
 * .eyebrow-Wiederverwendung -- .eyebrow steht an ueber 70 anderen
 * Stellen im Markup IMMER VOR dem Inhalt, den es beschriftet (Kicker-
 * Muster mit margin-bottom). Der App-Untertitel sitzt jetzt UNTER dem
 * Titel (Nutzer-Vorgabe), braucht also Abstand OBEN statt unten -- ein
 * globales Umdrehen von .eyebrow haette alle anderen Stellen verschoben.
 */
.brand-subtitle {
  margin: 0.2rem 0 0;
  color: var(--primary);
  font-size: 0.7rem;
  font-weight: 750;
  letter-spacing: 0.08em;
}

.brand-title-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/*
 * P3 Punkt 7 (Nutzerauftrag 2026-09-22): App-Name ist jetzt ein Sprungziel zum Cockpit -- Button-Reset, damit er weiterhin
 * wie die bisherige Ueberschrift aussieht (Groesse/Abstand kommen vom umschliessenden h1), nur mit Zeiger-Cursor und einer
 * dezenten Hover-Unterstreichung als Hinweis auf die Klickbarkeit.
 */
.app-name-link {
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  text-decoration: none;
}

.app-name-link:hover,
.app-name-link:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.app-info-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.68rem;
  font-weight: 700;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
}

.app-info-button:hover,
.app-info-button:focus-visible {
  color: var(--primary);
  border-color: var(--primary);
}

/*
 * Phase E5 (WCAG-2.2-Audit, 2026-09-15, SC 2.5.8 "Target Size
 * Minimum" -- neu in WCAG 2.2, 24x24px): der sichtbare 1,1rem-Kreis
 * (17,6px) bleibt bewusst unveraendert (visuelles Design neben der
 * Ueberschrift) -- stattdessen vergroessert ein unsichtbares
 * `::before` nur die klickbare/antippbare Flaeche auf 24x24px.
 */
.app-info-button::before {
  content: "";
  position: absolute;
  inset: -0.2rem;
}

.app-info-popover {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 20;
  margin-top: 0.4rem;
  width: max-content;
  max-width: min(320px, 80vw);
  padding: 0.6rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 400;
}

.app-info-popover p {
  margin: 0;
}

/*
 * Header-Verschlankung (2026-09-15): der ehemals permanente
 * .topbar-disclaimer-Text lebt jetzt als zweiter Absatz hier --
 * gleiche gedaempfte Optik (--text-muted, kleinere Schrift) wie
 * vorher im Header, optisch klar vom Marketing-Absatz darueber
 * abgesetzt statt gleichrangig vermischt.
 */
.app-info-popover p + .app-info-popover-disclaimer {
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.78rem;
}

/*
 * Rechtstexte-Ergaenzung (2026-09-15): Link zu Impressum/Datenschutz
 * innerhalb des Info-Popovers -- eigene Zeile, optisch als Link statt
 * als weiterer Fliesstext-Absatz erkennbar.
 */
.app-info-popover-legal-link {
  display: block;
  width: 100%;
  margin-top: 0.6rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--primary);
  font-size: 0.78rem;
  font-weight: 600;
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}

/*
 * AP-GOVERNANCE-1-Fund (2026-09-17): generischer Textlink-Stil fuer
 * die 2 neuen Datenschutz-Modal-Verlinkungen (Onboarding, NAS-Sync-
 * Aktivierung) -- gleiche Optik wie .app-info-popover-legal-link,
 * aber ohne deren Popover-spezifisches Block-Layout, damit er inline
 * in einem normalen <p class="hint"> sitzen kann.
 */
.legal-info-inline-link {
  padding: 0;
  border: none;
  background: none;
  color: var(--primary);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

#legalInfoModal {
  width: min(42rem, 92vw);
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 12px);
  background: var(--surface);
  color: var(--text);
}

#legalInfoModal::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

.legal-modal-chrome {
  position: sticky;
  top: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.legal-modal-body {
  padding: 1rem 1.25rem 1.5rem;
  overflow-y: auto;
  max-height: calc(88vh - 3.5rem);
}

.legal-modal-body h3 {
  margin-top: 2rem;
}

.legal-modal-body h3:first-child {
  margin-top: 0;
}

.legal-modal-body h4 {
  margin-bottom: 0.3rem;
}

.legal-modal-body p,
.legal-modal-body ul {
  margin: 0.3rem 0 0.9rem;
  color: var(--text-muted);
}

.legal-modal-body .legal-version-hint {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.app-shell {
  width: min(1480px, calc(100% - 2rem));
  margin: 0 auto;
  padding: 1rem 0 3rem;
  /*
   * AP12 Thread M1 (CSS-only, kein Markup-Umbau): benannter Container
   * fuer die Drei-Modi-@container-Ebene weiter unten (Side-Rail breit/
   * kompakt/Bottom-Tab-Nav, siehe Korb-E-Kommentar bei .app-navigation).
   * Bestehende @media-Breakpoints (1050px/760px/450px, oben/unten in
   * dieser Datei) bleiben UNVERAENDERT die Ebene fuer feingranulare
   * Grid-Spalten-Kollabierung innerhalb einzelner Panels -- zwei Ebenen,
   * keine Abloesung.
   *
   * Korb E, Paket E2 (Side-Rail, 2026-09-16): .app-shell ist jetzt ein
   * 2-Spalten-Grid (Rail + Inhaltsspalte) als BREITE/MITTLERE Vorgabe --
   * unter 728px Containerbreite loest die bestehende @container-Regel
   * das Grid wieder auf (einspaltig, Bottom-Tab-Nav). `align-items:
   * start` verhindert, dass die kuerzere Inhaltsspalte auf die Hoehe der
   * (durch `height: 100vh` immer viewport-hohen) Rail gestreckt wird.
   */
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  /* Kein `container:` mehr (v1.18.0): die Modus-Schwellen laufen ueber @media (siehe Kommentar vor den Modus-Regeln). */
}

.app-content-column {
  min-width: 0;
}

/*
 * Teil-D-Fix (2026-09-16, Nutzerauftrag): Topbar (App-Name/aktives
 * Profil/Live-Status via #globalTaskIndicator) bleibt beim Scrollen
 * sichtbar, auf allen Bildschirmgroessen -- vorher verschwand sie
 * vollstaendig, sobald der Nutzer nach unten scrollte, auch waehrend
 * z.B. ein Import im Hintergrund lief. `background: var(--bg)`
 * verhindert, dass durchscrollender Seiteninhalt unter der (teils
 * transparenten) Topbar durchscheint. z-index 40 liegt bewusst UNTER
 * Processing-Overlay (100) und Toast-Stack (300), aber UEBER normalem
 * Seiteninhalt und der mobilen Bottom-Tab-Nav (20).
 *
 * Korb E, Paket E2 (2026-09-16): umschliesst seit der Side-Rail-Umsetzung
 * NUR NOCH die Topbar (vorher zusaetzlich .app-navigation) -- die Rail
 * ist jetzt ein eigener, voll-hoher Sticky-Kontext auf Grid-Ebene, siehe
 * .app-navigation unten. Innerhalb von .app-content-column bleibt der
 * Scroll-Kontext (Viewport) derselbe, das Sticky-Verhalten aendert sich
 * dadurch nicht.
 */
.app-sticky-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--bg);
  border-bottom: 1px solid transparent;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /*
   * AP12 Thread M1: env(safe-area-inset-top) fuer Geraete mit Notch/
   * Dynamic Island (viewport-fit=cover ist bereits in index.html
   * gesetzt, bisher aber 0 env()-Verwendungen im Projekt). Fallback 0
   * auf Geraeten ohne Safe-Area -- additiv zum bestehenden 0.75rem.
   */
  padding: calc(0.75rem + env(safe-area-inset-top, 0px)) 0 1.25rem;
  flex-wrap: wrap;
}

/*
 * AP11 Thread I: persistenter Disclaimer -- width:100% zwingt den
 * Absatz im flex-wrap-Header auf eine eigene Zeile unterhalb von
 * .brand/.topbar-actions, ohne deren Layout zu beeinflussen.
 */
.topbar-disclaimer {
  width: 100%;
  margin: 0;
  font-size: 0.78rem;
  color: var(--text-muted);
}

/*
 * Release-1.0-Vorbereitung (2026-09-13): Feature-Detection-Hinweis,
 * siehe #browserSupportWarning in index.html -- gleiche Position/Groesse
 * wie .topbar-disclaimer, nur farblich als Warnung hervorgehoben statt
 * gedaempft.
 */
.topbar-disclaimer-warning {
  color: var(--warning);
  font-weight: 600;
}

.topbar-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.65rem;
  flex-wrap: wrap;
}

/*
 * App-Shell Auftrag 2026-10-01, Schritt 2b ("App-Shell Desktop"): Logo +
 * Wortmarke leben jetzt am Kopf der Rail (.nav-rail-brand, siehe weiter
 * oben, erzeugt von generateNavButtons() in js/ui/ui-core.js) -- am
 * Desktop (> 760px) blendet das hier den alten Marken-Block in der
 * Topbar aus, damit er nicht doppelt erscheint ("rechts nur das
 * Profilbild", Nutzervorgabe). #appInfoButton/#appInfoPopover bleiben
 * bewusst UNVERAENDERT in der Topbar sichtbar (kein Umzug in die Rail,
 * keine zweite Popover-Kopie dort) -- nur Icon-SVG und Ueberschrift
 * werden ausgeblendet. Unter 760px (siehe @media (max-width: 760px)
 * weiter unten): die Rail wird zur Bottom-Tab-Nav ohne Platz fuer
 * Logo+Wortmarke (.nav-rail-brand dort ausgeblendet) -- die Topbar
 * zeigt ihr eigenes Logo deshalb weiterhin mobil.
 */
@media (min-width: 761px) {
  .topbar .brand-title-row > .ikyru-wordmark-icon,
  .topbar .brand-title-row > h1 {
    display: none;
  }
}

/*
 * Korb B (2026-09-14): Konto-/Profilbild-Knopf-Paar bleibt bei jeder
 * Breite nebeneinander -- .topbar-actions selbst darf umbrechen (siehe
 * oben), dieses innere Paar nicht.
 */
.topbar-profile-icons {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  flex-shrink: 0;
  gap: 0.4rem;
}

/* Profilbild: Kopfzeile, "Aktuelles Profil"-Vorschau (gross) und
   Thumbnails in der Profilliste (klein) teilen sich dieselbe Optik --
   Bild als Hintergrund, gewaehlter Avatar (App.AvatarIcons, seit
   2026-09-28) als eingehaengtes <svg>, oder Initiale+deterministische
   Farbe als Fallback (siehe App.Utils.getProfilePictureInitial()/
   getProfilePictureColor()). */
.profile-picture-circle {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background-size: cover;
  background-position: center;
  color: #ffffff;
  font-weight: 750;
  font-size: 1rem;
}

.profile-picture-circle-large {
  width: 4.5rem;
  height: 4.5rem;
  font-size: 1.6rem;
}

.profile-picture-circle-small {
  width: 1.8rem;
  height: 1.8rem;
  margin-right: 0.5rem;
  font-size: 0.8rem;
}

/* Nutzerauftrag 2026-09-28 (10 vordefinierte Zen-Avatare): das per
   App.AvatarIcons.buildIconElement() eingehaengte <svg> braucht eine
   explizite Groesse -- ohne width/height faellt es sonst auf die
   SVG-Standardgroesse (300x150) zurueck statt den Kreis zu fuellen. */
.profile-picture-circle-avatar-icon svg {
  width: 64%;
  height: 64%;
  color: #ffffff;
}

.profile-picture-button {
  padding: 0;
  border: none;
  background: transparent;
  border-radius: 50%;
  cursor: pointer;
  transition: box-shadow 150ms ease;
}

.profile-picture-button:hover {
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.profile-picture-editor {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.profile-picture-editor-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/*
 * Nutzerauftrag 2026-09-28 (10 vordefinierte Zen-Avatare): schlanker Aufklapper (gleiches Muster
 * wie .chart-settings-disclosure -- Dreieck-Marker, kein Panel-Rahmen), da dies innerhalb eines
 * bestehenden .profile-picture-editor-Blocks sitzt statt in einem eigenen Panel.
 */
.avatar-picker-details {
  margin-bottom: 1rem;
}

.avatar-picker-details > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--text-muted);
  list-style: none;
  padding: 0.25rem 0;
}

.avatar-picker-details > summary::-webkit-details-marker {
  display: none;
}

.avatar-picker-details > summary::before {
  content: "\25b8 ";
}

.avatar-picker-details[open] > summary::before {
  content: "\25be ";
}

.avatar-picker-details[open] > summary {
  color: var(--text);
}

/* Praezisierung 2026-09-28: der Alternative-zum-Foto-Hinweistext braucht knapperen Abstand als der Browser-Standardabsatz. */
.avatar-picker-details > .hint {
  margin: 0.3rem 0 0;
  font-size: 0.85rem;
}

.avatar-picker-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.avatar-picker-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  width: 4.4rem;
  padding: 0.5rem 0.3rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  background: var(--surface);
  color: var(--text-muted);
  cursor: pointer;
  font-size: 0.72rem;
  line-height: 1.1;
  text-align: center;
  transition: border-color 150ms ease, color 150ms ease, background 150ms ease;
}

.avatar-picker-option svg {
  width: 1.8rem;
  height: 1.8rem;
}

.avatar-picker-option:hover {
  border-color: var(--primary);
  color: var(--text);
}

.avatar-picker-option[aria-pressed="true"] {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--text);
  font-weight: 700;
}

/* Zwei-Zonen-Gliederung innerhalb des Einstellungen-Tabs
   (Profilverwaltung / App-Einstellungen) -- ein Tab, klar getrennte
   Bereiche, keine neue Navigation. */
.settings-zone {
  margin-bottom: 1.75rem;
}

.settings-zone + .settings-zone {
  padding-top: 1.5rem;
  border-top: 2px solid var(--border);
}

.settings-zone-title {
  margin-bottom: 0.75rem;
}

/* Status-Toasts: ersetzen die frueher dauerhafte Kopfzeilen-Pille durch
   deutlich prominentere, sich selbst aufraeumende Popups. Container
   selbst ist klick-durchlaessig, nur die einzelnen Toasts fangen Klicks
   ab -- blockiert damit nie den Rest der App (bewusst getrennt vom
   absichtlich blockierenden .processing-overlay). */
.toast-stack {
  position: fixed;
  z-index: 300;
  top: 1rem;
  right: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: min(22rem, calc(100vw - 2rem));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-small);
  background: var(--surface-strong);
  color: var(--text);
  box-shadow: var(--shadow);
  font-size: 0.85rem;
  font-weight: 700;
  pointer-events: auto;
  animation: view-fade-in 160ms ease-out;
}

.toast[data-status="success"] {
  background: var(--success-soft);
  color: var(--success);
}

.toast[data-status="warning"] {
  background: var(--warning-soft);
  color: var(--warning);
}

.toast[data-status="error"] {
  background: var(--danger-soft);
  color: var(--danger);
}

.toast-close {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 0.2rem;
}

/* Korb C6 (2026-09-14): optionaler Toast-Aktionslink, siehe setStatus(). */
.toast-action {
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  padding: 0 0.2rem;
}

.status-pill,
.severity-pill,
.tag {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  padding: 0.3rem 0.65rem;
  border-radius: 999px;
  background: var(--surface-strong);
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}

.status-pill[data-status="success"] {
  background: var(--success-soft);
  color: var(--success);
}

.status-pill[data-status="warning"] {
  background: var(--warning-soft);
  color: var(--warning);
}

.status-pill[data-status="error"] {
  background: var(--danger-soft);
  color: var(--danger);
}

/*
 * Korb E, Paket E2 (Side-Rail, 2026-09-16, Nutzerauftrag): neue
 * BREITE/MITTLERE Vorgabe -- vertikale, voll-hohe, sticky Rail statt
 * der bisherigen horizontalen Top-Leiste. Grid-Kind von .app-shell
 * (siehe dort), daher `grid-column`/`grid-row` nicht noetig (erste
 * Spalte per `grid-template-columns: auto 1fr`). `height: 100vh` +
 * `position: sticky; top: 0` machen die Rail unabhaengig von der
 * tatsaechlichen Topbar-Hoehe voll-hoch und fixiert -- sie liegt
 * NEBEN Topbar+Inhalt, nicht darunter (anders als vorher). Unter
 * 728px Containerbreite (siehe @container-Regel unten) wird all das
 * auf die bestehende horizontale Bottom-Tab-Nav zurueckgesetzt.
 */
.app-navigation {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0.75rem 0.6rem;
  border-right: 1px solid var(--border);
  background: var(--surface);
  position: sticky;
  top: 0;
  height: 100vh;
  width: 15rem;
  flex-shrink: 0;
}

/*
 * App-Shell Auftrag 2026-10-01, Schritt 2b ("App-Shell Desktop"): Logo +
 * Wortmarke jetzt am Kopf der Rail statt in der Topbar (js/ui/ui-core.js
 * generateNavButtons() erzeugt das Element programmatisch als erstes
 * Kind). `.ikyru-wordmark-icon` liefert bereits Groesse/Farbe (currentColor,
 * selbes SVG wie bisher in der Topbar), hier nur Layout/Abstand ergaenzt.
 */
.nav-rail-brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.4rem 0.9rem 0.9rem;
  margin-bottom: 0.3rem;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  text-align: left;
}

.nav-rail-brand:hover {
  color: var(--primary);
}

.nav-rail-brand .ikyru-wordmark-icon {
  flex-shrink: 0;
  width: 1.6rem;
  height: 1.6rem;
}

.nav-rail-brand-label {
  font-weight: 700;
  font-size: 1rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-button {
  /*
   * UI/UX-Leitlinien Regel 1 (2026-09-11): Positionierungskontext fuer
   * .nav-button-badge (absolut positionierter Eck-Punkt).
   */
  position: relative;
  /*
   * Korb E, Paket E2: Icon + Label nebeneinander (vorher: Icon als
   * eigener Block, Label als nackter Textknoten in einer horizontalen
   * Leiste, kein eigenes Flex-Layout noetig). `justify-content: flex-start`
   * statt center -- Rail-Eintraege sind linksbuendig, wie bei den
   * meisten Navigation-Rail-Referenzimplementierungen (Material/Fluent).
   */
  display: flex;
  align-items: center;
  gap: 0.75rem;
  justify-content: flex-start;
  width: 100%;
  /* AP12 Thread M1: min-height ergaenzt (44px-Touch-Ziel, war zuvor nur
     ueber Padding implizit ~38-40px hoch). */
  min-height: 2.75rem;
  padding: 0.65rem 0.9rem;
  border: 0;
  border-radius: var(--radius-small);
  background: transparent;
  color: var(--text-muted);
  font-size: clamp(0.8rem, 0.3vw + 0.76rem, 0.88rem);
  font-weight: 700;
  text-align: left;
}

.nav-button-icon {
  flex-shrink: 0;
  width: 1.4rem;
  text-align: center;
}

.nav-button-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-button:hover {
  background: var(--surface-strong);
  color: var(--text);
}

.nav-button.active {
  background: var(--primary);
  color: #ffffff;
}

/*
 * Korb E, Paket E2.2 (manuelle Umschaltbarkeit, 2026-09-16): Button am
 * unteren Ende der Rail (siehe generateNavButtons(), ui-core.js --
 * `margin-top: auto` schiebt ihn in der Flex-Spalte nach unten). Nur
 * im breiten/mittleren Rail-Modus relevant -- unter 728px
 * Containerbreite blendet die dortige @container-Regel ihn aus (die
 * mobile Bottom-Tab-Nav kennt keinen Collapse-Zustand).
 */
.nav-rail-toggle {
  margin-top: auto;
  align-self: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-muted);
  color: var(--text-muted);
  font-size: 1rem;
  line-height: 1;
}

.nav-rail-toggle:hover {
  background: var(--surface-strong);
  color: var(--text);
}

/*
 * Korb E, Paket E2.2: manueller Collapse-Zustand -- wirkt unabhaengig
 * von der aktuellen Containerbreite (im Gegensatz zur automatischen
 * @container(max-width:1050px)-Kompaktierung weiter unten, die nur
 * BIS zu dieser Breite greift). Gleiche Icon-only-Darstellung wie dort,
 * bewusst dupliziert statt die @container-Regel wiederzuverwenden --
 * Container-Queries koennen nicht per Klassenzustand "erzwungen"
 * werden. Position VOR den @container-Bloecken unten: die dortige
 * 728px-Regel (Bottom-Tab-Nav) muss `.is-collapsed` bei schmaler
 * Breite weiterhin ueberschreiben koennen (gleiche Selektor-Spezifitaet,
 * Reihenfolge im Stylesheet entscheidet).
 */
.app-navigation.is-collapsed {
  width: 4.5rem;
}

.app-navigation.is-collapsed .nav-button {
  justify-content: center;
  padding-inline: 0.4rem;
}

.app-navigation.is-collapsed .nav-button-label {
  display: none;
}

/* Schritt 2b: eingeklappt nur das Logo, kein Wortmarken-Text (gleiches Prinzip wie .nav-button-label oben). */
.app-navigation.is-collapsed .nav-rail-brand {
  justify-content: center;
  padding-inline: 0.4rem;
}

.app-navigation.is-collapsed .nav-rail-brand-label {
  display: none;
}

/*
 * App-Shell Auftrag 2026-10-01, Schritt 2 ("App-Shell Desktop"): im
 * eingeklappten Zustand ist .nav-button-label oben per CSS ausgeblendet --
 * title/aria-label (generateNavButtons(), ui-core.js) decken Screenreader
 * und die verzoegerte Maus-Hover-Anzeige ab, aber sehende Tastatur-Nutzer
 * sahen beim Fokussieren bisher nichts sichtbar Beschriftetes. EIN
 * geteiltes Overlay-Tooltip-Element direkt unter <body>
 * (ensureNavTooltipElement(), ui-core.js), ein-/ausgeblendet ueber die
 * Klasse .is-visible (bindNavTooltip(): mouseenter/mouseleave/focus/
 * blur) -- aria-hidden, der Button ist per aria-label bereits
 * vollstaendig beschriftet (kein doppeltes Vorlesen).
 *
 * Zwei Funde beim Live-Test, beide Grund fuer die jetzige Form:
 * 1. `position: fixed` + JS-berechnete Koordinaten statt `position:
 *    absolute` + CSS-:hover/:focus-visible: .app-navigation hat
 *    `overflow-x: hidden` (Scroll-Leiste der Rail-Liste selbst), ein
 *    absolut positioniertes Kind haette den Tooltip dadurch
 *    abgeschnitten.
 * 2. EIN geteiltes Element unter <body> statt je Button ein eigenes
 *    Kind: `.app-navigation` setzt `position: sticky`, das erzeugt
 *    einen eigenen Stacking-Context fuer ALLE Nachfahren -- ein
 *    `position: fixed`-Kind darin blieb trotz hohem z-index auf diesen
 *    Context beschraenkt und landete sichtbar HINTER der Topbar.
 *
 * --text/--surface statt eigener Tooltip-Farbtoken: dasselbe
 * kontrastierende Paar in allen 5 Themes, kein neuer Token noetig.
 */
.nav-button-tooltip {
  position: fixed;
  z-index: 2000;
  padding: 0.35rem 0.6rem;
  border-radius: var(--radius-small);
  background: var(--text);
  color: var(--surface);
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.12s ease;
}

@media (prefers-reduced-motion: reduce) {
  .nav-button-tooltip {
    transition: none;
  }
}

.nav-button-tooltip.is-visible {
  opacity: 1;
  visibility: visible;
}

/*
 * UI/UX-Leitlinien Regel 1 ("Keine versteckten Warnungen",
 * PROJECT_STATUS.md): generischer Zaehler-Badge fuer Nav-Buttons,
 * gespeist von App.NavBadges (js/ui/nav-badges.js) ueber
 * App.UI.renderNavBadges() (ui-core.js). Roter Punkt mit Zahl statt
 * reiner Farbmarkierung -- Zahl ist Teil der Information, nicht nur
 * Dekoration (Regel 2, Klartext vor Icon-Raetsel: eine Zahl ist
 * eindeutig, ein reiner Farbpunkt waere es nicht).
 */
.nav-button-badge {
  position: absolute;
  top: 0.15rem;
  right: 0.15rem;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--danger);
  color: #ffffff;
  font-size: 0.65rem;
  font-weight: 750;
  line-height: 1;
  pointer-events: none;
}

.app-main {
  min-width: 0;
}

.view-panel {
  animation: view-fade-in 160ms ease-out;
}

@keyframes view-fade-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.page-heading,
.panel-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.page-heading {
  margin-bottom: 1.25rem;
}

/*
 * AP44 Substep 3: "Zurueck zum Cockpit"-Breadcrumb (nur sichtbar bei
 * Deep-Dive-Ankunft aus einer Cockpit-Trendkarte, siehe
 * setActiveView()s viaDeepDive-Flag, js/ui/ui-core.js).
 */
#analysisBackToCockpitBtn {
  margin-bottom: 0.75rem;
}

.page-heading-actions,
.export-actions,
.form-actions,
.qa-actions,
.table-actions,
.chart-heading-actions,
/* Status-Center (2026-10-01): "Spaeter"/"Erledigt"/Ansehen-Knoepfe je Hinweis-Karte. */
.status-center-notice-actions {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  flex-wrap: wrap;
}

.status-center-notice-actions {
  margin-top: 0.4rem;
}

/*
 * Block 1 ("AUFTRAG_ENTWICKLER_KI_NEXT_ROUND.md", 2026-09-20): schlichte
 * Liste ohne Aufzaehlungszeichen -- siehe #aiGateConfiguredProvidersList.
 */
.plain-list {
  list-style: none;
  margin: 0.5rem 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/*
 * Block 1 Punkt 3: "KI-Buttons bleiben sichtbar, aber visuell
 * deaktiviert" -- bewusst NUR Optik (kein pointer-events:none), der
 * Klick bleibt moeglich und oeffnet den Auswahldialog (App.UI.
 * openAiUnavailableDialog(), js/ui/ui-ai-gate-panel.js).
 */
.ai-gate-disabled {
  opacity: 0.5;
}

/*
 * Block 3 ("AUFTRAG_ENTWICKLER_KI_NEXT_ROUND.md", 2026-09-20):
 * Klartext-Darstellung des vollstaendigen gesendeten Kontext-Pakets/
 * der Antwort im KI-Aktivitaetsprotokoll -- siehe
 * js/ui/ui-ai-activity-log-panel.js.
 */
.ai-activity-log-entry {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.ai-activity-log-entry:last-child {
  border-bottom: none;
}

.ai-activity-log-pre {
  background: var(--surface-muted, var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.75rem;
  font-size: 0.78rem;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-x: auto;
  max-height: 20rem;
  overflow-y: auto;
}

.qa-action-group {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.35rem;
}

.qa-action-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 750;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.panel {
  margin-bottom: 1rem;
  padding: clamp(1rem, 2vw, 1.4rem);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.panel-heading {
  margin-bottom: 1rem;
}

.panel-heading.compact {
  align-items: center;
}

/*
 * Korb E, Paket E3.1 (2026-09-16): .panel-heading-toggle (der vormalige
 * separate runde "+"-Button) ist entfallen -- alle 19 Aufrufstellen, die
 * es nutzten, sind auf natives <details>/<summary> migriert (siehe
 * .panel-details weiter unten). Die Regel selbst wurde entfernt (tote
 * CSS, kein verbleibender Markup-Verweis mehr).
 *
 * .collapsible-form bleibt bestehen -- wird weiterhin vom Konto-
 * Einrichtungsassistenten genutzt (accountCreateFormWrapper u.a.,
 * ui-core.js), einem mehrstufigen Wizard-Ablauf, KEIN "+"-Erfassungs-
 * formular und daher bewusst NICHT Teil dieser Migration (andere
 * Interaktionslogik: sequenzielle Schritte statt Ein-/Ausklappen).
 */
.collapsible-form {
  margin-top: 1rem;
  animation: view-fade-in 160ms ease-out;
}

.collapsible-form[hidden] {
  display: none;
}

/*
 * Korb E, Paket E3.1 (generisches Panel-Details-Fundament, 2026-09-16,
 * Nutzerauftrag "EIN wiederverwendbares Muster statt 16 Einzelumbauten"):
 * Zielmuster fuer ALLE 1:n-Erfassungsformulare -- ersetzt schrittweise
 * .panel-heading-toggle + .collapsible-form (separater Button + separater
 * hidden-Div) durch natives <details class="panel-details">. Waehrend der
 * Migration existieren beide Muster nebeneinander (siehe App.UI.
 * setFormPanelExpanded()-Kommentar, ui-core.js) -- die alten Regeln oben
 * bleiben bestehen, bis alle Stellen umgestellt sind. Visuell bewusst
 * IDENTISCH zum bisherigen "+"-Rotations-Schema (gleiche Masse/Farben/
 * Rotation wie .panel-heading-toggle oben) -- reiner Mechanismus-Tausch,
 * keine optische Aenderung.
 */
.panel-details > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  cursor: pointer;
  list-style: none;
}

.panel-details > summary::-webkit-details-marker {
  display: none;
}

.panel-details-summary-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.panel-details-marker {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: var(--primary);
  color: #ffffff;
  font-size: 1.3rem;
  line-height: 1;
  transition: transform 200ms ease, background 150ms ease;
}

.panel-details-marker::before {
  content: "+";
}

.panel-details > summary:hover .panel-details-marker {
  background: var(--primary-hover);
}

.panel-details[open] > summary .panel-details-marker {
  transform: rotate(45deg);
}

.panel-details-body {
  margin-top: 1rem;
  animation: view-fade-in 160ms ease-out;
}

.hero-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(18rem, 0.75fr);
  align-items: stretch;
  gap: 1rem;
  margin-bottom: 1rem;
  padding: clamp(1.15rem, 2.5vw, 2rem);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background:
    linear-gradient(
      135deg,
      var(--surface) 0%,
      var(--primary-soft) 150%
    );

  box-shadow: var(--shadow);
}

.hero-copy {
  max-width: 46rem;
}

.hero-copy p:last-child {
  margin-bottom: 0;
  color: var(--text-muted);
}

.drop-zone {
  display: flex;
  min-height: 13rem;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 0.45rem;
  padding: 1rem;
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  color: var(--text-muted);
  text-align: center;
  transition:
    border-color 150ms ease,
    background 150ms ease,
    transform 150ms ease;
}

.drop-zone:hover,
.drop-zone.drag-over {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--text);
  transform: translateY(-2px);
}

/*
 * Android-Beta-Fund (2026-09-14, Testlauf 2): waehrend ein Import
 * laeuft, blieb die Drop-Zone bisher bedienbar (keine sichtbare
 * Sperre) -- App.State.processing wurde nur intern geprueft. Jetzt
 * per App.TaskStatus-Abo (ui-core.js renderImportDropZoneLock())
 * gesetzt, sobald eine "import"-Aufgabe laeuft. pointer-events:none
 * verhindert auch Drag&Drop, nicht nur den Klick/die Tastatur-
 * Aktivierung (dafuer zusaetzlich fileInput.disabled, siehe dort).
 */
.drop-zone.drop-zone-locked {
  opacity: 0.55;
  pointer-events: none;
  cursor: not-allowed;
}

.drop-icon {
  display: grid;
  width: 2.8rem;
  height: 2.8rem;
  place-items: center;
  border-radius: 50%;
  background: var(--primary);
  color: #ffffff;
  font-size: 1.55rem;
  font-weight: 700;
}

.drop-zone strong {
  color: var(--text);
}

.visually-hidden-file-input,
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.button {
  /* AP12 Thread M1: 2.6rem (41.6px) lag knapp unter der 44px-Touch-
     Ziel-Mindestgroesse -- auf 2.75rem (44px bei 16px-Basis) angehoben. */
  min-height: 2.75rem;
  padding: 0.65rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-small);
  font-weight: 750;
  transition:
    background 150ms ease,
    border-color 150ms ease,
    color 150ms ease,
    transform 150ms ease;
}

.button:not(:disabled):hover {
  transform: translateY(-1px);
}

.button.primary {
  background: var(--primary);
  color: #ffffff;
}

.button.primary:not(:disabled):hover {
  background: var(--primary-hover);
}

.button.secondary {
  border-color: var(--border-strong);
  background: var(--surface);
  color: var(--text);
}

.button.secondary:not(:disabled):hover {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.button.danger {
  background: var(--danger);
  color: #ffffff;
}

.button.danger:not(:disabled):hover {
  background: var(--danger-hover);
}

/*
 * Analyse/Diagramm-UI-Umbau Phase 4, Schritt 4.4 (Nutzerauftrag
 * 2026-09-13, Ist-Analyse Abschnitt 2.2): additive Aktionen ("+ Kanal
 * hinzufuegen", "Anwenden") und destruktive Aktionen ("Entfernen")
 * nutzten bisher identisch .button.secondary -- keine visuelle
 * Unterscheidung. Bewusst NICHT ueberall .button.danger (volles Rot) --
 * gleiche Begruendung wie bereits bei .administration-interaction-hint
 * oben etabliert ("nicht --danger/Rot, das Autoritaet/Blockade
 * suggerieren wuerde"): das Entfernen eines einzelnen Kanals aus einer
 * Diagramm-Instanz ist trivial reversibel (sofort wieder ueber "+
 * Kanal hinzufuegen" verfuegbar), verdient also nur die mildere
 * Warnfarbe. .button.danger bleibt reserviert fuer tatsaechlich
 * schwerwiegendere, nicht auf einen Klick rueckgaengig zu machende
 * Aktionen (z.B. "Diagramm entfernen" -- entfernt eine komplette
 * konfigurierte Instanz ohne Bestaetigungsdialog/Undo, siehe
 * index.html).
 */
.button.warning {
  border-color: var(--warning);
  background: var(--warning-soft);
  color: var(--warning);
}

.button.warning:not(:disabled):hover {
  background: var(--warning);
  color: #ffffff;
}

.compact-button {
  min-height: 2.2rem;
  padding: 0.4rem 0.7rem;
  font-size: 0.82rem;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

.overview-stat-grid,
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.8rem;
  margin-bottom: 1rem;
}

.stat-card {
  display: flex;
  min-height: 8rem;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.stat-card span {
  color: var(--text-muted);
  font-size: 0.82rem;
}

.stat-card strong {
  color: var(--text);
  font-size: clamp(1.35rem, 3vw, 2rem);
  line-height: 1;
}

.stat-card small {
  font-size: 0.76rem;
}

/*
 * AP6a: die "Markierte Werte"-Kachel ist jetzt ein echtes <button>-
 * Element (Tastatur-aktivierbar, springt zur Analyse) -- Reset der
 * Button-Default-Optik, gleiches Muster wie button.overview-alert
 * weiter unten.
 */
button.stat-card {
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  width: 100%;
}

/*
 * Korb E, Paket E6.2 (2026-09-15): generisches Cockpit-Kachel-Layout,
 * urspruenglich fuer die inzwischen entfernten Trendkarten (AP44)
 * eingefuehrt -- BLEIBT, da inzwischen von mehreren anderen Kacheln
 * mitgenutzt: der Auffaelligkeiten-Kachel (.overview-findings-card
 * unten, ueber App.UI.renderEmptyState()s baseClassName-Parameter
 * auch fuer deren Leerzustand) sowie dem Leerzustand der Wochen-
 * Heatmap (_renderOverviewWeekHeatmap(), ui-overview.js). Die
 * ehemals Trendkarten-exklusiven Sparkline-/Panel-Regeln (.trend-
 * card-panel, .trend-card-sparkline*) sind mit den Trendkarten
 * entfernt -- diese sechs Basisregeln haben eigenstaendige Nutzer.
 */
.trend-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  overflow: hidden;
}

.trend-card + .trend-card {
  margin-top: 0.6rem;
}

.trend-card-summary {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  width: 100%;
  padding: 0.85rem 1rem;
  border: none;
  background: none;
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
}

.trend-card-label {
  flex: 1 1 auto;
  color: var(--text-muted);
  font-size: 0.82rem;
}

.trend-card-value {
  color: var(--text);
  font-size: 1.1rem;
}

.trend-card-hint {
  color: var(--text-muted);
  font-size: 0.76rem;
  /*
   * Phase E5 (WCAG-2.2-Audit, 2026-09-15): `white-space: nowrap` liess
   * den Hinweistext bei Browser-Zoom/Reflow (SC 1.4.10) am
   * `overflow: hidden` der Elternkarte (.trend-card) hart abschneiden,
   * statt umzubrechen.
   */
  white-space: normal;
}

/*
 * Auffaelligkeits-Semantik-Klaerung (2026-09-14): neue konsolidierte
 * Cockpit-Auffaelligkeits-Kachel -- ersetzt die vormalige aufklappbare
 * Score-Karte (.overview-score-breakdown) und die separate Kontext-
 * faktoren-Chipreihe (.overview-score-context-factors, komplett
 * entfernt, siehe Kommentar in ui-overview.js _renderOverviewScoreCard()).
 */
.overview-findings-summary {
  cursor: default;
}

.overview-findings-channel-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
  padding: 0 1rem 1rem;
  list-style: none;
}

.overview-findings-channel-row {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.1rem 0.6rem;
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  cursor: pointer;
  font: inherit;
  color: inherit;
  text-align: left;
}

.overview-findings-channel-row:hover {
  border-color: var(--primary);
}

.overview-findings-channel-label {
  flex: 1 1 auto;
  font-weight: 600;
}

.overview-findings-channel-count {
  color: var(--text);
}

.overview-findings-channel-direction {
  color: var(--text-muted);
  font-size: 0.78rem;
  flex-basis: 100%;
}

.overview-findings-channel-trend {
  font-size: 0.78rem;
  font-weight: 600;
}

.overview-findings-channel-trend.trend-increasing {
  color: var(--warning);
}

.overview-findings-channel-trend.trend-decreasing {
  color: var(--success);
}

.overview-findings-channel-trend.trend-stable {
  color: var(--text-muted);
}

/*
 * AP54.4 (Wochen-Heatmap, L4.3): kompaktes Tag-x-Stunde-Raster,
 * gleiche Intensitaets-ueber-Deckkraft-Logik wie die bestehende
 * grosse Heatmap (chart-renderer.js resolveIntensityColor-Familie),
 * hier bewusst simpler (eine feste Primaerfarbe, nur die Deckkraft
 * variiert) fuer die kleine Cockpit-Kachel.
 */
/*
 * Kritischer Qualitaets-Sprint Teil 2 Punkt 5 (2026-09-13): zweite
 * Heatmap-Zeile (Atemfrequenz) neben der bestehenden (Herzfrequenz) --
 * einfacher vertikaler Stapel, jede Zeile mit eigener Kanal-
 * Beschriftung.
 */
.overview-week-heatmap-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.overview-week-heatmap-row-label {
  margin: 0 0 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--text-muted);
}

.overview-week-heatmap-svg {
  display: block;
  width: 100%;
  height: auto;
}

.overview-week-heatmap-label {
  fill: var(--text-muted);
  /* UX_AUDIT.md Gruppe 4 (2026-10-01): px -> rem, skaliert jetzt mit OS-Textgroesse/A11y-Theme. */
  font-size: 0.375rem;
}

.overview-week-heatmap-cell {
  fill: var(--primary);
}

.overview-week-heatmap-cell-empty {
  fill: var(--surface-muted);
}

/*
 * AP54.5 (L6.7, Koerperschema): neutrale Ausgangsfarbe, aktive
 * Auswahl in Primaerfarbe -- rein geometrische, selbst gezeichnete
 * Formen (keine Bilddatei/Lizenzfrage).
 */
.observation-body-diagram-svg {
  display: block;
  width: 100%;
  max-width: 22rem;
  height: auto;
}

.observation-body-region {
  fill: var(--surface-muted);
  stroke: var(--border);
  stroke-width: 1.5;
  cursor: pointer;
}

.observation-body-region:hover {
  fill: var(--primary-soft);
}

/*
 * AP-A-Fund 6 (2026-09-13, Nutzerauftrag "Priorisierung"): vorher mit
 * :hover zusammengelegt und outline:none -- Fokus/Hover waren fuer
 * Tastaturnutzer beim Durchtabben visuell nicht unterscheidbar.
 * Eigene Regel mit demselben sichtbaren Ring wie die generische
 * [tabindex]:focus-visible-Regel oben (css/styles.css, "outline: 2px
 * solid var(--primary)") -- hier bewusst wiederholt statt sich auf
 * die generische Regel zu verlassen, da beide dieselbe Spezifitaet
 * haben und die spaeter im File stehende gewinnt.
 */
.observation-body-region:focus-visible {
  fill: var(--primary-soft);
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

.observation-body-region-selected {
  fill: var(--primary);
  stroke: var(--primary);
}

/* AP54.5 (L6.8, Foto/Video-Anhang) */
.observation-attachment-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0;
  border-bottom: 1px solid var(--border);
}

.observation-attachment-thumb {
  width: 3rem;
  height: 3rem;
  object-fit: cover;
  border-radius: var(--radius-small);
}

/*
 * AP6a: Wegweiser-Zeile ueber "Aktuelle Hinweise" -- liest denselben
 * Befund-Stand wie resultsGlanceStrip, aber als einzelne, kompakte
 * Zeile statt einer Chip-Leiste. Border-left-Farbe nach Status,
 * gleiche Konvention wie .overview-alert.warning/.danger.
 */
.overview-health-status {
  display: block;
  width: 100%;
  margin: 0.75rem 0 0;
  padding: 0.6rem 0.9rem;
  border: none;
  border-left: 4px solid var(--border-strong);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  font: inherit;
  font-weight: 700;
  color: var(--text);
  text-align: left;
  cursor: pointer;
}

.overview-health-status[data-status="success"] {
  border-left-color: var(--success);
}

.overview-health-status[data-status="warning"] {
  border-left-color: var(--warning);
}

/*
 * Cockpit "Fokus"/"Erweitert" (Product-Owner-Entscheidung 2026-10-01, docs/concepts/
 * cockpit-fokus-erweitert-2026-10-01.md). Segmentierter Umschalter -- Mindest-Zielgroesse 44px
 * (Designregel des Auftrags), Zustand ueber aria-pressed statt Farbe allein.
 */
.cockpit-view-mode-toggle {
  display: inline-flex;
  gap: 0.25rem;
  margin: 0.75rem 0 0;
  padding: 0.25rem;
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.cockpit-view-mode-option {
  min-height: 44px;
  padding: 0 1rem;
  border: none;
  border-radius: calc(var(--radius-small) - 2px);
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.cockpit-view-mode-option[aria-pressed="true"] {
  background: var(--surface);
  color: var(--primary);
  box-shadow: var(--shadow);
}

/* Einmaliger Hinweis fuer Bestandsnutzer -- gleiche Grundform wie .hint.info, als eigener Block statt Inline-Text. */
.cockpit-focus-hint-banner {
  margin: 0.75rem 0 0;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-small);
  background: var(--primary-soft);
  color: var(--text);
}

.cockpit-focus-hint-banner p {
  margin: 0 0 0.5rem;
}

/*
 * Harte Viewport-Regel des Auftrags ("Profilkopf, Status, Hinweise/Aufgaben und Smart-Button
 * muessen auf JEDEM Geraet im ersten Viewport ohne Scrollen sichtbar sein"): auf einem kleinen
 * Handy (360x640, live geprueft 2026-10-01) reicht die Standard-.panel-Polsterung (clamp(1rem,
 * 2vw, 1.4rem) Innenabstand + 1rem Aussenabstand + 1rem Ueberschriftabstand je Karte) nicht --
 * zwei Karten plus Smart-Button sprengen den Viewport. Kompaktere Masse NUR fuer die beiden
 * Fokus-Karten, die "Erweitert"-Karten bleiben unveraendert (.panel ohne diese Klasse).
 */
.cockpit-focus-compact-panel {
  margin-bottom: 0.5rem;
  padding: 0.75rem 0.9rem;
}

.cockpit-focus-compact-heading {
  margin: 0 0 0.5rem;
  font-size: 1rem;
}

/*
 * "+ Neues Gesundheitsprofil anlegen" (Cockpit-Kopfzeile): in Fokus ausgeblendet -- seltene
 * Aktion, kostet aber feste Hoehe, die die obige Viewport-Regel braucht. In "Erweitert"
 * unveraendert sichtbar (body-Attribut wird nur gesetzt, wenn FEATURE_COCKPIT_FOCUS_VIEW an ist).
 */
body[data-cockpit-view-mode="focus"] #overviewAddProfileHint {
  display: none;
}

/*
 * Layer 1 "Fokus": Statuskarte kompakt (1 Satz + 2-3 Mini-Trends, keine grossen Diagramme --
 * Designregel des Auftrags). Mini-Trends sind reine Text-Chips, kein SVG (Performance-Regel:
 * "Layer 1 ohne grosse SVGs").
 */
.cockpit-focus-status-line {
  margin: 0;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--text);
}

.cockpit-focus-status-line[data-status="success"] {
  color: var(--success);
}

.cockpit-focus-status-line[data-status="warning"] {
  color: var(--warning);
}

.cockpit-focus-mini-trends {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.cockpit-focus-mini-trend {
  padding: 0.35rem 0.7rem;
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  color: var(--text-muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
}

/*
 * Smart-Button: normaler Dokumentfluss, keine eigene Sticky-Positionierung. Der Fokus-Inhalt
 * (Statuskarte + max. 3 Hinweise/Aufgaben + dieser Knopf) ist absichtlich kurz genug, um ohne
 * Scrollen in den ersten Viewport zu passen (Designregel des Auftrags) -- Sticky wuerde den
 * bestehenden, global fixierten FAB (.quick-entry-fab) ueberlappen, sobald der Seiteninhalt
 * kuerzer als der Viewport ist (live geprueft, 2026-10-01). Respektiert prefers-reduced-motion
 * schon dadurch, dass hier keinerlei Transition/Animation gesetzt wird.
 */
.cockpit-focus-smart-button-wrap {
  margin-top: 1rem;
}

.cockpit-focus-smart-button {
  width: 100%;
  min-height: 44px;
}

/*
 * AP6a: Top-3-Liste juengster markierter Werte, als Geschwister-
 * Element direkt unter der "Markierte Werte"-Alert-Karte (nicht
 * hineingeschachtelt, siehe Kommentar in ui-overview.js).
 */
.overview-alert-detail-list {
  display: grid;
  gap: 0.3rem;
  margin: -0.3rem 0 0;
  padding: 0.6rem 0.9rem 0.6rem 1.6rem;
  border: 1px solid var(--border);
  border-top: none;
  border-radius: 0 0 var(--radius-small) var(--radius-small);
  background: var(--surface-muted);
  color: var(--text-muted);
  font-size: 0.82rem;
  list-style: disc;
}

/*
 * AP6a: natives <details> statt eines immer offenen 4-Button-Grids --
 * gleiches Muster wie die bestehenden <details>-Elemente im Projekt
 * (z.B. .data-package-gallery-summary, .raw-data-details).
 */
.quick-action-menu summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--text);
  padding: 0.4rem 0;
}

.quick-action-menu .quick-action-grid {
  margin-top: 0.75rem;
}

.quality-stat-list {
  display: grid;
  gap: 0.6rem;
}

.quality-stat-list > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--border);
}

.quality-stat-list > div:last-child {
  border-bottom: 0;
}

.quality-stat-list span {
  color: var(--text-muted);
}

.overview-list,
.clinical-event-list,
.import-log-list {
  display: grid;
  gap: 0.7rem;
}

.overview-alert,
.clinical-event-item,
.import-log-item {
  padding: 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.overview-alert {
  display: grid;
  gap: 0.2rem;
  border-left: 4px solid var(--primary);
}

.overview-alert.warning {
  border-left-color: var(--warning);
}

.overview-alert.info {
  border-left-color: var(--primary);
}

/*
 * AENDERUNG 2026-08-23: dringlichere Variante fuer ueberfaellige
 * Medikamentengaben -- deutlicher als die bestehenden warning/info-
 * Typen, gleiche Konvention wie var(--danger) an anderen Stellen
 * (z.B. .chart-marker-medication_plan_change).
 */
.overview-alert.danger {
  border-left-color: var(--danger);
}

/*
 * f-Feature (generische Trendkarte, 2026-09-22): Grund-Text-Eintraege ("zu wenig Daten") -- bewusst zurueckhaltender als info/warning/danger,
 * derselbe Kanal wechselt in eine dieser Varianten, sobald ein echter Vergleich moeglich ist.
 */
.overview-alert.muted {
  border-left-color: var(--border);
  color: var(--text-muted);
}

/*
 * L1.1/L1.15-Vorbereitung, Phase 1 (2026-09-17): Konfidenz-Sparkline
 * der Suspicions-Cockpit-Karte -- reine Linie, Farbe folgt der
 * Textfarbe der jeweiligen .overview-alert-Variante (kein zusaetzlicher
 * Farbwert noetig).
 */
.overview-suspicion-sparkline {
  width: 120px;
  height: 24px;
  overflow: visible;
}

.overview-suspicion-sparkline polyline {
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.75;
}

/*
 * AENDERUNG 2026-08-23: die neuen, verlinkten Uebersicht-Hinweiskarten
 * sind echte <button>-Elemente (native Tastatur-Aktivierbarkeit ueber
 * Enter/Leertaste ohne eigenen Keydown-Handler) -- Reset der
 * Button-Default-Optik, .overview-alert liefert Rahmen/Hintergrund.
 */
button.overview-alert {
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  width: 100%;
}

.overview-alert span,
.import-log-item span {
  color: var(--text-muted);
  font-size: 0.87rem;
}

/*
 * Korb E, Paket E6.3 (2026-09-15): Herkunfts-Tag ("Hinweis"/
 * "Warnsystem") in der zusammengefuehrten Cockpit-Karte -- .overview-
 * alert ist display:grid, ohne justify-self:start wuerde das .tag-
 * Element (an sich inline-flex/content-breit) auf die volle Grid-
 * Spaltenbreite gestreckt (Grid-Default justify-items:stretch gilt
 * auch fuer inline-flex-Kinder).
 */
.overview-alert-source-tag {
  justify-self: start;
}

.empty-state-card,
.empty-state {
  padding: 1.25rem;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  color: var(--text-muted);
  text-align: center;
}

.quick-action-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
}

.quick-action {
  display: flex;
  min-height: 8rem;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.8rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  color: var(--text);
  text-align: left;
}

.quick-action:hover {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.quick-action strong {
  font-size: 0.96rem;
}

/*
 * AP54.1 (L4.6, docs/ap54/02-Luecken-Mapping.md): persistenter FAB,
 * auf jeder View sichtbar (siehe index.html-Kommentar an der
 * Einfuegestelle -- Geschwister von #mainContent, nicht Teil einer
 * View-Vorlage). z-index ueber .toast-stack (300), da ein Toast den
 * FAB nicht dauerhaft verdecken soll, aber unter einem etwaigen
 * Modal-Overlay (deutlich hoeher, hier nicht relevant).
 */
.quick-entry-fab {
  position: fixed;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 310;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}

.quick-entry-fab-button {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  border: none;
  background: var(--primary);
  color: #fff;
  font-size: 1.75rem;
  line-height: 1;
  box-shadow: var(--shadow);
  cursor: pointer;
}

.quick-entry-fab-button:hover {
  background: var(--primary-hover);
}

.quick-entry-fab-menu {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.quick-entry-fab-item {
  padding: 0.55rem 0.9rem;
  border: none;
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  color: var(--text);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.quick-entry-fab-item:hover {
  background: var(--primary-soft);
  color: var(--primary);
}

/*
 * Auf schmalen Bildschirmen liegt .app-navigation fest am unteren
 * Rand (siehe @media (max-width: 760px) weiter unten) -- der FAB
 * rueckt entsprechend nach oben, um sie nicht zu verdecken.
 */
@media (max-width: 760px) {
  .quick-entry-fab {
    /* Leiste mit zweizeiligen Labels ist live ~77px hoch (> 4.5rem). */
    bottom: calc(5.25rem + env(safe-area-inset-bottom, 0px));
  }
}

/*
 * UX-Bestandsaufnahme 2026-09-17 (Befund H4): die Annahme oben ("Modal-
 * Overlay deutlich hoeher") stimmt nicht -- alle blockierenden Overlays
 * (Verarbeitung, Konto-Anmeldung, Onboarding, Tipp-Bestaetigung,
 * Backup-Passwort) teilen .processing-overlay mit z-index 100. Der FAB
 * lag darueber, verdeckte den Dialog und schaltete bei Klick die
 * verdeckte Hintergrund-View um. Solange ein solches Overlay offen ist,
 * hat Schnellerfassung keinen Zweck -> ausblenden, statt die Overlays
 * ueber die Toasts (300) zu heben.
 */
body:has(.processing-overlay:not(.hidden)) .quick-entry-fab {
  display: none;
}

.quick-action span {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.assignment-list {
  display: grid;
  gap: 0.7rem;
}

.assignment-item {
  display: grid;
  grid-template-columns: minmax(12rem, 1.5fr) minmax(9rem, 0.75fr) 10rem 12rem;
  align-items: center;
  gap: 0.75rem;
  padding: 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.assignment-item small {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.import-log-item {
  display: grid;
  gap: 0.2rem;
}

/*
 * AP63 (2026-09-17, Ordner-Import-Uebersicht): Gruppen-Block je
 * erkanntem Profil/Konto in der Ordner-Uebersicht -- Header
 * (Bild+Name) + die zugehoerigen Backup-Zeilen darunter, optisch
 * leicht abgesetzt von den einzelnen .import-log-item-Karten.
 */
.import-folder-identity-group {
  display: grid;
  gap: 0.5rem;
  padding: 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
}

.import-folder-identity-header {
  display: flex;
  align-items: center;
}

/* AP41 Substep 4 (Konfliktregel-Regler, 2026-09-11) */
.import-conflict-rule {
  display: grid;
  gap: 0.35rem;
  margin-bottom: 0.8rem;
  font-size: 0.85rem;
}

.import-conflict-rule label {
  color: var(--text-muted);
}

/* AP41 Substep 2 (Vorschau-UI, 2026-09-11) */
.import-preview {
  display: grid;
  gap: 0.6rem;
  margin-top: 1rem;
  padding: 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.import-preview-files {
  display: grid;
  gap: 0.5rem;
}

.import-preview-file {
  display: grid;
  gap: 0.15rem;
  padding: 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
}

.import-preview-file small {
  color: var(--text-muted);
}

/* Bekannter Bug Nr. 9 (2026-09-28): Pro-Datei-Regelwahl, nur bei globaler Regel "manual" sichtbar. */
.import-preview-file-conflict-rule {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.2rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.import-preview-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
}

.timeline-filter-grid,
.analysis-filter-grid,
.export-config-grid,
.quick-range-grid,
.export-range,
.settings-grid,
.reference-grid,
.form-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.8rem;
}

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

.reference-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 1rem 0;
}

/*
 * THREAD H: einmalige Gesundheits-Eckdaten -- einfache Label/Wert-
 * Zeilenliste mit "x"-Entfernen-Knopf pro Zeile, gleiches minimalistische
 * Muster wie der bestehende Tag-Picker "+"-Zeile.
 */
.one-time-facts-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0.5rem 0;
}

.one-time-fact-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
}

.one-time-fact-row strong {
  min-width: 8rem;
}

.one-time-fact-row .one-time-fact-remove-btn {
  margin-left: auto;
}

.one-time-facts-add-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.one-time-facts-add-row input {
  flex: 1 1 12rem;
}

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

/*
 * UX/IA-Navigationsvereinheitlichung (2026-09-22): Ersatz fuer ein <label>
 * mit Formularelement, wenn stattdessen eine Tab-Leiste (.analysis-subnav)
 * unter derselben Beschriftung sitzt (z. B. Verwaltung > Kataloge) --
 * gleiche Optik wie die echten Feld-Labels in .settings-grid, aber ohne
 * <label>-Semantik fuer ein nicht-Formular-Element.
 */
.settings-grid-label-group {
  display: grid;
  gap: 0.35rem;
}

.settings-grid-label-group-heading {
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 700;
}

.form-grid label,
.settings-grid label,
.reference-grid label,
.timeline-filter-grid label,
.analysis-filter-grid label,
.export-config-grid label,
.quick-range-grid label,
.export-range label {
  display: grid;
  gap: 0.35rem;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 700;
}

.full-width {
  grid-column: 1 / -1;
}

/*
 * Phase C, Schritt 3.4: natives <details> fuer optionale/erweiterte
 * Formularfelder (z.B. Tags) innerhalb eines .form-grid -- gleiches
 * minimalistisches Prinzip wie .channel-sub-filter (ui-charts.js),
 * aber bewusst eigene, form-neutral benannte Klasse statt der dortigen
 * kanalspezifischen.
 */
.form-advanced-fields summary {
  cursor: pointer;
  font-weight: 700;
  color: var(--text-muted);
  font-size: 0.82rem;
}

.form-advanced-fields[open] summary {
  margin-bottom: 0.5rem;
}

.filter-panel {
  display: grid;
  gap: 0.8rem;
}

.filter-custom-range {
  margin-top: 0.2rem;
}

.quick-action.suggested {
  border-color: var(--primary);
  background: var(--primary-soft);
  box-shadow: 0 0 0 1px var(--primary);
}

.raw-data-details {
  padding: 0;
}

.raw-data-details > summary {
  cursor: pointer;
  padding: 1.1rem 1.3rem;
  font-weight: 700;
  list-style: none;
}

.raw-data-details > summary::-webkit-details-marker {
  display: none;
}

.raw-data-details > summary::before {
  content: "▸ ";
}

.raw-data-details[open] > summary::before {
  content: "▾ ";
}

.raw-data-details[open] > summary {
  border-bottom: 1px solid var(--border);
}

.raw-data-details > .timeline-filter-grid,
.raw-data-details > .table-wrap,
.raw-data-details > .hint {
  margin: 1rem 1.3rem;
}

.raw-data-details > .table-wrap {
  margin-top: 0;
}

/*
 * Diagramm-Grundprinzipien 2.3 (2026-09-14): dezenter Aufklapper fuer
 * die Diagramm-Einstellungen (Layer 2) -- gleiches Muster wie
 * .raw-data-details oben (Dreieck-Marker statt Browser-Default,
 * Rahmenlinie nur im offenen Zustand), eigene Klasse statt Wieder-
 * verwendung von .raw-data-details, da die Innenabstaende hier zu den
 * bereits bestehenden .chart-toolbar/.channel-options-section-Klassen
 * passen muessen statt zu .table-wrap/.timeline-filter-grid.
 */
.chart-settings-disclosure {
  margin-top: 0.75rem;
  border-top: 1px solid var(--border);
  padding-top: 0.75rem;
}

.chart-settings-disclosure > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--text-muted);
  list-style: none;
  padding: 0.25rem 0;
}

.chart-settings-disclosure > summary::-webkit-details-marker {
  display: none;
}

.chart-settings-disclosure > summary::before {
  content: "▸ ";
}

.chart-settings-disclosure[open] > summary::before {
  content: "▾ ";
}

.chart-settings-disclosure[open] > summary {
  color: var(--text);
  margin-bottom: 0.5rem;
}

/*
 * .chart-toolbar/.channel-options-section (Kinder von .chart-settings-
 * disclosure-body) tragen jeweils ihre eigene display:flex/block-Regel
 * -- diese Autoren-Regeln wuerden die UA-Stylesheet-Standardregel
 * (Kinder eines geschlossenen <details> werden ausgeblendet) einfach
 * ausser Kraft setzen. Ein einzelner Wrapper mit GENAU dieser Regel
 * macht das Ausblenden unabhaengig von den display-Werten der Kinder
 * (siehe Kommentar bei .chart-settings-disclosure-body in index.html).
 */
.chart-settings-disclosure:not([open]) > .chart-settings-disclosure-body {
  display: none;
}

.align-end {
  align-self: end;
}

.checkbox-label {
  display: flex !important;
  align-items: center;
  gap: 0.55rem;
  min-height: 2.6rem;
  color: var(--text) !important;
  font-size: 0.86rem !important;
}

.checkbox-label input {
  width: 1rem;
  height: 1rem;
  accent-color: var(--primary);
}

.activity-code-filter-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1rem;
  margin-top: 0.4rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.82rem;
}

.activity-code-filter-list .checkbox-label {
  min-height: auto;
  flex: 0 0 auto;
}

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
}

/*
 * AP44 Substep 4 (Rohdaten-Drilldown, openWindowDrilldown()):
 * begrenzte Hoehe mit eigenem vertikalem Scroll, damit ein Fenster
 * mit vielen Samples den Dialog nicht sprengt.
 */
.analysis-drilldown-raw {
  max-height: 16rem;
  overflow-y: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.86rem;
}

th,
td {
  padding: 0.75rem 0.85rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}

th {
  background: var(--surface-strong);
  color: var(--text-muted);
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

tbody tr:last-child td {
  border-bottom: 0;
}

tbody tr:hover td {
  background: var(--surface-muted);
}

.table-status {
  font-weight: 750;
}

.table-status.success {
  color: var(--success);
}

.table-status.warning {
  color: var(--warning);
}

.clinical-event-item {
  display: grid;
  gap: 0.35rem;
}

.clinical-event-item p {
  margin: 0.15rem 0;
  color: var(--text-muted);
}

.clinical-event-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

/*
 * Release v1.18.1 (live auf einem 412px-Geraet gemessen): der Eintrag "08:00 . Testmedikament" mit der Pille
 * "Zeitfenster abgelaufen -- nicht dokumentiert" (nowrap, 271px) machte die Grid-Spalte 432px breit und die ganze
 * Seite seitlich scrollbar. Titelzeile bricht um, Grid-Kinder duerfen schrumpfen, lange Pillen umbrechen hier.
 */
.clinical-event-list > *,
.clinical-event-item {
  min-width: 0;
}

.clinical-event-heading .severity-pill {
  max-width: 100%;
  white-space: normal;
}

/*
 * THREAD B: Aktivitaets-/Kontext-Zeile zwischen Zeitraum und Nachricht
 * eines Befunds -- dezent, wie die bestehende Zeitraum-Zeile.
 */
.finding-context-line {
  display: block;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

.severity-pill {
  min-height: auto;
  background: var(--warning-soft);
  color: var(--warning);
  white-space: nowrap;
}

/*
 * Block 7 ("AUFTRAG_ENTWICKLER_KI_NEXT_ROUND.md", 2026-09-20,
 * Medikamentenmodul-Kernstueck): bewusst minimal -- Visuelle Polierung
 * ist Block 4 (UI/UX-Ueberholung, im AUFTRAG selbst NACH Block 7
 * eingeplant), hier nur genug, damit der Konflikt-Hinweis nicht wie
 * normaler Fliesstext untergeht.
 */
.medication-recorded-by,
.medication-recipients-summary {
  display: block;
  color: var(--text-muted);
}

/*
 * Block 4 (WCAG 1.4.3, 2026-09-20): --warning auf --surface-muted liegt
 * nur knapp ueber 4.5:1 (light ~4.7:1) -- der Text nutzt daher die
 * Standard-Textfarbe (hoher Kontrast in beiden Themes), die Warnung
 * traegt der Randbalken UND das Wort "Achtung" (nicht Farbe allein).
 */
.medication-conflict-banner {
  display: block;
  color: var(--text);
  font-weight: 600;
  padding-left: 0.6rem;
  border-left: 4px solid var(--warning);
}

.medication-plan-block {
  display: grid;
  gap: 0.35rem;
}

.tag-list {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
}

.tag {
  min-height: auto;
  padding: 0.2rem 0.45rem;
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 0.7rem;
}

/*
 * AP9: atypisch-Befunde werden hervorgehoben, nicht abgewertet --
 * gleiche Farbe wie AP8s Guardrail-Banner (.comparison-warning-banner),
 * keine neue Farbe erfunden.
 */
.tag-atypisch {
  min-height: auto;
  padding: 0.2rem 0.45rem;
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.7rem;
}

/*
 * AP17.5 Teilschritt 2 (Hinweis-Chip-Anzeige, 2026-09-12): anzeigend,
 * NICHT blockierend -- gleiche gedeckte Warnfarbe wie .tag-atypisch
 * (nicht --danger/Rot, das Autoritaet/Blockade suggerieren wuerde).
 */
.administration-interaction-hint {
  border: 1px solid var(--warning);
  background: var(--warning-soft);
  border-radius: 0.5rem;
  padding: 0.5rem 0.65rem;
  margin: 0.35rem 0;
  font-size: 0.85rem;
}

.administration-interaction-hint p {
  margin: 0 0 0.3rem;
}

.administration-interaction-hint .tag {
  background: transparent;
  color: var(--warning);
  padding: 0.15rem 0;
  font-weight: 600;
}

.disease-template-select-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}

.disease-template-select-row label {
  font-size: 0.85rem;
  color: var(--text-muted);
}

.export-workflow-grid {
  display: grid;
  gap: 1.25rem;
}

.export-step {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.8rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.export-step > :not(.step-number) {
  grid-column: 2;
}

.step-number {
  display: grid;
  width: 2rem;
  height: 2rem;
  place-items: center;
  border-radius: 50%;
  background: var(--primary);
  color: #ffffff;
  font-size: 0.85rem;
  font-weight: 800;
}

.export-condensed-options {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.8rem;
  margin-top: 0.8rem;
}

.export-condensed-options label {
  display: grid;
  gap: 0.35rem;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 700;
}

.integrity-message,
.quality-report {
  padding: 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
  color: var(--text-muted);
}

/* Flexibler Versand (2026-09-22, share-invite-box/sharePackageDispatch): kleine Aktionsbox, gleiche Bausteine wie .integrity-message, aber ohne Statusfarbe. */
.share-invite-box,
#sharePackageDispatch {
  margin-bottom: 1rem;
  padding: 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.share-invite-box p,
#sharePackageDispatch p {
  margin-top: 0;
}

/* Nutzerauftrag 2026-09-28: Adressfeld fuer den optionalen Server-Versand, gleiche Optik wie die uebrigen Formular-Labels (.settings-grid label etc.). */
.share-invite-address-label {
  display: grid;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 700;
}

.integrity-message.success,
.quality-report.success {
  border-color: color-mix(in srgb, var(--success) 45%, var(--border));
  background: var(--success-soft);
  color: var(--success);
}

.integrity-message.warning,
.quality-report.warning {
  border-color: color-mix(in srgb, var(--warning) 45%, var(--border));
  background: var(--warning-soft);
  color: var(--warning);
}

.integrity-message.error,
.quality-report.error {
  border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
  background: var(--danger-soft);
  color: var(--danger);
}

.quality-report {
  display: grid;
  gap: 0.45rem;
  margin-top: 0.85rem;
}

.quality-report ul {
  display: grid;
  gap: 0.25rem;
  margin: 0;
  padding-left: 1.25rem;
}

.report-label {
  margin-top: 0.25rem;
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.report-label.error {
  color: var(--danger);
}

.report-label.warning {
  color: var(--warning);
}

.report-label.info {
  color: var(--primary);
}

.danger-panel {
  border-color: color-mix(in srgb, var(--danger) 35%, var(--border));
}

.data-cleanup-section {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.data-cleanup-section h4 {
  margin-bottom: 0.25rem;
}

.data-cleanup-danger {
  margin-top: 1.2rem;
  padding: 1rem;
  border: 1px solid var(--danger-soft);
  border-radius: var(--radius-small);
  background: var(--danger-soft);
}

.data-cleanup-danger h4 {
  color: var(--danger);
}

.processing-overlay {
  position: fixed;
  z-index: 100;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 1rem;
  /* Emulator-Vorabpruefung v1.19.0: Dialoge, die hoeher sind als der Bildschirm (Konto anlegen
   * auf 360 x 758 dp: Verschluesselungs-Haken, Hinweise und "Konto anlegen"), waren abgeschnitten
   * und nicht erreichbar. Das Overlay scrollt jetzt; die Seite dahinter bleibt stehen. */
  overflow-y: auto;
  overscroll-behavior: contain;
  background: rgba(5, 12, 22, 0.56);
  /* Korb B (2026-09-14): -webkit-Praefix fuer aeltere Safari-Versionen. */
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.processing-dialog {
  display: grid;
  min-width: min(100%, 22rem);
  max-width: 26rem;
  justify-items: center;
  gap: 0.65rem;
  padding: 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: center;
}

.processing-dialog span {
  color: var(--text-muted);
  font-size: 0.88rem;
}

/*
 * Popup-X-Auftrag (2026-10-03): Titelzeile mit kleinem X rechts oben fuer choiceDialog/
 * typedConfirmDialog -- .processing-dialog ist display:grid mit justify-items:center, diese
 * Zeile durchbricht das gezielt (justify-self:stretch + eigenes flex) fuer Titel links/X rechts.
 */
.dialog-title-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  justify-self: stretch;
  text-align: left;
}

.dialog-close-btn {
  flex-shrink: 0;
  display: inline-flex;
  border: none;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  padding: 0.2rem;
  border-radius: var(--radius-small);
}

.dialog-close-btn:hover,
.dialog-close-btn:focus-visible {
  color: var(--text);
  background: var(--surface-strong);
}

/*
 * UI/UX-Audit (2026-09-08, Teil 2 Punkt 10): additiver Fortschritts-
 * balken neben dem bestehenden Spinner -- ein Spinner allein signalisiert
 * "kurz warten" (<10s), waehrend grosse Importe/Restores mehrere
 * Minuten dauern koennen (Signal-Mismatch, siehe docs/audits/
 * ui-ux-audit-2026-09-08.md Abschnitt 2). justify-self:stretch
 * durchbricht bewusst .processing-dialogs justify-items:center --
 * ein Balken soll die volle Breite nutzen, nicht auf Inhaltsbreite
 * schrumpfen.
 */
.processing-progress-bar {
  justify-self: stretch;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--surface-muted);
  overflow: hidden;
}

.processing-progress-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--primary);
  border-radius: inherit;
  transition: width 200ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .processing-progress-bar-fill {
    transition: none;
  }
}

.profile-gate-dialog {
  max-width: 30rem;
  width: 100%;
  justify-items: stretch;
  text-align: left;
}

.profile-gate-dialog #profileGateHint {
  text-align: left;
}

.profile-gate-dialog .import-log-list {
  max-height: 14rem;
  overflow-y: auto;
}

.spinner {
  width: 2.2rem;
  height: 2.2rem;
  border: 3px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/*
 * AP12 Thread M6: prefers-reduced-motion. `.view-fade-in` ist rein
 * dekorativ (160ms Fade+Slide beim Ansicht-/Panel-Wechsel) -- entfaellt
 * komplett, Inhalt erscheint sofort. `spin` (Lade-Indikator) bleibt
 * bewusst NICHT komplett bewegungslos (waere sonst kein erkennbares
 * "laedt noch"-Signal mehr) -- deutlich verlangsamt statt entfernt.
 */
@media (prefers-reduced-motion: reduce) {
  .view-panel {
    animation: none;
  }

  .spinner {
    animation-duration: 2.4s;
  }
}

/*
 * Sprint 2 (2026-09-14, "Generischer Hintergrund-Verarbeitungs-
 * Status"): drei generische Bausteine, die von App.TaskStatus-
 * Konsumenten gemeinsam genutzt werden -- derselbe .spinner/@keyframes
 * spin wie oben (kein zweites Lade-Indikator-Muster), nur in kleineren
 * Groessen fuer Inline-Kontexte.
 */
.global-task-indicator {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--surface-muted);
  color: var(--text-muted);
  font-size: 0.82rem;
}

/* Test-Nutzer-Fund 3a (2026-09-20): Text + Fortschrittsbalken, aufklappbare Liste aller Vorgaenge. */
.global-task-wrapper {
  position: relative;
  min-width: 0;
}

.global-task-indicator {
  cursor: pointer;
  max-width: 100%;
}

.global-task-indicator-text {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
}

.global-task-progress {
  display: block;
  height: 3px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}

.global-task-progress-bar {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--primary);
  transition: width 400ms ease;
}

.global-task-progress-indeterminate {
  animation: task-pulse 1.2s ease-in-out infinite;
}

.global-task-list {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 60;
  width: min(26rem, 88vw);
  margin: 0;
  padding: 0.5rem 0.75rem;
  list-style: none;
  display: grid;
  gap: 0.4rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  font-size: 0.82rem;
}

.global-task-list-failed {
  color: var(--warning);
}

.global-task-indicator-failed {
  background: var(--warning-soft);
  color: var(--warning);
}

.global-task-indicator-failed .global-task-indicator-spinner {
  animation: none;
  border-top-color: var(--warning);
}

.global-task-indicator-spinner {
  width: 0.9rem;
  height: 0.9rem;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  flex-shrink: 0;
}

/*
 * Pulsierendes Label (Import-Listeneintrag "Import in Arbeit", siehe
 * ui-import.js). Reine Opazitaets-Pulsation -- kein Farbwechsel, damit
 * es in beiden Themes funktioniert, ohne eigene Dark-/Light-Werte
 * pflegen zu muessen.
 */
.task-pulsing-label {
  animation: task-pulse 1.6s ease-in-out infinite;
}

@keyframes task-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/*
 * Phase E5 (WCAG-2.2-Audit, 2026-09-15, SC 2.5.7/2.1.1): Klick-
 * Alternative zum bisher reinen Drag-/Pinch-Pan, siehe index.html
 * chartPanLeftBtn/chartPanRightBtn und ui-charts.js panChartWindow().
 */
.chart-pan-controls {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

/*
 * Diagramm-Ladezustand (ui-charts.js): das vorherige Diagramm bleibt
 * ausgegraut SICHTBAR (opacity, kein Ausblenden/Entfernen), der
 * Spinner+Text liegt darueber -- Nutzer-Vorgabe "vorherige Ergebnisse
 * bleiben ggf. ausgegraut sichtbar, statt zu verschwinden".
 */
.chart-loading-container {
  position: relative;
}

.chart-loading-container.chart-loading-active > *:not(.chart-loading-overlay) {
  opacity: 0.4;
  pointer-events: none;
}

.chart-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

/*
 * Nutzer-Auftrag "Daten-Uebersicht" (2026-09-14): profilweite
 * Abdeckungs-/Luecken-Zeitleiste (App.UI.openDataCoverageDialog(),
 * ui-overview.js). Bewusst ZWEI parallele Darstellungen derselben
 * Bloecke -- die SVG-Leiste fuer den plakativen Gesamteindruck, die
 * Liste darunter fuer barrierefreie/mobile Zugaenglichkeit (Hover-
 * Tooltips allein waeren auf Touch-Geraeten nicht erreichbar).
 */
.data-coverage-bar-wrapper {
  width: 100%;
  overflow-x: auto;
}

.data-coverage-bar {
  display: block;
  width: 100%;
  height: auto;
}

.data-coverage-bar-segment-gap {
  fill: var(--coverage-gap);
  opacity: 0.55;
}

.data-coverage-bar-segment-gap:hover {
  opacity: 0.8;
}

.data-coverage-block-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.data-coverage-block-item {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  font-size: 0.85rem;
}

.data-coverage-block-item.gap {
  border-color: var(--coverage-gap);
  background: color-mix(in srgb, var(--coverage-gap) 12%, transparent);
}

.data-coverage-swatch {
  flex-shrink: 0;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
}

/*
 * Korb C3 (2026-09-14): kompakte Cockpit-Karte "Daten-Verfuegbarkeit"
 * -- ganze Karte ist ein <button data-go-to-view="import">, siehe
 * index.html/ui-overview.js. Wiederverwendet .data-coverage-bar fuer
 * die SVG-Leiste selbst (skaliert bereits ueber viewBox/width:100%),
 * hier nur die umschliessende Button-Chrome + Klick-Hinweis.
 */
.data-coverage-cockpit-link {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.data-coverage-cockpit-link:hover .data-coverage-cockpit-link-hint,
.data-coverage-cockpit-link:focus-visible .data-coverage-cockpit-link-hint {
  text-decoration: underline;
}

.data-coverage-bar-wrapper.compact {
  max-width: 28rem;
}

.data-coverage-cockpit-link-hint {
  display: inline-block;
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--primary);
}

/*
 * Korb C4 (2026-09-14): Alert-Card-Navigationstext -- <button> statt
 * <strong> (klickbar, springt zum passenden Bereich), aber optisch
 * identisch zur bisherigen .overview-alert-Ueberschrift.
 */
.alert-card-navigate {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  font-weight: 600;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.alert-card-navigate:hover,
.alert-card-navigate:focus-visible {
  text-decoration: underline;
}

/*
 * Kontext-Aktionen-Rollout Schritt 3 (2026-09-23): Wrapper um .alert-card-navigate + den generischen
 * "(...)"-Baustein (js/ui/context-help-affordance.js) -- der Navigations-Button ist sonst
 * display:block/width:100% (siehe oben), das wuerde den "(...)"-Knopf in eine neue Zeile zwingen.
 */
.overview-finding-heading {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.overview-finding-heading .alert-card-navigate {
  width: auto;
  flex: 1;
}

/* Korb C4-Nachtrag (2026-09-15): Meldewege-Checkboxliste (Einstellungen). */
.notification-channel-list {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.75rem 0;
}

.notification-channel-item {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
}

/*
 * UX-Bestandsaufnahme 2026-09-17: ohne feste Groesse griff die globale
 * `input { width: 100% }`-Regel -- die Checkbox war so breit wie die
 * ganze Zeile und schob den Beschreibungstext rechts aus dem Panel
 * (auf 360px Handybreite bis x=542, die Seite wurde herausgezoomt).
 * Gleiche Groesse wie .checkbox-label input.
 */
.notification-channel-item input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  margin-top: 0.2rem;
  flex-shrink: 0;
  accent-color: var(--primary);
}

.notification-channel-item .notification-channel-copy strong {
  display: block;
}

.notification-channel-item .notification-channel-copy small {
  color: var(--text-muted);
}

/* Korb C4 (2026-09-15): Layer-3-Detail-Dialog fuer einen Alert. */
.alert-detail-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.3rem 0.75rem;
  margin: 0.75rem 0;
}

.alert-detail-list dt {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.alert-detail-list dd {
  margin: 0;
}

@media (prefers-reduced-motion: reduce) {
  .global-task-indicator-spinner {
    animation-duration: 2.4s;
  }

  .task-pulsing-label {
    animation: none;
  }
}

@media (max-width: 1050px) {
  .overview-stat-grid,
  .stat-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

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

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

  .assignment-item {
    grid-template-columns: minmax(10rem, 1fr) minmax(9rem, 1fr);
  }

  .assignment-item strong,
  .assignment-item small {
    grid-column: span 1;
  }
}

@media (max-width: 760px) {
  .app-shell {
    width: min(100% - 1rem, 1480px);
    padding-top: 0.5rem;
  }

  /*
   * App-Shell Auftrag 2026-10-01, Schritt 2b ("App-Shell Mobil", fester
   * Einzeiler): .topbar bewusst aus dieser Gruppe herausgenommen --
   * vorher stapelte sie sich hier wie .page-heading/.panel-heading
   * (eigene Zeile fuer Marke, eigene Zeile fuer Aktionen). Seit Schritt
   * 2b zeigt die Topbar mobil nur noch Logo+Wortmarke (links) und
   * Profilbild/Status (rechts, .topbar-actions) -- das passt bereits in
   * EINE Zeile (die Basisregel oben, `.topbar { flex-wrap: wrap }`,
   * laesst nur noch echte width:100%-Elemente wie .topbar-disclaimer
   * umbrechen). .page-heading/.panel-heading behalten das bisherige
   * Stapeln unveraendert (dort stehen laengere Titel/Aktionsleisten,
   * nicht Teil dieses Auftrags).
   */
  .page-heading,
  .panel-heading {
    align-items: flex-start;
    flex-direction: column;
  }

  .topbar-actions {
    justify-content: flex-end;
  }

  .profile-switcher,
  .profile-switcher select {
    width: 100%;
  }

  .hero-card,
  .dashboard-grid {
    grid-template-columns: 1fr;
  }

  .timeline-filter-grid,
  .analysis-filter-grid,
  .export-config-grid,
  .quick-range-grid,
  .export-range,
  .settings-grid,
  .form-grid,
  .export-condensed-options {
    grid-template-columns: 1fr;
  }

  .overview-stat-grid,
  .stat-grid,
  .quick-action-grid,
  .reference-grid {
    grid-template-columns: 1fr;
  }

  .export-step {
    grid-template-columns: 1fr;
  }

  .export-step > :not(.step-number) {
    grid-column: auto;
  }

  .step-number {
    margin-bottom: 0.2rem;
  }

  .assignment-item {
    grid-template-columns: 1fr;
  }

  .assignment-item strong,
  .assignment-item small {
    grid-column: auto;
  }

  .table-actions {
    width: 100%;
    align-items: stretch;
    flex-direction: column;
  }

  .table-actions label {
    width: 100%;
  }
}

@media (max-width: 450px) {
  .topbar-actions {
    align-items: stretch;
    flex-direction: column;
  }

  .topbar-actions .button,
  .status-pill {
    width: 100%;
    justify-content: center;
  }

  /*
   * App-Shell Auftrag 2026-10-01, Schritt 2 ("App-Shell Mobil"), Live-Fund: `align-items:
   * stretch` oben ist fuer Knoepfe/Status-Pillen gedacht (volle Breite = besseres Tastziel),
   * dehnt aber auch .topbar-profile-icons auf die volle Zeilenbreite -- der Profilbild-Knopf
   * darin (justify-content: flex-start, Default) landete dadurch GANZ LINKS statt rechts, und
   * sein Popover (.status-pill-detail-end, "right:0" relativ zum eigenen, jetzt links sitzenden
   * Anker) ragte komplett aus dem Bildschirm (links). align-self:flex-end haelt die Gruppe bei
   * ihrer natuerlichen (schmalen) Breite und rechtsbuendig -- genau wie bei jeder breiteren
   * Ansicht, nur jetzt auch unterhalb 450px.
   */
  .topbar-profile-icons {
    align-self: flex-end;
  }

  .nav-button {
    padding: 0.6rem 0.7rem;
    font-size: 0.8rem;
  }

  th,
  td {
    padding: 0.65rem;
  }
}

/*
 * AP12 Thread M1 / Korb E Paket E2 (Side-Rail, 2026-09-16): Drei-Modi-
 * @container-Ebene (CSS-only, kein weiterer Markup-Umbau ausser dem in
 * E2 bereits vorgenommenen Rail-DOM). ERGAENZT die obigen @media-
 * Breakpoints, ersetzt sie nicht (die regeln weiterhin die
 * feingranulare Spalten-Kollabierung einzelner Panels). Container ist
 * ".app-shell" (siehe `container: app-shell / inline-size` dort).
 *
 * Die drei Modi:
 * - BREIT (> 1050px, .app-shell-Basisregeln oben): Rail mit Icon+Label,
 *   15rem breit.
 * - MITTEL (728-1050px, Regel direkt unten): Rail bleibt links, aber
 *   kompakt/nur Icons -- ersetzt die urspruenglich fuer diese Breite
 *   vorgesehene, nie gebaute Idee eines "seitlich einblendbaren Panels"
 *   (brauchte eine echte Oeffnen/Schliessen-Interaktion, siehe alte
 *   Kommentar-Historie) mit der von Perplexity/Nutzer bevorzugten
 *   persistenten Kompakt-Rail (Material Navigation Rail/Fluent
 *   NavigationView-Muster).
 * - SCHMAL (< 728px, zweite Regel unten): bestehende Bottom-Tab-Nav,
 *   inhaltlich unveraendert gegenueber der vorigen Fassung.
 *
 * UI/UX-Audit (2026-09-08, Teil 2 Punkt 7): der 728px-Schwellenwert
 * selbst (728px Containerbreite = 760px Viewport, da .app-shell =
 * Viewport - 2rem) ist historisch bewusst auf denselben Wert wie die
 * Grid-/Topbar-Kollabierung ausgerichtet -- unveraendert uebernommen.
 *
 * Release v1.18.0 (Android-Huelle): die drei Schwellen sind jetzt
 * Viewport-Media-Queries (Containerbreite + 2rem: 728 -> 760, 1050 ->
 * 1082, 330 -> 362) statt @container. Grund: `container-type` macht in
 * aelteren Chromium/WebView-Staenden (live: Android-WebView 113) den
 * Container zum Bezugsblock fuer `position: fixed` -- die untere
 * Navigation und der "+"-Button klebten am Seitenende statt am
 * Bildschirmrand. Sichtbares Verhalten in aktuellen Browsern unveraendert.
 */
@media (max-width: 1082px) {
  /*
   * Korb E, Paket E2.1 (Kompakte Rail, MITTLERE Stufe): Label
   * verschwindet visuell, Accessible Name bleibt ueber
   * button.aria-label erhalten (siehe generateNavButtons(),
   * ui-core.js), title liefert einen nativen Hover-Tooltip -- exakt
   * die im Auftrag geforderte "Label via title/aria-label + Tooltip"-
   * Loesung.
   */
  .app-navigation {
    width: 4.5rem;
  }

  .nav-button {
    justify-content: center;
    padding-inline: 0.4rem;
  }

  .nav-button-label {
    display: none;
  }

  /* Schritt 2b: kompakte Rail zeigt nur das Logo, kein Wortmarken-Text (gleiches Prinzip wie .nav-button-label). */
  .nav-rail-brand {
    justify-content: center;
    padding-inline: 0.4rem;
  }

  .nav-rail-brand-label {
    display: none;
  }
}

@media (max-width: 760px) {
  /*
   * Korb E, Paket E2.2: `.is-collapsed` hat wegen der zwei
   * Klassen-Selektoren anderswo eine HOEHERE Spezifitaet als ein
   * einfaches `.app-navigation` -- ohne diese explizite
   * Mit-Qualifizierung wuerde der manuelle Collapse-Zustand die mobile
   * Bottom-Tab-Nav hier ueberstimmen, obwohl er dort keine Bedeutung
   * hat (kein Collapse-Konzept unter 728px).
   */
  .app-navigation,
  .app-navigation.is-collapsed {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    z-index: 20;
    width: auto;
    height: auto;
    flex-direction: row;
    /*
     * Korb E, Paket E2: die BREITE/MITTLERE Basisregel setzt nur noch
     * `border-right` (Rail-Trennlinie), nicht mehr den vollen
     * 4-Seiten-Rahmen der alten Top-Leiste -- hier explizit ein voller
     * Rahmen neu gesetzt (Farbe/Stil), BEVOR die Breiten-Kurzform
     * direkt danach drei Seiten auf 0 zieht. Ohne diesen Reset haette
     * die alte `border-width`-Kurzform allein KEINEN sichtbaren
     * oberen Rahmen mehr ergeben (border-style der oberen Kante war
     * seit E2 nie gesetzt).
     */
    border: 1px solid var(--border);
    border-width: 1px 0 0;
    border-radius: 0;
    justify-content: space-around;
    padding: 0.45rem 0.45rem calc(0.45rem + env(safe-area-inset-bottom, 0px));
  }

  /*
   * UI/UX-Audit (2026-09-08, Teil 2 Punkt 8, Befund 3.1): Labels
   * duerfen bereits umbrechen, aber .app-mains Kompensations-Padding
   * war fest auf 3.5rem verdrahtet -- bei 2-zeiligem Umbruch wuchs die
   * Nav-Leiste ueber diesen Wert hinaus und ueberlappte den
   * Seiteninhalt darunter.
   *
   * Fix: -webkit-line-clamp deckelt jedes Label hart auf maximal 2
   * Zeilen (mit Ellipsis als Sicherheitsnetz fuer extreme Faelle), so
   * ist die maximale Nav-Hoehe deterministisch und die Kompensation
   * unten kann sie zuverlaessig abdecken -- unabhaengig davon, ob 5
   * (heute) oder mehr Eintraege dargestellt werden, denn die
   * Zeilenzahl pro Button ist gedeckelt, nicht die Anzahl der Buttons
   * selbst. Seit Korb E/E2 auf .nav-button-label angewendet (vorher
   * ein nackter Textknoten direkt in .nav-button) -- .nav-button
   * selbst ist seit E2 ein Flex-Container (Icon+Label nebeneinander),
   * das Line-Clamping gilt daher gezielt fuer das Label-Element.
   */
  /*
   * UX-Bestandsaufnahme 2026-09-17 (Befund H4): `flex: 1 1 0` allein
   * reichte nicht -- Flex-Items schrumpfen standardmaessig nie unter
   * ihre min-content-Breite (laengstes Wort + Padding). Die Leiste war
   * dadurch bei JEDER Breite fest 382px breit, "Verwaltung" lag ab
   * 360px (haeufigste Android-Breite) teilweise, ab 320px komplett
   * ausserhalb des Bildschirms (overflow-x: hidden schneidet ab). Jetzt
   * min-width: 0 + knapperes Padding/kleinere Schrift + deutsche
   * Silbentrennung (html lang="de") innerhalb der bestehenden
   * 2-Zeilen-Begrenzung.
   */
  .app-navigation,
  .app-navigation.is-collapsed {
    gap: 0.1rem;
    padding-inline: 0.25rem;
  }

  .app-navigation .nav-button,
  .app-navigation.is-collapsed .nav-button {
    flex: 1 1 0;
    min-width: 0;
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    padding-inline: 0.15rem;
    text-align: center;
    line-height: 1.15;
  }

  .app-navigation .nav-button-label,
  .app-navigation.is-collapsed .nav-button-label {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    max-width: 100%;
    overflow: hidden;
    white-space: normal;
    text-overflow: clip;
    font-size: 0.68rem;
    hyphens: auto;
    -webkit-hyphens: auto;
  }

  /*
   * Korb E, Paket E2.2: der Collapse-Toggle ist ein rein Rail-
   * spezifisches Bedienelement (siehe .nav-rail-toggle oben) -- die
   * mobile Bottom-Tab-Nav kennt keinen Collapse-Zustand, daher hier
   * ausgeblendet statt einen (bedeutungslosen) dritten Zustand zu
   * riskieren.
   */
  .nav-rail-toggle {
    display: none;
  }

  /*
   * Schritt 2b: in der Bottom-Tab-Nav ist kein Platz fuer Logo+Wortmarke
   * (die View-Buttons sind hier schon knapp, siehe Kommentare oben) --
   * die Topbar behaelt ihr eigenes Logo/h1 auf dieser Breite (siehe
   * @media (min-width: 761px) weiter unten, das es NUR am Desktop
   * ausblendet).
   */
  .app-navigation .nav-rail-brand {
    display: none;
  }

  .app-main {
    padding-bottom: calc(5.25rem + env(safe-area-inset-bottom, 0px));
  }
}

/*
 * Sehr schmale Geraete (~320px Viewport = ~304px Container): die zwei
 * laengsten Einzelwoerter ("Gesundheit", "Verwaltung") brauchten live
 * gemessen 2-3px mehr, und Silbentrennung ist nicht in jedem Browser
 * fuer Deutsch verfuegbar.
 */
@media (max-width: 362px) {
  .app-navigation .nav-button,
  .app-navigation.is-collapsed .nav-button {
    padding-inline: 0;
  }

  .app-navigation .nav-button-label,
  .app-navigation.is-collapsed .nav-button-label {
    font-size: 0.64rem;
  }
}

.file-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.section-divider {
  margin: 2rem 0;
  border: 0;
  border-top: 1px solid var(--border-color, #d7dce5);
}

.chart-container {
  min-height: 28rem;
  overflow-x: auto;
  padding: 0.75rem;
  /* AP7b-2b: Anker fuer das absolut positionierte Hover-Tooltip. */
  position: relative;
  /*
   * UI/UX-Audit (2026-09-08, Teil 2 Punkt 9): overflow-x:auto war
   * bereits gesetzt, aber unsichtbar -- kein Hinweis, dass das
   * Hauptdiagramm bei schmalen Bildschirmen horizontal scrollt
   * (Befund 2.2, docs/audits/ui-ux-audit-2026-09-08.md). Gleiche,
   * bereits etablierte Loesung wie .app-navigation (Zeile ~596-616):
   * rein visuelles Fade an beiden Raendern, kein neuer Scroll-
   * Listener/Zustand, nur eine statische Masken-Andeutung.
   */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent,
    black 24px,
    black calc(100% - 24px),
    transparent
  );
  mask-image: linear-gradient(
    to right,
    transparent,
    black 24px,
    black calc(100% - 24px),
    transparent
  );
}

.chart-svg {
  display: block;
  width: 100%;
  min-width: 46rem;
  height: auto;
  overflow: visible;
}

.chart-grid-line {
  stroke: var(--border);
  stroke-width: 1;
}

.chart-axis-line {
  stroke: var(--border-strong);
  stroke-width: 1.2;
}

/*
 * UX_AUDIT.md Gruppe 4 (2026-10-01, "SVG-Diagrammtext nutzt px statt rem"): bei reiner
 * OS-Textgroessen-Einstellung (nicht Browser-Zoom) skalierte px-basierter SVG-Text bisher nicht
 * mit -- rem skaliert zusaetzlich automatisch mit dem :root-font-size der A11y-Themes
 * (:root[data-theme="ikyru-a11y"], 18px statt 16px Basis).
 */
.chart-axis-text {
  fill: var(--text-muted);
  font-size: 0.75rem;
}

.chart-axis-text-secondary {
  fill: var(--chart-af);
  font-size: 0.75rem;
}

/*
 * UX-Akzeptanztest Test D, Nachtrag (2026-09-23): Medikations-Spurenbeschriftung ohne Einheit
 * (Alt-Plan von vor der Pflichtfeld-Validierung) bekommt die Warnfarbe statt der neutralen
 * chart-axis-text-Farbe -- gleiche Token-Basis wie .hint.warning.
 */
.chart-axis-text-warning {
  fill: var(--warning);
  font-weight: 600;
}

.chart-axis-line-secondary {
  stroke: var(--chart-af);
  opacity: 0.6;
}

.chart-panel-title {
  font-size: 0.8125rem;
  font-weight: 700;
  fill: var(--text);
}

.chart-line-hr {
  fill: none;
  stroke: var(--chart-hr);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-line-af {
  fill: none;
  stroke: var(--chart-af);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * BEFUND 2026-10-02 (Band-Darstellung, Live-Pruefung des in
 * OPEN_ITEMS.md zurueckgestellten Funds): das HR/AF-Referenzband
 * (appendChannelBand(), chart-renderer.js) traegt neben chart-band-hr/
 * -af auch chart-line-hr/-af (fuer die Farbe, siehe Kommentar dort) --
 * dessen stroke-width:2.5 oben gewinnt aber gegen das vom Band selbst
 * gesetzte stroke-width-Praesentationsattribut (6), da echte CSS-
 * Regeln Praesentationsattribute immer schlagen. Live bestaetigt: das
 * Band rendert dadurch nur als duenne, mit der echten Linie
 * verwechselbare Zweitlinie statt eines breiten, transparenten
 * Streifens. Eine kombinierte Selektor-Regel (beide Klassen auf
 * demselben Element) hat hoehere Spezifitaet als die einfache
 * .chart-line-hr/-af-Regel oben und gewinnt daher zurueck.
 */
.chart-line-hr.chart-band-hr,
.chart-line-af.chart-band-af {
  stroke-width: 6;
}

.chart-line-ratio {
  fill: none;
  stroke: var(--chart-ratio);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-trend-line {
  fill: none;
  stroke: var(--text-muted);
  stroke-width: 1.5;
  stroke-dasharray: 6 5;
}

/*
 * Nutzerauftrag 2026-09-24 (medizinische Diagramm-Zusatzoptionen, Prioritaet 1
 * "Baseline-Band statt nur Linie"): Hintergrund-Flaeche fuer den individuellen
 * Referenzbereich (App.ChartRenderer appendSeriesOverlayBand()). Opazitaet kommt
 * bewusst als Inline-SVG-Attribut aus chart-renderer.js (gleiches Muster wie
 * appendChannelBand() oben) -- hier nur die Farbe je Kanal, keine feste Kanal-
 * Klasse noetig (bpm/rpm-Einheit entscheidet im Renderer, welche Skala genutzt
 * wird, dieselbe Klasse deckt beide ab, kein optischer Unterschied noetig, da
 * das Band ohnehin an der jeweiligen Kanal-Skala haengt).
 */
.chart-series-overlay-band-reference {
  fill: var(--text-muted);
  stroke: none;
}

/*
 * Nutzerauftrag 2026-09-24 (medizinische Diagramm-Zusatzoptionen, Prioritaet 3
 * "Datenluecken sichtbar machen"): graue Flaeche (appendDataGapMarker(),
 * chart-renderer.js) -- Opazitaet kommt als Inline-SVG-Attribut, siehe dortiger
 * Kommentar zur bewusst einfachen Farbwahl statt einer echten Schraffur-Textur.
 */
.chart-data-gap-marker {
  fill: var(--border-strong);
  stroke: var(--border-strong);
  stroke-width: 1;
  stroke-dasharray: 4 3;
}

/*
 * Nutzerauftrag 2026-09-24 (medizinische Diagramm-Zusatzoptionen, Prioritaet 4
 * "Vergleichszeitraum"): die Vorperiode wird in DERSELBEN Kanalfarbe wie die
 * aktuelle Periode gezeichnet (chart-line-hr/chart-line-af bleiben zusaetzlich
 * gesetzt, siehe chart-renderer.js), Unterscheidung NUR ueber Strichmuster
 * (Nutzerentscheidung: "nur Strichmuster, keine zusaetzliche Farbdaempfung").
 * --chart-comparison-overlay-opacity (Definition im :root-Block am Dateianfang)
 * ist die vorgebaute, aber noch nicht aktivierte Farbdaempfungs-Option (Default
 * 1 = keine Daempfung) -- eine spaetere Entscheidung kann diesen einen Token
 * auf <1 setzen, ohne Zeichencode anzufassen.
 */
.chart-line-comparison {
  stroke-dasharray: 6 4;
  opacity: var(--chart-comparison-overlay-opacity, 1);
}

/*
 * Ikyru Zen-Theme: urspruenglich (Nutzerauftrag 2026-09-24) teilten sich
 * alle Vitalwert-/Zusatzkanaele hier denselben --primary-Akzent, Kanaele
 * nur per Linienstil/-staerke unterschieden. Mit Nutzerauftrag 2026-10-01
 * ("Farben bei allen Diagrammen pruefen und optimieren, HR=rot/AF=blau,
 * gute Kontraste, unabhaengig vom Theme") haben die --chart-*-Tokens oben
 * jetzt echte, eigene Farben je Kanal (siehe Kommentar bei :root[data-
 * theme="ikyru-light"]) -- diese Linienstil-Regeln bleiben als
 * ZUSAETZLICHE, redundante Kodierung bestehen (hilft z.B. bei Farbfehl-
 * sichtigkeit), sind aber nicht mehr die EINZIGE Unterscheidung.
 * chart-line-hr/-af/-ratio sind eigene, kurze Klassennamen (siehe
 * chart-renderer.js Kombiniert-Layout); die uebrigen Kanaele nutzen den
 * generischen chart-line-<channel.id>-Namen (appendChannelMeanLine() in
 * chart-renderer.js, cssKey = channel.id UNVERAENDERT -- also mit
 * Unterstrich bei z.B. "resting_heartrate", kein Bindestrich). Nur 6
 * unterscheidbare Muster (mehr waeren im Diagramm nicht mehr auseinander-
 * zuhalten) -- Kanaele, die selten gleichzeitig im selben Diagramm aktiv
 * sind (z.B. hrv/resting_heartrate/spo2, alle Wearable-spezifisch),
 * teilen sich bewusst ein Muster mit einem der Hauptkanaele.
 */
:root[data-theme^="ikyru"] .chart-line-hr { stroke-dasharray: none; }
:root[data-theme^="ikyru"] .chart-line-af { stroke-dasharray: 5 3; }
:root[data-theme^="ikyru"] .chart-line-ratio { stroke-dasharray: 1 4; }
:root[data-theme^="ikyru"] .chart-line-weight { stroke-dasharray: 8 2 2 2; }
:root[data-theme^="ikyru"] .chart-line-height { stroke-dasharray: 10 3; }
:root[data-theme^="ikyru"] .chart-line-barking { stroke-dasharray: 2 2; }
:root[data-theme^="ikyru"] .chart-line-measurement { stroke-dasharray: 8 2 2 2; }
:root[data-theme^="ikyru"] .chart-line-stool { stroke-dasharray: 10 3; }
:root[data-theme^="ikyru"] .chart-line-resting_heartrate { stroke-dasharray: none; }
:root[data-theme^="ikyru"] .chart-line-spo2 { stroke-dasharray: 5 3; }
:root[data-theme^="ikyru"] .chart-line-hrv { stroke-dasharray: 1 4; }

/*
 * chart-line-comparison bleibt immer gestrichelt-abweichend vom jeweiligen
 * Hauptmuster des Kanals, sonst waeren aktuelle und Vorperiode bei einem
 * bereits gestrichelten Kanal (z.B. AF) nicht mehr unterscheidbar. Feinere,
 * dichtere Strichelung als jedes Kanal-Muster oben -- bleibt damit immer
 * die "kleinteiligste" Linie im Diagramm.
 */
:root[data-theme^="ikyru"] .chart-line-comparison {
  stroke-dasharray: 3 2 !important;
}

.chart-marker-medication {
  fill: var(--success);
  stroke: var(--surface);
  stroke-width: 1.5;
}

.chart-marker-clinical {
  fill: var(--warning);
  stroke: var(--surface);
  stroke-width: 1.5;
}

/*
 * ERGEBNISKANAL-AUDIT (Thread B, Distribution-/Box-Plot).
 */
.chart-boxplot-box {
  fill: color-mix(in srgb, var(--primary) 18%, transparent);
  stroke: var(--primary);
  stroke-width: 1.5;
}

.chart-boxplot-median {
  stroke: var(--primary);
  stroke-width: 2.5;
}

.chart-boxplot-whisker {
  stroke: var(--text-muted);
  stroke-width: 1.2;
}

.chart-boxplot-outlier {
  fill: var(--danger);
  stroke: var(--surface);
  stroke-width: 1;
}

/*
 * Kanal-basiertes Diagrammsystem: zusaetzliche Linien-Kanaele (Gewicht,
 * Bellen) und generalisierte Marker-Kanaele (beliebige Ereignis-Kanaele
 * statt nur Medikation/Klinisch) bekommen eigene Farben. Die Band-
 * Darstellung dieser Kanaele nutzt bewusst dieselbe .chart-line-*-Klasse
 * (gleiche Farbe wie die Linie, Opazitaet kommt als Inline-SVG-Attribut
 * aus chart-renderer.js) statt einer eigenen .chart-band-*-Klasse --
 * gleiches Muster wie bei HR/AF.
 */
.chart-line-weight {
  fill: none;
  stroke: var(--chart-weight);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-weight {
  fill: var(--chart-weight);
}

.chart-line-barking {
  fill: none;
  stroke: var(--chart-barking);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-barking {
  fill: var(--chart-barking);
}

/*
 * THREAD G (generisches Messwerte-System): eigene Farbe fuer den neuen
 * "measurement"-Kanal, gleiches Muster wie weight/barking oben.
 */
.chart-line-measurement {
  fill: none;
  stroke: var(--chart-measurement);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-measurement {
  fill: var(--chart-measurement);
}

/*
 * BEFUND 2026-10-01 (Nutzerauftrag "Farben bei allen Diagrammen fuer
 * alle Channels pruefen"): im Unterschied zu weight/barking/measurement
 * oben hatten height/resting_heartrate/spo2/hrv HIER UEBERHAUPT KEINE
 * .chart-line-<id>- bzw. .chart-point-<id>-Regel -- chart-renderer.js setzt fuer
 * Polyline/Punkt NUR die Klasse, keine Inline-Farbe (appendPolyline(),
 * appendChannelScatterPoints()), d.h. diese vier Kanaele liefen ohne
 * jede CSS-Regel auf den SVG-Default (Linie ohne Stroke = unsichtbar,
 * Punkt mit Default-Fill = schwarz) -- in ALLEN Themes, nicht nur
 * Ikyru (dort gab es zusaetzlich nur das stroke-dasharray-Muster weiter
 * unten, aber auch keine Farbe). Fix: gleiches Muster wie weight/
 * barking/measurement oben.
 */
.chart-line-height {
  fill: none;
  stroke: var(--chart-height);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-height {
  fill: var(--chart-height);
}

.chart-line-resting_heartrate {
  fill: none;
  stroke: var(--chart-resting-heartrate);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-resting_heartrate {
  fill: var(--chart-resting-heartrate);
}

.chart-line-spo2 {
  fill: none;
  stroke: var(--chart-spo2);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-spo2 {
  fill: var(--chart-spo2);
}

.chart-line-hrv {
  fill: none;
  stroke: var(--chart-hrv);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart-point-hrv {
  fill: var(--chart-hrv);
}

.chart-marker-generic {
  stroke: var(--surface);
  stroke-width: 1.5;
}

.chart-marker-medication_administration {
  fill: var(--success);
}

.chart-marker-medication_planned {
  fill: var(--text-muted);
}

.chart-marker-medication_plan_change {
  fill: var(--danger);
}

.chart-marker-observation {
  fill: var(--warning);
}

.chart-marker-context_event {
  fill: var(--primary);
}

/*
 * RUNDE 2: nutrition_event fehlte bisher eine eigene Fuellfarbe (fiel auf
 * die Browser-Default-Fuellung zurueck, da .chart-marker-generic nur
 * stroke setzt) -- gleiche Farbe wie der bestehende Messwert-Punkt
 * (.chart-point-measurement), da beide thematisch "Ernaehrung/Zusatz-
 * Messwert" nahe beieinander liegen. stool bekommt eine eigene, davon
 * unterscheidbare Farbe.
 */
.chart-marker-nutrition_event {
  fill: var(--chart-measurement);
}

.chart-marker-stool {
  fill: var(--chart-stool);
}

/*
 * BEFUND 2026-10-01: diagnosis/vet_appointment/symptom_episode hatten
 * bisher GAR KEINE Fuellfarbe (fielen auf .chart-marker-generic zurueck,
 * das nur stroke setzt) -- Raute blieb auf Browser-Default-Fuellung.
 * Fix: eigene --chart-<id>-Tokens (siehe :root oben), gleiches Muster
 * wie bei nutrition_event/stool.
 */
.chart-marker-diagnosis {
  fill: var(--chart-diagnosis);
}

.chart-marker-vet_appointment {
  fill: var(--chart-vet_appointment);
}

.chart-marker-symptom_episode {
  fill: var(--chart-symptom_episode);
}

/*
 * THREAD A (Ereigniskanal): Zeitraum-Marker-Band -- geringe Deckkraft,
 * kein Stroke (unterscheidet sich bewusst von den Punkt-Rauten oben,
 * die stroke:var(--surface) fuer Abstand zwischen benachbarten Markern
 * nutzen; ein Band braucht das nicht, da es selbst schon flaechig ist).
 */
.chart-marker-band {
  stroke: none;
  opacity: 0.35;
}

.chart-legend {
  display: flex;
  gap: 0.9rem;
  flex-wrap: wrap;
}

.chart-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-muted);
  font-size: 0.84rem;
  font-weight: 700;
}

/*
 * Nutzerauftrag 2026-10-01: Hintergrundfarbe kommt jetzt fuer JEDEN
 * Eintrag direkt aus renderChartLegend() (dot.style.background, aus
 * channel.cssColorVar bzw. App.ActivityCategories.getColor()) --
 * frueher musste jeder Kanal hier eine eigene ".hr"/".af"/".weight"/
 * ".marker-<id>"-Hintergrundregel bekommen, was bei neuen Kanaelen
 * regelmaessig vergessen wurde (siehe Kommentar bei den --chart-*-
 * Tokens in :root, css/styles.css: diagnosis/vet_appointment/
 * symptom_episode/context_event/nutrition_event fehlten hier bisher
 * ganz). Inline style gewinnt ohnehin gegen jede Klassenregel, daher
 * sind die alten Farbregeln ersatzlos entfernt -- nur Groesse/Form
 * bleiben hier (die duerfen weiter pauschal fuer alle Marker-Typen
 * gelten, sie haengen nicht vom einzelnen Kanal ab). default-Hintergrund
 * bleibt als Fallback fuer den seltenen Fall eines Eintrags ohne Farbe.
 */
.chart-legend-color {
  width: 1rem;
  height: 0.25rem;
  border-radius: 999px;
  background: var(--text-muted);
}

.chart-legend-color.medication {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: var(--success);
}

.chart-legend-color.clinical {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background: var(--warning);
}

/*
 * BUGFIX 2026-08-23: Marker-Kanaele werden im Diagramm jetzt als Raute
 * statt Kreis gezeichnet (siehe chart-renderer.js
 * appendMarkerChannelRow), damit sie sich optisch klar von echten
 * Messwert-Punkten (chart-point-*) unterscheiden. Die Legenden-Swatches
 * uebernehmen dieselbe Form ueber clip-path, damit Legende und Diagramm
 * konsistent bleiben. Gilt generisch fuer ALLE marker-<id>-Eintraege
 * (Attribut-Selektor statt Aufzaehlung -- keine Pflege pro Kanal mehr
 * noetig, Nutzerauftrag 2026-10-01).
 */
.chart-legend-color[class*="marker-"] {
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 0;
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

.chart-activity-segment {
  stroke: var(--surface);
  stroke-width: 1;
}

/*
 * AP7b-2a: das einzelne, austauschbare Hintergrundband -- sehr dezent
 * (opacity statt kraeftiger Fuellung), kein Stroke (keine Zellgrenzen
 * wie beim Aktivitaetsband, es ist eine Waesche, keine Sequenz von
 * Einzelsegmenten).
 */
.chart-band-background {
  stroke: none;
  opacity: 0.05;
}

/*
 * AP7b-2b: gestapelte Spuren-Zeile fuer Tag/Nacht bzw. Medikationsphase
 * (js/ui/chart-renderer.js appendBandTrackRow()) -- gleiche duenne
 * Segmenttrennung wie das bestehende Aktivitaetsband
 * (.chart-activity-segment), damit beide Spurenarten optisch als
 * dieselbe Sprache erkennbar sind.
 */
.chart-band-track-segment {
  stroke: var(--surface);
  stroke-width: 1;
}

/*
 * AP7b-2b: Hover-Cursor -- eine anfangs unsichtbare (display:none, per
 * JS umgeschaltet) vertikale Linie ueber das gesamte Diagramm plus ein
 * schwebendes Tooltip-Element, das fuer den Zeitpunkt unter dem Cursor
 * alle zutreffenden Band-Kategorien als Textzeilen auflistet (loest
 * Ueberschneidungen zwischen Kategorien textuell statt visuell auf).
 * pointer-events:none auf beiden -- duerfen den bestehenden Zoom-/Pan-
 * Drag darunter niemals blockieren.
 */
/*
 * Kernausbau 2026-09-22: Medikationsspuren. Zustand nie nur ueber die Farbe: gegeben = gefuellter Kreis, angenommen = Ring, ausgelassen/nicht
 * dokumentiert = Kreuz (zusaetzlich Hover-Text). Farben aus den vorhandenen Tokens (--primary / --text-muted), damit beide Farbschemata stimmen.
 */
.chart-med-baseline {
  stroke: var(--border);
  stroke-width: 1;
}

.chart-med-step {
  stroke: var(--primary);
  stroke-width: 1.5;
  fill: none;
}

.chart-med-stem {
  stroke: var(--text-muted);
  stroke-width: 1;
  opacity: 0.6;
}

.chart-med-dot {
  fill: var(--primary);
  stroke: var(--surface);
  stroke-width: 1;
}

.chart-med-ring {
  fill: var(--surface);
  stroke: var(--primary);
  stroke-width: 1.5;
}

.chart-med-cross {
  stroke: var(--text-muted);
  stroke-width: 1.5;
}

.chart-med-density {
  fill: var(--primary);
}

/*
 * P0d Teil 3 (2026-10-04, Diagrammueberlappungsfund): Schraffur + Textlabel fuer eine echte
 * Zeitueberlappung zwischen zwei unabhaengigen Behandlungsketten fuer denselben Wirkstoff.
 * Barrierefreiheit: die Schraffur allein reicht nicht -- chart-med-overlap-label traegt
 * dieselbe Aussage als sichtbaren Text (nicht nur als Hover-Title). chart-med-overlap-rect
 * ist per Tastatur erreichbar (tabindex, siehe chart-renderer.js) -- :focus-visible deshalb
 * wie bei anderen interaktiven Chart-Elementen mit einem sichtbaren Ring, nicht nur Browser-
 * Standard (SVG-Fokusringe werden sonst leicht vom umgebenden Diagramm verschluckt).
 */
.chart-med-overlap-hatch-bg {
  fill: var(--warning-soft);
}

.chart-med-overlap-hatch-line {
  stroke: var(--warning);
  stroke-width: 1.5;
}

.chart-med-overlap-rect {
  cursor: pointer;
}

.chart-med-overlap-rect:focus-visible {
  outline: 2px solid var(--warning);
  outline-offset: 2px;
}

.chart-med-overlap-label {
  fill: var(--warning);
  font-size: 11px;
}

.chart-band-track-density {
  stroke: none;
}

.chart-hist-bar {
  opacity: 0.75;
}

.chart-hist-bar-heartrate {
  fill: var(--chart-hr);
}

.chart-hist-bar-breathing {
  fill: var(--chart-af);
}

.chart-hist-bar-extra {
  fill: var(--primary);
}

.chart-hist-median {
  stroke: var(--text-muted);
  stroke-width: 1.5;
  stroke-dasharray: 4 3;
}

.chart-hover-cursor-line {
  stroke: var(--text-muted);
  stroke-width: 1;
  pointer-events: none;
}

.chart-hover-tooltip {
  position: absolute;
  z-index: 5;
  pointer-events: none;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-small);
  box-shadow: var(--shadow);
  padding: 0.4rem 0.6rem;
  font-size: 0.82rem;
  color: var(--text);
  white-space: nowrap;
}

/*
 * AP12 Thread M2c: Canvas-Aequivalent zu .chart-hover-cursor-line (SVG
 * <line>) -- das Canvas-Scatter-Panel hat kein DOM, daher ein absolut
 * positionierter Div derselben Rolle (duenne senkrechte Linie ueber die
 * Hoehe des gehoverten Panels). left/top/height werden per JS gesetzt
 * (ui-charts.js attachTrackHoverCursor()).
 */
.chart-hover-cursor-line-canvas {
  position: absolute;
  width: 1px;
  background: var(--text-muted);
  pointer-events: none;
  z-index: 4;
}

/*
 * WCAG 2.1.1 Keyboard (2026-10-01, UX_AUDIT.md Gruppe 5): Tastatur-Alternative zum
 * Hover-Tooltip der Canvas-Scatter-Charts -- macht die bereits vorhandene, bisher immer
 * `.visually-hidden` Datentabelle (chart-canvas-scatter.js buildAccessibleTable()) ueber einen
 * normalen, fokussierbaren Knopf sichtbar. <canvas>/<button> sind beide standardmaessig
 * inline-block -- ohne diese Regel wuerde der Knopf neben dem Canvas sitzen statt darunter.
 */
.chart-canvas-table-toggle {
  display: block;
  margin-top: 0.6rem;
}

.chart-canvas-table-wrap {
  margin-top: 0.6rem;
}

.chart-line-median {
  stroke-dasharray: 4 4;
  opacity: 0.85;
}

.chart-point-hr {
  fill: var(--chart-hr);
}

.chart-point-af {
  fill: var(--chart-af);
}

.chart-point-ratio {
  fill: var(--chart-ratio);
}

.chart-hover-point {
  opacity: 0;
}

.chart-hover-point:hover {
  opacity: 0.6;
}

.chart-point-flagged {
  stroke: var(--warning);
  stroke-width: 2;
}

/*
 * ROHDATEN-FIX (Thread F): Min-Max-Whisker hinter Punkte-Modus-
 * Datenpunkten fuer numeric_packet-Samples mit count>1 -- gleiche Farbe
 * wie der zugehoerige Punkt (stroke statt fill), ueber die bestehende
 * --chart-*-Custom-Property-Konvention (AP7b-1), keine neue Farbe.
 */
.chart-point-hr-whisker {
  stroke: var(--chart-hr);
}

.chart-point-af-whisker {
  stroke: var(--chart-af);
}

.chart-point-ratio-whisker {
  stroke: var(--chart-ratio);
}

.chart-point-weight-whisker {
  stroke: var(--chart-weight);
}

.chart-point-barking-whisker {
  stroke: var(--chart-barking);
}

.chart-point-measurement-whisker {
  stroke: var(--chart-measurement);
}

/* BEFUND 2026-10-01, gleicher Grund wie bei .chart-line-height etc. oben. */
.chart-point-height-whisker {
  stroke: var(--chart-height);
}

.chart-point-resting_heartrate-whisker {
  stroke: var(--chart-resting-heartrate);
}

.chart-point-spo2-whisker {
  stroke: var(--chart-spo2);
}

.chart-point-hrv-whisker {
  stroke: var(--chart-hrv);
}

.chart-heatmap-title {
  font-weight: 700;
  fill: var(--text);
}

.chart-heatmap-cell {
  stroke: var(--surface);
  stroke-width: 1;
}

.chart-heatmap-cell-empty {
  fill: var(--surface-muted);
}

.chart-heatmap-cell-flagged {
  stroke: var(--warning);
  stroke-width: 2;
}

.chart-heatmap-cell-muted {
  opacity: 0.15;
}

.chart-finding-marker {
  stroke: var(--surface);
  stroke-width: 1;
}

.chart-finding-high {
  fill: var(--chart-finding-high);
}

.chart-finding-medium {
  fill: var(--chart-finding-medium);
}

.chart-finding-low {
  fill: var(--chart-finding-low);
}

.health-block-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
}

.health-block-unauffaellig {
  color: var(--success);
  background: color-mix(in srgb, var(--success) 16%, transparent);
}

.health-block-auffaellig {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 16%, transparent);
}

.health-block-unklar {
  color: var(--text-muted);
  /*
   * AP12 Thread M6: Kontrast-Audit (live per getComputedStyle+relative
   * Luminanz geprueft, nicht geschaetzt) fand hier 4.327:1 -- knapp
   * unter der 4.5:1-Mindestschwelle fuer normalgrosse Schrift. Tint von
   * 16% auf 12% reduziert (nur dieser eine Badge-Wert, --text-muted
   * selbst und die anderen zwei Badges -- 4.66:1/5.02:1, bereits
   * ausreichend -- bleiben unangetastet) -> 4.57:1, ausreichend.
   */
  background: color-mix(in srgb, var(--text-muted) 12%, transparent);
}

/*
 * RUNDE 2 (Impfungen & Parasitenprophylaxe): "bald faellig"-Zwischenstufe
 * zwischen ueberfaellig (health-block-auffaellig, rot) und aktuell/kein
 * Termin (health-block-unklar, neutral) -- gleiches Wertfarb-Muster.
 */
.health-block-baldfaellig {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 16%, transparent);
}

/*
 * THREAD I (Theorien/Ursachenvermutungen): Typ-Badge fuer Beobachtung
 * vs. Theorie in derselben Liste -- gleiches Wertfarb-Muster wie
 * .health-block-badge, NICHT das starre .severity-pill-Muster.
 */
.record-type-badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 600;
}

.record-type-observation {
  color: var(--info, var(--primary));
  background: color-mix(in srgb, var(--primary) 16%, transparent);
}

.record-type-theory {
  color: var(--warning);
  background: color-mix(in srgb, var(--warning) 16%, transparent);
}

.reference-recommendation-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.8rem;
  margin: 1rem 0;
}

.reference-recommendation-card {
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.reference-recommendation-card h4 {
  margin: 0 0 0.6rem;
}

.reference-recommendation-columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.8rem;
}

.reference-recommendation-columns > div {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.reference-recommendation-columns span {
  color: var(--text-muted);
  font-size: 0.8rem;
}

.reference-recommendation-columns strong {
  font-size: 0.95rem;
}

/*
 * ERGEBNISKANAL-AUDIT (Thread D, aktivitaetsphasenabhaengiges
 * Referenzmodell): neuer Unterblock je Kanal-Karte, optisch abgesetzt
 * (Trennlinie) -- nur EINE Empfehlungs-Spalte (keine "allgemeine"
 * Aktivphasen-Empfehlung), daher eigene 1-Spalten-Regel statt der
 * bestehenden 2-Spalten-Regel fuer .reference-recommendation-columns.
 */
.reference-active-subsection {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed var(--border);
}

.reference-active-subsection h5 {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.reference-active-subsection .reference-recommendation-columns {
  grid-template-columns: minmax(0, 1fr);
}

.chart-options > .chart-options-panel {
  margin: 1rem 1.3rem;
  display: grid;
  gap: 1rem;
}

/* Kompakte Pillen-Toggles (Checkbox) fuer die Diagramm-Werkzeugleiste --
   ersetzt .checkbox-label an Stellen mit vielen, haeufig genutzten
   Optionen. Native Checkbox bleibt fuer Screenreader/Tastatur erhalten,
   wird aber visuell versteckt; :has(input:checked) steuert die Optik. */
.toggle-chip {
  display: inline-flex !important;
  align-items: center;
  gap: 0.35rem;
  /* AP12 Thread M1: 2.2rem (35.2px) auf 2.75rem (44px) angehoben --
     .toggle-chip wird auch fuer Tag-Picker-Chips wiederverwendet
     (kein separates .tag-picker-chip im Markup), Fix deckt beide ab. */
  min-height: 2.75rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted) !important;
  font-size: clamp(0.74rem, 0.2vw + 0.72rem, 0.8rem) !important;
  font-weight: 700;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.toggle-chip input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.toggle-chip:hover {
  border-color: var(--primary);
  color: var(--text) !important;
}

.toggle-chip:has(input:checked) {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary) !important;
}

.toggle-chip:has(input:focus-visible) {
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* Zusammenhaengende Pillengruppe fuer Radio-Auswahlen (z.B. Diagrammtyp,
   Diagrammlayout) -- gleiches Prinzip wie .toggle-chip, einzeiliger
   Wahlschalter statt Mehrfachauswahl. */
.segmented-control {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
}

.segmented-option {
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  /* AP12 Thread M1: 2rem (32px) auf 2.75rem (44px) angehoben -- gleiche
     Touch-Ziel-Audit-Runde wie .button/.nav-button/.toggle-chip. */
  min-height: 2.75rem;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  color: var(--text-muted) !important;
  font-size: clamp(0.74rem, 0.2vw + 0.72rem, 0.8rem) !important;
  font-weight: 700;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease;
}

.segmented-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.segmented-option:has(input:checked) {
  background: var(--primary);
  color: #ffffff !important;
}

.segmented-option:has(input:focus-visible) {
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* Versorgung-Layer-Prinzip Phase 3 (2026-10-03, Teil A): Kachel-Einstieg "Was moechtest du
   planen?" ersetzt die gewachsene <select>-Typ-Auswahl. Eigene Klasse statt .toggle-chip
   (Pillenform) -- Kacheln duerfen umbrechen und sind quadratischer/praesenter, da sie die
   EINZIGE Entscheidung dieses ersten Schritts sind (UX-Grundsatz GUARDRAILS Regel 18:
   Layer 1 = genau eine klare Frage). */
.care-type-picker {
  border: 0;
  margin: 0 0 1rem;
  padding: 0;
}

.care-type-picker legend {
  font-weight: 700;
  margin-bottom: 0.5rem;
  padding: 0;
}

.care-type-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
  gap: 0.5rem;
}

.care-type-tile {
  min-height: 2.75rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  background: var(--surface);
  color: var(--text) !important;
  font-size: 0.85rem;
  font-weight: 700;
  text-align: center;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.care-type-tile:hover {
  border-color: var(--primary);
}

.care-type-tile[aria-pressed="true"] {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary) !important;
}

.care-type-tile:focus-visible {
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* Segment-Schalter unterhalb der Kacheln (Art der Vorsorge / Ort der Kontrolle) --
   gleiches .segmented-control wie oben, nur mit Zeilen-Rahmung fuer den Kontext. */
.care-segmented-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  margin: 0 0 1rem;
}

.care-segmented-row-label {
  font-weight: 700;
}

/*
 * Versorgung-Layer-Prinzip Phase 3, Teil 2 (2026-10-04): Dosis-/Wiederholungs-Vorlagen
 * ("1x taeglich morgens", "alle 4 Wochen", ...) im Medikamentenplan- UND Vorsorge-Formular --
 * reine Komfort-Knoepfe, die bestehende Felder ausfuellen (kein eigener gespeicherter
 * Zustand, daher kein dauerhaftes aria-pressed wie bei der Art-Auswahl oben). Gleiche Optik wie
 * .care-type-tile, aber bewusst eigene Klasse: die Knoepfe erscheinen auch im Medikamentenplan-
 * Formular (js/ui/ui-medication.js), das sonst keine "care"-Klassen verwendet.
 */
.quickfill-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 0.75rem;
}

.quickfill-tile {
  min-height: 2.75rem;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  background: var(--surface);
  color: var(--text) !important;
  font-size: 0.82rem;
  font-weight: 700;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}

.quickfill-tile:hover {
  border-color: var(--primary);
}

.quickfill-tile:focus-visible {
  box-shadow: 0 0 0 3px var(--primary-soft);
}

/* AP8 (Vergleichsmodus) -- Expertenfunktions-Badge + Zweispalten-Layout. */
.expert-tag {
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.68rem;
  min-height: auto;
  padding: 0.1rem 0.45rem;
  vertical-align: middle;
}

.comparison-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin: 1rem 0;
}

.comparison-column {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
}

.comparison-warning-banner {
  margin: 1rem 0;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-small);
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.85rem;
  font-weight: 600;
}

.comparison-overlay-chart {
  margin-top: 1rem;
}

.comparison-overlay-chart svg {
  width: 100%;
  height: auto;
}

.chart-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.chart-toolbar-group {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.chart-toolbar-group-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 750;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.chart-toolbar-sep {
  width: 1px;
  height: 1.6rem;
  background: var(--border);
}

/* Diagramm-Instanzliste (ersetzt das frueher feste Einzeldiagramm +
   das separate "Aktivitaets-Vergleich"-Feature). */
.chart-instance-list {
  display: grid;
  gap: 1rem;
}

.chart-instance-list-actions {
  display: flex;
  margin: 0.5rem 0 1.5rem;
}

/*
 * Datenpaket-Galerie: mehrere Datenpakete mit je eigenen Diagrammen
 * nebeneinander (Reihe, horizontal scrollbar -- gleiches Muster wie
 * .app-navigation) oder untereinander (Spalte) anzeigen.
 */
.data-package-gallery-add-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  margin: 0.6rem 0 1rem;
}

.data-package-gallery-add-row select {
  flex: 1 1 14rem;
}

.data-package-gallery {
  display: grid;
  gap: 1rem;
}

.data-package-gallery[data-layout="row"] {
  grid-auto-flow: column;
  grid-auto-columns: minmax(22rem, 1fr);
  overflow-x: auto;
  padding-bottom: 0.4rem;
}

.data-package-gallery[data-layout="column"] {
  grid-template-columns: 1fr;
}

.data-package-gallery-card {
  min-width: 0;
}

.data-package-gallery-summary summary {
  cursor: pointer;
  font-weight: 700;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.data-package-gallery-summary summary small {
  font-weight: 400;
  color: var(--text-muted);
}

[data-gallery-layout].active {
  background: var(--primary);
  color: #ffffff;
  border-color: var(--primary);
}

/* Tag-Auswahl: bereits verwendete Tags als Toggle-Chips + Freitext-
   Eingabe fuer neue, eigene Tags. */
.tag-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.tag-picker-add {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}

.tag-picker-add input {
  min-height: 2.2rem;
  padding: 0.3rem 0.6rem;
  border: 1px dashed var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.8rem;
  width: 9rem;
}

.tag-picker-add button {
  min-height: 2.2rem;
  min-width: 2.2rem;
  border: 1px dashed var(--border-strong);
  border-radius: 999px;
  background: var(--surface);
  color: var(--primary);
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}

.tag-picker-add button:hover {
  border-color: var(--primary);
  background: var(--primary-soft);
}

/* "Kontrollleiste"-Optik fuer die Filterleiste oben im Analyse-Tab --
   grenzt sie visuell von normalen Inhalts-Panels ab. */
.filter-panel-host {
  border-left: 3px solid var(--primary);
  background: var(--surface-muted);
}

/* Ergebnisse-auf-einen-Blick-Leiste (Analyse-Tab, immer sichtbar
   unabhaengig vom aktiven Sub-Tab). */
.results-glance-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.results-glance-strip .status-pill,
.results-glance-strip .tag {
  cursor: pointer;
  gap: 0.4rem;
  font-size: 0.8rem;
}

.chart-options-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1rem;
}

.chart-options-grid fieldset {
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  padding: 0.6rem 0.8rem;
  display: grid;
  gap: 0.3rem;
}

.chart-options-grid legend {
  padding: 0 0.3rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.chart-options-supergroup {
  display: grid;
  gap: 0.6rem;
}

/*
 * Kanal-basiertes Diagrammsystem: dynamische Kanal-Optionsliste (eine
 * Karte je App.ChannelRegistry.listChartable()-Eintrag) -- ersetzt die
 * frueheren festen "Serien"/"Kennzahlen"/"Marker"/"Kontext"-Fieldsets.
 */
.channel-options-section {
  margin-top: 1rem;
}

.channel-options-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.7rem;
  margin-top: 0.4rem;
}

.channel-option-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  padding: 0.6rem 0.8rem;
  display: grid;
  gap: 0.4rem;
  align-content: start;
}

.channel-option-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  font-weight: 700;
}

.channel-option-remove-btn {
  flex: 0 0 auto;
}

/*
 * Phase 4, Schritt 4.5 (2026-09-13): Beschriftung ueber dem
 * pro-Kanal-Diagrammtyp-Schalter -- gleiche Kleinschrift-Konvention wie
 * .chart-toolbar-group-label (dort fuer den instanzweiten Schalter),
 * mit etwas Abstand nach oben zur vorherigen Karten-Zeile.
 */
.channel-option-chart-type-label {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.72rem;
  font-weight: 750;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/*
 * Phase B, Punkt 4 (U3): reduzierte Karte fuer einen aktivierten Kanal
 * ohne Daten im aktuellen Zeitraum -- dezent abgeschwaecht statt
 * komplettem Verschwinden, damit der "Entfernen"-Knopf erreichbar
 * bleibt (siehe ui-charts.js).
 *
 * UI/UX-Audit (2026-09-08): urspruenglich per opacity:0.6 abgeschwaecht --
 * das dimmt zwangslaeufig auch den Text mit, kompensiert-Kontrast fiel
 * dadurch auf ~2,4:1 (hell)/~4,2:1 (dunkel), unter dem WCAG-AA-Minimum
 * 4,5:1. Jetzt wie .empty-state-card ueber Rahmen/Hintergrund
 * abgeschwaecht (gleiches, bereits etabliertes Muster), Text bleibt bei
 * voller Deckkraft -- .channel-option-nodata-note (--text-muted) haelt
 * dadurch wieder ihren eigenen, bereits ausreichenden Kontrast.
 */
.channel-option-card--nodata {
  border-style: dashed;
  border-color: var(--border-strong);
  background: var(--surface-muted);
}

.channel-option-nodata-note {
  margin: 0;
  font-size: 0.85em;
  color: var(--text-muted);
}

/*
 * "+/x"-Schema 2026-08-23: kompakte Zeile fuer noch nicht aktivierte
 * Kanaele -- Auswahl + Hinzufuegen-Knopf, analog zum bereits
 * bestehenden "+ Diagramm/Periode hinzufuegen"-Muster.
 */
.channel-option-add-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  grid-column: 1 / -1;
}

.channel-option-add-row select {
  flex: 1 1 12rem;
}

.channel-option-kpis {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.6rem;
}

.channel-sub-filter {
  font-size: 0.82rem;
  color: var(--text-muted);
}

.channel-sub-filter summary {
  cursor: pointer;
  font-weight: 700;
}

.channel-sub-filter select {
  margin-top: 0.4rem;
  width: 100%;
}

.channel-sub-filter-discrete,
.channel-sub-filter-medication {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.8rem;
  margin-top: 0.4rem;
}

.channel-sub-filter-medication select {
  width: auto;
}

.channel-sub-filter-medication input[type="number"] {
  width: 4.5rem;
}

.chart-options-supergroup + .chart-options-supergroup {
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

.analysis-subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1rem;
}

.analysis-subnav-btn {
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 700;
}

.analysis-subnav-btn:hover {
  color: var(--text);
}

.analysis-subnav-btn.active {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
}

/*
 * Phase 5, Schritt 5.5 (2026-09-13, Nutzerauftrag "eigener Vorschlag
 * fuer eine visuelle Gruppierung, keine Rueckfrage noetig"): optionale
 * Gruppen-Ueberschrift ueber den Layer-2-Tabs ("Analysewerkzeuge"),
 * generisch aus dem optionalen `group`-Feld je Subview gerendert
 * (siehe generateSubnavButtons(), ui-core.js). flex-basis:100% erzwingt
 * einen Zeilenumbruch im flex-wrap-Subnav, damit die Ueberschrift wie
 * eine eigene Zeile statt wie ein weiterer Tab wirkt.
 */
.analysis-subnav-group-label {
  flex-basis: 100%;
  margin: 0.3rem 0 -0.1rem;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

/*
 * UX/IA-Navigationsvereinheitlichung (2026-09-22, Nutzerauftrag "besser sortieren und gruppieren",
 * Cockpit-Kartenliste): rein visueller Abschnitts-Trenner zwischen Kartengruppen -- keine eigene
 * Ueberschriftenebene, keine Navigation dahinter (siehe Kommentar in index.html).
 */
.cockpit-section-heading {
  margin: 1.6rem 0 0.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--border);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

/* AP7b-2a: exklusiver "Als Hintergrund anzeigen"-Knopf, aktiver Zustand. */
.band-background-toggle-btn.active {
  border-color: var(--primary);
  background: var(--primary-soft);
  color: var(--primary);
}

@media (max-width: 760px) {
  .chart-container {
    min-height: 22rem;
  }

  .chart-svg {
    min-width: 38rem;
  }
}

/*
 * AP10 (Thread E): Arztbericht-Vorschau/Druck. Vorschau UND Druck sind
 * strukturell dieselbe DOM (siehe report-arztbericht.js) -- diese
 * Regeln sind das EINZIGE, was den Druck vom Bildschirm unterscheidet.
 */
#arztberichtPreviewModal {
  width: min(52rem, 92vw);
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 12px);
  background: var(--surface);
  color: var(--text);
}

#arztberichtPreviewModal::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

.arztbericht-modal-chrome {
  position: sticky;
  top: 0;
  display: flex;
  /* Umbrechen statt ueberlaufen (Android/Telefon: Titel + Optionen + 2 Knoepfe sind breiter als der Dialog;
     live gemessen 605px in 373px, die Knoepfe lagen ausserhalb des Bildschirms). */
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.arztbericht-modal-body {
  padding: 1rem 1.25rem 1.5rem;
  overflow-y: auto;
  max-height: calc(88vh - 3.5rem);
}

.arztbericht-report {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.arztbericht-section h1 {
  margin: 0 0 0.5rem;
}

.arztbericht-section h2 {
  margin: 0 0 0.5rem;
  font-size: 1.05rem;
}

.arztbericht-section h3 {
  margin: 0.5rem 0 0.25rem;
  font-size: 0.95rem;
}

.arztbericht-section dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.25rem 0.75rem;
  margin: 0;
}

.arztbericht-section dt {
  color: var(--text-muted);
}

.arztbericht-section dd {
  margin: 0;
}

.arztbericht-findings table {
  width: 100%;
  border-collapse: collapse;
}

.arztbericht-findings th,
.arztbericht-findings td {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.arztbericht-charts figure {
  margin: 0 0 1rem;
}

.arztbericht-charts figcaption {
  margin-top: 0.25rem;
  color: var(--text-muted);
  font-size: 0.85rem;
}

.arztbericht-disclaimer {
  font-style: italic;
  color: var(--text-muted);
}

.arztbericht-provenance {
  font-size: 0.8rem;
  color: var(--text-muted);
}

@media print {
  body.printing-arztbericht > *:not(#arztberichtPreviewModal) {
    display: none !important;
  }

  #arztberichtPreviewModal,
  #arztberichtPreviewModal * {
    visibility: visible;
  }

  #arztberichtPreviewModal {
    position: absolute;
    inset: 0;
    max-height: none;
    /* Seitenanfang statt vertikal zentriert (UA-dialog: height fit-content + margin auto), Abdunklung nicht mitdrucken
       (Android-Druckvorschau, live: grauer Kasten um den Bericht). */
    height: auto;
    margin: 0;
    overflow: visible;
    width: auto;
    border: none;
    box-shadow: none;
  }

  #arztberichtPreviewModal::backdrop {
    background: transparent;
  }

  #arztberichtPreviewModal .arztbericht-modal-chrome {
    display: none !important;
  }

  .arztbericht-modal-body {
    max-height: none;
    overflow: visible;
  }
}

/*
 * Analyse/Diagramm-UI-Umbau Phase 5, Schritt 5.7 (2026-09-13):
 * generische Abkuerzungs-Tooltip-/Glossar-Komponente (siehe
 * js/ui/ui-glossary.js). Nutzt ausschliesslich bereits bestehende
 * Farb-Tokens -- funktioniert dadurch automatisch in beiden Themes,
 * ohne eigene dark-mode-Regeln.
 */
.glossary-term {
  cursor: help;
  text-decoration: underline dotted var(--text-muted);
  text-underline-offset: 2px;
}

.glossary-term:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 2px;
}

.glossary-tooltip {
  position: absolute;
  z-index: 60;
  max-width: 240px;
  padding: 0.5rem 0.7rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-small);
  box-shadow: var(--shadow);
  font-size: 0.82rem;
  line-height: 1.35;
}

.glossary-tooltip strong {
  display: block;
  margin-bottom: 0.15rem;
}

.glossary-tooltip span {
  color: var(--text-muted);
}


/*
 * Konto-Identitaet/ZTE E2 (2026-09-17, docs/CONCEPT_ACCOUNT_IDENTITY_ZTE.md
 * 3.4/3.5): Kontoauswahl, Gastmodus-Banner, Uebernahme-Dialog.
 *
 * Stapelreihenfolge der blockierenden Overlays (alle .processing-overlay,
 * z-index 100, sonst gewinnt die DOM-Reihenfolge):
 *   Profil-Gate (100) < Anmelde-Dialog (105, wird auch AUS dem Onboarding
 *   heraus geoeffnet) < Uebernahme-Dialog (106) < Verarbeitungsanzeige (110).
 * Die Verarbeitungsanzeige ganz oben behebt zugleich UX-Befund H5
 * (Walkthrough 2026-09-17): "Backup wird geprueft ..." lag beim
 * Wiederherstellen im Onboarding UNTER dem Profil-Gate und blieb unsichtbar.
 */
#accountGateOverlay {
  z-index: 105;
}

#guestClaimOverlay {
  z-index: 106;
}

#processingOverlay {
  z-index: 110;
}

.account-picker-list,
.guest-claim-list {
  display: grid;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-picker-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  min-height: 3rem;
  padding: 0.55rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.account-picker-item:hover,
.account-picker-item:focus-visible {
  border-color: var(--primary);
}

.account-picker-item-text {
  display: grid;
  min-width: 0;
}

.account-picker-item-text strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-picker-item-text small {
  color: var(--text-muted);
}

.account-gate-selected {
  margin: 0;
}

.guest-mode-choice {
  display: grid;
  gap: 0.35rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}

.guest-mode-choice .hint {
  margin: 0;
}

.guest-claim-list .checkbox-label {
  min-height: 2.2rem;
}

.profile-guest-badge {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  background: var(--warning-soft);
  color: var(--warning);
  font-size: 0.72rem;
  font-weight: 600;
  vertical-align: middle;
}

/*
 * ZTE E2 (2026-09-17): Ansichten im Anmelde-Dialog mit eigenem Abstand --
 * .processing-dialog setzt gap nur fuer seine direkten Kinder, innerhalb
 * einer Ansicht klebten Liste und Knopf sonst aneinander. :not([hidden]),
 * damit display:grid das hidden-Attribut nicht aushebelt.
 */
.account-gate-view:not([hidden]) {
  display: grid;
  gap: 0.75rem;
  text-align: left;
}

.account-gate-view .form-actions {
  margin: 0;
}

/* UX-Befund M10 (2026-09-17): Aktionen im Hinweis "Import unterbrochen". */
.import-checkpoint-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

/*
 * UX-Buendel 2, M1 (2026-09-17): In-App-Entscheidungsdialog. Liegt ueber
 * Profil-Gate/Anmelde-Dialog/Uebernahme (100/105/106), unter der
 * Verarbeitungsanzeige (110) -- requestChoice() wird nie bei laufender
 * Verarbeitung geoeffnet (_restoreBackupFileUnsafe() blendet sie vorher aus).
 */
#choiceDialog {
  z-index: 108;
}

/*
 * ZTE E4 (2026-09-17): die Passwortabfrage fuer Backups kann aus der
 * Kontoauswahl (105) heraus kommen ("Konto aus Backup wiederherstellen").
 */
#backupPasswordPromptDialog {
  z-index: 108;
}

/*
 * ZTE E5b (2026-09-17): der Entsperr-Dialog liegt ueber den Gates -- ohne
 * Schluessel gibt es nichts zu bedienen (Invariante E5-I4).
 */
#dataUnlockOverlay {
  z-index: 109;
}

.choice-dialog {
  text-align: left;
  justify-items: stretch;
  max-width: 30rem;
}

.choice-dialog-details {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.25rem 0.75rem;
  margin: 0;
  font-size: 0.86rem;
}

.choice-dialog-details dt {
  color: var(--text-muted);
}

.choice-dialog-details dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.choice-dialog-actions {
  display: grid;
  gap: 0.6rem;
}

.choice-dialog-option {
  display: grid;
  gap: 0.2rem;
}

.choice-dialog-option .hint {
  margin: 0;
}

/*
 * Konto-Identitaet/ZTE E3 (2026-09-17): Nur-Lesen-Modus und Zugriffsverwaltung.
 * #accessManageOverlay (107) liegt unter #choiceDialog (108), weil Uebergabe/
 * Freigabe aus ihm heraus eine Rueckfrage oeffnen.
 */
#accessManageOverlay {
  z-index: 107;
}

.read-only-banner {
  color: var(--primary);
  font-weight: 600;
}

.read-only-banner[hidden] {
  display: none;
}

/* Schnellerfassung schreibt immer ins aktive Profil -- im Nur-Lesen-Modus ausblenden. */
body[data-access-role="read"] .quick-entry-fab {
  display: none;
}

.access-role-badge.access-role-write,
.access-role-badge.access-role-read {
  background: var(--primary-soft);
  color: var(--primary);
}

.access-manage-dialog {
  max-width: 34rem;
}

.access-manage-list,
.access-manage-log {
  display: grid;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.access-manage-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.access-manage-row select {
  width: auto;
  min-width: 10rem;
}

.access-manage-section {
  display: grid;
  gap: 0.4rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--border);
}

.access-manage-section[hidden] {
  display: none;
}

.access-manage-log li {
  font-size: 0.82rem;
  color: var(--text-muted);
}

/*
 * ZTE E3 (2026-09-17): Nur-Lesen sichtbar machen -- Eingabefelder und
 * Dateiauswahl in den schreibenden Bereichen wirken sonst voll bedienbar.
 * Bedienkomfort; die Durchsetzung liegt in App.AccessService.
 */
body[data-access-role="read"] :is([data-view-panel="gesundheit"], [data-view-panel="import"], #activeProfilePanel) :is(input, select, textarea, label.file-button) {
  pointer-events: none;
  opacity: 0.55;
}

/*
 * Medikamentenmodul v2 (2026-09-20): Einstellungsdialog je Plan, Druckplan
 * (gleiche Dialog-/Druck-Mechanik wie die Arztbericht-Vorschau, eigener
 * body-Klassenname "printing-medplan"), kleine Formularhelfer.
 */
#medicationPlanSettingsDialog {
  width: min(40rem, 94vw);
  max-height: 90vh;
  overflow-y: auto;
}

#medicationPlanSettingsDialog fieldset {
  display: grid;
  gap: 0.6rem;
  margin: 0;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
}

#medicationPlanSettingsDialog label {
  display: grid;
  gap: 0.25rem;
}

.checkbox-row {
  display: flex !important;
  align-items: center;
  gap: 0.5rem;
}

.checkbox-row input[type="checkbox"],
.checkbox-row input[type="radio"] {
  width: auto;
  flex: none;
}

.medication-recipient-edit-list {
  margin: 0;
  padding-left: 1.1rem;
  display: grid;
  gap: 0.4rem;
}

.baseline-transparency {
  margin: 0.35rem 0;
  font-size: 0.9rem;
}

.baseline-transparency summary {
  cursor: pointer;
  color: var(--text-muted);
}

.baseline-transparency ul {
  margin: 0.25rem 0 0.25rem 1.1rem;
  padding: 0;
}

/*
 * v1.23 Teil-E-Galerie (Nutzerfreigabe 2026-09-22): "Details & Belege"-Sektion je Auffaelligkeits-
 * Karte -- gleiche Optik wie .baseline-transparency direkt darueber, eigene Klasse, weil inhaltlich
 * ein anderer Zweck (technische Herkunft/Kalibrierung statt Baseline-Vergleich).
 */
.finding-details-section {
  margin: 0.35rem 0;
  font-size: 0.9rem;
}

.finding-details-section summary {
  cursor: pointer;
  color: var(--text-muted);
}

.finding-details-section ul {
  margin: 0.25rem 0 0.25rem 1.1rem;
  padding: 0;
}

/*
 * v1.23 Teil-E-Galerie (Nutzerfreigabe 2026-09-22): Sortier-Umschalter Zeitlich/Nach Schweregrad +
 * Seiten-Navigation, gemeinsam fuer "weitere Auffaelligkeiten" und Trendhinweise.
 *
 * UX/IA-Navigationsvereinheitlichung (2026-09-22, Nutzerauftrag "Tabs konsequent oben, Navigation
 * nicht fragmentiert wirken lassen"): war bisher optisch fast identisch mit den echten Bereichs-Tabs
 * (.analysis-subnav-btn) -- einzelne eckige Kaestchen in einer Reihe -- obwohl semantisch etwas
 * anderes (role="group"/aria-pressed = Sortierung, keine Seiten-Navigation). Jetzt als geschlossene
 * Pillen-Umschaltgruppe (ein Rahmen, gefuellter aktiver Abschnitt) -- auf den ersten Blick klar von den
 * echten Tabs unterscheidbar, gleiches Muster wie ein Segmented Control.
 */
.finding-gallery-tabs {
  display: inline-flex;
  gap: 0.15rem;
  margin: 0.4rem 0;
  padding: 0.2rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
}

.finding-gallery-tab {
  padding: 0.3rem 0.75rem;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}

.finding-gallery-tab[aria-pressed="true"] {
  background: var(--primary);
  color: var(--surface);
}

.finding-gallery-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 0.5rem;
}

/*
 * v1.23 Zeitstrahl-Diagramm: SVG-Zellgitter analog der bestehenden Wochen-Heatmap
 * (.overview-week-heatmap-svg), horizontal scrollbar bei vielen Zeit-Abschnitten (Wide-Content-Regel).
 */
.findings-timeline-host {
  overflow-x: auto;
}

.findings-timeline-svg {
  display: block;
  height: 44px;
  min-width: 100%;
}

.findings-timeline-row-label {
  /* UX_AUDIT.md Gruppe 4 (2026-10-01): px -> rem, skaliert jetzt mit OS-Textgroesse/A11y-Theme. */
  font-size: 0.375rem;
  fill: var(--text-muted);
}

.findings-timeline-cell {
  cursor: default;
}

.findings-timeline-cell[role="button"] {
  cursor: pointer;
}

.findings-timeline-cell-empty {
  fill: var(--surface-muted);
}

.medication-plan-extras {
  display: block;
  color: var(--text-muted);
}

#medicationPlanPrintModal {
  width: min(52rem, 92vw);
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg, 12px);
  background: var(--surface);
  color: var(--text);
}

#medicationPlanPrintModal::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

@media print {
  body.printing-medplan > *:not(#medicationPlanPrintModal) {
    display: none !important;
  }

  #medicationPlanPrintModal,
  #medicationPlanPrintModal * {
    visibility: visible;
  }

  #medicationPlanPrintModal {
    position: absolute;
    inset: 0;
    max-height: none;
    height: auto;
    margin: 0;
    overflow: visible;
    width: auto;
    border: none;
    box-shadow: none;
  }

  #medicationPlanPrintModal::backdrop {
    background: transparent;
  }

  #medicationPlanPrintModal .arztbericht-modal-chrome {
    display: none !important;
  }

  #medicationPlanPrintModal .arztbericht-modal-body {
    max-height: none;
    overflow: visible;
  }
}

/*
 * AP57 (2026-09-20): Rueckmeldungs-Dialog -- lange unteilbare Zeichenfolgen (SHA-256, Pfade in Fundstellen) duerfen die einspaltige
 * Formularspalte auf schmalen Bildschirmen nicht aufweiten (live gemessen: Spalte 514 px in 343 px Dialog).
 */
#feedbackDialog form > * {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Analyse & Berichte (Block 5, 2026-09-22): Zweck-Satz je Reiter und kompakte Zusammenfassung. */
.analysis-purpose {
  margin: 0 0 12px;
  color: var(--text-muted);
  max-width: 70ch;
}

.analysis-summary-points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.analysis-summary-point {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.analysis-summary-point.tone-warning {
  border-color: var(--warning);
}

.analysis-summary-point.tone-error {
  border-color: var(--danger);
}

.analysis-summary-point.tone-success {
  border-color: var(--success);
}

/* Versorgung (2026-09-22): Aufgaben-Zeilen. Ueberfaellig faellt auf, Erledigtes tritt zurueck. */
.care-task.care-task-overdue {
  border-color: var(--danger);
}

.care-task.care-task-due {
  border-color: var(--warning);
}

.care-task.care-task-done,
.care-task.care-task-skipped {
  opacity: 0.8;
}

.care-section h4 {
  margin: 0 0 8px;
}

/* Schnellerfassung (2026-09-22): Kategorie-Chips, gewaehlte Kategorie hervorgehoben. */
.quick-capture-chip {
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
}

.quick-capture-chip.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

/* Freigabe-Paket (2026-09-22): Fingerabdruecke in Vierergruppen gut lesbar/vorlesbar. */
.share-fingerprint {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 0.04em;
  word-break: break-word;
}

/*
 * Quick Actions Contract Schritt 6 (2026-10-02, "QR-Code-Connect"): QR-Anzeige (lean-qr
 * zeichnet per toCanvas() in echten Pixeln -- image-rendering:pixelated haelt die Module
 * scharf statt verschmiert) und Kamera-Vorschau beim Scannen (js/ui/ui-qr-connect.js).
 */
.qr-connect-canvas {
  display: block;
  width: 220px;
  height: 220px;
  margin: 0.5rem 0;
  image-rendering: pixelated;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.qr-connect-video {
  display: block;
  width: 100%;
  max-width: 22rem;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  background: #000;
}

/* Zentrale Zeit-Eingabe (2026-09-22): Schnellauswahl, Freitext, Vorschau-Chip; das native Feld erscheint erst nach Tipp auf den Vorschau-Chip. */
.time-input {
  display: grid;
  gap: 8px;
}

.time-input-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.time-chip {
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  border-radius: 999px;
  padding: 4px 12px;
  font: inherit;
  font-size: 0.9rem;
  line-height: 1.4;
}

.time-chip:hover {
  border-color: var(--border-strong);
}

.time-chip.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.time-chip:focus-visible,
.time-input-preview:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.time-input-preview {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  justify-self: start;
  max-width: 100%;
  cursor: pointer;
  border: 1px solid var(--primary);
  background: var(--primary-soft);
  color: var(--text);
  border-radius: 999px;
  padding: 4px 12px;
  font: inherit;
  font-weight: 600;
  text-align: left;
}

.time-input-preview.is-empty {
  border-color: var(--border-strong);
  background: var(--surface-muted);
  color: var(--text-muted);
  font-weight: 400;
}

.time-input-preview-action {
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--primary);
  text-decoration: underline;
}

.time-input-message {
  margin: 0;
  font-size: 0.85rem;
  color: var(--warning);
}

.time-input-detail:not(.is-open) {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  border: 0;
  white-space: nowrap;
}

/* Sicherheits-Auftrag 2026-09-22: Staerkeanzeige fuer neue Passwoerter, Erklaerung/Druckblatt des Wiederherstellungsschluessels, Sicherheitshinweise. */
.password-meter {
  display: grid;
  gap: 4px;
}

.password-meter[hidden] {
  display: none;
}

.password-meter-bar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 4px;
}

.password-meter-bar span {
  height: 6px;
  border-radius: 3px;
  background: var(--border);
}

.password-meter[data-level="weak"] .password-meter-bar span:nth-child(-n + 1) {
  background: var(--danger);
}

.password-meter[data-level="fair"] .password-meter-bar span:nth-child(-n + 2) {
  background: var(--warning);
}

.password-meter[data-level="good"] .password-meter-bar span:nth-child(-n + 3) {
  background: var(--primary);
}

.password-meter[data-level="strong"] .password-meter-bar span:nth-child(-n + 4) {
  background: var(--success);
}

.password-meter-text {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.password-meter-label {
  font-weight: 600;
  color: var(--text);
}

.recovery-key-explainer {
  font-size: 0.9rem;
}

.recovery-key-explainer p,
.recovery-key-explainer ul {
  margin: 0 0 6px;
}

.recovery-key-explainer ul,
.security-notes-list {
  padding-left: 1.2em;
}

.security-notes-list li {
  margin-bottom: 6px;
}

.recovery-key-print-sheet {
  display: none;
}

@media print {
  body.printing-recovery-key > *:not(#recoveryKeyPrintSheet) {
    display: none !important;
  }

  /* Emulator-Vorabpruefung v1.19.0: sonst druckt der Farbverlauf des Seitenhintergrunds als hellblauer Bogen. */
  html:has(body.printing-recovery-key),
  body.printing-recovery-key {
    background: #fff !important;
  }

  body.printing-recovery-key #recoveryKeyPrintSheet {
    display: block !important;
    padding: 24px;
  }

  #recoveryKeyPrintSheet pre {
    margin: 0;
    white-space: pre-wrap;
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: 12pt;
    color: #000;
    background: #fff;
  }
}

.security-notes-list .hint-warning {
  color: var(--warning);
}

/*
 * Sicherheits-Selbstreview-Fund (2026-09-23): Zeichenzaehler #kiQuestionLengthHint
 * (js/ui/ui-ai-panel.js updateKiQuestionLengthHint()) faerbt sich ein, sobald das Limit
 * (App.PiiFilter.MAX_NOTE_LENGTH) erreicht ist -- gleiche Warnfarbe wie .security-notes-list oben.
 */
#kiQuestionLengthHint.hint-warning {
  color: var(--warning);
}

/* Untersuchung e (2026-09-22): aufklappbare Erklaerung der Verdachtsfaelle-Regeln (Layer 2). */
.overview-suspicion-explanation {
  margin-top: 0.75rem;
  text-align: left;
  font-size: 0.85rem;
}

.overview-suspicion-explanation ul {
  margin: 0.5rem 0 0;
  padding-left: 1.1rem;
}

/* Wochenverlauf (v1.20): kleine Linie je Kanal. */
.weekly-trend-card {
  display: grid;
  gap: 0.25rem;
}

.weekly-trend-sparkline {
  justify-self: start;
  width: 100%;
  max-width: 240px;
  height: 40px;
}

/* Rhythmus-Heatmap: Tageszeit-Abschnitte (Nachts/Morgens/Mittags/Abends) als Hintergrundbaender mit Beschriftung. */
.overview-week-heatmap-band {
  fill: currentColor;
}

.overview-week-heatmap-band-even {
  opacity: 0.07;
}

.overview-week-heatmap-band-odd {
  opacity: 0.02;
}

.overview-week-heatmap-section-label {
  /* UX_AUDIT.md Gruppe 4 (2026-10-01): px -> rem, skaliert jetzt mit OS-Textgroesse/A11y-Theme. */
  font-size: 0.5rem;
  fill: currentColor;
  opacity: 0.75;
}

/* Patientenuebersicht (Rolle Mediziner): dichte Tabelle, Zeilen als Drilldown. */
.clinician-overview {
  display: grid;
  gap: 0.75rem;
  text-align: left;
}

.clinician-head {
  font-weight: 600;
  margin: 0;
}

.clinician-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}

.clinician-table th,
.clinician-table td {
  padding: 0.3rem 0.5rem;
  text-align: left;
  border-bottom: 1px solid var(--border, #cbd5e1);
}

.clinician-row {
  cursor: pointer;
}

.clinician-row:hover,
.clinician-row:focus-visible {
  background: rgba(37, 99, 235, 0.08);
}

.clinician-quality ul {
  margin: 0.25rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.85rem;
}

.clinician-findings,
.clinician-lenses {
  margin: 0;
  font-size: 0.9rem;
}

/* Karte "Aktuell auffaellig": Status-Kennzeichnung und Legende. */
.overview-status-chip {
  justify-self: start;
  font-weight: 600;
}

.overview-status-legend {
  margin-top: 0.75rem;
  text-align: left;
  font-size: 0.85rem;
}

.overview-status-legend ul {
  margin: 0.4rem 0;
  padding-left: 1.1rem;
}

/* Workflow-Karte: Aktionen nach Anlass. */
.workflow-groups {
  display: grid;
  gap: 0.9rem;
}

.workflow-group h4 {
  margin: 0 0 0.35rem;
  font-size: 0.95rem;
}

/*
 * Generisches Layer-1/Layer-2-Statusmuster (js/ui/status-pill.js): Pille = Kurzansicht, .status-pill-detail = Detailfeld nach Klick.
 */
.topbar-status-row {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.4rem 0.6rem;
}

.topbar-status-row:empty {
  display: none;
}

.status-pill-host {
  position: relative;
  display: inline-block;
  min-width: 0;
}

.status-pill-host[hidden],
.status-pill-detail[hidden] {
  display: none;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  max-width: 100%;
  padding: 0.25rem 0.65rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-muted);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}

.status-pill:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.status-pill--warning {
  background: var(--warning-soft);
  color: var(--warning);
  border-color: var(--warning);
}

.status-pill--danger {
  background: var(--danger-soft, var(--warning-soft));
  color: var(--danger, var(--warning));
  border-color: var(--danger, var(--warning));
}

.status-pill--success {
  color: var(--success);
  border-color: var(--success);
}

.status-pill--info {
  color: var(--primary);
}

.status-pill-extra {
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}

.status-pill-detail {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  z-index: 60;
  width: min(26rem, 88vw);
  margin: 0;
  padding: 0.6rem 0.8rem;
  display: grid;
  gap: 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  font-size: 0.85rem;
  font-weight: 400;
  text-align: left;
}

.status-pill-detail p {
  margin: 0;
}

/*
 * P3 Punkt 7 (Nutzerauftrag 2026-09-22): Gastkonto-Hinweis als Warnzeichen-Overlay direkt auf dem Profilbild statt einer
 * eigenen Pille -- .profile-picture-slot positioniert Profilbild-Knopf und Warn-Badge relativ zueinander, das Detailfeld
 * (Layer 2, .status-pill-detail) bleibt unveraendert, nur rechtsbuendig (.status-pill-detail-end), da die Ecke oben rechts
 * sonst ueber den Fensterrand hinausragen wuerde.
 */
.profile-picture-slot {
  position: relative;
  display: inline-flex;
}

/*
 * App-Shell Auftrag 2026-10-01, Schritt 2 ("EIN Avatar-Popover"): rein visuelle Ecken-Badges,
 * kein eigener Klick mehr (vorher je eine eigene App.UI.StatusPill mit cursor:pointer) -- die
 * Bedienung laeuft jetzt ausschliesslich ueber den Avatar-Knopf selbst.
 */
.status-pill-badge {
  position: absolute;
  bottom: -0.15rem;
  right: -0.15rem;
  width: 1.1rem;
  height: 1.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 2px solid var(--surface);
  border-radius: 50%;
  pointer-events: none;
  font-size: 0.7rem;
  line-height: 1;
}

.status-pill-badge--warning {
  background: var(--warning);
  color: #ffffff;
}

/*
 * Status-Center-Avatar-Badge (Nutzerauftrag 2026-10-01): die beiden
 * weiteren Prioritaetsstufen neben --warning -- rot fuer die hoechste
 * Prioritaet (severity 0, "Alert"), gelb fuer die niedrigste (severity 2,
 * "Info"). Welche Klasse greift, entscheidet renderStatusCenterBanner()
 * (js/ui/status-center-ui.js) anhand der hoechsten severity im Ticker.
 */
.status-pill-badge--danger {
  background: var(--danger);
  color: #ffffff;
}

.status-pill-badge--info {
  background: var(--info);
  color: #ffffff;
}

/*
 * Status-Center-Avatar-Badge zeigt jetzt eine ZAHL statt eines Icons
 * (Nutzerauftrag 2026-10-01) -- eigene Schriftgroesse/-gewicht statt des
 * Icon-font-size von .status-pill-badge, zweistellige Zahlen (ab 10
 * Hinweisen unwahrscheinlich, aber moeglich) duerfen die Kreisform leicht
 * ueberschreiten (overflow: visible auf dem Text selbst durch kleineren
 * Font-Faktor statt eines zweiten Kreis-Umbaus).
 */
.status-pill-badge-count {
  font-size: 0.62rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

/*
 * Konto-Mini-Bild unten rechts (Nutzerauftrag 2026-10-01): wenn ein
 * echtes Konto angemeldet ist (kein Gastmodus), zeigt dieselbe Ecke
 * statt des Gastmodus-Warnzeichens ein kleines Abbild des aktiven
 * Profilbilds -- gleiche Position/Groesse wie .status-pill-badge, aber
 * ohne Kreis-Rahmenfarbe (das Bild selbst liefert die Flaeche).
 */
.status-pill-badge--account-picture {
  background: var(--surface-strong);
  background-size: cover;
  background-position: center;
  padding: 0;
}

/*
 * Status-Center (2026-10-01): eigene Ecke, damit sich der Hinweis-Punkt nicht mit
 * #guestModeBanner (unten rechts) ueberlappt, wenn beide gleichzeitig aktiv sind (z.B. ein
 * Gastkonto MIT offenen Hinweisen). Vorgriff auf die im App-Shell-Auftrag vorgesehene Konvention
 * "Konto-Badge unten rechts, Warn-Badge unten links".
 */
.status-pill-badge--corner-start {
  right: auto;
  left: -0.15rem;
}

.status-pill-detail-end {
  left: auto;
  right: 0;
}

/*
 * v1.23 Kopfzeile Account/Profil-Popover (Nutzerfreigabe 2026-09-22): Quick-Switch-Liste im
 * #topbarProfilePopover -- wiederverwendet .status-pill-detail/-end fuer den Popover-Rahmen selbst
 * (siehe oben), nur die Listenzeilen sind neu.
 */
/*
 * Badge-Overlay-Auftrag (2026-10-03): eigenes Scrollen statt den ganzen Popover (und damit die
 * Aktionsreihe "+ Neues Profil"/"Profil importieren"/"Alle Profile verwalten" darunter) beliebig
 * weit nach unten zu schieben -- live als Problem bemerkt bei vielen Profilen (Lasttest-Altlasten
 * eines Test-Tabs, 30+ Profile), aber ein vorbestehender Mangel (#topbarProfilePopover selbst hat
 * kein max-height/overflow-y), der bei genug Profilen JEDEN Nutzer treffen wuerde -- kein neuer
 * Fund dieser Aenderung, nur hier mit behoben, weil direkt betroffen.
 */
.topbar-profile-switch-list {
  display: grid;
  gap: 0.2rem;
  max-height: 40vh;
  overflow-y: auto;
}

/*
 * Badge-Overlay-Auftrag (2026-10-03): war bis dahin selbst ein <button> -- jetzt ein <div> mit
 * ZWEI GESCHWISTER-<button>s (Umschalten + optionales Bearbeiten), siehe
 * App.UI.buildTopbarProfileSwitchItem() (ui-core.js) fuer die Begruendung (keine verschachtelten
 * Buttons). Die eigentliche Knopf-Optik/-Interaktion sitzt jetzt in
 * .topbar-profile-switch-item-main.
 */
.topbar-profile-switch-item {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  width: 100%;
}

.topbar-profile-switch-item-main {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1;
  min-width: 0;
  padding: 0.35rem 0.4rem;
  border: none;
  border-radius: var(--radius-small);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.topbar-profile-switch-item-main:hover,
.topbar-profile-switch-item-main:focus-visible {
  background: var(--surface-strong);
}

.topbar-profile-switch-item-edit {
  flex-shrink: 0;
}

.topbar-profile-switch-item-label {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.topbar-profile-switch-item-label small {
  color: var(--text-muted);
}

/*
 * Badge-Overlay-Auftrag (2026-10-03): Kopfzeile des Popovers (aktuelles Profil + "Bearbeiten"
 * daneben, nur bei role:"owner" sichtbar) sowie die Aktionsreihe darunter ("+ Neues Profil",
 * "Profil importieren", "Alle Profile verwalten").
 */
.topbar-profile-popover-active-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.topbar-profile-popover-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.4rem;
}

/*
 * v1.23 Onboarding-Sprachumschaltung (Nutzerentscheidung 2026-09-22): ganz oben auf der ersten
 * Onboarding-Seite (#profileGateWelcomeStep), NICHT in der Kopfzeile -- siehe
 * docs/concepts/kopfzeile-account-sprache-konzept-2026-09-22.md Abschnitt 3.2.
 */
.profile-gate-language-toggle {
  display: flex;
  justify-content: flex-end;
  gap: 0.4rem;
  margin-bottom: 0.6rem;
}

.profile-gate-language-btn {
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}

.profile-gate-language-btn[aria-pressed="true"] {
  border-color: var(--primary);
  color: var(--primary);
  background: var(--surface-strong);
}

/*
 * P3 Punkt 6 (Cockpit-Umbau, Nutzerauftrag 2026-09-22): Vitalwerte-Karte -- Ring/Balken je Kanal, Tagesablauf-Donut,
 * Mediziner-Tabelle. Alle Farben ueber CSS-Variablen (Dark-Mode-faehig), Ampel-Stufen nutzen dieselben --success/
 * --warning/--danger-Tokens wie der Rest des Projekts (kein neues Farbsystem).
 */
.overview-vitals-list {
  display: block;
}

.vitals-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.vitals-widget {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 12rem;
  flex: 1 1 12rem;
}

.vitals-widget-donut {
  flex-direction: row;
}

/* Balken-Widget ist eine eigene Spalte (Ueberschrift oben, Balken darunter), keine Ring-Reihe -- siehe _buildVitalBarWidget(). */
.vitals-widget-bar {
  flex-direction: column;
  align-items: stretch;
  gap: 0.4rem;
  min-width: 14rem;
  flex-basis: 14rem;
}

.vitals-widget-info {
  display: grid;
  gap: 0.15rem;
  min-width: 0;
}

.vitals-widget-label {
  margin: 0;
  font-weight: 600;
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

.vitals-widget-status {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
}

/*
 * UX-Nachschaerfung "Vitalwerte informativer" (Nutzerauftrag 2026-09-22): IMMER sichtbare Kurzangabe
 * (Berechnungsart + Zeitraum), keine Extra-Interaktion noetig, um zu wissen "was ist das fuer ein Wert"
 * -- die volle Erklaerung (Referenzbereich-Herkunft, Einordnungsgrenzen, Abweichungs-Hinweis) steht im
 * "(?)"-Popover (.context-help-*, siehe unten).
 */
.vitals-widget-meta {
  margin: 0;
  font-size: 0.72rem;
  color: var(--text-muted);
}

.vitals-status-success { color: var(--success); }
.vitals-status-warning { color: var(--warning); }
.vitals-status-danger { color: var(--danger); }

.vitals-ring-track {
  fill: none;
  stroke: var(--border);
  stroke-width: 10;
}

.vitals-ring-fill {
  fill: none;
  stroke-width: 10;
  stroke-linecap: round;
  transition: stroke-dashoffset 300ms ease;
}

.vitals-ring-fill.vitals-status-success { stroke: var(--success); }
.vitals-ring-fill.vitals-status-warning { stroke: var(--warning); }
.vitals-ring-fill.vitals-status-danger { stroke: var(--danger); }

.vitals-ring-value {
  text-anchor: middle;
  /* UX_AUDIT.md Gruppe 4 (2026-10-01): px -> rem, skaliert jetzt mit OS-Textgroesse/A11y-Theme. */
  font-size: 1.25rem;
  font-weight: 700;
  fill: var(--text);
}

.vitals-ring-unit {
  text-anchor: middle;
  font-size: 0.625rem;
  fill: var(--text-muted);
}

.vitals-bar-chart {
  display: grid;
  gap: 0.3rem;
  min-width: 10rem;
}

.vitals-bar-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.vitals-bar-track {
  position: relative;
  flex: 1 1 auto;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--surface-muted);
  overflow: hidden;
}

.vitals-bar-fill {
  display: block;
  height: 100%;
  background: var(--primary);
  border-radius: 999px;
}

.vitals-bar-text {
  flex: 0 0 auto;
  font-size: 0.78rem;
  color: var(--text-muted);
  white-space: nowrap;
}

.vitals-activity-resting { fill: var(--primary); }
.vitals-activity-active { fill: var(--success); }
.vitals-activity-unknown { fill: var(--border); }

.vitals-donut-hole {
  fill: var(--surface);
}

.vitals-donut-legend {
  border-collapse: collapse;
  font-size: 0.8rem;
}

.vitals-donut-legend td {
  padding: 0.1rem 0.3rem 0.1rem 0;
  color: var(--text-muted);
}

.vitals-legend-swatch {
  display: inline-block;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 2px;
}

.vitals-legend-value {
  text-align: right;
  color: var(--text) !important;
  font-weight: 600;
}

/*
 * Generischer "(?)"-Baustein (js/ui/context-help-affordance.js, Nutzerauftrag 2026-09-22): NICHT
 * vitals-spezifisch, obwohl der erste Verwendungsort die Vitalwerte-Karte ist -- bewusst hier bei den
 * anderen kleinen, wiederverwendbaren UI-Bausteinen dieser Datei belassen (analog .analysis-subnav-*
 * und .finding-gallery-tab weiter unten). Dezent (kleiner, runder Kreis statt eines auffaelligen Buttons),
 * damit "unaufdringlich" (Nutzervorgabe) bleibt.
 */
.context-help {
  position: relative;
  display: inline-flex;
}

/*
 * UX-Akzeptanztest Test A (2026-09-23): "'(...)'-Kontextmenue an Karten schwer auffindbar -- im Test
 * selbst mit gezielten Versuchen kaum lokalisierbar." Live gemessen (echtes Desktop-Fenster, nicht die
 * kleine Test-Vorschau, wie in OPEN_ITEMS.md gefordert): der "..."-Text selbst hat sehr guten Kontrast
 * (~8,7:1 gegen die Kartenflaeche), aber die Umrandung -- das einzige, was den Knopf ueberhaupt als
 * eigenes, klickbares Element vom Hintergrund abhebt -- lag bei ~1,4:1 (var(--border) gegen
 * var(--surface), beide fast identisch dunkel), weit unter dem WCAG-2.1-Mindestwert 3:1 fuer
 * UI-Komponenten-Umrisse (SC 1.4.11). Das erklaert exakt den Testbefund: "kann ihn lesen, sobald ich
 * ihn gefunden habe, finde ihn aber nicht". Fix: var(--border-strong) statt var(--border) (~2,2:1 im
 * Dunkelmodus -- naeher am Zielwert, ohne den Knopf optisch zu ueberladen); Text/Icon selbst
 * unveraendert (war bereits gut lesbar).
 */
.context-help-btn {
  width: 1.1rem;
  height: 1.1rem;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}

.context-help-btn:hover,
.context-help-btn[aria-expanded="true"] {
  border-color: var(--primary);
  color: var(--primary);
}

.context-help-popover {
  position: absolute;
  z-index: 20;
  top: 1.4rem;
  left: 0;
  width: 17rem;
  max-width: 80vw;
  padding: 0.7rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.context-help-title {
  display: block;
  margin-bottom: 0.4rem;
  font-size: 0.85rem;
}

.context-help-details {
  margin: 0 0 0.6rem;
  display: grid;
  gap: 0.3rem;
}

.context-help-details dt {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-muted);
}

.context-help-details dd {
  margin: 0;
  font-size: 0.78rem;
}

.context-help-actions {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

/* Nutzerauftrag 2026-09-23: Direktantwort-Container am "(?)" -- gleiche Bausteine wie .integrity-message, dauerhaft (kein Popover, ueberlebt einen Klick daneben). */
.context-help-inline-answer {
  margin-top: 0.75rem;
  padding: 0.9rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-small);
  background: var(--surface-muted);
}

.context-help-inline-answer-heading {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0;
}

.vitals-mediziner-wrapper {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.vitals-mediziner-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.vitals-mediziner-table th {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-weight: 600;
}

.vitals-mediziner-table td {
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border);
}

.global-task-actions {
  display: inline-flex;
  gap: 0.4rem;
  margin-left: 0.5rem;
}

/*
 * Medikamentenplan-Stufen-Zeitleiste (2026-10-06, Punkt 5) -- nur fuer mehrstufige Ketten
 * (ui-medication.js renderMedicationPlanTimelines()). Desktop: horizontale Balkenreihe.
 * Mobil (<=760px, gleicher Breakpoint wie der Rest der App): vertikal gestapelt.
 */
.medication-chain-timeline {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.85rem 1rem;
  margin-bottom: 0.85rem;
  background: var(--surface-muted);
}

.medication-chain-timeline__header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}

.medication-chain-timeline__title {
  font-weight: 600;
}

.medication-chain-timeline__meta {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.medication-chain-timeline__track {
  display: flex;
  gap: 0.4rem;
}

.medication-chain-timeline__stage {
  position: relative;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  padding: 0.5rem 0.6rem;
  min-width: 0;
  flex-shrink: 0;
  flex-grow: 1;
}

/*
 * Proportionale Balkenbreite ueber feste Klassen statt element.style.flexGrow -- sauberer als
 * JS-Inline-Styles (ein urspruenglich vermuteter CSP-Zwang dafuer liess sich NICHT bestaetigen,
 * siehe OPEN_ITEMS.md "CSP-Konsolenfehler style-src"). 12 Stufen genuegen fuer realistische
 * Behandlungsdauern (ui-medication.js rechnet Tage in diese Stufen um, gedeckelt auf 1..12).
 */
.medication-chain-timeline__stage--grow-1 { flex-grow: 1; }
.medication-chain-timeline__stage--grow-2 { flex-grow: 2; }
.medication-chain-timeline__stage--grow-3 { flex-grow: 3; }
.medication-chain-timeline__stage--grow-4 { flex-grow: 4; }
.medication-chain-timeline__stage--grow-5 { flex-grow: 5; }
.medication-chain-timeline__stage--grow-6 { flex-grow: 6; }
.medication-chain-timeline__stage--grow-7 { flex-grow: 7; }
.medication-chain-timeline__stage--grow-8 { flex-grow: 8; }
.medication-chain-timeline__stage--grow-9 { flex-grow: 9; }
.medication-chain-timeline__stage--grow-10 { flex-grow: 10; }
.medication-chain-timeline__stage--grow-11 { flex-grow: 11; }
.medication-chain-timeline__stage--grow-12 { flex-grow: 12; }

.medication-chain-timeline__stage--current {
  border-color: var(--primary);
  background: var(--primary-soft);
}

.medication-chain-timeline__today-badge {
  position: absolute;
  top: -0.6rem;
  right: 0.4rem;
  background: var(--primary);
  color: var(--surface);
  font-size: 0.68rem;
  font-weight: 600;
  padding: 0.05rem 0.4rem;
  border-radius: 6px;
}

.medication-chain-timeline__stage--past {
  opacity: 0.7;
}

.medication-chain-timeline__stage--future {
  border-style: dashed;
}

.medication-chain-timeline__stage-dose {
  font-weight: 600;
  font-size: 0.9rem;
}

.medication-chain-timeline__stage-dates {
  color: var(--text-muted);
  font-size: 0.78rem;
}

.medication-chain-timeline__adherence {
  display: flex;
  gap: 0.2rem;
  margin-top: 0.35rem;
  flex-wrap: wrap;
}

.medication-chain-timeline__dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  display: inline-block;
}

.medication-chain-timeline__dot--given { background: var(--success); }
.medication-chain-timeline__dot--skipped { background: var(--border-strong); }
.medication-chain-timeline__dot--double { background: var(--warning); }

.medication-chain-timeline__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
  margin-top: 0.6rem;
}

.medication-chain-timeline__table th {
  text-align: left;
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-weight: 600;
}

.medication-chain-timeline__table td {
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--border);
}

@media (max-width: 760px) {
  .medication-chain-timeline__track {
    flex-direction: column;
  }

  .medication-chain-timeline__stage {
    flex-shrink: 1;
  }
}
