/* meteoCORE — Werte und Bausteine, Fassung 1.35.0.
   ERZEUGT aus design-tokens (scripts/build.mjs) — nicht von Hand aendern.
   Liegt auf images.meteocore.com und wird von den statischen Seiten
   per <link> geholt (E16). Anwendungen nehmen stattdessen das npm-Paket. */

/* meteoCORE Design Tokens
   GENERIERT von scripts/build.mjs — nicht von Hand ändern.
   Quelle: src/tokens.json, src/tokens.dark.json, src/tokens.light.json
   Erneuern mit: npm run build */

:root {
  /* Himmelblau — primär */
  --brand-blue: #007AC2;
  /* Signalblau — Verlaufsende, gedrückter Zustand, Links auf hellem Grund (E9) */
  --brand-blue-dark: #004B87;
  /* Leuchtorange — einzige Haupt-CTA-Farbe, Farbe des Rubrik-Kickers (E3) */
  --brand-orange: #F75E0E;
  /* Nachtmodus-Akzent */
  --brand-indigo: #1A237E;
  /* Verkehrsrot — Datenerfassung (meteoOBS, meteoCOLLECT) */
  --spectrum-ingest: #E6001A;
  /* Leuchtorange — Kerninfrastruktur (meteoCORE) */
  --spectrum-core: #F75E0E;
  /* Verkehrsgelb — Skalierung, provideragnostisches Mesh (meteoSCALE, meteoNODE) */
  --spectrum-scale: #F7B500;
  /* Reingrün — Korrelation und Business Intelligence (meteoDETECT, meteoPATTERN) */
  --spectrum-detect: #009739;
  /* Signalblau — Handel und Verteilung von Wetterdaten (meteoBROKER, meteoVECTOR) */
  --spectrum-broker: #004B87;
  /* Signalviolett — Endabnehmer (meteoNAVI, meteoREADY, meteoCOACH, meteoFORENSICS) */
  --spectrum-endkunde: #92278F;
  /* Wetterwarnung */
  --warn-1: #FFD500;
  /* Markantes Wetter */
  --warn-2: #FF9500;
  /* Unwetter */
  --warn-3: #FF2222;
  /* Extremes Unwetter */
  --warn-4: #C724B1;
  /* Keine Warnung, entwarnt */
  --warn-ok: #22C55E;
  /* Stufe unbekannt — ein Datenfall, keine Warnstufe */
  --warn-unknown: #9E9E9E;
  /* Die dunklere Fassung des Tons, wenn er gegen Helles stehen muss. Zwei Anwendungen: Umriss deckend gefüllter Warnflächen auf der Karte (warnlage-plan.md) und Bannerkante im Hell-Theme (E8). Gebildet als dieselbe Farbe auf 60 % Helligkeit, jeder Kanal mal 0,6 — multiplikativ statt über HSL, weil der Farbton dabei exakt erhalten bleibt. */
  --warn-1-edge: #998000;
  /* siehe warn-1-edge */
  --warn-2-edge: #995900;
  /* siehe warn-1-edge */
  --warn-3-edge: #991414;
  /* siehe warn-1-edge */
  --warn-4-edge: #77166A;
  /* siehe warn-1-edge; ergänzt 2026-09-07 (E8), wertgleich mit ui-success-edge */
  --warn-ok-edge: #147638;
  /* siehe warn-1-edge */
  --warn-unknown-edge: #5F5F5F;
  /* Hinweis */
  --ui-info: var(--brand-blue);
  /* Erfolg */
  --ui-success: var(--warn-ok);
  /* Achtung */
  --ui-warning: var(--warn-2);
  /* Fehler. War in Kontoverwaltung und Login-Theme bereits der faktische Fehlerton, hatte nur keinen Namen (DSG-32). Trägt Text und Kanten, nicht gefüllte Flächen. */
  --ui-danger: #FF6B6B;
  /* Gefüllte Gefahrflächen, etwa der Bestätigungsknopf eines destruktiven Dialogs (E18). ui-danger erreicht als Fläche mit weißer Schrift nur 2,78:1; dieser Ton erreicht 5,44:1. Bestimmt im Wertelabor 2026-09-07. */
  --ui-danger-solid: #C0392B;
  /* Die dunklere Fassung des Tons für hellen Grund — Bannerkante und zugleich Meldungstext im Hell-Theme (E8). Farbe mal 0,6. */
  --ui-info-edge: #004974;
  /* siehe ui-info-edge */
  --ui-success-edge: #147638;
  /* siehe ui-info-edge */
  --ui-warning-edge: #995900;
  /* siehe ui-info-edge */
  --ui-danger-edge: #994040;
  /* Öffentliche Entwickler-Instanz (*.meteocore.dev) */
  --env-dev: #F75E0E;
  /* Lokale Entwicklungsumgebung */
  --env-local: #F7B500;
  /* Schrift auf einem hellen gesättigten Marker — Leuchtorange, Verkehrsgelb und was sonst als Fläche gesetzt wird, aber keinen Text tragen kann. Weiß erreicht auf dem Orange nur 3,2:1 und fällt für den 11-px-Text durch, dieser Ton erreicht 5,84:1 beziehungsweise 10,3:1 auf dem Gelb. Gilt in beiden Helligkeiten: Der Marker trägt seinen Ton unabhängig vom Grund, also auch seine Schrift. */
  --text-on-marker: #171200;
  /* Altname aus der Zeit, als das Umgebungsband (E17) der einzige Fall war. Inzwischen tragen ihn auch der Zähler, das Spektrum-Tag „scale" und die bezahlten NAVI-Stufen — der Name log also. Er bleibt als Alias stehen, weil die Präsentationen ihre Tokenkopie noch unter diesem Namen führen. */
  --text-on-env: var(--text-on-marker);
  /* Rand eines Prognose-Termins. Bestimmt im Wertelabor 2026-09-07: der einzige geprüfte Ton mit 3:1 auf allen drei Chipfüllungen (6,67 / 7,41 / 3,23) und zugleich Abstand zu warn-4 (2,05:1). Der frühere Ton #92278F erreichte gegen die Chipfüllung nur 2,20:1. */
  --data-forecast: #E08ADB;
  /* sehr kalt */
  --viz-temp-1: #1A237E;
  /* kalt */
  --viz-temp-2: #004B87;
  /* mild */
  --viz-temp-3: #007AC2;
  /* warm */
  --viz-temp-4: #F7B500;
  /* heiß */
  --viz-temp-5: #F75E0E;
  /* sehr heiß */
  --viz-temp-6: #E6001A;
  /* Niederschlag — monochrome Blau-Rampe nach Intensität und Wahrscheinlichkeit */
  --viz-precip-1: #BFE3F5;
  --viz-precip-2: #6EC1E8;
  --viz-precip-3: #007AC2;
  --viz-precip-4: #004B87;
  /* Schnee — eigene, kühlere Cyan-Rampe */
  --viz-snow-1: #CFEFFA;
  --viz-snow-2: #7FD6EA;
  --viz-snow-3: #17A9C9;
  /* Gewitterwahrscheinlichkeit — Violett-Rampe, deckt sich mit der Gewitterfarbe der Signifikantes-Wetter-Legende */
  --viz-storm-1: #D9A6D8;
  --viz-storm-2: #92278F;
  --ensemble-member: rgba(0, 122, 194, 0.22);
  --ensemble-deterministic: #F75E0E;
  --ensemble-median: #EAF3F8;
  --ensemble-band-90: rgba(0, 122, 194, 0.10);
  --ensemble-band-50: rgba(0, 122, 194, 0.22);
  /* Wasserflächen. Ursprünglich #001F27 direkt aus einem Screenshot und damit dunkler als die Bedienoberfläche; eine Stufe angehoben, damit die Karte nicht mit der dunkelsten Chrome-Fläche konkurriert. */
  --map-water: #0C3345;
  /* Landflächen. Bewusst eine Stufe heller als Wasser (Tiefenwirkung). */
  --map-land: #17475E;
  /* Wald — gedecktes Grün, dunkler als Land */
  --map-forest: #123A22;
  /* Bebauung — neutrales Warmgrau, bewusst außerhalb der Blau-Grün-Familie, damit es auch in Graustufen und bei Farbfehlsichtigkeit von Land und Wasser unterscheidbar bleibt */
  --map-settlement: #3B4148;
  /* Autobahn. Wege sind Linien, keine Flächen, daher kräftiger als jede Flächenfarbe; die Autobahn deutlich wärmer und heller als das übrige Netz, damit die Hierarchie beim Zoomen sofort erkennbar ist. */
  --map-road-motorway: #D9A544;
  /* Übriges Straßennetz */
  --map-road-street: #4E6472;
  /* Ortsnamen — helle Schrift mit dunkler Kontur, damit Labels über jeder darunterliegenden Fläche lesbar bleiben, ohne eigenen Hintergrund */
  --map-label-text: #F4F9FC;
  /* Kontur der Ortsnamen */
  --map-label-halo: rgba(3, 14, 19, 0.85);
  --chart-series-1: #3987E5;
  --chart-series-2: #D95926;
  --chart-series-3: #199E70;
  --chart-series-4: #C98500;
  --gradient-hero: linear-gradient(180deg, rgba(1,10,15,0) 0%, rgba(1,10,15,.82) 55%, #010A0F 100%);
  /* Füllung des Primärbuttons (E2), der ausgewählten Schubladenzeile (E1) und des ausgewählten Chips (E20) */
  --gradient-brand: linear-gradient(135deg, #007AC2 0%, #004B87 100%);
  --gradient-signal: linear-gradient(90deg, #007AC2 0%, #F75E0E 100%);
  --gradient-panel: linear-gradient(160deg, #12303D 0%, #071B24 100%);
  --gradient-spectrum: linear-gradient(90deg, #E6001A, #F75E0E, #F7B500, #009739, #004B87, #92278F);
  --gradient-temp-scale: linear-gradient(90deg, #1A237E, #004B87, #007AC2, #F7B500, #F75E0E, #E6001A);
  /* Bühnen-Card auf Foto-Grund — Login, Landing, Rechtsseiten */
  --shadow-stage: 0 24px 60px rgba(0,0,0,.45);
  /* Schwebende Hüllen — Dropdown, Panel über der Karte */
  --shadow-float: 0 18px 40px rgba(0,0,0,.5);
  /* Nur die Hero-Buttonstufe auf Landing-Pages (E2) */
  --shadow-hero: 0 10px 30px -8px rgba(0,122,194,.55);
  /* Swatches, Checkbox, Slider-Track, Chart-Marker (E12) */
  --radius-xs: 3px;
  /* Buttons, Banner, Dropdown-Einträge, Badges */
  --radius-s: 6px;
  /* Dropdown-Hülle, Panel über der Karte */
  --radius-m: 10px;
  /* Flächen-Card, Bühnen-Card */
  --radius-l: 16px;
  /* Moderat gerundet statt Pille */
  --radius-chip: 9px;
  /* Ausschließlich runde Icon-Knöpfe, Avatare, Slider-Daumen (E12) */
  --radius-round: 999px;
  /* Überschriften. Gewicht 800 entfällt (E10). */
  --font-display: 'Barlow Semi Condensed', sans-serif;
  /* Fließtext und UI. Metrisch kompatibel zu Arial (E16). */
  --font-body: 'Arimo', Arial, sans-serif;
  /* Messwerte, Zeitstempel, Koordinaten, Kicker. Gewicht 500 entfällt (E10). */
  --font-mono: 'IBM Plex Mono', monospace;
  --fs-xs: 11px;
  --fs-s: 12px;
  --fs-sm: 13px;
  --fs-m: 14px;
  --fs-l: 16px;
  --fs-xl: 18px;
  --fs-2xl: 20px;
  --fs-3xl: 24px;
  --fs-4xl: 32px;
  --fs-5xl: 40px;
  /* Chips, Buttons, Tabellenzellen, Badges */
  --lh-tight: 1.15;
  /* Labels, Listenzeilen, Menüs, Formulare */
  --lh-ui: 1.3;
  /* Absätze, Rechtstexte, AGB, E-Mail, Katalog */
  --lh-text: 1.55;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  /* Deckblatt, Sektionswechsel, Foliengliederung */
  --space-8: 64px;
  /* Kleinster Abstand, etwa zwischen einem Label und seinem Wert */
  --space-hair: 2px;
  --breakpoint-mobile: 768px;
  /* Folien nutzen dieselbe Typo-Skala, multipliziert mit diesem Faktor — statt eigener Größen, die dann in Apps und Dokumenten herumliegen (E15). Die 2 ist der Entwurfswert fuer 1920x1080; wie er sich auf kleineren Flaechen staffelt, steht bei .praesentation in components.css. Eine Formel dafuer scheitert an CSS: `100dvh / 540` ergibt eine Laenge, keine Zahl, und `calc(11px * Laenge)` ist ungueltig — die Schrift fiel dabei auf den Browserstandard zurueck (gemessen 2026-09-10). */
  --presentation-factor: 2;
  /* Derselbe Wert wie --core-void im Dunkel-Theme, aber in beiden Themes. Traegt weisse und farbige Logos sowie Screenshots; schwarze Inhalte gehoeren nicht darauf. */
  --flaeche-dunkel-fest: #010A0F;
  /* Die Flaeche, die ALLE drei Logofassungen traegt — bunt, weiss und schwarz — in beiden Themes (Logos-Seite, Presse-Downloads). Der Ton ist der dunkelste, der Schwarz noch 3:1 laesst (3.34), und darueber bleibt Weiss bei 6.29; gegen den Seitengrund steht er dunkel wie hell ueber 3:1 (3.18 / 5.84). Heller ginge nicht ohne Verlust: Die Wortmarke `meteo` traegt Himmelblau #007AC2 mit der Luminanz 0.178, und genau dort liegt jedes Grau, das Schwarz und Weiss gleich gut traegt — ab #686868 faellt das Wort in den Grund (gemessen und angesehen 2026-09-12). Deshalb der dunkelste zulaessige Punkt und nicht die Mitte. */
  --flaeche-neutral-fest: #606060;
  /* Rand des Bildschirms, Kerbe des Telefons, untere Kante des Fusses */
  --geraet-rahmen: #05070A;
  /* obere Kante des Laptopfusses — der Verlauf dorthin gibt der Kante Tiefe */
  --geraet-fuss: #12181D;
  /* Die Flaeche hinter dem Screenshot. Fest dunkel, auch im Hell-Theme: Das Bild ist mit `contain` eingepasst, an den Raendern bleibt Flaeche frei — mit --core-void stand dort auf Hell ein weisser Streifen unter einem dunklen Screenshot (Nutzer-Befund 2026-09-09). */
  --geraet-schirm: var(--flaeche-dunkel-fest);
  /* Kameraauge des Monitors und Text des Platzhalters. Aus demselben Grund fest: Beides liegt auf dem Geraet, nicht auf der Anwendungsflaeche. */
  --geraet-detail: #5C7484;
  /* bei 18 % / 12 % */
  --glow-blue: rgba(0,122,194,.16);
  /* bei 84 % / 88 % */
  --glow-orange: rgba(247,94,14,.10);
  /* Radius der beiden Kegel auf Desktop, als Anteil der Flaeche. Bestimmt im Wertelabor 2026-09-07. */
  --glow-radius: 70%;
  /* Bei 390 px Breite liegen die Kegel nur rund 260 px auseinander; der kleinere Radius verhindert, dass sie zu einem diffusen Fleck verschmelzen. Bestimmt im Wertelabor 2026-09-07. */
  --glow-radius-mobile: 45%;

  /* Wertesatz Dunkel — die Vorgabe */
  /* App-Hintergrund; verankerte Flächen, also die Sidebar (E6) */
  --core-void: #010A0F;
  /* Schwebende Flächen, die den Grund überdecken: Schubladen, Dropdown-Hüllen, Modals. Vor einem void-Grund würde eine void-Schublade verschwinden (E6). */
  --core-abyss: #071B24;
  /* Flächen-Card und Panel über der Karte (E4) */
  --core-surface: #0D2530;
  /* Hover, aktive Zeile */
  --core-surface-2: #162933;
  /* Die große Inhaltsfläche, die bei Nimbus die Karte trägt. Heller als die Bedienleisten; die Flächen-Card liegt dunkler darauf, genau wie ein Nimbus-Panel auf der Karte (E6). Bestimmt im Wertelabor 2026-09-07. */
  --core-canvas: #12303C;
  /* Bedienleisten — die horizontale Leiste über der Karte in meteoNAVI und die Topbar der Kontoverwaltung. Eigenes Token statt core-abyss an der Aufrufstelle, damit sich beide Flächen später getrennt nachjustieren lassen. Seit dem Tausch von 2026-08 trägt die Sidebar bewusst void und die Leiste abyss; die beiden sind also nicht mehr dieselbe Fläche. */
  --core-topbar: var(--core-abyss);
  /* Auch die Kante der Flächen-Card auf dem Canvas: wirkt dort als #25414C und trennt mit 1,46:1. Eine dunkle Kante wurde geprüft und verworfen, sie wirkte als die Kartenfarbe selbst (E6). */
  --core-border: rgba(255, 255, 255, 0.08);
  /* Dropdown-Hülle (E7) */
  --core-border-strong: rgba(255, 255, 255, 0.16);
  /* Trenner zwischen Sidebar/Toolbar und Karte: dunkler Schatten statt heller Linie — der native Browser-Scrollbar ist sonst der hellste Punkt der ganzen App. */
  --panel-seam: rgba(0, 0, 0, 0.4);
  --scrollbar-track: var(--core-abyss);
  --scrollbar-thumb: var(--core-surface-2);
  /* Lesedeckel fuer Flaechen mit langem Text (AGB-Web, Praesentation): --core-void dieses Themes bei 60 %. Unveraendert gegenueber 1.12.0, nur aus dem gemeinsamen Kern hierher gezogen. */
  --glow-overlay: rgba(1,10,15,.6);
  /* Auch der Text im Warnbanner — Warnfarben tragen dort Kante und Tönung, nie den Text (E8) */
  --text-primary: #EAF3F8;
  --text-secondary: #93AAB8;
  --text-tertiary: #5C7484;
  --text-on-accent: #FFFFFF;
  /* Der Kicker trägt auf dunklem Grund das unveränderte Leuchtorange (6,24:1). Im Hell-Theme wechselt dieses Token auf eine dunklere Fassung. */
  --brand-orange-text: var(--brand-orange);
  --ui-info-text: #99D0F0;
  --ui-success-text: #95E7B4;
  --ui-warning-text: #FFC078;
  --ui-danger-text: #FFBCBC;
  /* Neuer Lauf. Die Bänder erscheinen nur, solange ein Lauf unvollständig ist. */
  --run-fresh: #19B14F;
  /* Noch der vorherige Lauf. Neutrales Grau statt Rot: Der Gegensatz lautet frisch gegen abgestanden, nicht gut gegen schlecht — ein alter Lauf ist kein Fehler. */
  --run-stale: #A3B7C3;
  /* Linkfarbe im Fließtext (E23). Bis 1.14.0 trugen Links --brand-blue und erreichten auf dem dunklen Grund 4,34:1 und auf Flächen 3,45:1 — beides unter der AA-Schwelle von 4,5. Dieser Ton erreicht 9,0 / 7,15 / 7,94 auf Grund, Fläche und schwebender Fläche. */
  --link: #73B6DD;
  /* Hover verstärkt den Kontrast in Richtung Textfarbe, statt die Farbe zu wechseln (E23): auf Dunkel heller, auf Hell dunkler. Der naheliegende Griff zum Markenorange scheidet aus, es erreicht auf Hell 2,97:1. */
  --link-hover: #A6D0EA;
}

/* Systemvorgabe des Betriebssystems, sofern der Nutzer nichts anderes gewählt hat */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    /* Seitengrund */
    --core-void: #F3F7FA;
    /* Schwebende Flächen — behält seine Rolle als der Ton, der sich vom Seitengrund abhebt */
    --core-abyss: #FFFFFF;
    /* Flächen-Card und Panel */
    --core-surface: #E8EFF4;
    /* Hover, aktive Zeile */
    --core-surface-2: #DCE6EC;
    /* OFFEN — abgeleitet, nicht im Wertelabor bestimmt. Behält die Beziehung aus dem Dunkel-Theme bei: geringfügig heller als die Card, sodass diese wie dort dunkler auf ihrem Grund liegt und die Trennung von der Kante getragen wird. Live zu prüfen, sobald das erste Artefakt hell gebaut wird. */
    --core-canvas: #EEF3F7;
    --core-topbar: var(--core-abyss);
    --core-border: rgba(7, 27, 36, 0.10);
    --core-border-strong: rgba(7, 27, 36, 0.18);
    /* OFFEN — abgeleitet. Auf hellem Grund braucht der Trenner weniger Tiefe als der dunkle Schatten im Dunkel-Theme. */
    --panel-seam: rgba(7, 27, 36, 0.12);
    --scrollbar-track: var(--core-surface);
    --scrollbar-thumb: var(--core-surface-2);
    /* Derselbe Deckel mit dem hellen --core-void. Bis 1.12.0 stand hier stumm der Dunkelwert, weil das Token im gemeinsamen Kern lag und die Deckungspruefung dort nicht greift — eine helle Leseflaeche waere damit unter einem 60-%-Schleier in Fast-Schwarz gelegen, im Druck (E14 setzt Hell) ebenso. */
    --glow-overlay: rgba(243,247,250,.6);
    /* 16,4:1 gegen den Seitengrund */
    --text-primary: #071B24;
    /* 7,3:1 */
    --text-secondary: #3D5563;
    /* 3,7:1 — nur für Nebenangaben ab 14 px */
    --text-tertiary: #6B8290;
    --text-on-accent: #FFFFFF;
    /* Der Kicker in Leuchtorange erreicht auf hellem Grund nur 3,0:1 und trägt dort nicht. Diese dunklere Fassung erreicht 4,58:1. Flächen und Streifen behalten das Original — auf Hell tragen gesättigte Farben nur Flächen, Kanten und Marker, nie Text (E9). */
    --brand-orange-text: #C4470A;
    --ui-info-text: var(--ui-info-edge);
    --ui-success-text: var(--ui-success-edge);
    --ui-warning-text: var(--ui-warning-edge);
    --ui-danger-text: var(--ui-danger-edge);
    /* 3,13:1 auf der hellen Chipfüllung */
    --run-fresh: #1A9A4D;
    /* 4,22:1 auf der hellen Chipfüllung */
    --run-stale: #5C7484;
    /* Linkfarbe im Fließtext (E23). Auf Hell trug bereits --brand-blue-dark mit 8,27:1; der Wert ist unverändert übernommen, steht jetzt aber unter eigenem Namen. Eine funktionale Bedeutung benutzt keine Markenfarbe mit. */
    --link: #004B87;
    /* Hover verstärkt den Kontrast in Richtung Textfarbe, statt die Farbe zu wechseln (E23): auf Dunkel heller, auf Hell dunkler. Der naheliegende Griff zum Markenorange scheidet aus, es erreicht auf Hell 2,97:1. */
    --link-hover: #00345E;
  }
}

/* Ausdrückliche Wahl des Nutzers — schlägt die Systemvorgabe in beide Richtungen */
:root[data-theme="light"] {
  /* Seitengrund */
  --core-void: #F3F7FA;
  /* Schwebende Flächen — behält seine Rolle als der Ton, der sich vom Seitengrund abhebt */
  --core-abyss: #FFFFFF;
  /* Flächen-Card und Panel */
  --core-surface: #E8EFF4;
  /* Hover, aktive Zeile */
  --core-surface-2: #DCE6EC;
  /* OFFEN — abgeleitet, nicht im Wertelabor bestimmt. Behält die Beziehung aus dem Dunkel-Theme bei: geringfügig heller als die Card, sodass diese wie dort dunkler auf ihrem Grund liegt und die Trennung von der Kante getragen wird. Live zu prüfen, sobald das erste Artefakt hell gebaut wird. */
  --core-canvas: #EEF3F7;
  --core-topbar: var(--core-abyss);
  --core-border: rgba(7, 27, 36, 0.10);
  --core-border-strong: rgba(7, 27, 36, 0.18);
  /* OFFEN — abgeleitet. Auf hellem Grund braucht der Trenner weniger Tiefe als der dunkle Schatten im Dunkel-Theme. */
  --panel-seam: rgba(7, 27, 36, 0.12);
  --scrollbar-track: var(--core-surface);
  --scrollbar-thumb: var(--core-surface-2);
  /* Derselbe Deckel mit dem hellen --core-void. Bis 1.12.0 stand hier stumm der Dunkelwert, weil das Token im gemeinsamen Kern lag und die Deckungspruefung dort nicht greift — eine helle Leseflaeche waere damit unter einem 60-%-Schleier in Fast-Schwarz gelegen, im Druck (E14 setzt Hell) ebenso. */
  --glow-overlay: rgba(243,247,250,.6);
  /* 16,4:1 gegen den Seitengrund */
  --text-primary: #071B24;
  /* 7,3:1 */
  --text-secondary: #3D5563;
  /* 3,7:1 — nur für Nebenangaben ab 14 px */
  --text-tertiary: #6B8290;
  --text-on-accent: #FFFFFF;
  /* Der Kicker in Leuchtorange erreicht auf hellem Grund nur 3,0:1 und trägt dort nicht. Diese dunklere Fassung erreicht 4,58:1. Flächen und Streifen behalten das Original — auf Hell tragen gesättigte Farben nur Flächen, Kanten und Marker, nie Text (E9). */
  --brand-orange-text: #C4470A;
  --ui-info-text: var(--ui-info-edge);
  --ui-success-text: var(--ui-success-edge);
  --ui-warning-text: var(--ui-warning-edge);
  --ui-danger-text: var(--ui-danger-edge);
  /* 3,13:1 auf der hellen Chipfüllung */
  --run-fresh: #1A9A4D;
  /* 4,22:1 auf der hellen Chipfüllung */
  --run-stale: #5C7484;
  /* Linkfarbe im Fließtext (E23). Auf Hell trug bereits --brand-blue-dark mit 8,27:1; der Wert ist unverändert übernommen, steht jetzt aber unter eigenem Namen. Eine funktionale Bedeutung benutzt keine Markenfarbe mit. */
  --link: #004B87;
  /* Hover verstärkt den Kontrast in Richtung Textfarbe, statt die Farbe zu wechseln (E23): auf Dunkel heller, auf Hell dunkler. Der naheliegende Griff zum Markenorange scheidet aus, es erreicht auf Hell 2,97:1. */
  --link-hover: #00345E;
}

:root[data-theme="dark"] {
  /* App-Hintergrund; verankerte Flächen, also die Sidebar (E6) */
  --core-void: #010A0F;
  /* Schwebende Flächen, die den Grund überdecken: Schubladen, Dropdown-Hüllen, Modals. Vor einem void-Grund würde eine void-Schublade verschwinden (E6). */
  --core-abyss: #071B24;
  /* Flächen-Card und Panel über der Karte (E4) */
  --core-surface: #0D2530;
  /* Hover, aktive Zeile */
  --core-surface-2: #162933;
  /* Die große Inhaltsfläche, die bei Nimbus die Karte trägt. Heller als die Bedienleisten; die Flächen-Card liegt dunkler darauf, genau wie ein Nimbus-Panel auf der Karte (E6). Bestimmt im Wertelabor 2026-09-07. */
  --core-canvas: #12303C;
  /* Bedienleisten — die horizontale Leiste über der Karte in meteoNAVI und die Topbar der Kontoverwaltung. Eigenes Token statt core-abyss an der Aufrufstelle, damit sich beide Flächen später getrennt nachjustieren lassen. Seit dem Tausch von 2026-08 trägt die Sidebar bewusst void und die Leiste abyss; die beiden sind also nicht mehr dieselbe Fläche. */
  --core-topbar: var(--core-abyss);
  /* Auch die Kante der Flächen-Card auf dem Canvas: wirkt dort als #25414C und trennt mit 1,46:1. Eine dunkle Kante wurde geprüft und verworfen, sie wirkte als die Kartenfarbe selbst (E6). */
  --core-border: rgba(255, 255, 255, 0.08);
  /* Dropdown-Hülle (E7) */
  --core-border-strong: rgba(255, 255, 255, 0.16);
  /* Trenner zwischen Sidebar/Toolbar und Karte: dunkler Schatten statt heller Linie — der native Browser-Scrollbar ist sonst der hellste Punkt der ganzen App. */
  --panel-seam: rgba(0, 0, 0, 0.4);
  --scrollbar-track: var(--core-abyss);
  --scrollbar-thumb: var(--core-surface-2);
  /* Lesedeckel fuer Flaechen mit langem Text (AGB-Web, Praesentation): --core-void dieses Themes bei 60 %. Unveraendert gegenueber 1.12.0, nur aus dem gemeinsamen Kern hierher gezogen. */
  --glow-overlay: rgba(1,10,15,.6);
  /* Auch der Text im Warnbanner — Warnfarben tragen dort Kante und Tönung, nie den Text (E8) */
  --text-primary: #EAF3F8;
  --text-secondary: #93AAB8;
  --text-tertiary: #5C7484;
  --text-on-accent: #FFFFFF;
  /* Der Kicker trägt auf dunklem Grund das unveränderte Leuchtorange (6,24:1). Im Hell-Theme wechselt dieses Token auf eine dunklere Fassung. */
  --brand-orange-text: var(--brand-orange);
  --ui-info-text: #99D0F0;
  --ui-success-text: #95E7B4;
  --ui-warning-text: #FFC078;
  --ui-danger-text: #FFBCBC;
  /* Neuer Lauf. Die Bänder erscheinen nur, solange ein Lauf unvollständig ist. */
  --run-fresh: #19B14F;
  /* Noch der vorherige Lauf. Neutrales Grau statt Rot: Der Gegensatz lautet frisch gegen abgestanden, nicht gut gegen schlecht — ein alter Lauf ist kein Fehler. */
  --run-stale: #A3B7C3;
  /* Linkfarbe im Fließtext (E23). Bis 1.14.0 trugen Links --brand-blue und erreichten auf dem dunklen Grund 4,34:1 und auf Flächen 3,45:1 — beides unter der AA-Schwelle von 4,5. Dieser Ton erreicht 9,0 / 7,15 / 7,94 auf Grund, Fläche und schwebender Fläche. */
  --link: #73B6DD;
  /* Hover verstärkt den Kontrast in Richtung Textfarbe, statt die Farbe zu wechseln (E23): auf Dunkel heller, auf Hell dunkler. Der naheliegende Griff zum Markenorange scheidet aus, es erreicht auf Hell 2,97:1. */
  --link-hover: #A6D0EA;
}

/* Folien: dieselbe Skala, ein Umrechnungsschritt (E15). Alles in
   dieser Fläche wächst mit — Bausteine ebenso wie Fließtext. */
.praesentation {
  --fs-xs: calc(11px * var(--presentation-factor));
  --fs-s: calc(12px * var(--presentation-factor));
  --fs-sm: calc(13px * var(--presentation-factor));
  --fs-m: calc(14px * var(--presentation-factor));
  --fs-l: calc(16px * var(--presentation-factor));
  --fs-xl: calc(18px * var(--presentation-factor));
  --fs-2xl: calc(20px * var(--presentation-factor));
  --fs-3xl: calc(24px * var(--presentation-factor));
  --fs-4xl: calc(32px * var(--presentation-factor));
  --fs-5xl: calc(40px * var(--presentation-factor));
}

/* Der Druck ist hell, immer — unabhängig von System und Nutzerwahl (E14) */
@media print {
  :root {
    /* Seitengrund */
    --core-void: #F3F7FA;
    /* Schwebende Flächen — behält seine Rolle als der Ton, der sich vom Seitengrund abhebt */
    --core-abyss: #FFFFFF;
    /* Flächen-Card und Panel */
    --core-surface: #E8EFF4;
    /* Hover, aktive Zeile */
    --core-surface-2: #DCE6EC;
    /* OFFEN — abgeleitet, nicht im Wertelabor bestimmt. Behält die Beziehung aus dem Dunkel-Theme bei: geringfügig heller als die Card, sodass diese wie dort dunkler auf ihrem Grund liegt und die Trennung von der Kante getragen wird. Live zu prüfen, sobald das erste Artefakt hell gebaut wird. */
    --core-canvas: #EEF3F7;
    --core-topbar: var(--core-abyss);
    --core-border: rgba(7, 27, 36, 0.10);
    --core-border-strong: rgba(7, 27, 36, 0.18);
    /* OFFEN — abgeleitet. Auf hellem Grund braucht der Trenner weniger Tiefe als der dunkle Schatten im Dunkel-Theme. */
    --panel-seam: rgba(7, 27, 36, 0.12);
    --scrollbar-track: var(--core-surface);
    --scrollbar-thumb: var(--core-surface-2);
    /* Derselbe Deckel mit dem hellen --core-void. Bis 1.12.0 stand hier stumm der Dunkelwert, weil das Token im gemeinsamen Kern lag und die Deckungspruefung dort nicht greift — eine helle Leseflaeche waere damit unter einem 60-%-Schleier in Fast-Schwarz gelegen, im Druck (E14 setzt Hell) ebenso. */
    --glow-overlay: rgba(243,247,250,.6);
    /* 16,4:1 gegen den Seitengrund */
    --text-primary: #071B24;
    /* 7,3:1 */
    --text-secondary: #3D5563;
    /* 3,7:1 — nur für Nebenangaben ab 14 px */
    --text-tertiary: #6B8290;
    --text-on-accent: #FFFFFF;
    /* Der Kicker in Leuchtorange erreicht auf hellem Grund nur 3,0:1 und trägt dort nicht. Diese dunklere Fassung erreicht 4,58:1. Flächen und Streifen behalten das Original — auf Hell tragen gesättigte Farben nur Flächen, Kanten und Marker, nie Text (E9). */
    --brand-orange-text: #C4470A;
    --ui-info-text: var(--ui-info-edge);
    --ui-success-text: var(--ui-success-edge);
    --ui-warning-text: var(--ui-warning-edge);
    --ui-danger-text: var(--ui-danger-edge);
    /* 3,13:1 auf der hellen Chipfüllung */
    --run-fresh: #1A9A4D;
    /* 4,22:1 auf der hellen Chipfüllung */
    --run-stale: #5C7484;
    /* Linkfarbe im Fließtext (E23). Auf Hell trug bereits --brand-blue-dark mit 8,27:1; der Wert ist unverändert übernommen, steht jetzt aber unter eigenem Namen. Eine funktionale Bedeutung benutzt keine Markenfarbe mit. */
    --link: #004B87;
    /* Hover verstärkt den Kontrast in Richtung Textfarbe, statt die Farbe zu wechseln (E23): auf Dunkel heller, auf Hell dunkler. Der naheliegende Griff zum Markenorange scheidet aus, es erreicht auf Hell 2,97:1. */
    --link-hover: #00345E;
  }
}

/* ---------- Marken (G7) ---------- */

:root {
  --marken-name: "meteoCORE";
  --marken-claim: "Wetter ohne Vielleicht.";
  --marken-domain: "meteocore.com";
  --marken-akzent: var(--spectrum-core);
  --marken-logo: url("https://images.meteocore.com/meteoCORE/PfadSVGs/meteocore-logo-pfad.svg");
  --marken-signet: url("https://images.meteocore.com/meteoCORE/PfadSVGs/meteocore-signet-pfad.svg");
}

[data-marke="meteocore"] {
  --marken-name: "meteoCORE";
  --marken-claim: "Wetter ohne Vielleicht.";
  --marken-domain: "meteocore.com";
  --marken-akzent: var(--spectrum-core);
  --marken-logo: url("https://images.meteocore.com/meteoCORE/PfadSVGs/meteocore-logo-pfad.svg");
  --marken-signet: url("https://images.meteocore.com/meteoCORE/PfadSVGs/meteocore-signet-pfad.svg");
}
[data-marke="meteoobs"] {
  --marken-name: "meteoOBS";
  --marken-claim: "Messen, wo andere schätzen.";
  --marken-domain: "meteoobs.com";
  --marken-akzent: var(--spectrum-ingest);
  --marken-logo: url("https://images.meteocore.com/meteoOBS/PfadSVGs/meteoobs-logo-pfad.svg");
  --marken-signet: url("https://images.meteocore.com/meteoOBS/PfadSVGs/meteoobs-signet-pfad.svg");
}

/* ===================================================================
   meteoCORE — Bausteine

   Bewusst kein Generat und bewusst von den Token getrennt: Token sind
   Werte, Bausteine sind Gestaltung. Sie haben verschiedene
   Änderungsgründe (react-grundregeln.md, Regel 42).

   Herkunft jeder Festlegung: vision/05-Design/ci-entscheidungsvorlage-2026-09.md,
   E1 bis E22, entschieden am 2026-09-07. Die Verweise (E…) stehen an
   jedem Baustein.

   Setzt tokens.css voraus.

   ── Zwei Regeln, die hier stehen und nicht nur in der Dokumentation,
      weil sie sonst beim nächsten Einbau wieder verlorengehen: ──

   1. Der Innenabstand eines Bausteins gehört zu seiner Definition (E11).
      Die Spacing-Skala (--space-*) regelt Abstände ZWISCHEN Elementen —
      Gap, Margin, Sektionsabstand. Deshalb stehen hier Zahlen wie 9/16
      und keine var(--space-*): Das Padding eines Buttons ist Teil dessen,
      was ihn zu diesem Button macht.

   2. Verschachtelte Radien werden gerechnet, nicht gewählt (E12):
      innen = außen minus Einrückung, per calc(). Literale Zwischenwerte
      sind es, die verboten sind, nicht abgeleitete.
   =================================================================== */


/* ==================================================================
   Fokus (E21)
   ------------------------------------------------------------------
   Entschieden: Es gibt keinen Fokusring. Der Standardring des Browsers
   wird abgeschaltet, und es tritt nichts an seine Stelle.

   Bewusst in Kauf genommen: Wer per Tabulator navigiert, sieht nicht
   mehr, wo er steht. Wird Barrierefreiheit über Ausschreibungen oder
   das BFSG verbindlich, ist das der erste Punkt, der wieder
   aufzumachen ist.
   ================================================================== */
:where(a, button, input, select, textarea, summary, [tabindex]):focus,
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: none;
}


/* ==================================================================
   Kicker (E3)
   ------------------------------------------------------------------
   Das kleinste und häufigste Wiedererkennungselement. Zwei Stufen,
   nie in --font-display und nie in --font-body.

   Die Größe folgt dem Medium; --brand-orange-text wechselt im
   Hell-Theme auf eine dunklere Fassung, weil das Leuchtorange dort
   als Text nur 3,0:1 erreicht (E9).
   ================================================================== */
.kicker {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--fs-xs);           /* App-UI; Dokument 12, Präsentation 13, Druck 9pt */
  line-height: var(--lh-tight);
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--brand-orange-text);
}

/* Zweite Stufe: Stat-Beschriftung, Gruppenlabel, Chart-Überschrift */
.kicker--neben {
  letter-spacing: .08em;
  color: var(--text-tertiary);
}

@media print { .kicker { font-size: 9pt; } }


/* ==================================================================
   Button (E2)
   ------------------------------------------------------------------
   Fünf Stufen. Nimbus gibt die Skala vor: Was dort trägt — platzsparend
   und übersichtlich zugleich —, trägt überall.

   Wer die Stufe wählt: für xs bis md die DICHTE DES CONTAINERS, nicht
   das Gerät und nicht die App. Small-Desktop und Tablet-Portrait erben
   damit eine bestehende Dichte, statt eine sechste Größe zu erfinden.
   lg und hero werden bewusst gesetzt.
   ================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  position: relative;
  border: none;
  /* Ohne diese Zeile faellt ein <button class="btn"> ohne Ausprägung auf den
     Browser-Standard zurueck — und der ist weiss. Die Grundform muss neutral
     sein, damit eine vergessene oder falsch geschriebene Ausprägung als
     unauffaelliger Knopf erscheint und nicht als weisser Fremdkoerper. */
  background: transparent;
  color: var(--text-secondary);
  /* Ein Knopf ist oft ein <a> — der Mailknopf im Fuss, „Weiterlesen",
     die Schlagworte unter einem Beitrag. Ohne diese Zeile traegt er die
     Unterstreichung des Browser-Standards mitten durch seine Flaeche.
     In den React-Anwendungen faellt das nicht auf, weil deren Reset
     `a { text-decoration: none }` global setzt; ein Baustein darf sich
     darauf nicht verlassen (dieselbe Falle wie bei box-sizing, DSG-49).
     Gemessen am 2026-09-11 im WordPress-Theme, das die Stelle bisher
     dreimal einzeln geflickt hatte. */
  text-decoration: none;
  border-radius: var(--radius-s);
  font-family: var(--font-body);
  font-weight: 600;
  line-height: var(--lh-tight);
  cursor: pointer;
  transition: filter .12s ease, background .12s ease, border-color .12s ease;

  font-size: var(--fs-m);            /* md — die Grundform aus dem Katalog */
  padding: 11px 20px;
}

.btn:hover { filter: brightness(1.12); }
.btn:disabled,
.btn.is-disabled {
  background: var(--core-surface-2);
  color: var(--text-tertiary);
  box-shadow: none;
  cursor: not-allowed;
  filter: none;
}

/* Dichte des Containers wählt die Vorgabe (E2).
   dicht  = Nimbus-Karte, Topbar, Panels, Sidebar-Raster
   normal = Formularseiten, Dialoge, Kontoverwaltungs-Inhalt */
[data-density="dicht"] .btn              { font-size: var(--fs-sm); padding: 8px 14px; }
[data-density="dicht"] .btn--nebenaktion { font-size: var(--fs-s);  padding: 6px 12px; }
[data-density="normal"] .btn             { font-size: var(--fs-m);  padding: 11px 20px; }
[data-density="normal"] .btn--nebenaktion{ font-size: var(--fs-sm); padding: 8px 14px; }

/* Größen. Sie stehen NACH der Dichte und tragen die doppelte Klasse: Eine
   ausdrücklich gesetzte Stufe soll die Vorgabe des Containers schlagen.

   Bis 2026-09-08 standen sie davor. Beide Formen wiegen gleich schwer
   (zwei Klassen bzw. Attribut und Klasse), also entschied die Reihenfolge --
   und damit gewann die Dichte. Im Login-Theme war `btn--lg` am Anmeldeknopf
   dadurch wirkungslos. */
.btn.btn--xs   { font-size: var(--fs-s);  padding: 6px 12px; }
.btn.btn--sm   { font-size: var(--fs-sm); padding: 8px 14px; }
.btn.btn--md   { font-size: var(--fs-m);  padding: 11px 20px; }
.btn.btn--lg   { font-size: var(--fs-l);  padding: 13px 22px; }
.btn.btn--hero { font-size: var(--fs-xl); padding: 15px 32px; }

/* Ausprägungen */
.btn--primary {
  background: var(--gradient-brand);
  color: var(--text-on-accent);
  box-shadow: 0 4px 18px rgba(0, 122, 194, .35);
}
.btn--accent {                        /* orange bleibt DER einen wichtigsten Aktion pro Ansicht vorbehalten */
  background: var(--brand-orange);
  color: var(--text-on-accent);
  box-shadow: 0 4px 18px rgba(247, 94, 14, .3);
}
.btn--outline {
  background: transparent;
  color: var(--brand-blue);
  border: 1.5px solid var(--brand-blue);
}
.btn--ghost {
  background: transparent;
  color: var(--text-secondary);
}
.btn--ghost:hover { color: var(--text-primary); filter: none; }

/* Gefahr. Nicht --warn-3 (das heißt "Unwetter") und nicht
   --spectrum-ingest (das heißt "Datenerfassung"), sondern ein eigener
   Ton für gefüllte Gefahrflächen — --ui-danger erreicht als Fläche mit
   weißer Schrift nur 2,78:1 (E8, E18). */
.btn--danger {
  background: var(--ui-danger-solid);
  color: var(--text-on-accent);
}

/* Nur hero trägt den großen Auftritt; lg bekommt den normalen Schatten
   und hebt nicht an. */
.btn--hero { box-shadow: var(--shadow-hero); }
.btn--hero:hover { transform: translateY(-1px); }

/* Der Schein gehört zur Füllung, nicht zur Größe: Ein Umriss-Knopf, der
   blau leuchtet, sieht aus wie ein gefüllter, dem die Füllung fehlt. Das
   Anheben bleibt — das ist die Größe. */
.btn--outline.btn--hero { box-shadow: none; }

/* xs und sm liegen unter dem Fingermaß. Auf Mobile wächst nicht der
   sichtbare Knopf, sondern seine Trefferfläche — so bleibt Nimbus
   platzsparend und trotzdem bedienbar (E2). */
@media (pointer: coarse) {
  .btn--xs::after,
  .btn--sm::after,
  [data-density="dicht"] .btn::after {
    content: "";
    position: absolute;
    inset: 50% 0 auto 0;
    height: 44px;
    transform: translateY(-50%);
  }
}


/* ==================================================================
   Umschalter (E2)
   ------------------------------------------------------------------
   Zwei bis drei gleichwertige Ansichten derselben Sache: Relativ
   gegen Termine, Echtzeit gegen Vorhersage, 10min gegen 1h gegen 6h.

   KEIN Button und kein Chip, obwohl er aus beidem etwas hat. Ein
   Button löst eine Aktion aus, ein Chip wählt aus einer Menge. Hier
   ist die Menge immer vollständig sichtbar und genau eine Taste
   gedrückt — das Bedienmuster ist der Radioknopf, nicht die Aktion.
   Deshalb ein eigener Baustein und nicht eine vierte Buttongröße.

   Die Vertiefung trägt die Zusammengehörigkeit: Der Behälter liegt
   auf --core-surface, die aktive Taste eine Stufe heller darauf. Ohne
   ihn stünden zwei Knöpfe nebeneinander, von denen einer zufällig
   dunkler ist.
   ================================================================== */
.umschalter {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-s);
  background: var(--core-surface);
}

.umschalter__taste {
  padding: 3px 8px;
  border: none;
  /* innen = außen minus Einrückung (E12) */
  border-radius: calc(var(--radius-s) - 2px);
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  line-height: var(--lh-ui);
  cursor: pointer;
}
.umschalter__taste:hover { color: var(--text-primary); }

/* Fett NUR im aktiven Zustand: Die Taste soll beim Umschalten nicht
   die Breite wechseln — sie trägt deshalb schon inaktiv den Platz des
   fetten Schnitts. */
.umschalter__taste.is-active {
  background: var(--core-surface-2);
  color: var(--text-primary);
  font-weight: 600;
}

/* Symbolfassung — für den Theme-Umschalter, nicht für den Baustein.
   ------------------------------------------------------------------
   Der Umschalter trägt zwei Aufgaben: die Wahl der Darstellung (hell,
   dunkel, System) und die segmentierte Auswahl in den Anwendungen
   (Relativ/Termine, 10min/1h/6h). Die erste steht überall in einer Ecke
   oder einem schmalen Menü, wo drei Wörter mehr Platz brauchen, als die
   Sache wert ist — sie trägt deshalb Sonne, Mond und Bildschirm bei
   15 px, das Wort bleibt als title und aria-label. Die zweite braucht
   ihre Wörter.

   Deshalb ein Modifikator und keine neue Grundform: Ein pauschales
   26 × 22 px an .umschalter__taste hätte die Textfassung zerquetscht.
   Beim Einbau am 2026-09-10 genau so passiert und von der Demo
   aufgedeckt — sie zeigt beide Fälle. */
.umschalter--symbole .umschalter__taste {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 22px;
  padding: 0;
}

.umschalter--symbole .umschalter__taste svg {
  display: block;
}


/* Unter dem Fingermaß, wie xs und sm beim Button: Auf Mobile wächst
   die Trefferfläche, nicht die Taste. */
@media (pointer: coarse) {
  .umschalter__taste {
    position: relative;
  }
  .umschalter__taste::after {
    content: "";
    position: absolute;
    inset: 50% 0 auto 0;
    height: 44px;
    transform: translateY(-50%);
  }
}


/* ==================================================================
   Chip (E20, E22)
   ------------------------------------------------------------------
   Farbe trägt in Chips nichts mehr: Die Familienfarben sind mit E20
   entfallen. Auswahl ist überall --gradient-brand, wie die aktive
   Schubladenzeile und der Primärbutton.

   Ein Terminchip trägt fünf voneinander unabhängige Sachverhalte.
   Jeder bekommt einen eigenen Kanal, damit sie sich nicht gegenseitig
   überschreiben:

     Auswahl        Füllung        surface -> gradient-brand
     Verfügbarkeit  Deckkraft      100 % -> 36 %, not-allowed
     Ladezustand    Grundfläche    surface -> abyss (tritt zurück)
     Datenherkunft  Rand           border -> data-forecast
     Laufstand      Band oben      run-fresh / run-stale
   ================================================================== */
.chip {
  position: relative;
  overflow: hidden;
  padding: 9px 16px;
  border-radius: var(--radius-chip);   /* moderat gerundet, keine Pille */
  font-family: var(--font-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-tight);
  color: var(--text-secondary);
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}

/* Zweite Größe für Raster in Sidebar und Topbar. Die sieben festen
   Breiten der Topbar bleiben Layoutkonstanten der Rasterspalten und
   gehören nicht hierher. */
.chip--dense { font-size: var(--fs-s); padding: 4px 8px; }

.chip:hover {
  background: var(--core-surface-2);
  color: var(--text-primary);
  border-color: var(--core-border-strong);
}

.chip.is-selected {
  background: var(--gradient-brand);
  color: var(--text-on-accent);
  border-color: transparent;
}

.chip.is-disabled,
.chip.is-disabled:hover {
  opacity: .36;
  cursor: not-allowed;
  color: var(--text-tertiary);
  background: var(--core-surface);
  border-color: var(--core-border);
}

/* Ladezustand: flacher, tritt zurück — sichtbar, ohne Aufmerksamkeit
   zu ziehen. */
.chip[data-loaded="false"] { background: var(--core-abyss); }

/* Datenherkunft. Messung gegen Vorhersage ist die grundlegendste
   Unterscheidung der Anwendung und gilt überall gleich — am Chip wie
   an der Zeitleiste. */
.chip[data-source="vorhersage"] { border-color: var(--data-forecast); }

/* Laufstand. Die Bänder erscheinen NUR, solange ein Lauf unvollständig
   ist; danach stammen alle Termine aus demselben Lauf und ein Band
   unterschiede nichts mehr.

   Die 1-px-Kontur ist der Grund, warum die Farben frei wählbar sind:
   Ohne sie versagt der Streifen auf einer der drei Füllungen — dasselbe
   Mittel wie bei der Schraffur in warnlage-plan.md. */
.chip__band {
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  box-shadow: 0 0 0 1px var(--core-void);
}
.chip__band[data-run="neu"] { background: var(--run-fresh); }
.chip__band[data-run="alt"] { background: var(--run-stale); }


/* ==================================================================
   Banner (E8)
   ------------------------------------------------------------------
   Eine Anatomie, zwei Farbsysteme, die nie vermischt werden.

   Warnungen erscheinen GESTAPELT — neutraler Text hält die Spalte
   lesbar und lässt die Signalfarben eine scanbare Kante bilden.
   Eine Bedienmeldung steht ALLEIN und behält gefärbten Text.

   Die Kante verhält sich in beiden Systemen gleich: auf Dunkel der Ton
   selbst, auf Hell die -edge-Variante (eine gelbe Linie auf fast weißem
   Grund erreicht sonst 1,27:1).
   ================================================================== */
.banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border-radius: var(--radius-s);
  border-left: 4px solid transparent;
  font-family: var(--font-body);
  font-size: var(--fs-m);            /* auf die Skala gerundet, vorher 13,5 (E10) */
  font-weight: 600;
  line-height: var(--lh-ui);
}
.banner .ico { font-family: var(--font-mono); font-size: var(--fs-l); }

/* -- Wetterwarnungen: Text neutral, Farbe in Kante und Tönung -- */
.banner[data-level] { color: var(--text-primary); }
.banner[data-level="1"]       { border-left-color: var(--warn-1);       background: rgba(255,213,0,.12); }
.banner[data-level="2"]       { border-left-color: var(--warn-2);       background: rgba(255,149,0,.12); }
.banner[data-level="3"]       { border-left-color: var(--warn-3);       background: rgba(255,34,34,.12); }
.banner[data-level="4"]       { border-left-color: var(--warn-4);       background: rgba(199,36,177,.14); }
.banner[data-level="ok"]      { border-left-color: var(--warn-ok);      background: rgba(34,197,94,.12); }
.banner[data-level="unknown"] { border-left-color: var(--warn-unknown); background: rgba(158,158,158,.12); }

/* -- Bedienmeldungen: gefärbter Text --

   Jeder Ton ist zusätzlich als Klasse ansprechbar. Grund: Nicht jedes
   Markup gehört uns. Keycloakify rendert die Formularfehler und den
   Wiederherstellungscode-Hinweis des Login-Themes selbst und lässt nur
   Klassennamen einsetzen, keine Attribute — ohne die Klassenfassung
   müsste das Theme die Bannerform dort abschreiben.

   Nur die Bedienmeldungen, nicht die Warnstufen: Warnungen rendern
   unsere eigenen Komponenten. */
.banner[data-tone="info"],    .banner--info    { border-left-color: var(--ui-info);    background: rgba(0,122,194,.12);  color: var(--ui-info-text); }
.banner[data-tone="success"], .banner--success { border-left-color: var(--ui-success); background: rgba(34,197,94,.12);  color: var(--ui-success-text); }
.banner[data-tone="warning"], .banner--warning { border-left-color: var(--ui-warning); background: rgba(255,149,0,.12);  color: var(--ui-warning-text); }
.banner[data-tone="danger"],  .banner--danger  { border-left-color: var(--ui-danger);  background: rgba(255,107,107,.12);color: var(--ui-danger-text); }

/* Auf Hell nimmt die Kante die dunklere Fassung des Tons. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .banner[data-level="1"] { border-left-color: var(--warn-1-edge); }
  :root:not([data-theme="dark"]) .banner[data-level="2"] { border-left-color: var(--warn-2-edge); }
  :root:not([data-theme="dark"]) .banner[data-level="3"] { border-left-color: var(--warn-3-edge); }
  :root:not([data-theme="dark"]) .banner[data-level="4"] { border-left-color: var(--warn-4-edge); }
  :root:not([data-theme="dark"]) .banner[data-level="ok"] { border-left-color: var(--warn-ok-edge); }
  :root:not([data-theme="dark"]) .banner[data-level="unknown"] { border-left-color: var(--warn-unknown-edge); }
  :root:not([data-theme="dark"]) .banner[data-tone="info"], :root:not([data-theme="dark"]) .banner--info { border-left-color: var(--ui-info-edge); }
  :root:not([data-theme="dark"]) .banner[data-tone="success"], :root:not([data-theme="dark"]) .banner--success { border-left-color: var(--ui-success-edge); }
  :root:not([data-theme="dark"]) .banner[data-tone="warning"], :root:not([data-theme="dark"]) .banner--warning { border-left-color: var(--ui-warning-edge); }
  :root:not([data-theme="dark"]) .banner[data-tone="danger"], :root:not([data-theme="dark"]) .banner--danger { border-left-color: var(--ui-danger-edge); }
}
:root[data-theme="light"] .banner[data-level="1"]       { border-left-color: var(--warn-1-edge); }
:root[data-theme="light"] .banner[data-level="2"]       { border-left-color: var(--warn-2-edge); }
:root[data-theme="light"] .banner[data-level="3"]       { border-left-color: var(--warn-3-edge); }
:root[data-theme="light"] .banner[data-level="4"]       { border-left-color: var(--warn-4-edge); }
:root[data-theme="light"] .banner[data-level="ok"]      { border-left-color: var(--warn-ok-edge); }
:root[data-theme="light"] .banner[data-level="unknown"] { border-left-color: var(--warn-unknown-edge); }
:root[data-theme="light"] .banner[data-tone="info"], :root[data-theme="light"] .banner--info     { border-left-color: var(--ui-info-edge); }
:root[data-theme="light"] .banner[data-tone="success"], :root[data-theme="light"] .banner--success  { border-left-color: var(--ui-success-edge); }
:root[data-theme="light"] .banner[data-tone="warning"], :root[data-theme="light"] .banner--warning  { border-left-color: var(--ui-warning-edge); }
:root[data-theme="light"] .banner[data-tone="danger"], :root[data-theme="light"] .banner--danger   { border-left-color: var(--ui-danger-edge); }

/* Feldfehler: dieselbe Form, kleiner, ohne Schließen-X. */
.banner--feld { padding: 8px 12px; font-size: var(--fs-sm); }

/* Informationsleiste in Nimbus: volle Breite, ohne Radius — und eine
   Zeile hoch. Sie sitzt zwischen Bedienleiste und Karte und nimmt echten
   Layout-Platz; jeder Punkt Polster geht der Karte ab. Deshalb ist die
   knappere Höhe hier im Baustein und nicht als Abweichung in Nimbus:
   E8 nennt die Leiste ausdrücklich als einen der Fälle dieser Form. */
.banner--leiste {
  border-radius: 0;
  margin: 0;
  padding: 7px 16px;
  font-size: var(--fs-sm);
}


/* ==================================================================
   Eingabefeld (DSG-55)
   ------------------------------------------------------------------
   Die Form kommt aus der Ortssuche in Nimbus, wo sie zuerst entstand:
   36 px hoch, Radius s, kräftige Kante, die ruhige Fläche darunter.
   Sie gilt für alles, was Eingaben entgegennimmt — Suchschlitz,
   Kontaktformular, Anmeldung.

   Ein Feld ist ein Bedienelement, also muss der Baustein die
   Browser-Standards mitlöschen: Ein <input> bringt eigene Schrift,
   eigene Farbe und einen eigenen Fokusring mit, und keiner davon
   gehört uns.
   ================================================================== */
.feld {
  box-sizing: border-box;
  width: 100%;
  height: 36px;
  padding: 0 12px;
  border-radius: var(--radius-s);
  border: 1px solid var(--core-border-strong);
  background: var(--core-surface);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-m);
  line-height: var(--lh-ui);
}

.feld::placeholder {
  color: var(--text-tertiary);
}

/* Der Fokusring des Browsers ist abgeschaltet (E21) — die Kante
   übernimmt seine Aufgabe und ist hier die einzige Rückmeldung. */
.feld:focus,
.feld:focus-visible {
  outline: none;
  border-color: var(--brand-blue);
}

.feld:disabled {
  opacity: .5;
  cursor: not-allowed;
}

/* Ein mehrzeiliges Feld wächst; die feste Höhe gilt nur der Zeile. */
textarea.feld {
  height: auto;
  min-height: 96px;
  padding: 10px 12px;
  resize: vertical;
}

/* Fehlerhafte Eingabe: die Kante trägt es, nicht der Text. Die Meldung
   darunter ist .banner--feld — zwei Zeichen für denselben Zustand, und
   die Farbe allein trägt ihn nie (E8). */
.feld[aria-invalid="true"] {
  border-color: var(--ui-danger);
}

/* Auf Mobile wächst die Trefferfläche, wie bei den Buttons (E2). */
@media (pointer: coarse) {
  .feld {
    height: 44px;
  }
}

/* Die Beschriftung steht über dem Feld und trägt den Kicker: Sie sagt,
   was hier hineingehört, und ist damit eine Dachzeile. */
.feld-label {
  display: block;
  margin-bottom: var(--space-2);
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--fs-xs);
  line-height: var(--lh-tight);
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--brand-orange-text);
}


/* ==================================================================
   Lesestrecke (E23, E24)
   ------------------------------------------------------------------
   Alles, was gelesen wird: Rechtsseiten, AGB-Web-Fassung, Beiträge,
   Unternehmensseiten. Der Text steht FREI auf dem Grund — keine Fläche,
   kein Rahmen. Eine Karte beantwortet, worüber ein Element liegt (E4);
   liegt die ganze Seite darin, beantwortet sie nichts mehr und ist ein
   Seitenrahmen. Für die Lesbarkeit über dem Foto trägt das Overlay aus
   E5 (.seitengrund--lesen am <body>).

   Der Baustein setzt den Satzspiegel, die Links, die Aufzählungen und
   die FORM der Überschriften. Die Größe der tragenden Überschrift (h2)
   bleibt bei der Anwendung: Sie hängt an deren Fließtext — 16 px auf der
   Website, 15 px auf den Rechtsseiten — und damit an einem Wert, den das
   Paket nicht kennt. Form und Farbe hängen dagegen an der Marke und
   gehören hierher; sonst stehen dieselben Überschriften auf zwei
   Domains verschieden da (bis 1.28.0 war genau das der Fall).
   ================================================================== */
.lesestrecke {
  width: 100%;
  max-width: 760px;
  hyphens: auto;
}

/* Im Fließtext trägt der Unterstrich die Information mit, damit nicht die
   Farbe allein sie trägt (WCAG 1.4.1). In Menüs, Listen und Kacheln
   trägt die Position die Bedeutung — dort steht er nicht. */
/* Überschriften: h2 trägt, ab h3 wird markiert.

   Die tragende Überschrift steht in der Schrift der Marke und in ihrer
   Farbe. Ab der zweiten Ebene wechselt die FORM statt nur der Größe:
   Mono, Versalien, gesperrt — der Kicker. Zwei Ebenen, die sich nur um
   ein paar Pixel unterscheiden, liest niemand als zwei Ebenen; zwei
   verschiedene Formen schon.

   Ab h3 tragen alle Ebenen dieselbe Größe. Eine dritte Stufe wäre eine
   Unterscheidung ohne Unterschied — wer so tief gliedert, hat ein
   Gliederungsproblem und kein Gestaltungsproblem. (Im Bestand der
   Website kommt nach dem Richten der Ebenen ohnehin nichts unter h3
   mehr vor.)

   Die Größe von h2 fehlt hier mit Absicht, siehe oben.

   Der Abstand ÜBER einer Überschrift ist deutlich größer als der
   darunter, und zwar um ein Vielfaches. Eine Überschrift gehört zu dem,
   was ihr folgt; steht sie in der Mitte zwischen zwei Absätzen, liest
   sie sich als Nachtrag zum vorigen. */
.lesestrecke h2 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--lh-tight);
  color: var(--brand-orange-text);
  margin-top: 48px;
  margin-bottom: 12px;
}

.lesestrecke h3,
.lesestrecke h4,
.lesestrecke h5,
.lesestrecke h6 {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--fs-sm);
  line-height: var(--lh-tight);
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--brand-orange-text);
  margin-top: 34px;
  margin-bottom: 10px;
}

/* Am Anfang einer Lesestrecke steht kein Absatz, von dem abzusetzen
   wäre — dort wäre der Abstand eine Lücke unter dem Titel. */
.lesestrecke h2:first-child,
.lesestrecke h3:first-child,
.lesestrecke h4:first-child {
  margin-top: 0;
}

/* Aufzählungen im Fließtext.
   
   Die Werte stammen von den Rechtsseiten, wo sie bis 1.26.0 lokal
   standen: 22 px Einzug statt der rund 40 des Browsers, und 6 px Luft
   zwischen den Einträgen. Ohne die Luft kleben sie aneinander — eine
   dreizeilige Aufzählung liest sich dann wie ein Absatz mit Punkten
   davor (Nutzer-Befund an einem Beitrag). */
.lesestrecke ul,
.lesestrecke ol {
  /* Nur der Abstand NACH der Liste, nicht die Kurzform: Die setzt auch
     margin-top auf null und nimmt der Liste damit die Luft zum Absatz
     davor. In den Rechtsseiten fiel das nicht auf, dort bringt der
     Absatz seine eigenen 18 px mit; im Theme regelt WordPress den
     Abstand zwischen Blöcken, und der war damit weg — der erste
     Listenpunkt klebte am Text darüber (Nutzer-Befund). */
  margin-bottom: 18px;
  padding-left: 22px;
}
.lesestrecke li {
  margin-bottom: 6px;
}
.lesestrecke li:last-child {
  margin-bottom: 0;
}

/* Knöpfe bleiben außen vor: Ein Knopf trägt seine Bedeutung in der
   Fläche, und ein Unterstrich darin sähe aus wie ein Fehler. */
.lesestrecke a:not(.btn) {
  color: var(--link);
  text-decoration: underline;
  text-underline-offset: .18em;
  text-decoration-thickness: from-font;
}

.lesestrecke a:not(.btn):hover {
  color: var(--link-hover);
}

/* Wo ein Link keine Stelle im Satz ist, sondern eine Zeile für sich:
   Fußzeilen, Verweislisten, Kacheln. */
.link-liste a {
  color: var(--link);
  text-decoration: none;
}

.link-liste a:hover {
  color: var(--link-hover);
}


/* ==================================================================
   Flächen (E4)
   ------------------------------------------------------------------
   Drei Formen, und was gilt, bestimmt der Grund, auf dem das Element
   liegt — nie die App. Die Unterscheidung ist nicht "ruhig gegen
   unruhig", sondern WORÜBER es liegt: über einer Fläche, über einem
   Bild oder über Daten.
   ================================================================== */

/* Über einer Fläche: die ruhige App-Fläche (--core-canvas).
   Liegt DUNKLER als ihr Grund, genau wie ein Nimbus-Panel auf der Karte. */
.card {
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-l);
  padding: 24px 26px;
}

/* Über einem Bild: Login, Landing, Rechtsseiten. Der Schatten ist kein
   Stil, sondern die Antwort auf den unruhigen Grund. */
.card--buehne {
  background: var(--core-abyss);
  box-shadow: var(--shadow-stage);
  padding: 40px 48px;
}

/* Über Daten: die Ecken-Panels auf der Nimbus-Karte. Bewusst kleiner
   und leichter als eine Card — ein Panel darf die Daten nicht
   erschlagen.

   Heisst .datenpanel und nicht .panel: "panel" ist ein zu allgemeines Wort.
   Die Kontoverwaltung nannte damit schon ihre Seitensektion, und die bekam
   durch das Paket ungewollt Flaeche, Rand und Schatten — eine zweite
   Umrahmung um den ganzen Inhalt. Der Name sagt jetzt, worueber das Panel
   liegt. */
.datenpanel {
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-float);
  padding: 12px 14px;
}

/* Medium-Ausnahme E-Mail: kein Rand, weil Mail-Clients Ränder
   unzuverlässig zeichnen. Dafür der hellere Ton der Flächen-Card —
   ohne Rand hebt sich abyss am wenigsten vom Void ab. */
.card--mail { border: none; }


/* ==================================================================
   Dropdown-Hülle (E7)
   ------------------------------------------------------------------
   Es ist dieselbe Liste wie die Schublade: Das Benutzermenü auf Desktop
   zeigt, was auf Mobile die Schublade zeigt. Deshalb dieselbe Größe der
   Einträge.

   abyss trägt auf beiden Gründen — über der hellen Karte wie über dem
   helleren Canvas. surface läge auf dem Canvas dicht am Grund.
   ================================================================== */
.dropdown {
  background: var(--core-abyss);
  border: 1px solid var(--core-border-strong);
  border-radius: var(--radius-m);
  box-shadow: var(--shadow-float);
  padding: 6px;
}

.dropdown__eintrag {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  /* Der Baustein loescht den Browser-Standard des <button> mit: In dieser
     Liste steht neben Verweisen (<a>) immer auch mindestens eine Aktion --
     "Abmelden" -- und ein <button> bringt ohne diese drei Zeilen seine
     graue Systemflaeche, seinen Rahmen und zentrierten Text mit. In Nimbus
     stand "Abmelden" deshalb ab 2026-09-08 als graue Kachel zwischen zwei
     flachen Zeilen (Nutzer-Befund 2026-09-09). Die Anwendung soll das nicht
     je Aufrufer nachholen muessen -- genau dafuer ist es ein Baustein. */
  background: transparent;
  border: none;
  text-align: left;
  text-decoration: none;
  /* innen = außen minus Einrückung (E12) */
  border-radius: calc(var(--radius-m) - 6px);
  font-family: var(--font-body);
  font-size: var(--fs-m);
  font-weight: 600;
  line-height: var(--lh-ui);
  color: var(--text-secondary);
  cursor: pointer;
}
.dropdown__eintrag:hover { background: var(--core-surface); color: var(--text-primary); }
.dropdown__eintrag.is-active {
  background: var(--gradient-brand);
  color: var(--text-on-accent);
}


/* ==================================================================
   Schublade (E1)
   ------------------------------------------------------------------
   EIN Baustein mit einem Parameter: dem Anker.

   Der Auslöser trägt die Bedeutung, nicht die Position:
     oben rechts, Benutzer-Icon -> alles, was den Nutzer betrifft
     unten rechts, Burger       -> Navigation im Produkt

   Der Inhalt richtet sich zur selben Kante aus wie sein Auslöser, und
   der Schließen-Knopf legt sich exakt darauf — der Daumen muss zwischen
   Auf und Zu nicht wandern.
   ================================================================== */
.drawer {
  /* Ohne diese Zeile ergeben 252 px Breite plus 16 px Innenabstand 284 px.
     Die React-Apps setzen box-sizing global, ein WordPress-Theme nicht —
     ein Baustein darf sich darauf nicht verlassen. */
  box-sizing: border-box;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  width: min(252px, 80vw);
  padding: 16px;
  background: var(--core-abyss);      /* schwebt über dem Grund (E6) */
  box-shadow: 0 0 40px rgba(0, 0, 0, .5);
  transition: transform 200ms ease;
}
.drawer[data-anchor="oben"]  { justify-content: flex-start; }
.drawer[data-anchor="unten"] { justify-content: flex-end; }

/* Kopf. Steht in JEDER Nutzer-Schublade — auch in der Kontoverwaltung,
   die ihn bisher nicht hatte. */
.drawer__kopf {
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--core-border);
}
.drawer__name  { font-family: var(--font-body); font-size: var(--fs-m); font-weight: 700; color: var(--text-primary); }
.drawer__login { font-family: var(--font-mono); font-size: var(--fs-s); color: var(--text-tertiary); }

.drawer__eintrag {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-m);
  /* Dieselbe Sache wie beim Dropdown-Eintrag darueber: Die Schubladenzeile
     ist mal Verweis, mal Aktion. */
  background: transparent;
  border: none;
  text-align: left;
  text-decoration: none;
  font-size: var(--fs-m);
  font-weight: 600;
  color: var(--text-secondary);
  cursor: pointer;
}
.drawer__eintrag.is-active {
  background: var(--gradient-brand);
  color: var(--text-on-accent);
}

.drawer__fuss {
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--core-border);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text-tertiary);
}

/* 40 px überall; die FORM folgt dem Auslöser — rund über dem runden
   Benutzer-Icon, eckig über dem eckigen Burger. Damit werden aus den
   drei heutigen Formen zwei, und welche gilt, hängt nicht mehr von der
   App ab. */
.drawer__close {
  position: absolute;
  right: 16px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  /* Ein <button> erbt keine Textfarbe, er nimmt den Browser-Standard
     buttontext — und der ist weiß, sobald color-scheme dunkel meldet.
     Auf Hell stand hier ein weißes X auf hellgrauer Fläche. Ein Baustein
     auf einem Bedienelement muss dessen Standard mitlöschen. */
  color: var(--text-primary);
  cursor: pointer;
}
/* Der Abstand zur Ankerkante ist einstellbar, und das hat einen Grund:
   Deckungsgleich ist der Knopf nur, wenn er dort sitzt, wo der Auslöser
   sitzt — und wo der sitzt, sagt die Kopf- oder Fußleiste der Anwendung,
   nicht dieser Baustein. Bei 16 px Standard deckt sich der Knopf mit
   einem 40er Auslöser in einer 72 px hohen Leiste. Die Kontoverwaltung
   hat 56 px (Auslöser bei 8), Nimbus 52 px bei 36er Knöpfen — beide
   brauchen einen anderen Wert, und keiner soll ihn abschreiben müssen.

   Seitlich bleibt es bei 16 px: Die waagerechte Deckung hängt am
   Seitenpolster der Leiste, und das ist in allen dreien dasselbe. */
.drawer[data-anchor="oben"]  .drawer__close { top: var(--drawer-close-abstand, 16px); }
.drawer[data-anchor="unten"] .drawer__close { bottom: var(--drawer-close-abstand, 16px); }

/* Die Form folgt dem AUSLÖSER, nicht dem Anker. In den Anwendungen fällt
   beides zusammen — oben das runde Benutzer-Icon, unten der eckige Burger.
   Auf einer Website steht der Burger oben, und dann trennt sich beides:
   Der Anker sagt, wohin der Inhalt rückt, data-form sagt, wie der Knopf
   aussieht. Ohne Angabe gilt weiter die Zuordnung der Anwendungen. */
.drawer__close                              { border-radius: var(--radius-s); }
.drawer[data-anchor="oben"] .drawer__close  { border-radius: var(--radius-round); }
.drawer .drawer__close[data-form="eckig"]   { border-radius: var(--radius-s); }
.drawer .drawer__close[data-form="rund"]    { border-radius: var(--radius-round); }


/* ==================================================================
   Bestätigungsdialog (E18)
   ------------------------------------------------------------------
   Grundsatz statt Liste: Jede Aktion, die sich nicht rückgängig machen
   lässt, bekommt einen Dialog. Reversible Aktionen (E-Mail ändern,
   Speichern) bekommen keinen.

   Bestätigende Aktion rechts und gefüllt, verwerfende links und
   zurückhaltend. Bei destruktiven Dialogen liegt der ANFANGSFOKUS auf
   Abbrechen — wer mit der Eingabetaste wegdrückt, soll nichts löschen.

   Kein Bottom-Sheet auf Mobile: Das Sheet ist in Nimbus für Auswahl
   belegt, eine Bestätigung soll anders aussehen als eine Auswahl.
   ================================================================== */
.dialog {
  border: 1px solid var(--core-border-strong);
  border-radius: var(--radius-l);
  background: var(--core-abyss);
  box-shadow: var(--shadow-float);
  padding: 24px 26px;
  max-width: 440px;
  color: var(--text-primary);
  font-family: var(--font-body);
  line-height: var(--lh-text);
}
.dialog::backdrop { background: rgba(1, 10, 15, .6); }

.dialog__aktionen {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-3);
  margin-top: var(--space-5);
}


/* ==================================================================
   Umgebungsband (E17)
   ------------------------------------------------------------------
   Drei Zustände. Produktionshosts tragen kein Band.

   Dunkler Text auf beiden Zuständen: Weiß erreicht auf dem Orange nur
   3,2:1 und fällt für den 11-px-Text durch.

   Eigene Token statt Spektrumfarben — Umgebungsanzeige und
   Markenspektrum dürfen sich unabhängig ändern.
   ================================================================== */
.envband {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 6px 12px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-on-marker);
}
.envband[data-env="dev"]   { background: var(--env-dev); }
.envband[data-env="local"] { background: var(--env-local); }
/* Wegklickbar bis zum Neuladen — auch im Login-Theme. Der
   Keycloak-Ablauf besteht aus mehreren Seitenladungen, das Band ist
   dort also bei jedem Schritt wieder da. */
/* Wie bei .btn: ohne diese Zeilen faellt ein <button> auf den Browser-
   Standard zurueck -- grauer Grund, Outset-Rand. Ein Baustein, der auf ein
   <button> gelegt wird, muss den mitloeschen. */
.envband__close {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  /* Zurueckhaltend, bis jemand hinzeigt: Das X ist ein Angebot, keine
     Aufforderung. */
  opacity: .55;
  cursor: pointer;
}
.envband__close:hover { opacity: 1; }


/* ==================================================================
   Icon-Kachel und Icon-Knopf (E13, E15)
   ------------------------------------------------------------------
   Die Kachel gab es dreimal mit drei Rezepten. Vereinheitlicht:
   Radius m, Tönung 15 %, Rand 45 % derselben Farbe, zwei Größen.

   Icon-Knöpfe folgen der Dichte-Logik aus E2: 28 (dicht), 32
   (Standard), 40 (freistehend), mit Icons 16/20/24 darin.
   ================================================================== */
.icon-kachel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-m);
  background: color-mix(in srgb, currentColor 15%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
}
.icon-kachel--sm { width: 32px; height: 32px; }

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  border-radius: var(--radius-s);
  color: var(--text-secondary);
  cursor: pointer;
}
.icon-btn:hover { background: var(--core-surface-2); color: var(--text-primary); }
.icon-btn--xs   { width: 28px; height: 28px; }
.icon-btn--lg   { width: 40px; height: 40px; }
.icon-btn--rund { border-radius: var(--radius-round); }


/* ==================================================================
   Sidebar (E6)
   ------------------------------------------------------------------
   VERANKERT trägt void, SCHWEBEND trägt abyss. Die Sidebar ist
   verankert — auch die der Kontoverwaltung, deren Datei das bereits
   sagt und deren Ladereihenfolge es bisher überschreibt (DSG-30).

   Der Trenner zur Karte ist ein dunkler Schatten statt einer hellen
   Linie: Der native Browser-Scrollbar ist sonst der hellste Punkt der
   ganzen App.
   ================================================================== */
.sidebar {
  background: var(--core-void);
  box-shadow: 6px 0 16px var(--panel-seam);
  border-right: 1px solid rgba(0, 0, 0, .5);
  scrollbar-width: thin;
  scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}
.sidebar::-webkit-scrollbar { width: 8px; }
.sidebar::-webkit-scrollbar-track { background: var(--scrollbar-track); }
.sidebar::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 4px; }
.sidebar::-webkit-scrollbar-thumb:hover { background: var(--brand-blue-dark); }

/* Bedienleisten — die horizontale Leiste über der Karte und die Topbar
   der Kontoverwaltung. */
.topbar { background: var(--core-topbar); }

/* Die große Inhaltsfläche, die bei Nimbus die Karte trägt. */
.canvas { background: var(--core-canvas); }


/* ==================================================================
   Seitengrund (E5)
   ------------------------------------------------------------------
   Drei Ebenen von unten nach oben: Void, die beiden Glows, das Foto.

   Die Glows sind der ERSATZ für das Foto, keine Schicht darüber.
   Solange es lädt, deckt es sie ab; fehlt es, treten sie an seine
   Stelle — ohne JavaScript, nur über die Reihenfolge im Stapel.
   Der Rückfall ist Void plus Glows, nie Weiß.
   ================================================================== */
.seitengrund {
  background-color: var(--core-void);
  /* Das Foto steht als Rueckfallwert und nicht als eigene Deklaration: So
     ist --seitengrund-foto eine Eigenschaft, die von aussen gesetzt werden
     KANN -- vom Hell-Zweig weiter unten, spaeter von einem Aufrufer mit
     eigenem Bild -- und nicht ein Token, das global herumstuende, ohne
     global etwas zu bedeuten. Dieselbe Bauweise wie --geraet-schein. */
  background-image:
    var(--seitengrund-foto, url("https://images.meteocore.com/files/meteocore-hintergrund-blurred.png")),
    radial-gradient(ellipse var(--glow-radius) var(--glow-radius) at 84% 88%, var(--glow-orange), transparent 70%),
    radial-gradient(ellipse var(--glow-radius) var(--glow-radius) at 18% 12%, var(--glow-blue), transparent 70%);
  background-size: cover, auto, auto;
  background-position: center, center, center;
  background-repeat: no-repeat;
  /* Am Sichtfenster verankert, nicht am Dokument. Ohne diese Zeile skaliert
     `cover` das Foto auf die GESAMTE Seitenhoehe -- auf einer Rechtsseite von
     2600 px heisst das rund dreifache Vergroesserung, und uebrig bleibt ein
     dunkler Fleck. Auf kurzen Seiten (Login, Landing) aendert die Zeile
     nichts. iOS Safari ignoriert `fixed` und verhaelt sich dort wie zuvor. */
  background-attachment: fixed;
}

/* Nur für Leseflächen mit langem Text (AGB-Web, Präsentation), und dort
   über beiden Varianten gleichermaßen — der Textkontrast soll nicht
   davon abhängen, ob das Foto geladen hat. */
.seitengrund--lesen::before {
  content: "";
  /* Am Sichtfenster, nicht am Dokument: Auf position:absolute bezieht sich
     inset:0 ohne positionierten Vorfahren auf den Initial Containing Block.
     Der Deckel wird dann genau eine Fensterhöhe hoch, klebt am
     Dokumentanfang und schiebt sich beim Scrollen aus dem Bild — bei einer
     AGB-Seite von 23718 px war ein Zwanzigstel gedämpft. Der Grund darunter
     hängt ebenfalls am Sichtfenster (background-attachment: fixed).
     z-index hält ihn zwischen Grund und Inhalt, sonst läge er über dem
     Text. */
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--glow-overlay);
  pointer-events: none;
}

@media print {
  /* Auf Papier ist Hell gesetzt (E14); ein Deckel für ein Foto, das dort
     nicht gedruckt wird, hat nichts zu suchen. */
  .seitengrund--lesen::before { display: none; }
}

/* Auf Hell traegt ein eigenes Bild: der Himmel, als Gegenstueck zum
   Rechenzentrum. Bis 1.10.0 stand hier `none`, weil das dunkle Foto auf Hell
   eine helle Oberflaeche auf dunklen Grund gestellt haette (Nutzer-Befund
   2026-09-09). Das galt dem Bild, nicht dem Grundsatz -- der Kommentar an
   dieser Stelle sagte damals schon, dass ein eigenes helles Bild genau diese
   Zeile aendern wuerde. Seit 1.11.0 tut es das.

   Dasselbe Rezept wie beim dunklen Bild, zum hellen Ende hin gespiegelt:
   Graustufen, Weichzeichnung, Duotone auf einen einzigen Markenton
   (Weiss -> --brand-blue, auf 22 % gemischt), Vignette nach aussen in den
   Seitengrund hinein. Der mittlere Ton liegt bei 229, 240, 247 und damit
   etwas dunkler als --core-void auf Hell -- so wie das dunkle Bild etwas
   heller liegt als sein Void.

   Die Glows bleiben auch hier der Rueckfall: Faellt images.meteocore.com aus,
   treten sie an die Stelle des Bildes, in beiden Themes gleich. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .seitengrund {
    --seitengrund-foto: url("https://images.meteocore.com/files/meteocore-hintergrund-hell-blurred.jpg");
  }
}
:root[data-theme="light"] .seitengrund {
  --seitengrund-foto: url("https://images.meteocore.com/files/meteocore-hintergrund-hell-blurred.jpg");
}

/* Bei 390 px liegen die Kegel nur rund 260 px auseinander und
   verschmelzen sonst zu einem diffusen Fleck. Die Marke aendert nur den
   Radius, nicht den Stapel. */
@media (max-width: 768px) {
  .seitengrund { --glow-radius: var(--glow-radius-mobile); }
}

/* Auf Papier bleibt der Grund weiss. Das Foto ist Schmuck fuer den
   Bildschirm; gedruckt kostet es einen erheblichen Teil einer
   Tonerkartusche, macht den Text schlechter lesbar und uebersteht Kopieren
   und Scannen schlecht -- dieselbe Begruendung, mit der E14 den Druck aufs
   Hell-Theme legt. Ohne diese Regel legt sich das Foto ueber jede Seite,
   weil background-attachment:fixed es auf jeder wiederholt. */
@media print {
  .seitengrund {
    background-image: none;
    background-color: transparent;
  }
}


/* ==================================================================
   Logo (E19)
   ------------------------------------------------------------------
   Eine Regel, zwei Größen — und den Ausschlag gibt der Ort, nicht die
   Seite. Bis 2026-09-10 nannte die Größentabelle Seiten ("Login-Karte,
   Landing 260, Rechtsseiten 320"), und genau daran ist sie
   auseinandergelaufen: Zwei Landing-Pages standen auf 260, die
   Rechtsseiten auf 320, obwohl das Logo dort dasselbe tut.

   Was es tut, hängt am Ort:

     FREI AUF DEM GRUND (Landing, Rechtsseiten) trägt es die Seite. Es
     hat keine Fläche neben sich, an der es Maß nimmt, und darf deshalb
     größer stehen — 360 px.

     IN EINER FLÄCHE (Anmeldekarte) ist es die Absenderangabe über einem
     Formular. Es teilt sich die Breite mit dem, was darunter steht, und
     bleibt bei 260 px.

   Das Rezept ist in beiden Fällen dasselbe und nur der Deckel
   verschieden: width:100% lässt das Logo in einer schmalen Spalte
   mitschrumpfen, statt sie zu sprengen — auf 390 px steht es damit
   bündig mit der Karte darunter.

   Der Abstand nach unten gehört dem Aufrufer: Er hängt am Satzspiegel
   der Seite, nicht am Logo.
   ================================================================== */
.logo {
  display: block;
  width: 100%;
  max-width: 360px;
  /* height:auto steht hier und nicht nur an der Bildregel darunter: Die
     Klasse sitzt mal auf einer Hülle (Rechtsseiten: <a> um das <img>,
     Login-Theme: <span> um das inline <svg>), mal auf dem Bild selbst
     (Landing-Pages). Im zweiten Fall gäbe width:100% ohne diese Zeile ein
     verzerrtes Logo, sobald die Datei ein height-Attribut trägt. */
  height: auto;
  margin-inline: auto;
}

/* Der erste Fall: Hülle außen, Bild innen. Gilt für beide Bezugswege
   (E19) — das <img> der Rechtsseiten und das inline eingesetzte <svg>
   des Login-Themes. */
.logo img,
.logo svg {
  display: block;
  width: 100%;
  height: auto;
}

.logo--in-flaeche { max-width: 260px; }


/* ==================================================================
   Spektrumleiste
   ------------------------------------------------------------------
   Die sechs Signalfarben in gleich breiten Segmenten, als Abschluss
   einer Seite oder eines Deckblatts.

   Harte Kanten, kein weicher Verlauf: --gradient-spectrum ist die
   ineinander laufende Fassung und sagt „ein Spektrum"; diese hier sagt
   „sechs Bereiche" und ist damit dasselbe Zeichen wie die Segmente auf
   dem Deckblatt der Rechtsdokumente.

   Der Baustein entstand, weil das Rezept bereits an zwei Orten stand —
   unten auf den Rechtsseiten und im Deckblatt der gedruckten AGB — und
   dort schon auseinandergelaufen war: Der Kommentar der Rechtsseiten
   behauptete, die Leiste stehe „genauso hoch wie auf dem gedruckten
   Deckblatt", tatsächlich waren es 8 mm gegen 6. Genau das passiert mit
   sechs abgetippten Prozentgrenzen.

   Die Grenzen rechnen statt zu runden: 16,6 % ist nicht ein Sechstel,
   und sechs solcher Rundungen lassen am Ende 0,4 % offen.

   Die Höhe ist Sache des Aufrufers, denn sie hängt am Ort — ein
   Deckblatt misst in Millimetern, ein Seitenfuß in Pixeln. Die Vorgabe
   ist die schmale Fassung für den Bildschirm.
   ================================================================== */
.spektrumleiste {
  height: var(--spektrumleiste-hoehe, 8px);
  background: linear-gradient(90deg,
    var(--spectrum-ingest)   0                calc(100% / 6),
    var(--spectrum-core)     calc(100% / 6)   calc(100% / 3),
    var(--spectrum-scale)    calc(100% / 3)   50%,
    var(--spectrum-detect)   50%              calc(100% * 2 / 3),
    var(--spectrum-broker)   calc(100% * 2 / 3) calc(100% * 5 / 6),
    var(--spectrum-endkunde) calc(100% * 5 / 6) 100%);
}


/* ==================================================================
   Badges (E12)
   ------------------------------------------------------------------
   Badges sind keine Pillen. Bei rund 18 px Höhe wäre schon
   --radius-chip eine volle Rundung; Textbadges tragen deshalb
   --radius-s.

   Ausnahme ist der Benachrichtigungszähler: eine runde Zahl, die nach
   --radius-round verlangt. Damit erweitert er die in E12 genannte
   Liste (runde Icon-Knöpfe, Avatare, Slider-Daumen) um einen vierten
   Fall — bewusst und hier vermerkt.
   ================================================================== */
.tier-badge,
.navi-badge {
  display: inline-flex;
  align-items: center;
  padding: 5px 13px;
  border-radius: var(--radius-s);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
}

/* Farbe kennzeichnet das SYSTEM (API-Tier), nicht die einzelne Stufe —
   welche Stufe es ist, sagt der Text. Spektrumfarben bewusst nicht,
   weil Blau für tier:basic UND für nimbus zwei Dinge bedeutet hätte. */
.tier-badge[data-tier="tier:opendata"]      { background: var(--core-surface-2); color: var(--text-secondary); border: 1px solid var(--core-border-strong); }
.tier-badge[data-tier="tier:basic"],
.tier-badge[data-tier="tier:professional"],
.tier-badge[data-tier="tier:enterprise"]    { background: var(--brand-blue); color: var(--text-on-accent); }

/* Zweite, produktspezifische Dimension: Zugang zur NAVI-Oberfläche,
   nicht die API-Rate-Limits. Bewusst dieselbe Struktur, damit beide
   Leitern als Analogie lesbar sind. */
.navi-badge[data-access="nimbus-beta"]      { background: var(--core-surface-2); color: var(--text-secondary); border: 1px solid var(--core-border-strong); }
/* Dunkle Schrift, anders als bei der Tier-Leiter: Weiss auf dem Blau
   traegt mit 4,60:1, auf dem Orange nur mit 3,20:1 — bei 11 px fett
   sind 4,5 die Schwelle (DSG-56). Die Analogie der beiden Leitern haengt
   an der Flaeche (neutral mit Kante gegen gefuellte Markenfarbe), nicht
   an der Schriftfarbe; die folgt dem Grund (E4). */
.navi-badge[data-access="nimbus"],
.navi-badge[data-access="nimbus-premium"],
.navi-badge[data-access="nimbus-lifetime"]  { background: var(--brand-orange); color: var(--text-on-marker); }

/* ==================================================================
   Zähler
   ------------------------------------------------------------------
   Eine Anzahl, rund und knapp: Mono, fett, 18 px hoch, ab zwei Stellen
   wächst er in die Breite.

   Zwei Fälle, ein Körper. `.zaehler` steht im Fluss — neben einer
   Beschriftung, in einem Knopf, hinter einer Überschrift — und zählt
   Dinge. `.notif-badge` sitzt auf einem Icon und meldet die höchste
   aktive Warnstufe; er bringt seine Position, den Rand gegen den Grund
   und die Stufenfarben selbst mit.

   Getrennt sind sie in der Farbe, und zwar mit Absicht: Eine Anzahl ist
   keine Warnstufe (E8). Ein Zähler im Fluss trägt deshalb Markenorange
   — als Marker ist der Ton zulässig (E9) — und nie eine Warnfarbe.
   ================================================================== */
.zaehler,
.notif-badge {
  /* Der Baustein misst sich selbst. Die React-Apps setzen box-sizing
     global, ein WordPress-Theme nicht — ohne diese Zeile wäre derselbe
     Zähler dort 28 statt 18 px breit, weil min-width dann für die
     Inhaltsbox gilt und die Innenabstände obendrauf kämen. */
  box-sizing: border-box;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-round);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1;
}

.zaehler {
  background: var(--brand-orange);
  /* Dunkle Schrift, nicht weiße: Weiß erreicht auf dem Orange nur
     3,2:1. Dieselbe Stelle steht in den CI-Regeln beim Umgebungsband,
     das aus demselben Grund --text-on-marker trägt. */
  color: var(--text-on-marker);
}

/* Farbe = Warnfarbe der höchsten Stufe unter den AKTIVEN
   Benachrichtigungen. Eigenständige Skala, keine Summe. */
.notif-badge {
  position: absolute;
  top: -3px;
  right: -3px;
  border: 2px solid var(--core-void);
}
.notif-badge[data-level="1"] { background: var(--warn-1); color: #3A2E00; }
.notif-badge[data-level="2"] { background: var(--warn-2); color: var(--text-on-accent); }
.notif-badge[data-level="3"] { background: var(--warn-3); color: var(--text-on-accent); }
.notif-badge[data-level="4"] { background: var(--warn-4); color: var(--text-on-accent); }


/* ==================================================================
   Spektrum-Tag
   ------------------------------------------------------------------
   Kennzeichnung eines Geschäftsfelds. Die Wertschöpfungskette von der
   Datenerfassung bis zum Endabnehmer — NICHT Wetter-Domänen und NICHT
   Warnstufen.
   ================================================================== */
.spectrum-tag[data-domain="ingest"]   { background: var(--spectrum-ingest); }
.spectrum-tag[data-domain="core"]     { background: var(--spectrum-core); }
.spectrum-tag[data-domain="scale"]    { background: var(--spectrum-scale); color: var(--text-on-marker); }
.spectrum-tag[data-domain="detect"]   { background: var(--spectrum-detect); }
.spectrum-tag[data-domain="broker"]   { background: var(--spectrum-broker); }
.spectrum-tag[data-domain="endkunde"] { background: var(--spectrum-endkunde); }

/* ==================================================================
   Präsentation (E15)
   ------------------------------------------------------------------
   Aus der Gründerpreis-Bewerbung übernommen — dem einzigen und zugleich
   reifsten Präsentationsmaterial im Bestand. Sie wegzuwerfen hieße, sie
   beim nächsten Pitch neu zu erfinden.

   Die Größen wachsen über .praesentation (tokens.css) mit dem
   Präsentations-Faktor: dieselbe Skala, ein Umrechnungsschritt, keine
   eigenen Folienwerte.
   ================================================================== */

/* Zitat auf einer Folie: die Bühnen-Card mit einer Kante in
   --brand-blue-dark. Sie hebt das Zitat vom übrigen Folientext ab, ohne
   eine zweite Fläche einzuführen. */
.zitat {
  background: var(--core-abyss);
  border: 1.5px solid var(--brand-blue-dark);
  border-radius: var(--radius-l);
  padding: 26px 30px;
  display: flex;
  gap: 20px;
}
.zitat p {
  font-style: italic;
  font-size: var(--fs-l);
  line-height: var(--lh-text);
  margin: 0;
}

/* Zeitachse. Der Punkt trägt einen Ring in --core-void, damit er auf der
   Linie sitzt statt sie zu unterbrechen -- dasselbe Mittel wie die Kontur
   am Laufstand-Band (E22). */
.timeline {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: var(--space-4);
}
.timeline__datum {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--fs-l);
  margin-bottom: 6px;
}
.timeline__punkt {
  /* Über der Achse, nicht darunter: Die Linie ist ein absolut gesetztes
     ::before und läge sonst über diesem statischen Geschwister. */
  position: relative;
  width: 14px;
  height: 14px;
  border-radius: var(--radius-round);
  margin-bottom: var(--space-3);
  background: var(--brand-blue);
  box-shadow: 0 0 0 3px var(--core-void);
}

/* Die Achse selbst.

   Sie war bis 1.33.0 nur gemeint, nicht gezeichnet: Der Ring am Punkt
   sollte ihn „auf der Linie sitzen lassen, statt sie zu unterbrechen" —
   die Linie gab es aber gar nicht (Nutzer-Befund am Pitchdeck).

   Sie hängt am Eintrag und nicht am Punkt: So läuft je ein Stück von
   einer Station zur nächsten, über die Lücke des Rasters hinweg, und
   die letzte Station lässt es weg. Eine durchgehende Linie am Container
   müsste dagegen wissen, wo die Punktmitte liegt — sie hängt an der
   Schrifthöhe des Datums und wäre bei jeder Änderung daneben. Hier sind
   es die 7 px der halben Punkthöhe, und die stehen fest, weil der Punkt
   das erste Element im Eintrag ist. */
.timeline__eintrag {
  position: relative;
}

.timeline__eintrag::before {
  content: "";
  position: absolute;
  top: 7px;
  left: 7px;
  right: calc(var(--space-4) * -1);
  height: 1px;
  /* Die kräftigere Kante und nicht --core-border: Die Achse verbindet die
     Stationen und ist damit Inhalt, keine Flächenkante. Mit dem Ton der
     Kartenränder verschwand sie neben den Karten, die sie verbinden
     soll. */
  background: var(--core-border-strong);
}

.timeline__eintrag:last-child::before {
  content: none;
}
/* Der Eintrag ist eine Spalte, damit seine Karte die Resthöhe füllen
   kann: Das Raster streckt die Eintraege auf gleiche Höhe, die Karte
   darin richtete sich aber nach ihrem Text — bei fünf Stationen mit
   unterschiedlich vielen Punkten endeten sie auf fünf verschiedenen
   Höhen (Nutzer-Befund am Pitchdeck, 221 bis 261 px in einem Eintrag
   von 343). */
.timeline__eintrag {
  display: flex;
  flex-direction: column;
}

.timeline__phase {
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-m);
  padding: var(--space-4);
  flex: 1;
}

/* Die Aufzählung in einer Station rückt 16 px ein, nicht die 40 des
   Browsers: In einer Karte von rund 240 px Breite ist der Standardeinzug
   ein Sechstel der Zeile, und der Text steht sichtbar zu weit rechts
   (Nutzer-Befund am Pitchdeck). Der Einzug sitzt am Punkt selbst, damit
   die Liste als Ganzes an der Kartenkante beginnt. */
.timeline__phase ul {
  margin: 0;
  padding: 0;
  list-style: disc;
}
.timeline__phase li {
  margin: 0 0 7px 16px;
  font-size: var(--fs-s);
  color: var(--text-secondary);
  line-height: var(--lh-tight);
}
.timeline__phase li:last-child { margin-bottom: 0; }

/* Nebeneinander nur, solange nebeneinander lesbar ist. Auf einem Telefon
   stünden sechs Stationen als sechs Streifen von je 50 px da; als Zeilen
   bleibt jede Station lesbar, und die Achse liest sich von oben nach
   unten statt von links nach rechts. Dieselbe Schwelle wie beim
   Präsentationsfaktor: Darunter wird gelesen, nicht projiziert (E15). */
@media (max-width: 899px) {
  .timeline {
    grid-auto-flow: row;
    gap: var(--space-3);
  }

  /* Untereinander kippt die Achse mit: Der Punkt rückt nach links außen,
     die Linie läuft von ihm nach unten zur nächsten Station, und Datum
     und Karte rücken daneben. Eine waagerechte Linie wäre hier ein
     Strich zwischen zwei Karten und keine Achse mehr. */
  .timeline__eintrag {
    padding-left: 26px;
  }

  .timeline__punkt {
    position: absolute;
    left: 0;
    top: 4px;
    margin-bottom: 0;
  }

  .timeline__eintrag::before {
    top: 11px;
    left: 6px;
    right: auto;
    bottom: calc(var(--space-3) * -1);
    width: 1px;
    height: auto;
  }
}

/* Erledigt ist ein Zustand, keine Domäne (E8). Die Marke sitzt am
   Eintrag, nicht an der Karte: Punkt und Karte sind Geschwister, und
   beide sollen sie tragen. */
.timeline__eintrag.is-erledigt .timeline__punkt { background: var(--ui-success); }
.timeline__eintrag.is-erledigt .timeline__phase { border-color: var(--ui-success); }

/* Kontaktblock der Schlussfolie: zwei Spalten über einer Trennlinie,
   Angaben in Mono, weil sie gelesen und abgetippt werden. */
.kontaktblock {
  border-top: 1px solid var(--core-border);
  padding-top: var(--space-5);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}
.kontaktblock span {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  font-family: var(--font-mono);
  font-size: var(--fs-m);
  color: var(--text-secondary);
}

/* Folien-Fußzeile. Links die Angabe, rechts die Seitenzahl -- wie im
   Druck (E14), nur ohne @page. */
.folienfuss {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-tertiary);
}

/* ------------------------------------------------------------------
   Wie groß eine Folie wird (E15)

   Der Faktor 2 ist für 1920x1080 entworfen. Ein Browserfenster ist aber
   nie so hoch wie der Schirm: Tableiste, Adressleiste und Lesezeichen
   kosten zusammen 250 bis 350 px, und mit festem Faktor stand dort eine
   Folie, die nicht mehr daraufpasste (Nutzer-Befund 2026-09-10).

   Gestaffelt und nicht gerechnet: `min(100dvh / 540, …)` wäre die
   schönere Formel, ergibt in CSS aber eine LÄNGE statt einer Zahl —
   `calc(11px * 1.34px)` ist ungültig, und die Schrift fällt auf den
   Browserstandard zurück. Gemessen, nicht vermutet.

   Gestaffelt wird nach der HÖHE, nicht nach der Breite. Die Höhe ist der
   Engpass: Die Breite der Folie folgt ihr ohnehin (16:9), und die Stufen
   entsprechen dem, was der Entwurfswert bei 1080 px hergibt — 2 mal
   Höhe durch 1080, auf die Stufe gerundet. Die Mindestbreite von 900 px
   steht daneben, damit ein schmales hohes Gerät nicht die große Stufe
   bekommt: Ein Tablet im Hochformat ist hoch genug dafür, aber zu
   schmal.

   Nach oben ist bei 2 Schluss. Auf einem 4K-Schirm wächst die Fläche
   weiter, die Schrift nicht — sonst liest man dasselbe Deck aus
   doppelter Entfernung.
   ------------------------------------------------------------------ */

.praesentation { --presentation-factor: 1; }

@media (min-width: 900px) and (min-height: 640px)  { .praesentation { --presentation-factor: 1.2; } }
@media (min-width: 900px) and (min-height: 760px)  { .praesentation { --presentation-factor: 1.45; } }
@media (min-width: 900px) and (min-height: 880px)  { .praesentation { --presentation-factor: 1.7; } }
@media (min-width: 900px) and (min-height: 1000px) { .praesentation { --presentation-factor: 2; } }


/* ------------------------------------------------------------------
   Der Foliensatz (E15, DSG-43)

   Bis hierher stand die Folienwelt lokal in den Bewerbungs-HTMLs — als
   .slide, .grid2/.grid3, .split, .zrow, .erloes. Sie steht jetzt hier,
   damit sie nicht ein zweites Mal im WordPress-Theme entsteht.

   Die Namen sagen, WAS das Element ist, nicht was gerade darin steht:
   `.erloes` hieß nach dem Erlösmodell, das auf einer bestimmten Folie
   stand — beim nächsten Deck mit anderem Inhalt wäre der Name falsch.

   Blättern ist Scrollen. Der Container schnappt ein, und damit
   funktioniert der Foliensatz OHNE JavaScript; was folien.js ergänzt,
   sind Tastatur, Punkte, Tiefenlink und Fortschritt (DSG-46). Fällt es
   aus, bleibt eine bedienbare Seite — dieselbe Rückfall-Logik wie bei
   den Glows unter dem Hintergrundfoto (E5).
   ------------------------------------------------------------------ */

.folien {
  /* Die Höhe kommt aus einer Eigenschaft mit Rückfallwert, weil zwei
     Dinge sie brauchen: der Container selbst und die Breitengrenze der
     Folie darin. Wer über dem Foliensatz noch etwas stehen hat — eine
     Adminleiste zum Beispiel —, setzt --folien-hoehe einmal um, und
     beides stimmt.

     dvh und nicht vh: Auf dem Telefon wandert die Adressleiste beim
     Scrollen ein und aus, und `vh` rechnet mit dem größeren Zustand —
     die Folie wäre dann immer ein Stück höher als das, was man sieht. */
  height: var(--folien-hoehe, 100dvh);
  overflow-y: auto;
  scroll-snap-type: y mandatory;
  /* Der Sprung von Folie zu Folie gehört zur Bedienung, nicht zur
     Zierde — er bleibt auch bei reduzierter Bewegung, nur eben ohne
     Weichzeichnung (siehe unten). */
  scroll-behavior: smooth;
}

.folie {
  /* Die Folie füllt den CONTAINER, nicht das Sichtfenster. Beides ist
     meist dasselbe — aber eben nur meist: Steht über dem Foliensatz eine
     Kopfzeile, ist der Container kleiner, und mit 100vh wäre jede Folie
     genau um deren Höhe zu hoch. Sichtbar wird das als Scrollen INNERHALB
     einer Folie, obwohl sie eingerastet ist (an der Probe gemessen: 819
     gegen 723 px).

     Und sie misst sich selbst: Ohne box-sizing kommt das Polster von
     zweimal 48 px zur Höhe HINZU, und die Folie ist wieder zu groß —
     dieselbe Falle wie bei .drawer und .zaehler. Die React-Apps setzen
     es global, ein WordPress-Theme nicht. */
  box-sizing: border-box;
  min-height: 100%;
  /* Seitlich auf die Skala gerundet, im Pitchdeck standen 56/64 (E10).
     Oben und unten 32 statt 48: Der obere Rand war mit dem Eigenrand des
     ersten Blocks zusammen 61 px und damit groesser als der untere von
     48 — ein Additionsergebnis, das niemand gesetzt hatte. Beide stehen
     jetzt auf 32; der untere traegt zusaetzlich die Fusszeile mit
     Nummerierung und Marke und wirkt damit ohnehin gefuellter. */
  padding: var(--space-6) var(--space-8);
  /* Die Folie behält das Format einer Folie: 16:9, gerechnet aus der
     Höhe, die tatsächlich zu sehen ist.
     
     Ein Browserfenster ist breiter als hoch, und zwar deutlich — bei
     1920 x 1036 bleiben nach Tab-, Adress- und Lesezeichenleiste rund
     880 px Höhe übrig. Eine Folie, die dann die vollen 1920 nimmt, ist
     kein 16:9 mehr, sondern 22:9; die Zeilen laufen auseinander und der
     Blick springt (Nutzer-Befund 2026-09-10). Links und rechts bleibt
     stattdessen Grund stehen.

     Die 1920 sind die absolute Obergrenze darüber: Auf einem sehr hohen
     Schirm wächst die Fläche weiter, der Satz nicht. */
  width: 100%;
  max-width: min(1920px, calc(var(--folien-hoehe, 100dvh) * 16 / 9));
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  position: relative;
  scroll-snap-align: start;
}

/* Der erste Block einer Folie bringt keinen eigenen oberen Rand mit.
   Sonst addiert er sich zum Polster, und heraus kommt ein Abstand, den
   niemand gesetzt hat: gemessen 61 px, wo 48 standen. Dasselbe gilt am
   Fuss — ein letzter Block darf den unteren Rand nicht verdoppeln. */
.folie > :first-child { margin-top: 0; }
.folie > .folienfuss:last-child,
.folie > :last-child { margin-bottom: 0; }

/* Die Überschrift einer Folie. Als eigene Klasse und nicht als `.folie h2`,
   weil eine Folie mehr als eine Überschrift tragen kann — die zweite ist
   dann eine Zwischenüberschrift und soll nicht wie die Folientitelzeile
   aussehen. */
.folie__titel {
  font-family: var(--font-display);
  font-size: var(--fs-5xl);
  font-weight: 700;
  margin: var(--space-2) 0 var(--space-6);
}

/* Die Titelfolie und die eine große Aussage: beides steht mittig, beides
   hat keinen Fließtext daneben. */
.folie--titel,
.folie--zentriert {
  justify-content: center;
  align-items: center;
  text-align: center;
}

/* Die Fußzeile heftet sich unten an, statt absolut zu stehen: In einer
   Spalte mit flex-direction ist `margin-top: auto` der ehrlichere Weg,
   und im Lesemodus (unter 900 px, wo die Folienhöhe frei wird) rutscht
   sie damit hinter den Inhalt statt über ihn. */
.folie > .folienfuss {
  margin-top: auto;
  padding-top: var(--space-5);
  /* Über die ganze Folienbreite, auch wo die Folie ihre Kinder mittig
     stellt: `.folie--zentriert` setzt align-items auf center, und ein
     Flex-Kind schrumpft dann auf seine Inhaltsbreite. `space-between`
     hat nichts mehr zu verteilen, und aus „meteoCORE ··· 7 / 8" wird
     „meteoCORE7 / 8" (Nutzer-Befund 2026-09-10). */
  align-self: stretch;
}

/* Was in der Fußzeile verlinkt ist, bleibt so leise wie der Rest von
   ihr: Die Fußzeile ist eine Randangabe, kein Verweisziel — sie soll
   nicht die einzige Stelle der Folie sein, die farbig unterstrichen
   ist. */
.folienfuss a {
  color: inherit;
  text-decoration: none;
}
.folienfuss a:hover {
  color: var(--text-secondary);
}

/* Die Rasterformen einer Folie. Drei Fälle, mehr braucht es nicht: zwei
   gleiche Spalten, drei gleiche, oder eine geteilte — links der Text,
   rechts die Hervorhebung. Das Verhältnis 1.35 zu 1 stammt aus dem
   Pitchdeck und ist gemessen, nicht geraten: Es ist der Punkt, an dem
   die rechte Spalte noch als Nebensache liest. */
/* minmax(0, …) und nicht bloß 1fr: Eine fr-Spur ist implizit mindestens
   so breit wie ihr Inhalt (min-width:auto). Sobald in einer Spalte etwas
   steht, das selbst eine Mindestbreite mitbringt — ein zweites Raster mit
   Karten zum Beispiel —, drückt es die Spur auf und das erklärte
   Verhältnis gilt nicht mehr. Auf der Pitchfolie „Markt & Problem"
   gemessen: deklariert 1,35fr zu 1fr, tatsächlich 279 zu 446 px. Die
   linke Spalte war schmaler als die rechte, obwohl sie breiter sein
   sollte, und keine Einstellung daran änderte etwas.

   Mit minmax(0, …) darf die Spur schmaler werden als ihr Inhalt; der
   bricht dann um, was in einem Raster das erwartete Verhalten ist. */
.folienraster {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-5);
}
.folienraster--drei    { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.folienraster--geteilt { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: start; }

/* Bildkarte: links ein Bild bis an die Kante, rechts der Text.

   Die Form gibt es auf der Website längst — die Anrissliste der
   Neuigkeiten ist genau das. Sie hing dort aber an den Klassen der
   WordPress-Abfrageblöcke und war damit nur für Beiträge zu haben. Hier
   steht sie ohne diese Bindung und trägt beliebigen Inhalt: eine Folie,
   eine Landing, eine Karte in einer Anwendung.

   Das Bild läuft bis an die Kartenkante. Ein Anschnitt mit Rand darum
   sähe aus wie ein gerahmtes Bild in einem Rahmen — deshalb trägt die
   Karte kein eigenes Polster, sondern die Textspalte (E4).

   Die Bildspalte ist quadratisch und bestimmt damit die Mindesthöhe der
   Karte. Ein Bild, das seine Spalte nur füllt, wäre bei wenig Text ein
   flacher Streifen und bei viel Text eine hohe Säule; beides ist kein
   Bildausschnitt mehr, sondern ein Zufall. --bildkarte-bild nimmt ein
   anderes Verhältnis entgegen, wo das Motiv es verlangt.

   Die Spaltenteilung steht auf 1 zu 1.6: Das Bild ist der Einstieg, der
   Text die Sache. minmax(0, …) wie beim Folienraster, sonst drückt der
   Inhalt die Spuren auf und das Verhältnis gilt nicht. */
.bildkarte {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, var(--bildkarte-teilung, 1.6fr));
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-l);
  overflow: hidden;
}

.bildkarte__bild {
  aspect-ratio: var(--bildkarte-bild, 1);
  min-width: 0;
}

/* Die Höhe muss die ganze Kette hinunter, nicht nur ans Bild: Zwischen
   Spalte und <img> steht je nach Anwendung noch eine <figure> und
   womöglich ein <a>, und ein height:100% verpufft an der ersten Stelle,
   die selbst keine Höhe hat. Ohne diese Zeilen sitzt das Bild in seiner
   natürlichen Größe mitten in der Spalte statt sie zu füllen. */
.bildkarte__bild > *,
.bildkarte__bild > * > * {
  display: block;
  height: 100%;
  margin: 0;
}

.bildkarte__bild img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Der Text sitzt mittig zur Bildhöhe: Eine Karte, deren Höhe das Bild
   bestimmt, hat neben kurzem Text sonst unten ein Loch. */
.bildkarte__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-6);
  min-width: 0;
}

/* Die Blockstile der Anwendung setzen an Überschriften und Absätze
   eigene Ränder; zusammen mit dem gap ergäbe das Abstände, die niemand
   gesetzt hat — dieselbe Addition wie am oberen Folienrand. */
.bildkarte__text > * {
  margin-block: 0;
}

/* Der Kicker ist die Dachzeile des Titels und gehört eng an ihn. */
.bildkarte__text > .kicker + * {
  margin-top: calc(var(--space-3) * -1 + var(--space-1));
}

/* Bildbühne: ein Bild über die volle Breite einer Fläche, darunter
   seine Unterschrift.

   Der Unterschied zur Bildkarte ist nicht die Anordnung, sondern was
   danebensteht: Die Bildkarte trägt einen Text, der für sich steht —
   Kicker, Titel, Anriss, Knopf. Hier steht eine Bildunterschrift, und
   die gehört unter ihr Bild, nicht neben es. Eine Zeile in der rechten
   Spalte einer Bildkarte lässt diese Spalte leer und halbiert die
   Breite des Bildes an einen Anschnitt, den niemand wollte.

   Die Bühnenfläche, nicht die Flächen-Card: Das Bild steht in einem
   redaktionellen Text über dem Seitengrund mit Foto, und darüber liegt
   eine Bühne (E4). Das Rezept steht hier ein zweites Mal und nicht als
   `.card--buehne` am selben Element — sonst müsste diese Klasse das
   Polster der Card wieder auf null drehen, und wer die Reihenfolge der
   Stylesheets einmal vertauscht, bekommt ein gerahmtes Bild im Rahmen
   zurück. Dieselbe Entscheidung wie bei .bildkarte.

   Kein aspect-ratio: Ein Bild im Text zeigt, was es zeigt. Der
   Anschnitt gehört der Liste, wo gleich hohe Karten nebeneinander
   stehen müssen — hier steht ein einzelnes Bild, und ein Beschnitt
   wäre eine Entscheidung über fremdes Material. */
.bildbuehne {
  background: var(--core-abyss);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-stage);
  overflow: hidden;
  padding: 0;
}

/* Der Verweis dazwischen ist der Normalfall, sobald das Bild verlinkt
   ist: WordPress schiebt ein <a> zwischen Figur und Bild. Ohne die
   zweite Zeile bliebe darunter der Zeilenabstand des <a> als heller
   Streifen stehen. */
.bildbuehne > img,
.bildbuehne > a,
.bildbuehne > a > img {
  display: block;
  width: 100%;
  height: auto;
}

/* Die Unterschrift trägt das Polster, das die Fläche nicht hat. In der
   zweiten Textfarbe und EINE Stufe kleiner als der Fließtext, nicht
   zwei: Bei 16 px Fließtext ist --fs-m die Stufe darunter. --fs-s (12)
   stand hier zuerst und war die Größe des Kickers — eine Bildunterschrift
   ist aber ein Satz, den jemand lesen soll, und keine Dachzeile
   (gemessen an der Stilprobe, 2026-09-12). */
.bildbuehne > figcaption {
  margin: 0;
  padding: var(--space-4) var(--space-5);
  color: var(--text-secondary);
  font-size: var(--fs-m);
  line-height: var(--lh-ui);
  text-align: left;
}

/* Eine Merkzeile: Icon-Kachel, Fettzeile, Beschreibung. Die Aufzählung
   einer Folie, die keine Aufzählungspunkte tragen soll. */
.merkzeile {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  background: var(--core-surface);
  border: 1px solid var(--core-border);
  border-radius: var(--radius-m);
  padding: var(--space-3) var(--space-4);
}
.merkzeile + .merkzeile { margin-top: var(--space-3); }
.merkzeile__titel {
  display: block;
  font-size: var(--fs-l);
  font-weight: 700;
}
.merkzeile__text {
  font-size: var(--fs-s);
  color: var(--text-secondary);
}

/* Die abgesetzte Aussage — eine Bühnenfläche mit blauer Kante, wie das
   Zitat, aber mit Kicker und mehreren Punkten darin. */
.hervorhebung {
  background: var(--core-abyss);
  border: 1.5px solid var(--brand-blue-dark);
  border-radius: var(--radius-l);
  padding: var(--space-5);
}
.hervorhebung__kicker {
  font-family: var(--font-mono);
  font-size: var(--fs-s);
  color: var(--brand-blue);
  letter-spacing: .25em;
  text-transform: uppercase;
  margin-bottom: var(--space-4);
}
.hervorhebung__titel {
  display: block;
  font-size: var(--fs-m);
  font-weight: 700;
  margin-top: var(--space-3);
}
/* Nur der Fließtext, nicht jeder Absatz: Kicker und Titel tragen eigene
   Klassen, und `.hervorhebung p` wiegt mehr als sie — in der Demo stand
   der Kicker dadurch grau statt blau. */
.hervorhebung p:not([class]) {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

/* Der Nachsatz unter einer Folie: kursiv, mittig, leiser als der Inhalt. */
.foliennotiz {
  text-align: center;
  font-style: italic;
  color: var(--text-tertiary);
  font-size: var(--fs-sm);
  margin-top: var(--space-5);
}

/* Die herausgestellte Kennzahl oder Eigenschaft — Mono, weil sie gelesen
   und verglichen wird. */
.folienmerkmal {
  font-family: var(--font-mono);
  font-size: var(--fs-l);
  font-weight: 600;
  color: var(--brand-blue);
  letter-spacing: .06em;
}

/* Punktnavigation und Fortschritt. Beides ist neu — die Foliensätze im
   Repo haben bisher keine Bedienung —, und beides steht ÜBER den Folien,
   nicht in ihnen: Es gehört dem Satz, nicht der einzelnen Folie. */
.folien__punkte {
  position: fixed;
  right: var(--space-5);
  top: 50%;
  translate: 0 -50%;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  z-index: 20;
}
.folien__punkt {
  width: 9px;
  height: 9px;
  padding: 0;
  border: 1px solid var(--core-border-strong);
  border-radius: var(--radius-round);
  background: transparent;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}
.folien__punkt:hover { border-color: var(--text-secondary); }
.folien__punkt.is-active {
  background: var(--brand-orange);
  border-color: var(--brand-orange);
}

.folien__fortschritt {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform-origin: 0 50%;
  scale: var(--folien-stand, 0) 1;
  background: var(--gradient-brand);
  z-index: 20;
}

/* Unterhalb der Folienbreite wird gelesen, nicht projiziert (E15).
   Die Höhe wird frei, das erzwungene Einschnappen entfällt — die
   Punktnavigation bleibt, sie ist dann ein Inhaltsverzeichnis. */
@media (max-width: 899px) {
  /* Den Faktor regelt die Formel am Token selbst — unter 900 px ist sie
     ohnehin bei 1 angekommen. Was hier steht, ist die MECHANIK: Unter der
     Folienbreite wird gelesen, nicht projiziert. */
  .folien {
    height: auto;
    overflow-y: visible;
    scroll-snap-type: none;
  }
  .folie {
    min-height: 0;
    padding: var(--space-6) var(--space-5);
    scroll-snap-align: none;
    /* Kein Folienformat mehr: Hier wird gelesen, und ein Text soll die
       Breite nehmen, die das Gerät hergibt. */
    max-width: none;
  }
  .folienraster,
  .folienraster--drei,
  .folienraster--geteilt {
    grid-template-columns: 1fr;
  }

  /* Nebeneinander bleibt für eine Bildkarte auf einem Telefon nichts
     übrig: Das Bild wäre ein Daumennagel und der Text eine Spalte aus
     Einzelwörtern. Also untereinander — und das Bild wird flacher, weil
     ein Quadrat über die volle Breite den Text unter den Falz schiebt. */
  .bildkarte {
    grid-template-columns: 1fr;
  }

  .bildkarte__bild {
    aspect-ratio: var(--bildkarte-bild-schmal, 16 / 9);
  }

  /* Die Punkte liegen quer statt längs und unten statt in der Mitte: Am
     rechten Rand eines Telefons stehen sie sonst mitten im Text, und bei
     acht Folien ist die Spalte länger als der halbe Schirm. */
  .folien__punkte {
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    translate: none;
    flex-direction: row;
    justify-content: center;
    padding: var(--space-3);
    background: color-mix(in srgb, var(--core-void) 85%, transparent);
    backdrop-filter: blur(6px);
  }
}

/* Wer weniger Bewegung möchte, bekommt weniger Bewegung — aber dieselbe
   Bedienung: Der Sprung passiert sofort statt gleitend. */
@media (prefers-reduced-motion: reduce) {
  .folien { scroll-behavior: auto; }
  .folien__punkt { transition: none; }
}

/* Im Druck ist jede Folie eine Seite (E14). Die Bedienelemente entfallen —
   auf Papier gibt es nichts zu klicken. */
@media print {
  .folien {
    height: auto;
    overflow: visible;
    scroll-snap-type: none;
  }
  .folie {
    min-height: 0;
    break-after: page;
  }
  .folie:last-child { break-after: auto; }
  .folien__punkte,
  .folien__fortschritt { display: none; }
}


/* ------------------------------------------------------------------
   Gerät (E15)

   EIN Baustein für zwei Stellen: den Geräterahmen der Screenshot-Vorlage
   und den Geräte-Showcase der Landing. Sie zeigten dasselbe mit zwei
   Rezepten und zwei Gehäusefarben — eine davon --core-surface, womit das
   Gerät aussah wie eine weitere Panelfläche der Anwendung statt wie ein
   Gerät.

   Das Gehäuse ist deshalb fast schwarz und neutral (--geraet-rahmen).
   Die Größe bestimmt der Aufrufer; hier stehen nur Rahmen, Verhältnis
   und Schatten.

   THEMEFEST ist nicht nur das Gehäuse, sondern das ganze Gerät: Schirm,
   Kameraauge und Platzhalter ziehen eigene Token und nicht die der
   Anwendung. Der Schirm zeigt einen Screenshot, und der ist dunkel
   aufgenommen -- auf Hell stand mit --core-void ein weisser Streifen
   unter dem Bild, dort wo `contain` Fläche frei lässt (Nutzer-Befund
   2026-09-09, am Telefon der Landing). Ein Gerät folgt dem Theme der
   Seite nicht; es zeigt, was auf ihm läuft.
   ------------------------------------------------------------------ */
.geraet {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: var(--radius-m);
  background: var(--geraet-schirm);
  border: 3px solid var(--geraet-rahmen);
  /* Der farbige Schein ist optional und gehört dem Aufrufer: Auf der
     Landing hebt er das Gerät vom Foto ab, im Katalog und in der
     Screenshot-Vorlage wäre er Schmuck ohne Anlass. Als eigene
     Eigenschaft, weil box-shadow sich nicht ergänzen lässt -- sonst
     müsste jede Stelle alle drei Schichten neu schreiben. */
  box-shadow:
    0 40px 70px -24px rgba(0, 0, 0, .65),
    0 0 0 1px var(--core-border-strong),
    0 0 90px -30px var(--geraet-schein, transparent);
}

/* Das Telefon ist schmaler, hat den engeren Radius und das reale
   Seitenverhältnis — nicht das der Browser-Screenshots. */
.geraet--telefon {
  aspect-ratio: 9 / 19.5;
  border-width: 2px;
  border-radius: 12px;
  box-shadow:
    0 20px 34px -14px rgba(0, 0, 0, .6),
    0 0 0 1px var(--core-border-strong),
    0 0 50px -20px var(--geraet-schein, transparent);
}

/* Der Fuß gehört zum Monitor und steht als Geschwister darunter. */
.geraet__fuss {
  height: 12px;
  margin: 0 -4%;
  border-radius: 0 0 var(--radius-s) var(--radius-s);
  background: linear-gradient(180deg, var(--geraet-fuss) 0%, var(--geraet-rahmen) 100%);
  box-shadow: 0 10px 18px -6px rgba(0, 0, 0, .5);
}

/* Kerbe des Telefons und Kameraauge des Monitors -- dasselbe Zeichen in
   zwei Formen. */
/* Sitzt INNERHALB des Geraets, direkt unter dem Rand -- .geraet schneidet
   ab, ein negatives top waere dort weg. */
.geraet__kerbe {
  position: absolute;
  top: 0;
  left: 50%;
  translate: -50% 0;
  width: 32%;
  height: 10px;
  border-radius: 0 0 6px 6px;
  background: var(--geraet-rahmen);
  z-index: 2;
}
.geraet__kamera {
  position: absolute;
  top: 4px;
  left: 50%;
  translate: -50% 0;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-round);
  background: var(--geraet-detail);
  z-index: 2;
}

/* Das Bild darin: contain statt cover -- ein Screenshot soll vollständig
   zu sehen sein, nicht beschnitten. */
.geraet__bild {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}

/* Platzhalter, solange kein Screenshot vorliegt (Screenshot-Vorlage). */
.geraet__platzhalter {
  position: absolute;
  inset: 0;
  background: var(--geraet-schirm);
  border: 1.5px dashed var(--brand-blue);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--geraet-detail);
}
