/* ============================================================================
   Zählwerk — das Stylesheet der Anwendung
   Die einzige Stilschicht seit Bootstrap-Stufe 3d: css/bootstrap.min.css gibt
   es nicht mehr (docs/bootstrap-stufe3-plan.md). Geladen von main.php und
   index.php.

   Design-Sprache (Dieter Rams / Braun): Die Akzentfarbe ist ein Funktionssignal,
   keine Dekoration. Siehe docs/design-refresh-plan.md.

   DAS ATTRIBUT data-bs-theme BLEIBT, obwohl Bootstrap weg ist. Es ist der
   Dunkelmodus-Schalter des ganzen Projekts: rund 20 Regeln in dieser Datei
   haengen daran, dazu die beiden FOUC-Vermeidungsskripte in index.php und
   main.php, die es setzen, BEVOR das CSS laedt. Umbenennen waere reiner
   Kosmetikgewinn gegen ein Risiko, das genau einmal auffaellt — beim weissen
   Blitz auf dem Telefon morgens um sechs.
   ============================================================================ */

/* ===========================================================================
   Reboot — das Minimum aus Bootstrap, das bleiben musste (Stufe 3d)
   Was hier steht, stand vorher in bootstrap.min.css und wird gebraucht; der
   Rest des Reboots betraf Elemente, die das Projekt nicht benutzt.

   Drei Stuecke, ohne die nichts mehr stimmt, und zwar auf einen Schlag und
   ueberall:
     - box-sizing: border-box auf allem. Ohne das rechnet JEDE Breite mit
       Polsterung falsch.
     - die Grundschrift am body. Ohne sie faellt die ganze Anwendung auf die
       Serifenschrift des Browsers zurueck.
     - font-family/-size/line-height an den Formularelementen. Die erben die
       Schrift NICHT von selbst — ohne die Zeile stehen Felder und Knoepfe in
       der UA-Schrift, meist 13,33px Arial, und die Oberflaeche wirkt schief,
       ohne dass irgendwo ein Fehler auftaucht.
   =========================================================================== */
*,
::before,
::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--app-font-sans);
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 1.5;
  color: var(--app-ink);
  background-color: var(--app-bg);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4, h5, h6 {
  margin-top: 0;
  margin-bottom: .5rem;
  font-weight: 500;
  line-height: 1.2;
}

/* Bootstraps Groessen, ohne die fluide Zwischenstufe: dort wuchsen h1 bis h4
   bis 1200px mit dem Fenster. Das Projekt setzt seine beiden Ueberschriften
   ohnehin selbst (.feeds-title, .fc-page-title) — hier steht nur der Endwert. */
h1 { font-size: 2.5rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.75rem; }
h4 { font-size: 1.5rem; }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }

p { margin-top: 0; margin-bottom: 1rem; }

dl, ol, ul { margin-top: 0; margin-bottom: 1rem; }
ol, ul     { padding-left: 2rem; }
dt         { font-weight: 700; }
dd         { margin-bottom: .5rem; margin-left: 0; }

hr {
  margin: 1rem 0;
  color: inherit;
  border: 0;
  border-top: 1px solid;
  opacity: .25;
}

b, strong { font-weight: bolder; }
small     { font-size: .875em; }

/* <code> steht in zwei Beschriftungen (maintain-feed.php, maintain-alarm.php),
   <pre> im Rohabzug der Geraetediagnose. Ohne die Schriftfamilie faellt beides
   auf die UA-Schrift zurueck und wird groesser statt kleiner. */
code, kbd, pre, samp { font-family: var(--app-font-mono); font-size: 1em; }
pre  { display: block; margin-top: 0; margin-bottom: 1rem; overflow: auto; font-size: .875em; }
code { font-size: .875em; color: var(--app-code); word-wrap: break-word; }

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

img, svg { vertical-align: middle; }

table { caption-side: bottom; border-collapse: collapse; }
th { text-align: inherit; }
tbody, td, tfoot, th, thead, tr { border-color: inherit; border-style: solid; border-width: 0; }

label { display: inline-block; }

/* DIE ZEILE, die Felder und Knoepfe an die Schrift der Seite bindet. */
button, input, optgroup, select, textarea {
  margin: 0;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
}

button { border-radius: 0; }
button, select { text-transform: none; }
button:focus:not(:focus-visible) { outline: 0; }
select { word-wrap: normal; }
textarea { resize: vertical; }

/* Die vier Herstellerregeln an Formularelementen. Sie sehen nach Beiwerk aus,
   sind aber genau die Stellen, an denen ein Feld sonst seine Hoehe oder seine
   Polsterung selbst waehlt: das Zahlenfeld der Nachkommastellen und die beiden
   Datumsfelder des Diagramms. */
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-year-field { padding: 0; }
::-webkit-inner-spin-button { height: auto; }
::-moz-focus-inner { padding: 0; border-style: none; }

[type="button"], [type="reset"], [type="submit"], button { -webkit-appearance: button; }
[type="button"]:not(:disabled),
[type="reset"]:not(:disabled),
[type="submit"]:not(:disabled),
button:not(:disabled) { cursor: pointer; }
[role="button"] { cursor: pointer; }

fieldset { min-width: 0; padding: 0; margin: 0; border: 0; }

summary { display: list-item; cursor: pointer; }

/* Der Browser kennt das Attribut, aber nicht gegen ein display aus einer
   Regel. Bootstrap setzte deshalb !important — hier genauso, sonst steht
   #chart_range_fields[hidden] sichtbar da. */
[hidden] { display: none !important; }

/* ---- Inter, selbst-gehostet (Variable-Font, alle Gewichte) ---------------- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;          /* eine Datei, alle Gewichte */
  font-display: swap;            /* Fallback rendert sofort, kein FOIT */
  src: url('../fonts/inter-latin.woff2') format('woff2');
  /* Latin + Latin-Ext (deckt deutsche Umlaute / ß ab) — kombinierte Datei */
  unicode-range:
    U+0000-00FF, U+0100-02AF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
    U+02DA, U+02DC, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
    U+2000-206F, U+2020, U+2074, U+20A0-20AB, U+20AC, U+20AD-20C0, U+2113,
    U+2122, U+2191, U+2193, U+2212, U+2215, U+2C60-2C7F, U+A720-A7FF,
    U+FEFF, U+FFFD;
}

/* ---- Icons — Material Symbols Outlined als Inline-Sprite ------------------
   Die Zeichen kommen aus includes/icon-sprite.php (einmal im <body> von
   main.php) und werden als <svg class="icon"><use href="#i-NAME"></use></svg>
   benutzt. Zwei Eigenschaften tragen alles Weitere:

   - 1em statt einer festen Größe: die Größe folgt der font-size des Ortes,
     genau wie bei einer Icon-Schrift. Wer ein Zeichen größer will, setzt
     font-size am Icon oder an seinem Behälter, nie width/height.
   - fill: currentColor: die Farbe folgt der Textfarbe. Alle bestehenden
     Regeln, die color am Icon setzen, wirken deshalb unverändert weiter.

   Die Achse wght@300 ist auf ~24 px gezeichnet. Unter 14 px werden die Striche
   subpixelig und waschen aus — deshalb steht in dieser Datei nirgends mehr eine
   Icon-Größe unter .875rem. Wer eine kleiner setzt, bekommt einen grauen Schleier
   statt eines Zeichens. */
.icon {
  width: 1em;
  height: 1em;
  flex: none;
  fill: currentColor;
  vertical-align: -.15em;   /* setzt den Glyph auf die Schriftlinie, wie es die Icon-Schrift tat */
}
/* Feste Vielfache für die beiden Ladeanzeigen, die vorher fa-2x / fa-5x trugen. */
.icon-2x { font-size: 2em; }
.icon-5x { font-size: 5em; }

/* ===========================================================================
   Token — Light (Default)
   Bis Stufe 3d hiess der Abschnitt "Token + Bootstrap-Verdrahtung": die Haelfte
   der Werte hat nur Bootstrap gelesen (--bs-primary, --bs-link-*, die vierzehn
   --bs-btn- des Accent-Fills). Die sind mit der Datei gegangen. Geblieben und
   auf --app-* umbenannt ist, was das Projekt selbst liest.
   =========================================================================== */
:root {
  /* --- Typografische Skala --------------------------------------------
     Fuenf Textstufen. Jede ist von ihrer Nachbarin auf einen Blick zu
     unterscheiden und liegt bei 16-px-Wurzel auf ganzen Pixeln. */
  --fs-xs:    .75rem;   /* 12 — Abschnittsmarke, Legende, Zeitachse       */
  --fs-sm:    .875rem;  /* 14 — Label, Hinweis, Knopf, Listenzeile        */
  --fs-base:  1rem;     /* 16 — Grundschrift, Feldwert, Kacheltitel       */
  --fs-lg:    1.25rem;  /* 20 — Blatt-, Dialog- und Einzelkacheltitel     */
  --fs-xl:    2rem;     /* 32 — Seitenueberschrift, Anmeldetitel          */

  /* --- Icon-Reihe ------------------------------------------------------
     font-size am .icon ist die Kantenlaenge des Glyphen, keine Schrift.
     Untergrenze 14 px aus docs/icons.md — darunter waescht wght@300 aus. */
  --fi-sm:  .875rem;    /* 14 */
  --fi-md:  1rem;       /* 16 */
  --fi-lg:  1.125rem;   /* 18 */
  --fi-xl:  1.25rem;    /* 20 */

  /* --- Anzeigegroessen -------------------------------------------------
     Der Leitwert der Kachel ist ein Anzeigeinstrument, keine Textstufe.
     Zahl und Einheit gehoeren paarweise zusammen. */
  --fd-lead:                  2.5rem;   --fd-lead-unit:             1rem;
  --fd-lead-narrow:           2.125rem; --fd-lead-unit-narrow:      .9375rem;
  --fd-lead-chart:            2.75rem;  --fd-lead-unit-chart:       1.0625rem;
  --fd-lead-single:           4rem;     --fd-lead-unit-single:      1.375rem;
  --fd-lead-single-wide:      5.5rem;   --fd-lead-unit-single-wide: 1.625rem;

  /* Design-Token */
  --color-accent:      #ed3f1c;
  --color-accent-rgb:  237, 63, 28;
  /* Die Flaeche des gefuellten Knopfes IST der reine Accent — dieselbe Farbe,
     die das App-Icon traegt und die MedFolio als Referenz setzt. Die
     Abdunklung auf #d13719 ist im September 2026 zurueckgenommen worden: ein
     abgedunkelter Signalton ist kein Signal mehr. Was das an Kontrast kostet
     und warum es trotzdem so steht: Log-Eintrag "Der Accent bleibt rein" in
     docs/design-entscheidungen.md.
     Das Token bleibt als eigener Name stehen, weil es die Hover-Rampe traegt:
     der Hover dunkelt ab, in BEIDEN Saetzen und mit derselben Stufe wie
     MedFolio (--button-hover-bg dort). */
  --color-accent-fill:       var(--color-accent);
  --color-accent-fill-hover: color-mix(in srgb, var(--color-accent) 85%, black);
  --color-on-accent:   #ffffff;
  /* Accent als Text auf accent-getoenter Flaeche (Badge-Muster des Guides).
     Der reine Accent kommt gegen jeden hellen Grund ueber 3,94:1 nicht hinaus —
     zu wenig fuer 13-px-Text. Der Wert ist derselbe wie --bs-link-hover-color
     unten, also keine zusaetzliche Farbe im Palettenraum. Im Dark liegt der
     Accent hell auf dunkel und braucht die Abdunklung nicht. */
  --color-accent-ink:  var(--color-accent);
  --color-error:       #b3361d;
  --color-error-rgb:   179, 54, 29;

  /* Warme Interaktions-Skala (color-mix mit warmem Anker, kein kühles Grau).
     Light: der Anker dunkelt warm ab. */
  --state-shade:    #2e2018;
  --state-hover:    color-mix(in srgb, var(--state-shade)  6%, transparent);
  --state-press:    color-mix(in srgb, var(--state-shade) 12%, transparent);
  --state-selected: color-mix(in srgb, var(--state-shade) 18%, transparent);

  /* Resting-Elevation auf Cards (weicher, warmer Schatten statt flacher Border) */
  --shadow-rest: 0 1px 2px rgba(46, 32, 24, 0.08), 0 1px 1px rgba(46, 32, 24, 0.04);

  /* --- Grundwerte der Seite --- */
  /* Der Fokusring beantwortet "wo bin ich" und gehoert damit nach
     docs/design-entscheidungen.md dem Accent. */
  --app-focus-ring:       rgba(var(--color-accent-rgb), .25);
  --app-focus-ring-width: .25rem;

  /* Radius: straffer & konsistent (~4px) — instrumenten-nahe Anmutung */
  --app-radius:    0.25rem;
  --app-radius-sm: 0.2rem;

  /* Warme Grundfläche (dezent). --app-bg-soft ist die Flaeche, auf die eine
     Zeile unter dem Zeiger geht, --app-border-soft der leise Rand von Kachel
     und Menue (Bootstraps border-color-translucent). */
  --app-bg:          #FAF8F5;
  --app-bg-soft:     #F4F1EB;
  --app-border:      #E7E2DB;
  --app-border-soft: rgba(0, 0, 0, 0.175);

  /* Schrift auf der Flaeche. Beide Werte kamen bis Stufe 3d aus Bootstraps
     Palette und sind unveraendert uebernommen. */
  --app-ink:       #212529;
  --app-ink-muted: rgba(33, 37, 41, 0.75);

  /* Die dritte Stufe des Kachelrasters: Beschriftung und Einheit — was den
     Messwert benennt, ohne selbst gelesen werden zu muessen (.feed-meta,
     .feed-metric-label, .feed-lead-unit, die Summenzeilen einer Gruppe). Sie
     liegt eine Spur leiser als --app-ink-muted, damit Label und Wert in
     derselben Zeile auseinanderfallen, bleibt aber ueber 4,5:1 auf --app-bg
     (5,11:1) — es ist Text, kein Rand. Bis September 2026 stand hier achtmal
     das Literal #868e96 im <style>-Block von main.php: Bootstraps kuehles Grau,
     3,13:1, und es kippte im Dunkelmodus nicht mit. */
  --app-ink-soft:  #736860;

  /* Typografie: Inter mit System-Stack als Fallback */
  --app-font-sans:
    'Inter', system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    "Noto Sans", "Liberation Sans", Arial, sans-serif;

  /* Schreibmaschine fuer <code> und <pre>. Beides Bootstraps Werte,
     unveraendert uebernommen — die Farbe eingeschlossen. */
  --app-font-mono:
    SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
    monospace;
  --app-code: #d63384;

  /* Sagt dem Browser, in welchem Satz er SEINE eigenen Sachen zeichnet:
     Fokusring, Bildlaufleiste, Datumsauswahl, die Vorgabeflaechen der
     Formularelemente. Stand bis Stufe 3d in bootstrap.min.css. Ohne die
     Zeile im Dunkelmodus bleibt der Fokusring hell umrandet und der
     Datumswaehler weiss — beides sieht nicht nach Fehler aus, nur falsch. */
  color-scheme: light;
}

/* ===========================================================================
   Panel = Seite, keine Karte
   Seit die Grundansicht waehrend eines Fragments ausgeblendet ist, liegt ein
   Panel auf nichts mehr auf und ist nicht drueckbar — Rand und Schatten grenzten
   es gegen nichts mehr ab (Leitregel in docs/design-entscheidungen.md).
   Traeger ist .app-panel, gesetzt von include() in js/main.js.

   Hier standen bis Stufe 3c der Ruheschatten auf .card und darunter sechs
   Regeln, die die Kartenhuelle eines Panels wieder zurueckbauten
   (.app-panel > .container > .card…). Beides ist weg: die Kartenhuelle haben
   die Panels schon mit Vorschlag 7B verloren — die Regeln trafen seither
   nichts —, und die Geraetekachel war der letzte .card im Projekt. Sie traegt
   Rahmen, Flaeche, Radius und Ruheschatten jetzt selbst (.feed-card im
   Inline-Block von main.php).
   =========================================================================== */

/* NProgress-Bar = Accent (Bar-Hintergrund liegt im Inline-Block von main.php) */

/* ===========================================================================
   Dark Mode — OS-gesteuert (prefers-color-scheme via data-bs-theme)
   Aus dem Inline-Block von main.php hierher verschoben, damit die Login-Seite
   konsistent dunkel wird. Nur Werte, die von Bootstraps Dark-Palette abweichen.
   =========================================================================== */
[data-bs-theme="dark"] {
  /* Token-Hue-Shift: Dark-Accent ist spürbar oranger (gewollt) */
  --color-accent:     var(--color-accent);
  --color-accent-rgb: var(--color-accent-rgb);
  --color-accent-ink: var(--color-accent);
  /* --color-accent-fill, --color-accent-fill-hover und --color-on-accent
     stehen hier bewusst NICHT: die Flaeche ist im hellen Satz aus
     --color-accent abgeleitet und kippt damit von selbst mit, die Schrift
     darauf ist in beiden Saetzen weiss. Dieselbe Regel wie in MedFolio, das
     seine --button-*-Token aus demselben Grund nicht redefiniert. */
  --color-error:      #ff7e62;
  --color-error-rgb:  255, 126, 98;

  /* Warme Interaktions-Skala — Dark: der Anker hellt warm auf */
  --state-shade: #f0e6da;

  /* Eigener warmer Dunkelton (statt Bootstraps #212529) */
  --app-bg:          #2A2A29;
  --app-border:      #414141;
  --app-border-soft: rgba(255, 255, 255, 0.1);

  /* Die drei kamen bis Stufe 3d aus Bootstraps Dunkelpalette und sind
     unveraendert uebernommen — auch --app-bg-soft, das im Dunkeln als einziger
     Wert kuehl bleibt (es ist die Zeilenflaeche des Menues). */
  --app-bg-soft:   #2b3035;
  --app-ink:       #dee2e6;
  --app-ink-muted: rgba(222, 226, 230, 0.75);
  --app-code:      #e685b5;

  /* Beschriftungsstufe des Kachelrasters, Dark: 5,16:1 auf --app-bg. Warm wie
     der helle Wert, nur von der anderen Seite — dieselbe Rolle, dasselbe
     Verhaeltnis zu --app-ink-muted. */
  --app-ink-soft:  #a09a93;

  color-scheme: dark;
}

/* Navigationsleiste (Dark): dieselbe Logik wie im Light, andere Werte. Die
   Leiste ist eine Fläche ÜBER dem Seitengrund (#2A2A29), kein eigener Grund —
   deshalb #333332 statt eines Schattens; die Trennlinie trennt. Die aktive
   Markierung ist der hellste warme Ton (--state-shade), nie die Akzentfarbe:
   sie bleibt Funktionssignal. Die Interaktionsflächen kommen aus den
   State-Token, damit sie mit der übrigen Oberfläche wandern.
   Ersetzt die früheren Regeln für .bg-dark / .navbar-Schatten. */
[data-bs-theme="dark"] .main-nav {
  --nav-surface:      #333332;
  --nav-border:       #414141;
  --nav-ink:          #DFDFDF;
  --nav-ink-2:        #B4B0AB;
  --nav-ink-3:        #929291;
  --nav-ink-4:        #807C77;
  --nav-mark:         var(--state-shade);
  --nav-hover:        var(--state-hover);
  --nav-selected:     var(--state-press);
  --nav-avatar:       #454545;
  --nav-avatar-open:  #4F4F4E;
  --nav-sep:          #414141;
  --nav-rule:         #414141;
  --nav-shadow-menu:  0 6px 20px rgba(0, 0, 0, 0.45);
}

/* Verlaufsleiste der Gerätekachel — Dark aus den State-Token abgeleitet statt
   aus zwei weiteren Literalen: --state-selected (18 %) ist der Balken mit Wert,
   --state-press (12 %) die 1-px-Linie einer Stunde ohne Daten — dasselbe
   Verhältnis wie #E4DED6 zu #EDE8E1 im Light-Mode. Der letzte Balken bleibt der
   kräftigste Ton. Nie die Akzentfarbe — sie bleibt Funktionssignal. */
[data-bs-theme="dark"] .feed-card .feed-spark-bar {
  background-color: var(--state-press);
}
[data-bs-theme="dark"] .feed-card .feed-spark-bar.feed-spark-value {
  background-color: var(--state-selected);
}

/* ---- Diagramm in der Geraetekachel (Dark) --------------------------------
   Dieselbe Logik wie im Light, andere Werte: die Textschalter nehmen als
   aktive Flaeche --state-press — dieselbe Ableitung wie --nav-selected in der
   Leiste —, nie die Akzentfarbe. Die Light-Werte stehen im Inline-Block von
   main.php, hier werden nur dieselben Variablen umgelegt. */
[data-bs-theme="dark"] #chart_tools,
[data-bs-theme="dark"] #chart_panel {
  --chart-ink-2:      #B4B0AB;
  --chart-ink-3:      #929291;
  --chart-switch-bg:  var(--state-press);
  --chart-switch-ink: #DFDFDF;
}

/* ===========================================================================
   Liste links, Blatt rechts (Vorschlag 7B)
   Referenz: "Feed Konfiguration.dc.html", Abschnitt 7B. Eine Zeile je Gerät
   statt je Datensatz; die Bearbeitung von Serie und Gerät steht im Blatt
   rechts, nicht mehr in Modalen.

   Der Traeger heisst .fc-scope, nicht .feed-config: die Benutzerverwaltung
   benutzt seit "Benutzer als Blatt" dieselben Rahmen, Felder und Abstaende
   (maintain-user.php). .feed-config bleibt auf der Feed-Seite stehen, aber nur
   noch als Ansatzpunkt fuer js/app.js, nicht mehr fuer Stil.

   Die Werte des Entwurfs sind Licht-Werte. Sie stehen deshalb als Token auf
   .fc-scope und werden im Dark Mode einmal umgelegt, statt zwei Kopien der
   Regeln zu pflegen.
   =========================================================================== */
.fc-scope {
  --fc-sheet:        #FFFFFF;
  --fc-edge-strong:  #DED7CD;
  --fc-edge:         #E2DCD3;
  --fc-edge-soft:    #EDE8E1;
  --fc-edge-hair:    #F1ECE5;
  --fc-edge-edit:    #C9C0B5;
  --fc-fill-active:  #F0EBE4;
  --fc-fill-hover:   #F7F4EF;
  --fc-ink:          #212529;
  --fc-ink-2:        #5c534b;
  --fc-ink-3:        #736860;
  --fc-ink-4:        #7a6f66;
  --fc-warn:         #b3361d;
}

[data-bs-theme="dark"] .fc-scope {
  --fc-sheet:        #333332;
  --fc-edge-strong:  #4A4A49;
  --fc-edge:         #414141;
  --fc-edge-soft:    #3C3C3B;
  --fc-edge-hair:    #383837;
  --fc-edge-edit:    #5A5A58;
  --fc-fill-active:  var(--state-press);
  --fc-fill-hover:   var(--state-hover);
  --fc-ink:          #DFDFDF;
  --fc-ink-2:        #B4B0AB;
  /* Die beiden unteren Stufen tragen im dunklen Satz DENSELBEN Wert, und das ist
     kein Versehen: fc-Text steht auf dem Blatt (--fc-sheet #333332), nicht auf
     --app-bg, und #333332 ist der hellere Grund. Der dunkelste Ton, der dort noch
     4,5:1 traegt, ist #a09a93 (4,54:1) — unter --fc-ink-2 ist dunkel keine vierte
     Stufe mehr herstellbar, ohne unter AA zu fallen. Der Name bleibt, damit die
     Rolle im hellen Satz (dort 5,42 zu 4,89 auf dem Blatt) ihren Traeger behaelt. */
  --fc-ink-3:        #a09a93;
  --fc-ink-4:        #a09a93;
  --fc-warn:         var(--color-error);
}

.fc-scope.fc-page { margin-bottom: 1.5rem; }   /* loest .mb-4 ab (Stufe 3c) */

/* Der genannte Name im Loesch- bzw. Aufloesen-Dialog. Loest .lead, .text-danger
   und .fw-bold ab (Stufe 3c); die Werte sind Bootstraps Werte.
   Die drei Fundstellen sehen UNTERSCHIEDLICH aus, und das ist Bestand, nicht
   Absicht: alle drei trugen einmal ein Fett, aber zwei davon als .font-weight-bold
   — das ist Bootstrap 4 und wirkt seit dem Umstieg auf 5 nicht mehr. Nur der
   Benutzername trug das 5er .fw-bold und ist deshalb als einziger fett.
   Angeglichen wird das hier nicht: 3c raeumt auf und aendert nicht das Aussehen. */
.fc-scope .fc-dialog-name         { font-size: var(--fs-lg); font-weight: 300; }
.fc-scope .fc-dialog-name--danger { color: var(--color-error); }
.fc-scope .fc-dialog-name--bold   { font-weight: 700; }

.fc-scope .fc-page-title {
  margin: 0 0 1.125rem;
  font-size: var(--fs-xl);
  font-weight: 500;
  line-height: 1.2;
  color: var(--fc-ink);
}
/* Kein Fokusring: focus_fragment() (js/main.js) legt den Fokus nach dem Laden
   auf die Ueberschrift, damit ein Screenreader das neue Panel vorliest. Sie
   traegt tabindex="-1", ist also nie per Tab erreichbar und kein Bedienelement
   — der Ring saehe nur aus, als stuende der Seitentitel unter Fokus. */
.fc-scope .fc-page-title:focus,
.fc-scope .fc-page-title:focus-visible { outline: none; }

.fc-scope .fc-layout {
  display: grid;
  grid-template-columns: 288px 1fr;
  gap: 28px;
  align-items: start;
}

/* ---- Knöpfe und Textknöpfe --------------------------------------------- */
.fc-scope .fc-button {
  flex: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border: 1px solid var(--fc-edge-strong);
  border-radius: 4px;
  background: transparent;
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--fc-ink);
  cursor: pointer;
}
.fc-scope .fc-button:hover:not(:disabled) { background-color: var(--state-hover); }
.fc-scope .fc-button:disabled { color: var(--fc-ink-4); cursor: default; }
.fc-scope .fc-button > .icon { font-size: var(--fi-md); color: var(--fc-ink-4); }

/* Die eine Vorwaertsaktion des Blattes — "Speichern". Gefuellte Flaeche, wie
   docs/design-entscheidungen.md es unter "Accent-Fill" verlangt; bis dahin trug
   die Klasse Rand und Text und war damit von "Loeschen" (.fc-danger, Warn-Rand
   #b3361d) auf einen Blick nicht zu unterscheiden — zwei umrandete Knoepfe in
   fast derselben Farbe. Fill gegen Rand loest das, und genau dieser Gegensatz
   ist der Grund, warum der destruktive Knopf umrandet BLEIBT.
   Die Flaeche ist der reine Accent — dieselbe Farbe wie das App-Icon. Sie
   steht als --color-accent-fill da, weil dieses Token die Hover-Rampe traegt;
   der Wert ist --color-accent (siehe oben).
   Nicht fuer Aktionen in einem Aufklapper — "Passwort aendern" ist die
   primaere Aktion ihres Aufklappers, nicht die des Blattes; "Regel speichern"
   traegt sie deshalb nur in der Alarm-Uebersicht (includes/alarm-view.php).
   Deaktiviert faellt die Flaeche weg und der Knopf wird blass und neutral —
   anders als beim Anmelde-Knopf unten, der dafuer seinen Grund hat. */
.fc-scope .fc-button--primary {
  border-color:     var(--color-accent-fill);
  background-color: var(--color-accent-fill);
  color:            var(--color-on-accent);
}
.fc-scope .fc-button--primary > .icon { color: inherit; }
.fc-scope .fc-button--primary:hover:not(:disabled) {
  background-color: var(--color-accent-fill-hover);
  border-color:     var(--color-accent-fill-hover);
}
.fc-scope .fc-button--primary:disabled {
  border-color:     var(--fc-edge-strong);
  background-color: transparent;
  color:            var(--fc-ink-4);
}

/* Der Anmelde-Knopf. Er sieht aus wie .fc-button--primary oben und ist doch
   eine eigene Klasse — der Unterschied steht in der letzten Regel: deaktiviert
   bleibt HIER die Flaeche stehen und wird blass (Bootstrap machte das mit
   --bs-btn-disabled-opacity: .65), weil der Knopf auf der Anmeldemaske
   zunaechst gesperrt ist und ein farbloser Knopf dort aussaehe wie ein Fehler.
   Genau das soll --primary nicht haben; zusammenlegen hiesse, den Sonderfall
   als Ausnahme zurueckzuholen. Bis Stufe 3b war er .btn.btn-lg.btn-primary und
   lebte damit von den ~14 --bs-btn-*-Zeilen in .btn-primary; die Groesse setzt
   jetzt index.php selbst, weil sie nur dort gebraucht wird. */
.fc-scope .fc-button--fill {
  border-color:     var(--color-accent-fill);
  background-color: var(--color-accent-fill);
  color:            var(--color-on-accent);
}
.fc-scope .fc-button--fill > .icon { color: inherit; }
.fc-scope .fc-button--fill:hover:not(:disabled) {
  background-color: var(--color-accent-fill-hover);
  border-color:     var(--color-accent-fill-hover);
}
.fc-scope .fc-button--fill:disabled {
  border-color:     var(--color-accent-fill);
  background-color: var(--color-accent-fill);
  color:            var(--color-on-accent);
  opacity: .65;
}

/* Die destruktive Aktion eines Dialogs — "Loeschen". Loest .btn-outline-danger
   ab (Stufe 3a) und nimmt dafuer dieselbe Farbrolle wie .fc-textbutton.fc-danger
   eine Zeile weiter unten: Text und Rand in der Warnfarbe, kein Fill. */
.fc-scope .fc-button.fc-danger { border-color: var(--fc-warn); color: var(--fc-warn); }
.fc-scope .fc-button.fc-danger > .icon { color: inherit; }
.fc-scope .fc-button.fc-danger:hover:not(:disabled) { background-color: color-mix(in srgb, var(--fc-warn) 10%, transparent); }

.fc-scope .fc-textbutton {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--fc-ink-2);
  cursor: pointer;
}
.fc-scope .fc-textbutton:hover:not(:disabled) { color: var(--fc-ink); }
.fc-scope .fc-textbutton:disabled { color: var(--fc-ink-4); cursor: default; }
.fc-scope .fc-textbutton > .icon { font-size: var(--fi-md); color: var(--fc-ink-4); }
.fc-scope .fc-textbutton.fc-danger { color: var(--fc-warn); }
.fc-scope .fc-textbutton.fc-danger > .icon { font-size: var(--fi-md); color: inherit; }

/* Symbolknöpfe: der Glyph steht auf 18 px, die Trefferfläche wächst auf Touch */
.fc-scope .fc-icon-button {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 3px;
  background: none;
  font-size: var(--fi-lg);
  color: var(--fc-ink-2);
  cursor: pointer;
}
.fc-scope .fc-icon-button:hover { background-color: var(--state-hover); }
.fc-scope .fc-icon-button.is-active { background-color: var(--fc-fill-active); color: var(--fc-ink); }
@media (pointer: coarse) {
  .fc-scope .fc-icon-button { width: 44px; height: 44px; }
}

/* ---- Linke Spalte — Geräteliste ---------------------------------------- */
.fc-scope .fc-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 4px 8px;
  border-bottom: 1px solid var(--fc-edge-strong);
}
.fc-scope .fc-list-title { font-size: var(--fs-xs); font-weight: 500; line-height: 1; color: var(--fc-ink-2); }
.fc-scope .fc-list-count { font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); font-variant-numeric: tabular-nums; }

.fc-scope .fc-list-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 0 12px;
  border-bottom: 1px solid var(--fc-edge-soft);
  text-decoration: none;
  color: inherit;
}
.fc-scope .fc-list-item:hover { background-color: var(--fc-fill-hover); }

/* Die gewählte Zeile greift optisch in das Blatt rechts: keine rechte Kante,
   der Radius nur links, und eine Marke an der linken Flanke. */
.fc-scope .fc-list-item.is-selected {
  background: var(--fc-sheet);
  border: 1px solid var(--fc-edge);
  border-right: none;
  border-radius: 4px 0 0 4px;
  box-shadow: -1px 1px 2px rgba(46, 32, 24, 0.05);
}
/* Die Marke beantwortet "hier bist du" und ist damit der Fall, den
   docs/design-entscheidungen.md unter Accent-Text ausdruecklich erlaubt
   (aktive Eintraege in Verwaltungslisten). Nur die Marke — Flaeche, Rand und
   Radius der Zeile bleiben neutral: dass die Zeile ins Blatt hineingreift, ist
   Geometrie und kein Signal. Die Leiste bleibt dagegen neutral markiert
   (Entscheidung vom 2026-06, --nav-mark): ihre Marke steht auf jeder Seite und
   wuerde durch Dauerhaftigkeit wieder Dekoration, waehrend diese hier bei jedem
   Blattwechsel neu beantwortet, welches Geraet gerade offen ist.
   Mit dieser Zeile und den beiden Fokus-Outlines darueber verliert --fc-mark
   seinen letzten Verbraucher und ist deshalb aus den Token-Bloecken raus. */
.fc-scope .fc-list-item.is-selected::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  bottom: 10px;
  width: 2px;
  background: var(--color-accent);
}
.fc-scope .fc-item-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.fc-scope .fc-item-name { font-size: var(--fs-base); line-height: 1.2; color: var(--fc-ink); overflow-wrap: anywhere; }
.fc-scope .fc-list-item.is-selected .fc-item-name { font-weight: 500; }
.fc-scope .fc-item-sub { font-size: var(--fs-sm); line-height: 1.2; color: var(--fc-ink-3); }

.fc-scope .fc-item-status { margin-left: auto; font-size: var(--fs-sm); line-height: 1; white-space: nowrap; }
.fc-scope .fc-status-ok      { color: var(--fc-ink-2); }
.fc-scope .fc-status-none,
.fc-scope .fc-status-nodata  { color: var(--fc-ink-4); }
.fc-scope .fc-status-overdue { font-weight: 500; color: var(--fc-warn); }

.fc-scope .fc-list-foot { padding: 14px 12px 0; }

/* ---- Rechte Spalte — das Gerät als Blatt -------------------------------- */
.fc-scope .fc-sheet {
  display: flex;
  flex-direction: column;
  background: var(--fc-sheet);
  border: 1px solid var(--fc-edge);
  border-radius: 4px;
  box-shadow: 0 1px 2px rgba(46, 32, 24, 0.06);
}
.fc-scope .fc-sheet-empty { padding: 22px 24px; }
.fc-scope .fc-empty-text { margin: 0; color: var(--fc-ink-3); }

.fc-scope .fc-sheet-head {
  display: flex;
  /* Umbrechen, sobald Ueberschrift und Aktionen nicht mehr nebeneinander
     passen: .fc-sheet-actions ist flex: none, und bei einer Gruppe stehen dort
     ZWEI Knoepfe ("Gruppe aufloesen" und "Speichern"). Ohne die Zeile lief das
     Blatt auf dem Telefon ueber seinen Behaelter hinaus. */
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 24px 18px;
  border-bottom: 1px solid var(--fc-edge-soft);
}
.fc-scope .fc-sheet-heading { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.fc-scope .fc-sheet-title { font-size: var(--fs-lg); font-weight: 500; line-height: 1.2; color: var(--fc-ink); overflow-wrap: anywhere; }
.fc-scope .fc-sheet-sub { font-size: var(--fs-sm); line-height: 1.3; color: var(--fc-ink-3); }
.fc-scope .fc-sheet-actions { flex: none; display: flex; align-items: center; gap: 8px; }

.fc-scope .fc-sheet > .error-message:not(:empty) { padding: 16px 24px 0; }

.fc-scope .fc-section { display: flex; flex-direction: column; }
.fc-scope .fc-section-device {
  gap: 16px;
  padding: 20px 24px;
  border-bottom: 1px solid var(--fc-edge-soft);
}
.fc-scope .fc-section-series { gap: 14px; padding: 20px 24px 24px; }

/* Gemischte Schreibweise wie .fc-list-title, die Ueberschrift der linken
   Spalte: gesperrte Versalien in 12 px waren auf --fc-ink-4 nur 2,61:1 und
   damit unter AA. Der Rang steht jetzt im Gewicht und in der dunkleren
   Farbe, nicht in der Schreibweise. */
.fc-scope .fc-section-title {
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1;
  color: var(--fc-ink-2);
}
.fc-scope .fc-section-head { display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap; }
.fc-scope .fc-section-tools { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* Die Legende benennt die Glyphen der chartyp-Schrift einmal, statt sie in
   jeder Zeile zu wiederholen. */
.fc-scope .fc-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); }

/* ---- Felder ------------------------------------------------------------- */
.fc-scope .fc-field-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }

/* Die Felder eines Aufklappers richten sich nach dessen Breite, nicht nach dem
   festen Dreierraster der Gerätezeile darüber: nebeneinander steht ein
   Aufklapper nur halb so breit wie das Blatt, und drei Spalten waren dort keine
   100 px breit — die Beschriftung "Benachrichtigungs-E-Mail" lief in "Schwelle
   (Min.)" hinein, "Monat" schnitt seinen Wert ab, und "Bericht senden" stand
   als nicht umbrechender Knopf über der Kante des Blattes. Statt fester
   Spaltenzahl deshalb eine Reihe, die umbricht: jedes Feld ist mindestens
   168 px breit, was nicht mehr nebeneinander passt, rutscht in die nächste
   Zeile, und die zwei Felder der Überwachung teilen die volle Breite unter
   sich auf, statt ein Drittel leer zu lassen. */
.fc-scope .fc-field-grid-inner { display: flex; flex-wrap: wrap; margin-top: 12px; }
.fc-scope .fc-field-grid-inner > .fc-field { flex: 1 1 168px; }

/* Breite nach Inhalt statt für alle gleich. Mit der einen Basis von 168 px stand
   eine E-Mail-Adresse so breit wie eine dreistellige Minutenzahl: die Adresse
   war abgeschnitten ("mailbox@rene-morge"), das Zahlenfeld halb leer. Die
   Adresse bekommt deshalb den dreifachen Anteil am freien Platz und bricht
   notfalls auf eine eigene Zeile um; das Zahlenfeld wächst gar nicht mit. */
.fc-scope .fc-field-grid-inner > .fc-field--mail   { flex: 3 1 260px; }
.fc-scope .fc-field-grid-inner > .fc-field--narrow { flex: 0 1 150px; }

/* Die Felder hängen an der Unterkante ihrer Zeile — eine Beschriftung, die auf
   zwei Zeilen umbricht, schiebt dann nur sich selbst nach oben und nicht die
   Eingabe daneben nach unten. Für den Knopf tat das bisher .fc-field-action
   allein. */
.fc-scope .fc-field { display: flex; flex-direction: column; justify-content: flex-end; gap: 6px; min-width: 0; }
/* Der Knopf behält seine eigene Breite, statt sich über das Feld zu ziehen — in
   einer Zeile, in der er allein steht, wäre das die ganze Breite des
   Aufklappers. .fc-field-wide macht es für den Knopf darunter genauso. */
.fc-scope .fc-field-action { justify-content: flex-end; align-items: flex-start; }
/* Ein Knopf in einer Feldzeile ist so hoch wie ein Eingabefeld. Aus Polsterung
   und Zeilenhoehe ergaben sich 32 px, und der Knopf stand damit sichtbar
   niedriger als die Eingabe daneben — beim Monatsbericht wie beim Passwort. */
.fc-scope .fc-field .fc-button { min-height: 38px; }
/* Eine Beschriftung darf umbrechen; mit line-height 1 klebten die zwei Zeilen
   aneinander. */
.fc-scope .fc-field-label { font-size: var(--fs-sm); line-height: 1.25; color: var(--fc-ink-3); }
/* Erlaeuterung UNTER einem Feld (loest .form-text ab, Stufe 3a): der Hinweis
   der Zaehlergruppe und die Mindestlaenge des Passworts. */
.fc-scope .fc-field-hint { font-size: var(--fs-sm); line-height: 1.3; color: var(--fc-ink-3); }

.fc-scope .fc-input {
  min-height: 38px;
  width: 100%;
  padding: 0 10px;
  border: 1px solid var(--fc-edge);
  border-radius: 3px;
  background: var(--fc-sheet);
  font-size: var(--fs-base);
  line-height: 1.2;
  color: var(--fc-ink);
}
.fc-scope .fc-input:focus-visible { outline: 2px solid var(--color-accent); outline-offset: -1px; }
.fc-scope .fc-input[readonly] { background-color: var(--fc-fill-hover); color: var(--fc-ink-2); pointer-events: none; }
.fc-scope .fc-num { font-variant-numeric: tabular-nums; }

/* ---- Kontrollkaestchen -------------------------------------------------- */
/* Der Haken ist GEZEICHNET, kein Bild: zwei Kanten eines ::after, um 45 Grad
   gedreht. Bootstraps .form-check-input traegt ihn als Data-URI-SVG im
   kompilierten CSS (Falle 4 in docs/bootstrap-stufe3-plan.md) — was still
   bricht, ist das Wegnehmen der Datei: das Kaestchen waere dann ein oranges
   Quadrat ohne Haken, und das sieht plausibel aus. Ein Sprite-Icon ginge hier
   nicht, index.php bindet includes/icon-sprite.php nicht ein.
   Das Kaestchen steht auf der ERSTEN Textzeile, nicht auf der Mitte des ganzen
   Blocks: die Beschriftung des Stromzaehlers (maintain-feed.php) bricht um, und
   mit align-items: center rutschte das Kaestchen dann zwischen ihre Zeilen.
   Daher flex-start und die eine Zeile Versatz am Kaestchen. Ein Hinweis unter
   dem Kaestchen ist KEIN Geschwister von input und label — er gehoert in die
   Zeile darunter (.fc-field darum herum), sonst macht ihn das Flex zur
   dritten Spalte der Zeile. */
.fc-scope .fc-check { display: flex; align-items: flex-start; gap: 8px; }
.fc-scope .fc-check-input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  position: relative;
  width: 1rem;
  height: 1rem;
  margin: 1px 0 0;
  border: 1px solid var(--fc-edge-strong);
  border-radius: 3px;
  background: var(--fc-sheet);
  cursor: pointer;
}
.fc-scope .fc-check-input:checked { border-color: var(--color-accent); background-color: var(--color-accent); }
.fc-scope .fc-check-input:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 4px;
  height: 8px;
  border: solid var(--color-on-accent);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.fc-scope .fc-check-input:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 1px; }
/* Volle Vordergrundfarbe, anders als .fc-field-label: die Beschriftung eines
   Kaestchens ist die Wahl selbst und nicht die Aufschrift ueber einem Feld. */
.fc-scope .fc-check-label { font-size: var(--fs-sm); line-height: 1.25; color: var(--fc-ink); cursor: pointer; }

/* Diagrammtyp-Auswahl: die Glyphe zeigt die Form der Kurve, der Name steht in
   der Auswahlliste und im title. Der versteckte Text trägt den Wert, den das
   Speichern liest — deshalb ein <span hidden>, kein entfernter Knoten. */
.fc-scope .fc-select-wrap { display: block; }
.fc-scope .fc-select {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  cursor: pointer;
}
.fc-scope .fc-select [class^="icon-"] { font-size: var(--fi-md); }
.fc-scope .fc-select-caret { margin-left: auto; font-size: .5625rem; color: var(--fc-ink-4); }

/* ---- Aufklappbare Gerätezusätze ---------------------------------------- */
.fc-scope .fc-disclosures { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 24px; padding-top: 4px; }
.fc-scope .fc-disclosure { flex: 1 1 320px; min-width: 0; }

/* Untereinander statt nebeneinander (Geräteblatt). Nebeneinander stand jeder
   Aufklapper nur halb so breit wie das Blatt, und was er aufklappte, öffnete
   sich in dieser Hälfte — die Felder mussten sich stapeln, obwohl rechts das
   halbe Blatt leer blieb. Eine Spalte: jede Zeile ein Abschnitt, jeder
   Abschnitt die ganze Breite.

   Die volle Breite darf aber kein Feld ganz ausfüllen. Ohne Deckel wäre die
   Eingabe für eine 30-Zeichen-Adresse über tausend Pixel breit; die Felder
   stehen deshalb nebeneinander bis zu ihrer sinnvollen Breite, und was dann
   noch übrig ist, bleibt leer. */
.fc-scope .fc-disclosures--stacked { display: grid; grid-template-columns: 1fr; gap: 12px; }
.fc-scope .fc-disclosures--stacked .fc-field-grid-inner > .fc-field         { max-width: 320px; }
.fc-scope .fc-disclosures--stacked .fc-field-grid-inner > .fc-field--mail   { max-width: 360px; }

/* Der Monatswähler trägt den längsten Monatsnamen plus Jahr ("September 2026")
   und bekommt dafür ein Fach fester Breite. Der Knopf daneben schrumpft nicht,
   weil seine Beschriftung nicht umbricht; reicht der Platz nicht, bricht die
   Zeile um. */
.fc-scope .fc-disclosures--stacked .fc-field-grid-inner > .fc-field--month  { flex: 0 0 190px; }
.fc-scope .fc-disclosures--stacked .fc-field-grid-inner > .fc-field-action  { flex: 0 0 auto; }
.fc-scope .fc-disclosure-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  background: none;
  font-size: var(--fs-sm);
  line-height: 1.4;
  text-align: left;
  color: var(--fc-ink-2);
  cursor: pointer;
}
.fc-scope .fc-disclosure-toggle .icon { font-size: var(--fi-sm); color: var(--fc-ink-4); }
.fc-scope .fc-disclosure-summary { color: var(--fc-ink-3); }

/* ---- Serienkarten ------------------------------------------------------- */
.fc-scope .fc-series-list { display: flex; flex-direction: column; gap: 10px; }

.fc-scope .fc-series-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 16px;
  border: 1px solid var(--fc-edge-soft);
  border-radius: 3px;
}
.fc-scope .fc-series-card.is-editing {
  gap: 12px;
  border-color: var(--fc-edge-edit);
  box-shadow: 0 1px 2px rgba(46, 32, 24, 0.06);
}

.fc-scope .fc-series-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.fc-scope .fc-series-name { font-size: var(--fs-base); font-weight: 500; line-height: 1.2; color: var(--fc-ink); overflow-wrap: anywhere; }
.fc-scope .fc-series-role { font-size: var(--fs-sm); line-height: 1.2; color: var(--fc-ink-3); }
.fc-scope .fc-series-hidden-hint { margin-left: auto; font-size: var(--fs-sm); line-height: 1.2; color: var(--fc-ink-4); }
.fc-scope .fc-series-rows { font-size: var(--fs-sm); line-height: 1.2; color: var(--fc-ink-3); font-variant-numeric: tabular-nums; }
.fc-scope .fc-series-hidden-hint + .fc-series-rows { margin-left: 0; }
.fc-scope .fc-series-hidden-hint[hidden] + .fc-series-rows { margin-left: auto; }
.fc-scope .fc-series-actions { display: flex; align-items: center; gap: 2px; }

.fc-scope .fc-dataset-list { display: grid; gap: 8px; }
.fc-scope .fc-dataset {
  display: grid;
  grid-template-columns: 28px 1fr 84px 92px 40px;
  gap: 12px;
  align-items: center;
  font-variant-numeric: tabular-nums;
}
.fc-scope .fc-ds-nr { font-size: var(--fs-xs); line-height: 1.4; color: var(--fc-ink-4); }
.fc-scope .fc-ds-label { font-size: var(--fs-sm); line-height: 1.4; color: var(--fc-ink); overflow-wrap: anywhere; }
.fc-scope .fc-ds-unit,
.fc-scope .fc-ds-decimals { font-size: var(--fs-sm); line-height: 1.4; color: var(--fc-ink-2); }
.fc-scope .fc-ds-type [class^="icon-"] { font-size: var(--fi-sm); color: var(--fc-ink-2); }

/* ---- Serienkarte, Bearbeiten-Ansicht ------------------------------------ */
.fc-scope .fc-edit-identity { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.fc-scope .fc-edit-grid { display: grid; gap: 6px; margin-top: 12px; }
.fc-scope .fc-edit-headrow,
.fc-scope .fc-edit-row {
  display: grid;
  grid-template-columns: 28px 1fr 84px 104px 88px;
  gap: 12px;
  align-items: center;
}
.fc-scope .fc-edit-head { font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); }
.fc-scope .fc-edit-nr { font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); }
.fc-scope .fc-edit-row .fc-input { min-height: 34px; padding: 0 9px; font-size: var(--fs-sm); }

.fc-scope .fc-edit-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 10px;
  border-top: 1px solid var(--fc-edge-hair);
  margin-top: 12px;
}
.fc-scope .fc-edit-hint { font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); }

/* ---- Diagnose des Particle-Geräts -------------------------------------- */
/* Der Abschnitt steht im Geräteblatt und wird beim Aufklappen nachgeladen
   (maintain-feed-diag.php, js/app.js). Keine eigene Farbwelt: "gut" bleibt
   ruhige Tinte wie bei .fc-status-ok, auffällig ist --fc-warn. Grün gibt es in
   dieser Oberfläche nicht, und ein Gerät, das läuft, muss nicht leuchten. */
.fc-scope .fc-diag-content { padding-top: 4px; }

.fc-scope .fc-diag-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--fc-edge-hair);
}
.fc-scope .fc-diag-state { font-size: var(--fs-sm); font-weight: 500; color: var(--fc-ink-2); }
.fc-scope .fc-diag-state--bad { color: var(--fc-warn); }
.fc-scope .fc-diag-name { font-size: var(--fs-base); color: var(--fc-ink); overflow-wrap: anywhere; }
.fc-scope .fc-diag-id {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-xs);
  color: var(--fc-ink-4);
  overflow-wrap: anywhere;
}
.fc-scope .fc-diag-reload { margin-left: auto; }

.fc-scope .fc-diag-grid { margin: 0; padding-top: 4px; }
.fc-scope .fc-diag-row {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 4px 16px;
  padding: 10px 0;
  border-bottom: 1px solid var(--fc-edge-hair);
}
.fc-scope .fc-diag-row:last-child { border-bottom: 0; }
.fc-scope .fc-diag-row dt {
  font-size: var(--fs-sm);
  font-weight: 400;
  line-height: 1.5;
  color: var(--fc-ink-3);
}
.fc-scope .fc-diag-row dd {
  margin: 0;
  min-width: 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--fc-ink-2);
}
.fc-scope .fc-diag-lead { font-size: var(--fs-base); color: var(--fc-ink); }
.fc-scope .fc-diag-sep { padding: 0 6px; color: var(--fc-ink-4); }
.fc-scope .fc-diag-note {
  display: block;
  padding-top: 3px;
  font-size: var(--fs-xs);
  color: var(--fc-ink-3);
  overflow-wrap: anywhere;
}
.fc-scope .fc-diag-tag {
  margin-left: 8px;
  font-size: var(--fs-xs);
  color: var(--fc-ink-3);
}
.fc-scope .fc-diag-tag--warn,
.fc-scope .fc-diag-tag--bad  { color: var(--fc-warn); }
.fc-scope .fc-diag-tag--muted { color: var(--fc-ink-4); }
.fc-scope .fc-diag-body {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--fs-xs);
  color: var(--fc-ink-3);
}

.fc-scope .fc-diag-notice {
  margin: 10px 0 0;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--fc-ink-2);
  overflow-wrap: anywhere;
}
.fc-scope .fc-diag-notice--bad,
.fc-scope .fc-diag-notice--warn  { color: var(--fc-warn); }
.fc-scope .fc-diag-notice--muted { color: var(--fc-ink-4); }

.fc-scope .fc-diag-loading { margin: 10px 0 0; font-size: var(--fs-sm); color: var(--fc-ink-3); }
.fc-scope .fc-diag-loading .icon { margin-right: 8px; color: var(--fc-ink-4); }

.fc-scope .fc-diag-raw { padding-top: 12px; }
.fc-scope .fc-diag-raw > summary {
  cursor: pointer;
  font-size: var(--fs-sm);
  color: var(--fc-ink-3);
}
.fc-scope .fc-diag-raw > summary:hover { color: var(--fc-ink); }
.fc-scope .fc-diag-rawblock { padding-top: 10px; }
.fc-scope .fc-diag-rawname {
  font-size: var(--fs-xs);
  color: var(--fc-ink-4);
}
.fc-scope .fc-diag-rawblock pre {
  margin: 4px 0 0;
  padding: 8px 10px;
  overflow-x: auto;
  background: var(--fc-fill-hover);
  border: 1px solid var(--fc-edge-hair);
  border-radius: 3px;
  font-size: var(--fs-xs);
  line-height: 1.45;
  color: var(--fc-ink-2);
}

/* ---- Wertalarme --------------------------------------------------------- */
/* Der Aufklapper "Alarme" im Geraeteblatt. Aufbau wie die Ereignisliste des
   API-Logs: kein <table>, sondern ein Raster aus Spalten, damit die Zeile auf
   dem Telefon umbrechen kann. Keine neuen Farbtoken — "ausgeloest" ist
   --fc-warn wie jeder andere auffaellige Zustand, "ruhig" bleibt ruhige Tinte.
   Gruen gibt es in dieser Oberflaeche nicht. */
.fc-scope .fc-alarms { padding-top: 4px; }

.fc-scope .fc-alarm-empty {
  margin: 0;
  padding: 4px 4px 10px;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--fc-ink-3);
}

.fc-scope .fc-alarm-list { display: flex; flex-direction: column; }
.fc-scope .fc-alarm {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr) minmax(0, 1.2fr) 150px auto;
  gap: 16px;
  align-items: center;
  min-height: 44px;
  padding: 0 4px;
  border-bottom: 1px solid var(--fc-edge-soft);
  font-size: var(--fs-sm);
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  color: var(--fc-ink);
}
.fc-scope .fc-alarm:hover { background-color: var(--fc-fill-hover); }
/* Eine stumme Regel bleibt lesbar, tritt aber zurueck — sie wertet nicht aus. */
.fc-scope .fc-alarm.is-muted .fc-alarm-series,
.fc-scope .fc-alarm.is-muted .fc-alarm-rule,
.fc-scope .fc-alarm.is-muted .fc-alarm-to { color: var(--fc-ink-4); }

.fc-scope .fc-alarm-series { color: var(--fc-ink-2); overflow-wrap: anywhere; }
.fc-scope .fc-alarm-rule   { font-weight: 500; overflow-wrap: anywhere; }
.fc-scope .fc-alarm-to     { color: var(--fc-ink-3); overflow-wrap: anywhere; }
.fc-scope .fc-alarm-state  { color: var(--fc-ink-3); }
.fc-scope .fc-alarm-state--bad   { font-weight: 500; color: var(--fc-warn); }
.fc-scope .fc-alarm-state--muted { color: var(--fc-ink-4); }
.fc-scope .fc-alarm-actions { display: flex; align-items: center; gap: 2px; justify-self: end; }

.fc-scope .fc-alarm-foot { display: flex; align-items: center; padding-top: 10px; }

/* ---- Befunde und Übersicht (Nachtrag 2) ---------------------------------
   Additiv, damit sich am Geräteblatt kein Pixel bewegt: .fc-alarm ist ein
   Fünf-Spalten-Raster mit eigener Mobil-Umlegung über grid-area, und es gehört
   dem Blatt. Eine sechste Spalte hieße, beide Regelsätze zu ändern. Der Befund
   ist deshalb eine zweite ZEILE in der betroffenen Zelle — das Raster bleibt
   unberührt, die Zeile wächst. Das Blatt gibt .fc-alarm-flag nie aus. */
.fc-scope .fc-alarm-flag {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-xs);
  line-height: 1.3;
  font-weight: 400;
  color: var(--fc-warn);
}

/* "mit Entwarnung" — dieselbe additive Bauform wie der Befund darüber, aber in
   Fließtextfarbe: das ist eine EINSTELLUNG der Regel, kein Fund. In Warnfarbe
   gelesen wäre sie ein Problem, das sie nicht ist. Diese Zeile geben beide
   Seiten aus, das Geräteblatt und die Übersicht. */
.fc-scope .fc-alarm-note {
  display: block;
  margin-top: 2px;
  font-size: var(--fs-xs);
  line-height: 1.3;
  font-weight: 400;
  color: var(--fc-ink-3);
}
.fc-scope .fc-alarm.is-muted .fc-alarm-note { color: var(--fc-ink-4); }

/* Der Schalter im Regelformular steht in einer Rasterzeile neben .fc-input-
   Feldern und braucht deren Höhe, sonst sitzt er am oberen Rand seiner Zelle —
   dieselbe Angleichung wie bei .fc-alarm-own. */
.fc-scope .fc-alarm-switch { min-height: 38px; }

/* Der Seitenkopf der Übersicht: die Zählung steht neben dem Neuladen-Knopf,
   nicht in der Navigationsleiste — main.php lädt einmal je Sitzung, ein Zähler
   dort wäre nach dem ersten Alarm stundenlang falsch. */
.fc-scope .fc-alarm-counts {
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--fc-ink-3);
  font-variant-numeric: tabular-nums;
}

/* Der Seitenkopf des API-Logs steht direkt ueber .fc-column-list, deren
   .fc-list-head den Abstand mitbringt. Die Uebersicht hat keine Liste
   darunter, sondern gleich eine Gruppenueberschrift — sie holt sich den
   Abstand, den .fc-page-title im Seitenkopf abgibt, hier zurueck. Auf die
   eigene Seite begrenzt, damit das API-Log sich nicht bewegt. */
.fc-scope.alarm-overview .al-pagehead { margin-bottom: 1.125rem; }

.fc-scope .fc-alarm-group + .fc-alarm-group { margin-top: 26px; }
.fc-scope .fc-alarm-group-title {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 0 4px 6px;
  border-bottom: 1px solid var(--fc-edge);
  font-size: var(--fs-xs);
  line-height: 1.3;
  font-weight: 500;
  color: var(--fc-ink-2);
}
.fc-scope .fc-alarm-group-title--warn { color: var(--fc-warn); }
.fc-scope .fc-alarm-group-count {
  font-weight: 400;
  color: var(--fc-ink-4);
  font-variant-numeric: tabular-nums;
}

/* Marker in der Geräteliste: die Glocke steht rechts, vor dem Lieferzustand.
   .fc-item-status trägt margin-left:auto — zwei automatische Ränder teilten
   sich den Freiraum und schöben die Glocke in die Mitte, deshalb übernimmt sie
   ihn und die Nachbarregel nimmt ihn dem Zustand wieder ab. Ohne ausgelöste
   Regel wird keines der beiden Elemente gerendert und die Liste ist wie zuvor. */
.fc-scope .fc-item-alarm {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-sm);
  line-height: 1;
  font-weight: 500;
  white-space: nowrap;
  color: var(--fc-warn);
  font-variant-numeric: tabular-nums;
}
.fc-scope .fc-item-alarm + .fc-item-status { margin-left: 0; }

/* Das Formular traegt Anlegen UND Bearbeiten und steht deshalb nur EINMAL auf
   der Seite. js/app.js haengt es unter die Zeile, die es bearbeitet — in der
   Alarm-Uebersicht stuende es sonst unter Dutzenden Regeln statt unter der
   gemeinten. Die Liste rueckt dabei um seine Hoehe nach; der Rahmen grenzt es
   gegen die Zeilen ab, zwischen denen es dann steht. */
.fc-scope .fc-alarm-form {
  margin: 4px 0;
  padding: 12px 14px 14px;
  border: 1px solid var(--fc-edge-edit);
  border-radius: 3px;
}
.fc-scope .fc-alarm-form .fc-field-grid-inner { margin-top: 0; }

/* Die Feineinstellung im Regelformular. Steht nach der Regel selbst und rückt
   von ihr ab; die Regel oben ist die Aussage, das hier sind die Vorbehalte.
   Der margin-top muss nach der Zeile darüber stehen — die nimmt ihn sonst als
   Nachfahre von .fc-alarm-form auf 0 zurück. */
.fc-scope .fc-alarm-fine { margin-top: 14px; }
.fc-scope .fc-alarm-fine .fc-field-grid-inner { margin-top: 10px; }
.fc-scope .fc-alarm-form-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 12px;
}
/* Kein Eingabefeld, sondern ein fester Wert an der Stelle, an der sonst eins
   staende: der Hinweis, an wen die Mail geht (fuer Nicht-Administratoren setzt
   der Endpunkt die Adresse selbst), und in der Alarm-Uebersicht Serie und
   Datensatz — dort sind sie nicht waehlbar, sie SIND die Regel. Gleiche Hoehe
   wie ein Eingabefeld, damit die Reihe nicht springt. */
.fc-scope .fc-alarm-own,
.fc-scope .fc-alarm-fixed {
  min-height: 38px;
  display: flex;
  align-items: center;
  font-size: var(--fs-sm);
  line-height: 1.3;
  color: var(--fc-ink-3);
  overflow-wrap: anywhere;
}
/* Der feste Wert ist die Aussage, nicht der Vorbehalt — er traegt deshalb die
   normale Schriftfarbe. */
.fc-scope .fc-alarm-fixed { color: var(--fc-ink); font-weight: 500; }

/* ---- Responsiv ---------------------------------------------------------- */
@media (max-width: 1099.98px) {
  .fc-scope .fc-layout { grid-template-columns: 240px 1fr; gap: 20px; }
  .fc-scope .fc-edit-identity { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 899.98px) {
  /* Einspaltig: Liste zuerst, das Blatt darunter. Die gewählte Zeile greift
     dann in nichts mehr hinein und bekommt ihre rechte Kante zurück. */
  .fc-scope .fc-layout { grid-template-columns: 1fr; gap: 20px; }
  .fc-scope .fc-list-item.is-selected { border-right: 1px solid var(--fc-edge); border-radius: 4px; }

  .fc-scope .fc-field-grid { grid-template-columns: 1fr; }
  .fc-scope .fc-edit-identity { grid-template-columns: 1fr; }

  /* Bezeichnung ueber den Wert: 132px Spalte lassen auf dem Telefon zu wenig
     fuer die Zahlen daneben. */
  .fc-scope .fc-diag-row { grid-template-columns: 1fr; gap: 2px; }
  .fc-scope .fc-diag-reload { margin-left: 0; }

  /* Die Regelzeile wird zweizeilig: Regel und Zustand oben, Serie und
     Empfaenger darunter — fuenf Spalten sind auf dem Telefon keine 60 px breit. */
  .fc-scope .fc-alarm {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 12px;
    padding: 10px 4px;
  }
  .fc-scope .fc-alarm-rule    { grid-area: 1 / 1 / 2 / 2; }
  .fc-scope .fc-alarm-actions { grid-area: 1 / 2 / 3 / 3; align-self: start; }
  .fc-scope .fc-alarm-state   { grid-area: 2 / 1 / 3 / 2; }
  .fc-scope .fc-alarm-series  { grid-area: 3 / 1 / 4 / 2; }
  .fc-scope .fc-alarm-to      { grid-area: 4 / 1 / 5 / 2; }

  .fc-scope .fc-dataset { grid-template-columns: 28px 1fr auto; gap: 2px 12px; }
  .fc-scope .fc-ds-nr       { grid-area: 1 / 1 / 3 / 2; align-self: start; }
  .fc-scope .fc-ds-label    { grid-area: 1 / 2 / 2 / 3; }
  .fc-scope .fc-ds-unit     { grid-area: 1 / 3 / 2 / 4; }
  .fc-scope .fc-ds-decimals { grid-area: 2 / 2 / 3 / 3; }
  .fc-scope .fc-ds-type     { grid-area: 2 / 3 / 3 / 4; }

  .fc-scope .fc-edit-headrow { display: none; }
  .fc-scope .fc-edit-row { grid-template-columns: 28px 1fr 96px; gap: 6px 12px; }
  .fc-scope .fc-edit-row .fc-edit-nr { grid-area: 1 / 1 / 3 / 2; align-self: center; }
  .fc-scope .fc-edit-row > :nth-child(2) { grid-area: 1 / 2 / 2 / 3; }
  .fc-scope .fc-edit-row > :nth-child(3) { grid-area: 1 / 3 / 2 / 4; }
  .fc-scope .fc-edit-row > :nth-child(4) { grid-area: 2 / 2 / 3 / 3; }
  .fc-scope .fc-edit-row > :nth-child(5) { grid-area: 2 / 3 / 3 / 4; }
}

/* ===========================================================================
   Benutzerverwaltung — dasselbe Blatt, andere Felder
   maintain-user.php trägt .fc-scope und benutzt damit Rahmen, Liste, Felder
   und Aufklapper der Feed-Konfiguration unverändert. Hier stehen nur die
   Stücke, die es dort nicht gibt: die Einspalter-Ansicht des Anwenders, die
   Zeilen des Feed-Zugriffs, die gespeicherten Anmeldungen und der Fuß des
   Blattes, in dem das Löschen sitzt.
   =========================================================================== */

/* Ein Anwender verwaltet nur sich selbst — ohne Liste links steht das Blatt
   allein, und über die volle Breite wären drei Felder in viel Leere. Gedeckelt
   sind deshalb Überschrift UND Blatt, und beide mittig: deckelt man nur das
   Blatt, klebt die Karte am linken Rand des .app-container und rechts bleibt
   die Lücke stehen, die im Adminfall die Benutzerliste füllt. Der Deckel sitzt
   bewusst nicht am .app-container selbst — der bringt die gestuften Breiten
   und die Seitenabstände mit, die sonst beide überschrieben wären. */
.user-config--single > .fc-page-title,
.user-config--single > .uc-single { max-width: 880px; margin-inline: auto; }

.fc-scope .fc-section-access   { gap: 14px; padding: 20px 24px; border-bottom: 1px solid var(--fc-edge-soft); }
.fc-scope .fc-section-sessions { gap: 14px; padding: 20px 24px 24px; }

/* Der Fuß trägt links die destruktive Aktion, rechts denselben Hinweis wie die
   Serienbearbeitung der Feed-Konfiguration. */
.fc-scope .fc-sheet-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 24px;
  border-top: 1px solid var(--fc-edge-hair);
}

/* Ein Feld über die ganze Zeile — die Passwortzeile des eigenen Kontos hat drei
   Felder und den Knopf, der damit in die zweite Zeile rutscht. */
.fc-scope .fc-field-wide { grid-column: 1 / -1; align-items: flex-start; }
/* Im Aufklapper ist die Zeile kein Raster mehr, sondern eine umbrechende Reihe
   (siehe .fc-field-grid-inner) — die ganze Zeile macht dort die Flex-Basis. */
.fc-scope .fc-field-grid-inner > .fc-field-wide { flex: 1 1 100%; }

/* ---- Feed-Zugriff -------------------------------------------------------- */
.user-config .uc-access-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 16px;
  border: 1px solid var(--fc-edge-soft);
  border-radius: 3px;
}
.user-config .uc-access-card:hover { background-color: var(--fc-fill-hover); }
/* Ein gesperrtes Gerät tritt zurück, statt sich durch Farbe zu melden — der
   Haken rechts ist das Signal, nicht die Zeile. */
.user-config .uc-access-card.is-off .fc-series-name { font-weight: 400; color: var(--fc-ink-3); }
.user-config .uc-access-hint {
  margin-left: auto;
  font-size: var(--fs-sm);
  line-height: 1.2;
  color: var(--fc-ink-4);
}

/* Die noch nicht freigegebenen Geräte — zugeklappt, bis „Gerät hinzufügen“ im
   Kopf des Abschnitts sie öffnet. Der Abschnitt selbst zeigt nur, was frei
   ist; alle zu zeigen hiess, die Liste mit jedem neuen Feed um eine Zeile
   „kein Zugriff“ zu verlängern. Die Trennlinie hält die beiden Listen
   auseinander. */
.user-config .uc-access-picker {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 14px;
  border-top: 1px solid var(--fc-edge-hair);
}
/* display: flex schlägt das hidden-Attribut — ohne diese Zeile stünde die
   Auswahl immer offen. */
.user-config .uc-access-picker[hidden] { display: none; }
.user-config .uc-access-picker-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.user-config .uc-access-picker-title {
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1;
  color: var(--fc-ink-2);
}

/* ---- Gespeicherte Anmeldungen ------------------------------------------- */
.user-config .uc-session {
  display: grid;
  /* minmax(0, …) statt 1fr: der Client-String steht auf einer Zeile und ohne
     die 0 als Minimum waere die Spalte so breit wie er — die Zeile liefe aus
     dem Blatt heraus, statt zu kuerzen. */
  grid-template-columns: 22px minmax(0, 1fr) auto 28px;
  gap: 12px;
  align-items: center;
  min-height: 44px;
  border-bottom: 1px solid var(--fc-edge-hair);
}
.user-config .uc-session:last-child { border-bottom: 0; }
.user-config .uc-session-icon { font-size: var(--fi-sm); color: var(--fc-ink-4); }
.user-config .uc-session-client {
  font-size: var(--fs-sm);
  line-height: 1.3;
  color: var(--fc-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user-config .uc-session-when {
  font-size: var(--fs-sm);
  line-height: 1.3;
  color: var(--fc-ink-3);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 899.98px) {
  /* Der Client-String ist auf dem Telefon länger als die Zeile — Zeitpunkt
     darunter statt daneben, Symbol und Knopf über beide Zeilen. */
  .user-config .uc-session {
    grid-template-columns: 22px minmax(0, 1fr) 44px;
    grid-template-areas: "icon client button" "icon when button";
    gap: 4px 10px;
    min-height: 52px;
  }
  .user-config .uc-session-icon   { grid-area: icon; }
  .user-config .uc-session-client { grid-area: client; }
  .user-config .uc-session-when   { grid-area: when; }
  .user-config .uc-session > .fc-icon-button { grid-area: button; }

  .user-config .uc-access-card { flex-wrap: wrap; }
  .fc-scope .fc-sheet-foot { flex-direction: column; align-items: flex-start; gap: 10px; }
}

/* ===========================================================================
   API-Log — dasselbe Blatt, andere Einheit
   maintain-api-log.php traegt .fc-scope und benutzt damit Seitenkopf, Layout,
   Liste, Blatt, Abschnitte und Felder der Feed-Konfiguration unveraendert.
   Hier steht nur, was es dort nicht gibt: der Schalter "nur Fehler" im
   Seitenkopf und die Ereignisliste des Blattes.

   Die Ereignisliste ist bewusst kein <table>: sie traegt keine Kopfspalten,
   die sich sortieren liessen, und jede Zeile klappt einen Block darunter auf.
   Ein Raster aus vier Spalten sagt dasselbe und laesst den Aufklapper ueber
   die ganze Breite laufen.
   =========================================================================== */

/* ---- Seitenkopf ---------------------------------------------------------- */
.fc-scope .al-pagehead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
}
/* .fc-page-title bringt seinen eigenen Abstand nach unten mit — im Seitenkopf
   traegt ihn die Zeile, sonst haengen die Bedienelemente daneben zu hoch. */
.fc-scope .al-pagehead > .fc-page-title { margin-bottom: 0; }
.fc-scope .al-pagetools { display: flex; align-items: center; gap: 14px; }

/* ---- Schalter "nur Fehler" ------------------------------------------------
   Kein .form-check.form-switch: dessen Spur ist ein Hintergrundbild, das sich
   nur ueber --bs-form-switch-bg umfaerben laesst, und im dunklen Satz braeuchte
   es ein zweites. Zwei Kaesten und ein Knauf tun dasselbe mit den Tokens. */
.fc-scope .al-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--fc-ink-2);
  cursor: pointer;
}
/* Das Kaestchen bleibt bedienbar und fokussierbar — es liegt unter der Spur,
   nicht in display:none. */
.fc-scope .al-switch-input {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 18px;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.fc-scope .al-switch-track {
  flex: none;
  width: 32px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  padding: 0 2px;
  border: 1px solid var(--fc-edge-strong);
  border-radius: 9px;
  background-color: var(--fc-fill-active);
}
.fc-scope .al-switch-knob {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 1px rgba(46, 32, 24, 0.18);
  transition: transform .15s ease-out;
}
.fc-scope .al-switch-input:checked ~ .al-switch-track { border-color: var(--color-accent); }
.fc-scope .al-switch-input:checked ~ .al-switch-track .al-switch-knob { transform: translateX(14px); }
.fc-scope .al-switch-input:focus-visible ~ .al-switch-track {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .fc-scope .al-switch-knob { transition: none; }
}

/* ---- Liste und Blatt ----------------------------------------------------- */
.fc-scope .al-list-empty { padding: 16px 4px; }
/* Vier Kennzahlen statt der drei Felder der Geraetezeile. */
.fc-scope .al-metrics { grid-template-columns: repeat(4, 1fr); }
.fc-scope .al-value--bad { color: var(--fc-warn); }

/* ---- Ereignisse ---------------------------------------------------------- */
.fc-scope .al-events  { display: flex; flex-direction: column; }
.fc-scope .al-head,
.fc-scope .al-event   { display: grid; grid-template-columns: 96px 72px 1fr 96px;
                        gap: 16px; padding: 0 4px; align-items: center;
                        font-variant-numeric: tabular-nums; }
.fc-scope .al-head    { align-items: baseline; padding-bottom: 6px;
                        border-bottom: 1px solid var(--fc-edge-strong);
                        font-size: var(--fs-xs); font-weight: 500; line-height: 1;
                        color: var(--fc-ink-4); }
.fc-scope .al-event   { min-height: 44px; border-bottom: 1px solid var(--fc-edge-soft);
                        font-size: var(--fs-sm); line-height: 1.3;
                        color: var(--fc-ink); text-decoration: none; }
.fc-scope .al-event:hover { background-color: var(--fc-fill-hover); }
.fc-scope .al-code    { color: var(--fc-ink-2); }
.fc-scope .al-msg     { color: var(--fc-ink-3); overflow-wrap: anywhere; }
.fc-scope .al-msg--warn { color: var(--fc-ink-2); }
.fc-scope .al-code--bad, .fc-scope .al-msg--bad { font-weight: 500; color: var(--fc-warn); }
.fc-scope .al-dur     { text-align: right; color: var(--fc-ink-2); }
.fc-scope .al-day     { padding: 10px 4px 6px; font-size: var(--fs-xs); line-height: 1;
                        color: var(--fc-ink-4); }

/* Die geoeffnete Zeile und ihr Block sind eine Flaeche: der Aufklapper steht
   als Geschwister hinter der Zeile (ein <a> darf ihn nicht enthalten), also
   tragen beide dieselbe Toenung, und die Zeile gibt ihre Trennlinie an ihn ab.
   Der Wert ist das einzige Literal dieses Blocks — im dunklen Satz uebernimmt
   ihn --state-hover. */
.fc-scope .al-event.is-open,
.fc-scope .al-detail  { background-color: #FDFCFA; }
[data-bs-theme="dark"] .fc-scope .al-event.is-open,
[data-bs-theme="dark"] .fc-scope .al-detail { background-color: var(--state-hover); }
.fc-scope .al-event.is-open { border-bottom: none; }
.fc-scope .al-event.is-open:hover { background-color: #FDFCFA; }
[data-bs-theme="dark"] .fc-scope .al-event.is-open:hover { background-color: var(--state-hover); }
.fc-scope .al-event.is-open .al-time,
.fc-scope .al-event.is-open .al-code { font-weight: 500; }

.fc-scope .al-detail  { display: flex; flex-direction: column; gap: 8px;
                        padding: 4px 4px 14px;
                        border-bottom: 1px solid var(--fc-edge-soft); }
.fc-scope .al-detail-head { display: flex; align-items: baseline; gap: 12px;
                        font-size: var(--fs-xs); line-height: 1; color: var(--fc-ink-4); }
.fc-scope .al-detail-count { margin-left: auto; font-variant-numeric: tabular-nums; }
.fc-scope .al-raw     { margin: 0; padding: 12px 14px;
                        background-color: var(--fc-sheet-raw, #FAF8F5);
                        border: 1px solid var(--fc-edge-soft); border-radius: 3px;
                        font: 400 .8125rem/1.65 ui-monospace, SFMono-Regular, Menlo, monospace;
                        color: var(--fc-ink); white-space: pre-wrap; overflow-wrap: anywhere; }
[data-bs-theme="dark"] .fc-scope .al-raw { background-color: var(--fc-edge-hair); }

/* ---- Fuss des Abschnitts ------------------------------------------------- */
.fc-scope .al-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 10px;
  border-top: 1px solid var(--fc-edge-hair);
  font-size: var(--fs-sm);
  line-height: 1;
  color: var(--fc-ink-2);
}
.fc-scope .al-record-value { color: var(--fc-ink-3); }

@media (max-width: 899.98px) {
  /* Vier Kennzahlen nebeneinander sind auf dem Telefon vier schmale Kaesten —
     .fc-field-grid faellt dort ohnehin auf eine Spalte, hier auf zwei. */
  .fc-scope .al-metrics { grid-template-columns: repeat(2, 1fr); }
  /* Die Meldung bekommt die Breite, die Dauer wandert unter den Code. */
  .fc-scope .al-head { display: none; }
  .fc-scope .al-event { grid-template-columns: 84px 1fr; gap: 2px 12px; padding: 8px 4px; }
  .fc-scope .al-event .al-time { grid-area: 1 / 1 / 2 / 2; }
  .fc-scope .al-event .al-code { grid-area: 2 / 1 / 3 / 2; }
  .fc-scope .al-event .al-msg  { grid-area: 1 / 2 / 2 / 3; }
  .fc-scope .al-event .al-dur  { grid-area: 2 / 2 / 3 / 3; }
  .fc-scope .al-foot { flex-direction: column; align-items: flex-start; gap: 8px; }
}

/* ===========================================================================
   Bootstrap-JS abgeloest (Stufe 2, docs/bootstrap-evaluation.md)
   Das Verhalten von Dialog, Aufklapper, Menue und Tooltip steht in js/ui.js.
   Seit Stufe 3c (docs/bootstrap-stufe3-plan.md) steht hier auch ihre ganze
   Optik: Dialog (3a), dazu Aufklapper und Menue — alle vier tragen eigene
   Klassen (.ui-*), keine erbt noch etwas von Bootstrap.
   =========================================================================== */

/* ---- Dialog: <dialog class="ui-dialog"> -----------------------------------
   Stufe 3a: eigene Klassen statt .modal/.modal-dialog/.modal-content/.fade.
   Der Grund fuer eigene Namen statt "Bootstraps Namen behalten und
   ueberschreiben" steht im Plan: nur so ist der Schnitt beweisbar — Bootstraps
   .modal*-Regeln greifen an keinem Element mehr, und grep sagt das. Der Preis
   waren zwei Selektoren in js/app.js.

   Die Huelle ist BEWUSST UNSCOPED (wie .ui-tooltip), der Inhalt bleibt fc-*.
   Die --fc-*-Token stehen aber auf .fc-scope: ein Dialog ausserhalb steht ohne
   sie da und ist farblos. Die fuenf Dialoge liegen innerhalb (maintain-feed.php,
   maintain-user.php) — EIN NEUER DIALOG TRAEGT .fc-scope SELBST.

   Nicht gesetzt wird display: ein geschlossenes <dialog> versteckt die
   UA-Regel, ein offenes zeigt sie. Bootstraps .modal{display:none} war der
   einzige Grund, warum hier frueher ein dialog[open]{display:block} stehen
   musste. */
dialog.ui-dialog {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  overflow-y: auto;
  /* Kein Weiterreichen des Scrollens an die Seite darunter. Bootstrap sperrte
     dafuer den Body und musste die Scrollbar-Breite ausgleichen; das hier
     kostet keinen Layout-Sprung. */
  overscroll-behavior: contain;
  /* Ersetzt .fade: js/ui.js setzt .show im naechsten Frame nach showModal()
     und nimmt sie DIALOG_FADE_MS vor dem close() wieder weg. */
  opacity: 0;
  transition: opacity .15s linear;
}

dialog.ui-dialog.show { opacity: 1; }

/* Ersetzt .modal-backdrop. Die Werte sind Bootstraps --bs-backdrop-bg und
   --bs-backdrop-opacity. */
dialog.ui-dialog::backdrop {
  background-color: #000;
  opacity: .5;
}

/* pointer-events: none IST DER RANDKLICK. <dialog> fuellt den Bildschirm; der
   Rahmen laesst Klicks durch, der Inhalt faengt sie wieder (.ui-dialog-panel),
   der Treffer landet also auf dem Dialog selbst — und genau darauf prueft
   js/ui.js. Faellt die Zeile weg, passiert zweierlei ohne Fehlermeldung: der
   Randklick schliesst nicht mehr, und ein Klick INS Formular schliesst den
   Dialog samt Eingaben. */
.ui-dialog-frame {
  position: relative;
  width: auto;
  margin: .5rem;
  pointer-events: none;
  transform: translateY(-50px);
  transition: transform .3s ease-out;
}

dialog.ui-dialog.show .ui-dialog-frame { transform: none; }

@media (min-width: 576px) {
  .ui-dialog-frame { max-width: 500px; margin: 1.75rem auto; }
}

/* Bootstrap blendet seine Uebergaenge hier selbst aus (.fade{transition:none}).
   Ohne dieselbe Ausnahme wartete js/ui.js auf ein transitionend, das nie kommt
   — reduceMotion() dort und diese Regel gehoeren zusammen. */
@media (prefers-reduced-motion: reduce) {
  dialog.ui-dialog,
  .ui-dialog-frame { transition: none; }
}

/* Flaeche wie ein Blatt (.fc-sheet): derselbe Traeger, dieselben Kanten. Damit
   faellt auch der dunkle Sonderfall weg, der frueher .modal-header und
   .modal-footer auf #454545 legte — die Token machen das mit. */
.ui-dialog-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  pointer-events: auto;
  border: 1px solid var(--fc-edge);
  border-radius: 4px;
  background: var(--fc-sheet);
  box-shadow: var(--shadow-rest);
  color: var(--fc-ink);
}

.ui-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 24px;
  border-bottom: 1px solid var(--fc-edge-soft);
}

.ui-dialog-title {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 500;
  line-height: 1.3;
  color: var(--fc-ink);
}

/* Die Abstaende zwischen den Feldern kommen aus dem gap, nicht mehr aus einem
   .mb-3 an jedem einzelnen. Zwei Folgen, beide gewollt: ein leerer
   Fehlerbehaelter darf keine Luecke aufreissen (er steht in jedem Dialog und
   ist die meiste Zeit leer), und ein Absatz bringt seine eigenen Raender nicht
   mehr mit. */
.ui-dialog-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 20px 24px;
  overflow-y: auto;
}

.ui-dialog-body > .error-message:empty { display: none; }
.ui-dialog-body > p { margin: 0; }

.ui-dialog-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 24px;
  border-top: 1px solid var(--fc-edge-soft);
}

/* ---- Aufklapper: .ui-collapse / .ui-collapsing ----------------------------
   Stufe 3c: eigene Klassen statt .collapse/.collapsing. .show bleibt als
   Zustandsklasse — sie ist generisch, js/ui.js setzt sie selbst und teilt sie
   mit Dialog, Menue und Tooltip.

   DIE TRANSITION IST TEIL DES VERTRAGS mit js/ui.js: die Funktion misst die
   Hoehe, setzt sie und wartet auf transitionend, mit setTimeout(finish, 500)
   als Notausgang. Faellt die Transition weg (oder wird sie laenger als die
   500 ms), springt der Aufklapper statt zu fahren und niemand sieht einen
   Fehler. Die .35s hier und die 500 ms dort gehoeren zusammen. */
.ui-collapse:not(.show) { display: none; }

.ui-collapsing {
  height: 0;
  overflow: hidden;
  transition: height .35s ease;
}

/* Der zweite Ausschalter der Uebergaenge: js/ui.js fragt dieselbe Media Query
   ab und geht dann ohne Animation durch (reduceMotion()). */
@media (prefers-reduced-motion: reduce) {
  .ui-collapsing { transition: none; }
}

/* ---- Menue: .ui-menu, Position ohne Popper --------------------------------
   Stufe 3c: eigene Klassen statt .dropdown/.dropdown-menu/.dropdown-menu-end/
   .dropdown-item. Die Werte sind Bootstraps Werte; die Token heissen --ui-menu-*
   statt --bs-dropdown-*, damit die Leiste sie weiter umlegen kann (main.php,
   .main-nav .nav-menu).

   Bootstrap setzte top/right/left ausschliesslich unter [data-bs-popper] —
   ohne Popper stuende das Menue sonst an seiner statischen Stelle. Beide
   Menues der App haengen rechtsbuendig unter ihrem Schalter: das Kontomenue
   der Leiste und der Diagrammtyp der Serienbearbeitung. */
.ui-menu-wrap { position: relative; }

.ui-menu {
  --ui-menu-padding-x:    0;
  --ui-menu-padding-y:    .5rem;
  --ui-menu-spacer:       .125rem;
  --ui-menu-min-width:    10rem;
  --ui-menu-bg:           var(--app-bg);
  --ui-menu-border-color: var(--app-border-soft);
  --ui-menu-border-radius: var(--app-radius);

  position: absolute;
  z-index: 1000;
  display: none;
  min-width: var(--ui-menu-min-width);
  padding: var(--ui-menu-padding-y) var(--ui-menu-padding-x);
  margin: 0;
  font-size: var(--fs-base);
  color: var(--app-ink);
  text-align: left;
  list-style: none;
  background-color: var(--ui-menu-bg);
  background-clip: padding-box;
  border: 1px solid var(--ui-menu-border-color);
  border-radius: var(--ui-menu-border-radius);
}

.ui-menu.show {
  display: block;
  top: 100%;
  left: 0;
  right: auto;
  margin-top: var(--ui-menu-spacer);
  margin-bottom: 0;
}

.ui-menu--end.show {
  left: auto;
  right: 0;
}

/* Kein Platz nach unten — js/ui.js klappt dann nach oben, wie Popper es tat. */
.ui-menu.show.is-dropup {
  top: auto;
  bottom: 100%;
  margin-top: 0;
  margin-bottom: var(--ui-menu-spacer);
}

/* Der Eintrag. Nur das Menue der Serienbearbeitung benutzt ihn; die Leiste hat
   mit .nav-menu-item ihren eigenen (main.php). */
.ui-menu-item {
  display: block;
  width: 100%;
  padding: .25rem 1rem;
  clear: both;
  font-weight: 400;
  color: var(--app-ink);
  text-align: inherit;
  text-decoration: none;
  white-space: nowrap;
  background-color: transparent;
  border: 0;
  border-radius: 0;
}

.ui-menu-item:hover,
.ui-menu-item:focus { background-color: var(--app-bg-soft); }

/* Gedrueckt. Bootstrap legte hier sein kompiliertes #0d6efd hin — ein Blau,
   das keine Variable mehr liest und im Projekt sonst nirgends vorkommt
   (derselbe Fall wie der Fokusring, siehe ganz oben). Es weicht der warmen
   Interaktionsskala; das ist die einzige bewusste Abweichung von "3c aendert
   nichts am Aussehen", und sie faellt nur beim Druecken auf. */
.ui-menu-item:active { background-color: var(--state-press); }

/* Der Abstand zwischen Typ-Glyphe und Name — stand als .me-2 im Markup
   (js/app.js). */
.ui-menu-item [class^="icon-"] { margin-right: .5rem; }

/* ---- Tooltip --------------------------------------------------------------
   Bewusst ohne Pfeil: ohne Poppers Randkorrektur zeigte er am Bildschirmrand
   nicht mehr auf sein Element. Werte sonst wie Bootstraps .tooltip-inner. */
.ui-tooltip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1080;                 /* == --bs-tooltip-zindex */
  max-width: 200px;
  padding: .25rem .5rem;
  border-radius: var(--app-radius);
  background-color: #000;
  color: #fff;
  font-size: var(--fs-sm);
  line-height: 1.4;
  text-align: center;
  pointer-events: none;          /* darf das eigene Element nie ueberdecken */
  opacity: 0;
  transition: opacity .15s linear;
}

.ui-tooltip.show { opacity: .9; }   /* == --bs-tooltip-opacity */

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

/* ===========================================================================
   Bootstrap-CSS abgeloest (Stufe 3c, docs/bootstrap-stufe3-plan.md)
   Hier steht, was vorher Bootstraps CSS beigesteuert hat und wofuer es keine
   eigene Komponente gab: die Seitenbreite, die Warnhinweise und die eine
   Zustandsklasse, die aus JavaScript gesetzt wird.

   Wie bei den Dialogen in 3a: EIGENE NAMEN, nicht Bootstraps behalten. Nur so
   ist der Schnitt beweisbar — Bootstraps .container, .alert und .d-none greifen an
   keinem Element mehr, und grep sagt das.

   Die Werte sind Bootstraps Werte, nicht neue. 3c ist Aufraeumen, kein
   Redesign: so bleibt der Screenshot-Vergleich aus docs/ui-preview.php eine
   echte Pruefung und keine Erwartungsliste.
   =========================================================================== */

/* ---- Seitenbreite: loest .container ab ------------------------------------
   Die GESTUFTEN Breiten sind der Punkt. css/theme.css beruft sich weiter unten
   ausdruecklich darauf (".user-config--single" — der Deckel sitzt bewusst
   nicht hier). Wer sie durch ein pauschales max-width ersetzt, verschiebt das
   Blatt der Benutzerverwaltung auf jedem Breakpoint und die Leiste gleich mit.

   Der Seitenabstand ist fest statt ueber --bs-gutter-x gerechnet: die Variable
   hatte genau einen Leser (diese Regel) und einen Schreiber (die Mobil-Regel
   unten, frueher im Inline-Block von main.php). */
.app-container {
  width: 100%;
  padding-inline: .75rem;
  margin-inline: auto;
}

/* Mehr Luft auf dem Telefon — frueher --bs-gutter-x: 2rem in main.php. */
@media (max-width: 767.98px) { .app-container { padding-inline: 1rem; } }

@media (min-width:  576px) { .app-container { max-width:  540px; } }
@media (min-width:  768px) { .app-container { max-width:  720px; } }
@media (min-width:  992px) { .app-container { max-width:  960px; } }
@media (min-width: 1200px) { .app-container { max-width: 1140px; } }
@media (min-width: 1400px) { .app-container { max-width: 1320px; } }

/* ---- Warnhinweise: loesen .alert/.alert-danger/-warning/-success ab --------
   Vier Fundstellen im Markup (main-feeds.php) und zwei in JavaScript
   (js/main.js, js/app.js — dort als `app-alert app-alert--${type}`, der Typ
   kommt aus _showModalAlert()). Die Anmeldemaske hat ihren eigenen Hinweis im
   Inline-CSS von index.php; sie laedt den Icon-Sprite nicht und hat genau
   einen Fall (Stufe 3b).

   Die Farben sind Bootstraps kompilierte Werte fuer *-bg-subtle,
   *-border-subtle und *-text-emphasis, hier als feste Hex-Werte statt als
   --bs-*-Variablen: die Variablen verschwinden mit der Datei (Stufe 3d), und
   ein Hinweis ohne Flaeche faellt nicht auf — er sieht aus wie Text.
   Sie auf --color-error umzustellen waere ein Design-Durchgang, kein
   Aufraeumen, und gehoert damit nicht hierher. */
.app-alert {
  position: relative;
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid transparent;
  border-radius: var(--app-radius);
}

.app-alert--danger  { color: #58151c; background-color: #f8d7da; border-color: #f1aeb5; }
.app-alert--warning { color: #664d03; background-color: #fff3cd; border-color: #ffe69c; }
.app-alert--success { color: #0a3622; background-color: #d1e7dd; border-color: #a3cfbb; }

[data-bs-theme="dark"] .app-alert--danger  { color: #ea868f; background-color: #2c0b0e; border-color: #842029; }
[data-bs-theme="dark"] .app-alert--warning { color: #ffda6a; background-color: #332701; border-color: #997404; }
[data-bs-theme="dark"] .app-alert--success { color: #75b798; background-color: #051b11; border-color: #0f5132; }

/* ---- Ausblenden: loest .d-none ab -----------------------------------------
   Die einzige generische Hilfsklasse, die uebrig bleibt, und die einzige, die
   aus JavaScript gesetzt wird (js/main.js: Ladeanzeige des Diagramms und die
   Zoomstufen einer Gruppe; js/app.js: der Hinweis unter dem Haekchen der
   Zaehlergruppe). Der Name folgt .is-active/.is-off/.is-dropup, die es im
   Projekt schon gibt.

   !important wie bei Bootstrap: die Klasse muss gegen ein display aus einer
   Komponentenregel gewinnen, sonst blendet sie nichts aus. */
.is-hidden { display: none !important; }

/* ---- Ladeanzeige: loest .text-secondary.text-center ab --------------------
   Zwei Fundstellen in js/main.js: die grosse Anzeige, solange die Kachelseite
   laedt, und die kleine im Panel eines Fragments. Die Panel-Variante trug
   zusaetzlich .mt-4.mb-4 am Icon — der Abstand gehoert an den Absatz, nicht an
   das Zeichen darin. #6c757d ist Bootstraps --bs-secondary-rgb, das in beiden
   Themes denselben Wert hat. */
.app-loading { text-align: center; color: #6c757d; }
.app-loading--panel { margin-block: 1.5rem; }
