/* BENSA Wetter PWA (Phase 1) - Design-Tokens bewusst analog monitoring/index.html gehalten
   (gleiche Variablennamen/Werte), damit App und Monitoring-Seite optisch zusammengehören. */
:root {
  --bg: #0f1420;
  --panel: #1a2130;
  --panel2: #212a3d;
  --text: #e8ecf4;
  --muted: #93a0b8;
  --accent: #4da3ff;
  --link-color: #8cc8ff;
  --link-hover-color: #b7dcff;
  --link-visited-color: #b4c6ff;
  --link-active-color: #e0f1ff;
  --ok: #3ecf8e;
  --warn: #f5b942;
  --bad: #f06a6a;
  --severe: #c62828;
  --border: #2c3850;
  /* Premium-Kartenschatten (Ticket "Desktop-Redesign Aktuell-Tab"): identischer Wert wie
     landing/css/landing.css --shadow-card, damit Landingpage und App optisch als dasselbe
     Produkt erkennbar bleiben - bewusst nur an der neuen Hero-Karte eingesetzt (siehe
     .current-hero .card unten), nicht global auf jede bestehende Karte angewendet. */
  --shadow-card: 0 1px 2px rgba(0, 0, 0, .35), 0 12px 28px -14px rgba(0, 0, 0, .55);
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f2f5fa; --panel: #ffffff; --panel2: #eef2f8;
    --text: #1c2536; --muted: #5b6b85; --border: #d7dfeb;
    --link-color: #1d4ed8; --link-hover-color: #1e40af; --link-visited-color: #5b21b6; --link-active-color: #1e3a8a;
    --shadow-card: 0 1px 2px rgba(30, 41, 59, .06), 0 14px 28px -16px rgba(30, 41, 59, .18);
  }
}
/* Manuelle Auswahl (Automatisch/Hell/Dunkel) überstimmt prefers-color-scheme.
   Speicherschlüssel wm_theme_v1 - getrennt vom Lernstand-Local-Storage. */
:root[data-theme="dark"] {
  --bg: #0f1420; --panel: #1a2130; --panel2: #212a3d; --text: #e8ecf4;
  --muted: #93a0b8; --border: #2c3850;
  --link-color: #8cc8ff; --link-hover-color: #b7dcff; --link-visited-color: #b4c6ff; --link-active-color: #e0f1ff;
  --shadow-card: 0 1px 2px rgba(0, 0, 0, .35), 0 12px 28px -14px rgba(0, 0, 0, .55);
}
:root[data-theme="light"] {
  --bg: #f2f5fa; --panel: #ffffff; --panel2: #eef2f8; --text: #1c2536;
  --muted: #5b6b85; --border: #d7dfeb;
  --link-color: #1d4ed8; --link-hover-color: #1e40af; --link-visited-color: #5b21b6; --link-active-color: #1e3a8a;
  --shadow-card: 0 1px 2px rgba(30, 41, 59, .06), 0 14px 28px -16px rgba(30, 41, 59, .18);
}
.theme-switch button.active { background: var(--accent); color: #fff; border-color: var(--accent); }
* { box-sizing: border-box; }
/* Muss vor den button/.button-Regeln stehen bzw. mit ausreichender Spezifität: ohne diese Regel
   ueberschreibt "button, .button { display: inline-flex }" das Standardverhalten des
   hidden-Attributs (Autoren-CSS gewinnt in der Kaskade unabhaengig von der Spezifitaet gegen
   User-Agent-Stylesheets) - betroffen waeren u. a. die Push-Buttons (pwa/js/app.js), die per
   .hidden ein-/ausgeblendet werden. */
[hidden] { display: none !important; }
html { max-width: 100%; }
html, body { margin: 0; padding: 0; overflow-x: hidden; }
body {
  background: var(--bg); color: var(--text); font-family: "Segoe UI", system-ui, sans-serif;
  min-height: 100vh; max-width: 100vw; overflow-x: hidden;
  padding-top: var(--safe-top); padding-bottom: var(--safe-bottom);
  padding-left: var(--safe-left); padding-right: var(--safe-right);
}
a:not(.button) { color: var(--link-color); text-decoration: underline; text-underline-offset: .16em; }
a:not(.button):visited { color: var(--link-visited-color); }
a:not(.button):hover, a:not(.button):focus-visible { color: var(--link-hover-color); text-decoration-thickness: .12em; }
a:not(.button):active { color: var(--link-active-color); }
/* ── Responsive Überlaufabsicherung (allgemein) ── */
a, code, pre { overflow-wrap: anywhere; word-break: normal; }
img, svg { max-width: 100%; height: auto; }
.current-grid-primary, .current-grid-secondary, .tabbar { min-width: 0; }
.current-grid-primary > *, .current-grid-secondary > *, .tabbar > * { min-width: 0; }
table { table-layout: auto; max-width: 100%; }
td, th { overflow-wrap: anywhere; }
.skip-link {
  position: absolute; left: -999px; top: 0; background: var(--accent); color: #fff;
  padding: .6rem 1rem; border-radius: 0 0 8px 0; z-index: 200;
}
.skip-link:focus { left: 0; }

.app-header { padding: 1rem 1rem .4rem; }
/* Branding (Logo + "BENSA Wetter") in einer Zeile, vertikal zentriert am Logo ausgerichtet -
   derselbe Zeilenaufbau wie .brand auf der Landingpage (landing/css/landing.css), nur ohne
   Link-Umhuellung (der Header ist bereits die App selbst, kein Sprungziel). */
.app-brand { display: flex; align-items: center; gap: .55rem; }
.app-brand-icon { border-radius: 6px; flex: 0 0 auto; display: block; }
.app-header h1 { font-size: 1.25rem; margin: 0; }
.app-header .subtitle { color: var(--muted); font-size: .85rem; margin-top: .15rem; }

.tabbar {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(5.4rem, 1fr)); gap: .35rem;
  padding: 0 .8rem .6rem;
  position: sticky; top: 0; background: var(--bg); z-index: 10;
}
.tab {
  min-height: 44px; padding: .55rem .5rem; border: 1px solid var(--border);
  border-radius: 10px; background: var(--panel2); color: var(--text); font-size: .85rem; cursor: pointer;
  display: flex; align-items: center; justify-content: center; text-align: center;
  white-space: normal; overflow-wrap: anywhere;
}
.tab.active { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 600; }
.tab:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
@media (max-width: 359px) {
  .tabbar { grid-template-columns: repeat(auto-fit, minmax(4.6rem, 1fr)); gap: .3rem; padding: 0 .5rem .5rem; }
  .tab { font-size: .78rem; padding: .45rem .35rem; }
}
@media (min-width: 480px) {
  .tabbar { grid-template-columns: repeat(auto-fit, minmax(5.9rem, 1fr)); }
  .tab { font-size: .9rem; }
}

main { padding: 0 1rem 2rem; max-width: 640px; margin: 0 auto; }
/* Desktop-Contentbreite (Ticket "PWA Desktop-Redesign"): main blieb bislang bei JEDER
   Viewport-Breite auf 640px begrenzt, obwohl .tabbar (Geschwisterelement, kein max-width) die
   volle Breite nutzt - dadurch wirkte der App-Inhalt auf breiten Displays wie ein schmaler
   Mobile-Schlauch neben einer breiten Navigation. Ab hier wird main SCHRITTWEISE breiter, bleibt
   dabei zentriert und deckelt sich final bei ~1360px (Vorgabe "ungefaehr 1280-1440px") statt sich
   beliebig auf 100% zu strecken - unterhalb von 860px bleibt das bisherige, bereits getestete
   Verhalten unveraendert (kein max-width-Sprung fuer Tablet/Mobile). .tabbar erhaelt dieselbe
   Breite/Zentrierung, damit Navigation und Inhalt wieder sichtbar zusammengehoeren. Bewusst als
   eigene, allgemeine Regel (nicht ueber body.wide-panel, siehe @media (min-width:860px) weiter
   unten) - die bestehende wide-panel-Sonderbreite fuer den "Mehr"-Tab bleibt dadurch unangetastet
   (hoehere CSS-Spezifitaet gewinnt dort weiterhin).
   .app-header (Ticket "Branding-/Alignment-Problem", Folgefund derselben urspruenglichen Luecke):
   hatte bislang KEIN max-width/margin:auto, waehrend main/.tabbar bereits zentriert breiter
   wurden - der Header klebte dadurch weiterhin links am Fensterrand, obwohl Navigation/Inhalt
   schon auf der neuen, breiteren Content-Achse sassen. Bekommt hier dieselben drei Stufen wie
   main/.tabbar, keine eigene, abweichende Breite - eine gemeinsame horizontale Achse fuer
   Branding/Navigation/Inhalt statt fester Pixel-Margins. */
@media (min-width: 860px) {
  main, .tabbar, .app-header { max-width: 900px; margin-left: auto; margin-right: auto; }
}
@media (min-width: 1100px) {
  main, .tabbar, .app-header { max-width: 1160px; }
}
@media (min-width: 1440px) {
  main, .tabbar, .app-header { max-width: 1360px; }
}
.panel { padding-top: .4rem; }
.panel[hidden] { display: none; }
h2 { font-size: 1.05rem; margin: .8rem 0 .5rem; }
h3 { font-size: .95rem; margin: .6rem 0 .3rem; }

.status-region { padding: 0 1rem; min-height: 1.4em; font-size: .85rem; color: var(--muted); }
.status-region.error { color: var(--bad); }

/* ── Update-Erkennung (v1.9.10) ── */
.update-banner { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin: 0 1rem .6rem; padding: .6rem .9rem; border-radius: 10px; background: var(--accent); color: #fff; font-size: .85rem; }
.update-banner[hidden] { display: none; }
.update-banner button { background: #fff; color: var(--accent); border: none; border-radius: 8px; padding: .35rem .7rem; font-weight: 600; cursor: pointer; }

.card { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 1rem; margin-bottom: .9rem; }

.status-badge { display: inline-flex; align-items: center; gap: .4rem; padding: .4rem .8rem; border-radius: 999px; font-weight: 600; font-size: .9rem; border: 2px solid var(--border); }
.status-badge.tone-ok { border-color: var(--ok); color: var(--ok); }
.status-badge.tone-info { border-color: var(--accent); color: var(--accent); }
.status-badge.tone-attention { border-color: var(--warn); color: var(--warn); }
.status-badge.tone-warning { border-color: var(--warn); color: var(--warn); background: rgba(245,185,66,.12); }
.status-badge.tone-severe { border-color: var(--bad); color: var(--bad); background: rgba(240,106,106,.14); }
.status-badge.tone-unknown { border-color: var(--muted); color: var(--muted); }

.freshness { font-size: .85rem; color: var(--muted); margin-top: .5rem; }

/* ── Live-Modus (v1.9.8, siehe docs/mobile-api.md "Live-Modus") ── */
.live-mode-card { padding: .8rem 1rem; }
.live-mode-row { display: flex; align-items: center; justify-content: space-between; gap: .6rem; flex-wrap: wrap; }
.live-toggle { display: flex; align-items: center; gap: .5rem; font-weight: 600; cursor: pointer; }
.live-toggle input { width: 1.2rem; height: 1.2rem; accent-color: var(--accent); }
.live-countdown { font-variant-numeric: tabular-nums; color: var(--muted); font-size: .85rem; min-width: 3ch; text-align: right; }
.live-status-line { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; margin-top: .6rem; font-size: .85rem; padding: .35rem .6rem; border-radius: 8px; border: 1px solid var(--border); }
.live-status-line.tone-ok { border-color: var(--ok); color: var(--ok); }
.live-status-line.tone-info { border-color: var(--accent); color: var(--accent); }
.live-status-line.tone-attention { border-color: var(--warn); color: var(--warn); }
.live-status-line.tone-warning { border-color: var(--warn); color: var(--warn); background: rgba(245,185,66,.12); }
.live-status-line.tone-offline, .live-status-line.tone-error { border-color: var(--bad); color: var(--bad); }
.live-status-line.tone-unknown { border-color: var(--muted); color: var(--muted); }
.live-radar-status { color: var(--muted); font-size: .8rem; }
.live-mode-hint { font-size: .78rem; color: var(--muted); margin: .6rem 0 0; }
/* Manueller Refresh innerhalb der Karte "Aktueller Datenstand" (Ticket "Daten erneut abrufen ohne
   sichtbares Feedback") - Statuszeile links (immer sichtbar: "Zuletzt aktualisiert"-Zeitstempel im
   Ruhezustand, Lade-/Erfolgs-/Fehlertext waehrend/nach einem Klick), Button rechts. Bricht auf
   schmalen Breiten sauber untereinander um (derselbe Ansatz wie .live-mode-row). */
.manual-refresh-row { display: flex; align-items: center; justify-content: space-between; gap: .6rem; flex-wrap: wrap; margin-top: .7rem; }
.manual-refresh-status { margin: 0; font-size: .82rem; color: var(--muted); min-height: 1.1em; flex: 1 1 auto; }
.manual-refresh-status.error { color: var(--bad); }
#refreshBtn { flex: 0 0 auto; }
@media (prefers-reduced-motion: reduce) {
  .live-status-line, .live-countdown { transition: none; }
}
.freshness .absolute { display: block; }

/* ── Kartenhierarchie "Aktuell": primaer (Temperatur/Wetter) groesser als sekundaer
   (Regen/Menge/Wind/Boeen, vier eigenstaendige Kacheln, siehe app.js renderCurrentValues) ──
   Produktionsbefund (Ticket "kompakte Wetter-Kennzahlen-Kacheln"): Wert+Einheit brachen in der
   schmalen Kachel unlogisch um (z. B. "30,7 m" / "m", "bis" / "50 km/h"), weil eine Kachel zwei
   Werte kombinierte ("100 % · 30,7 mm") UND nicht jeder Wert in .nowrap-unit stand. Fix: vier
   gleichwertige Kacheln, jede mit GENAU einem Wert, konsequent nowrap. Prioritaet bei knapper
   Breite (Anforderung): 1) Padding reduzieren, 2) Spaltenbreiten flexibilisieren,
   3) Schriftgroesse moderat verkleinern, 4) ERST DANACH auf ein 2x2-Raster umbrechen (siehe
   @media (max-width: 419px) unten - "bis 120 km/h" passt bei ueblichen Telefonbreiten
   (320-390px) selbst bei kleinster vertretbarer Schrift nicht vierspaltig, deshalb 2x2 als
   Foerdergrenze statt eines noch kleineren Fonts). Ab 420px (u. a. iPhone 14 Pro Max, Tablet,
   Desktop) passen alle vier Kacheln nebeneinander - Desktop-Darstellung bleibt dadurch
   unveraendert wie zuvor. */
.current-subheading { font-size: .82rem; color: var(--muted); margin: -.3rem 0 .7rem; }
.current-grid-primary { display: grid; grid-template-columns: 1fr; gap: .6rem; margin-bottom: .6rem; }
.current-grid-secondary { display: grid; grid-template-columns: repeat(2, 1fr); gap: .4rem; }
.value-card-full-mobile { grid-column: 1 / -1; }
.value-card { background: var(--panel2); border-radius: 12px; min-width: 0; }
.value-card-primary { padding: .9rem 1rem; }
.value-card-secondary { padding: .55rem .5rem; }
.value-card-temp { min-width: 0; }
.value-card-label { font-size: .7rem; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; margin-bottom: .3rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Responsive Schriftgroesse statt fester Breakpoint-Spruenge: waechst sanft mit der Viewport-Breite,
   gedeckelt nach oben/unten, damit "14,5–20 °C" bei ueblichen Breiten nie umbricht. */
.value-main { font-size: clamp(1.35rem, 1.05rem + 2vw, 1.75rem); font-weight: 700; line-height: 1.15; }
.value-main-small { font-size: clamp(.95rem, .82rem + 1vw, 1.1rem); font-weight: 600; }
/* Ganze Wert+Einheit-Kombination (z. B. "14,5–20 °C", "18,4 km/h", "bis 45,3 km/h", "30,7 mm",
   "100 %") darf nie umbrechen - weder am geschuetzten Leerzeichen vor der Einheit noch (Browser-
   Default, auch ohne overflow-wrap:anywhere) am Schraegstrich in "km/h" oder mitten im Wort. Wert
   und Einheit sind semantisch EINE Einheit (Anforderung), white-space:nowrap erzwingt das
   verbindlich statt sich auf zufaellige Umbruchpunkte zu verlassen. */
.nowrap-unit { white-space: nowrap; }
.value-sub { font-size: .85rem; color: var(--muted); margin-top: .25rem; }
.value-card-weather .weather-body { display: flex; align-items: center; gap: .6rem; }
.value-card-weather .weather-icon { font-size: 1.8rem; line-height: 1; flex: 0 0 auto; }
/* Premium-Wettervisual (Ticket "Einheitliches Premium-Wettericon-System") statt Emoji - frei
   stehende transparente Illustration, kein Kreiszuschnitt (object-fit:contain statt cover, kein
   border-radius). */
.value-card-weather .weather-icon-img { width: 4.5rem; height: 4.5rem; object-fit: contain; object-position: center; flex: 0 0 auto; }
.value-card-weather .weather-textblock { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
/* Kurzer Haupttext, klar und ohne Wort-fuer-Wort-Umbrueche (normaler Wortumbruch an Leerzeichen,
   kein overflow-wrap:anywhere) - der Zusatzhinweis darunter bleibt bewusst kleiner/gedaempft. */
.value-card-weather .weather-text { display: block; font-size: clamp(1.05rem, .95rem + .6vw, 1.2rem); line-height: 1.3; font-weight: 700; overflow-wrap: normal; word-break: normal; }
.value-card-weather .weather-hint { display: block; font-size: .85rem; color: var(--muted); font-weight: 500; overflow-wrap: normal; word-break: normal; }

/* Engste Telefonbreiten (u. a. 320/360/390px) - Schritt 1+3 der Prioritaetenliste: Padding und
   Schriftgroesse zusaetzlich verkleinern, BEVOR (siehe oben) auf 2x2 umgebrochen wird. */
@media (max-width: 359px) {
  .value-card-secondary { padding: .45rem .4rem; }
  .value-main-small { font-size: clamp(.8rem, .7rem + 1vw, .95rem); }
}

/* Ab 420px passen bis zu vier gleich breite Kacheln nebeneinander (Schritt 2: flexible
   Spaltenbreiten reichen hier aus, kein Umbruch mehr noetig) - deckt u. a. 412/430px und alles
   daueber ab. repeat(auto-fit, minmax(...)) statt eines starren repeat(4,1fr) (Ticket "leere
   vierte Spalte bei nur 3 Kennzahlen"): renderObservation() ("Jetzt gemessen") zeigt bei einer
   echten Messung typischerweise nur drei Werte (Regen/Wind/Boeen, kein "Menge"-Feld), waehrend
   renderCurrentValues() ("Prognose") weiterhin vier zeigt (Regen/Menge/Wind/Boeen) - auto-fit
   erzeugt automatisch immer nur so viele Spalten wie tatsaechlich Kacheln vorhanden sind (leere
   Spuren kollabieren auf 0 Breite, siehe CSS-Grid-Spezifikation), die vorhandenen Kacheln teilen
   sich per 1fr den gesamten verfuegbaren Platz - bei drei Werten je ein Drittel statt einer
   sichtbar leeren vierten Spalte, bei vier Werten weiterhin vier gleich breite Kacheln wie zuvor.
   Reagiert auf die tatsaechliche Containerbreite (nicht nur den Viewport) - funktioniert dadurch
   unveraendert korrekt sowohl in der vollen Breite (Mobile) als auch in der schmaleren
   Hero-Spalte auf Desktop (siehe .current-hero unten). */
@media (min-width: 420px) {
  .current-grid-secondary { grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr)); }
}

@media (min-width: 600px) {
  .current-grid-primary { grid-template-columns: minmax(11.5rem, 1fr) minmax(14rem, 1.3fr); align-items: stretch; }
}

/* ── "Aktuell"-Hero/Sekundaerbereich (Ticket "PWA Desktop-Redesign"): die eigentliche Wetterlage
   (#observationCard "Jetzt gemessen" + #currentValuesCard "Prognose fuer den aktuellen Zeitraum" -
   beide bereits vorhandene, mit echten Daten gefuellte Karten, siehe app.js renderObservation()/
   renderCurrentValues()) steht jetzt im HTML VOR den eher technischen Karten (Hinweis/
   Messwertalter, Live-Modus) - dieselben Kartenbausteine (value-card-primary/-secondary/-weather),
   keine neue Kartensorte. .current-hero/.current-secondary sind reine Grid-Wrapper ohne eigene
   Kartenoptik, damit auf Mobile (Default: 1 Spalte) exakt dieselbe vertikale Reihenfolge wie
   bisher entsteht, auf Desktop aber Platz nebeneinander genutzt wird statt weiterhin schmal
   untereinander zu stehen. */
.current-hero { display: grid; grid-template-columns: 1fr; gap: .9rem; margin-bottom: .9rem; }
.current-secondary { display: grid; grid-template-columns: 1fr; gap: .7rem; margin-bottom: .9rem; }
.current-hero > .card, .current-secondary > .card { margin-bottom: 0; }
/* Sekundaerbereich (Hinweis/Messwertalter, Live-Modus) bewusst kompakter/gedaempfter als die
   Hero-Karten - technische Informationen sollen nicht vor der eigentlichen Wetterlage dominieren
   (Anforderung), bleiben aber vollstaendig erhalten/erreichbar, nur kleiner. */
.current-secondary .card { padding: .75rem .9rem; }
.current-secondary h3 { font-size: .88rem; }
@media (min-width: 860px) {
  .current-hero { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .current-secondary { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  /* Premium-Elevation nur an der wichtigsten Flaeche der Seite (siehe --shadow-card oben) - kein
     globaler Schatten auf jede bestehende Karte, um bestehende Bereiche visuell unveraendert zu
     lassen. */
  .current-hero > .card { box-shadow: var(--shadow-card); }
  /* Groesseres Premium-Wettericon in der Hero-Flaeche (Ticket "grosses Premium-Wettericon") -
     dieselbe Bildquelle/Aufloesung (weatherIconImgHtml() fordert bereits size:"large"), nur
     groesser dargestellt, sobald dafuer Platz ist. */
  .current-hero .weather-icon-img { width: 6rem; height: 6rem; }
}

.summary-text { font-size: 1rem; line-height: 1.45; }
.quality-note { font-size: .8rem; color: var(--muted); margin-top: .5rem; }
.quality-note.has-issues { color: var(--warn); }

/* "Jetzt gemessen" (v1.9.13, siehe docs/live-observation.md): Station/Messzeitpunkt/Alter direkt
   unter der Ueberschrift - bewusst kein Alarm-Rot bei einem veralteten Messwert, ein alter
   Stationswert ist ein normaler Betriebszustand, keine akute Wetterwarnung (Anforderung Abschnitt
   8 "zurueckhaltender gelber Hinweis, keine rote Alarmoptik"). */
.observation-meta-line { margin: .15rem 0; font-size: .92rem; color: var(--text); }
.observation-age-line { color: var(--muted); }
.observation-checked-line { color: var(--muted); font-size: .82rem; }
.observation-hint {
  margin: .5rem 0; padding: .5rem .7rem; border-radius: 10px; font-size: .85rem;
  color: var(--warn); background: rgba(245, 185, 66, .12); border: 1px solid rgba(245, 185, 66, .35);
}
.observation-refresh-status { margin-top: .5rem; font-size: .85rem; color: var(--muted); min-height: 1.1em; }
.observation-refresh-status.error { color: var(--bad); }
/* Zurueckhaltende Statuszeile fuer die AUTOMATISCHE Stationspruefung (v1.9.17, siehe
   docs/automatic-observation-refresh.md) - bewusst kleiner/dezenter als der manuelle
   Erfolgstext oben, damit ein automatischer Lauf nicht aufdringlich wirkt. */
.observation-auto-status { margin-top: .25rem; font-size: .78rem; color: var(--muted); min-height: 1em; }
.observation-auto-status.error { color: var(--bad); }
#observationRefreshBtn { margin-top: .6rem; }
.metric-horizon-details { margin-top: .6rem; font-size: .85rem; }
.metric-horizon-details summary { cursor: pointer; font-weight: 600; }
.metric-horizon-list { margin: .4rem 0; padding-left: 1.1rem; }
.metric-horizon-list li { margin-bottom: .25rem; }

button, .button {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  min-height: 44px; padding: .6rem 1.1rem; border-radius: 10px; border: 0; cursor: pointer;
  background: var(--accent); color: #fff; font-size: .9rem; text-decoration: none; font-weight: 600;
}
button.secondary, .button.secondary { background: var(--panel2); color: var(--text); border: 1px solid var(--border); }
button:disabled { opacity: .6; cursor: default; }
button:focus-visible, .button:focus-visible, a:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.period-card { border-left: 4px solid var(--border); }
.period-card.important { border-left-color: var(--warn); }
.period-card .period-head { display: flex; align-items: center; gap: .5rem; font-weight: 600; margin-bottom: .4rem; }
.period-card dl { display: grid; grid-template-columns: auto 1fr; gap: .25rem .8rem; font-size: .88rem; margin: 0; }
.period-card dt { color: var(--muted); }
.period-card dd { margin: 0; }
.period-tip { margin-top: .5rem; font-size: .85rem; }
.period-warning { margin-top: .5rem; font-size: .85rem; display: flex; gap: .4rem; align-items: flex-start; }
.period-warning.important { color: var(--warn); font-weight: 600; }
.forecast-day-heading { margin-top: 1rem; }
.forecast-day-heading:first-child { margin-top: 0; }
.current-hint { color: var(--muted); font-size: .9rem; }

/* ── Gefahrenklassifikation (siehe docs/hazard-classification.md): farbiger Rand + Badge +
   Hintergrundtoenung + Gefahrenzeile - ausschliesslich bei relevanten Gefahren (severity !=
   'info'), niemals bei normalen Wetterabweichungen (keine Alarmoptik ohne echten Anlass). ──
/* Feste rgba-Toenungen statt color-mix() - bewusst breitere Browserkompatibilitaet (auch
   aeltere iOS-Safari-Versionen fuer die installierte PWA), Werte je an --warn/--bad/--severe
   angelehnt. */
#currentValuesCard.highlight-notice, .period-card.highlight-notice { border-left: 4px solid var(--warn); background: rgba(245, 185, 66, .1); }
#currentValuesCard.highlight-warning, .period-card.highlight-warning { border-left: 4px solid var(--bad); background: rgba(240, 106, 106, .12); }
#currentValuesCard.highlight-severe, .period-card.highlight-severe { border-left: 4px solid var(--severe); background: rgba(198, 40, 40, .16); }
.hazard-banner { margin: .5rem 0; display: flex; flex-direction: column; gap: .4rem; }
.hazard-row { display: flex; gap: .5rem; align-items: flex-start; padding: .5rem .6rem; border-radius: 8px; font-size: .85rem; }
.hazard-row.hazard-notice { background: rgba(245, 185, 66, .16); color: var(--text); }
.hazard-row.hazard-warning { background: rgba(240, 106, 106, .18); color: var(--text); }
.hazard-row.hazard-severe { background: rgba(198, 40, 40, .22); color: var(--text); font-weight: 600; }
.hazard-icon { font-size: 1.1rem; line-height: 1.3; }
.hazard-tip { display: block; margin-top: .25rem; font-weight: 400; color: var(--muted); }

.warning-card { border-left: 4px solid var(--bad); }
.warning-card.inactive { border-left-color: var(--muted); opacity: .8; }
.warning-card .warning-head { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; font-weight: 700; }
.warning-card dl { display: grid; grid-template-columns: auto 1fr; gap: .25rem .8rem; font-size: .85rem; margin: .5rem 0 0; }
.warning-card dt { color: var(--muted); }
.warning-card dd { margin: 0; }
.no-warnings { display: flex; align-items: center; gap: .5rem; color: var(--ok); font-weight: 600; }
.warnings-section-heading { margin-top: 1.2rem; }
.warnings-section-heading:first-child { margin-top: 0; }
.own-hazards-note { font-size: .8rem; color: var(--muted); margin: 0 0 .5rem; }
.hazard-card.hazard-notice { border-left: 4px solid var(--warn); }
.hazard-card.hazard-warning { border-left: 4px solid var(--bad); }
.hazard-card.hazard-severe { border-left: 4px solid var(--severe); }
.hazard-card p { margin: .4rem 0 0; font-size: .9rem; }
.own-hazard-badge { margin-left: auto; font-size: .7rem; font-weight: 400; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: .1rem .5rem; white-space: nowrap; }
/* v1.9.12: Gültigkeitszeitraum je Warnung/Hinweis - eigener Zeilentyp, damit "Amtlich"/"Eigener
   Hinweis" plus Zeitfenster auf jedem Gerät ohne Textabschneidung lesbar bleiben (Anforderung
   "mobile Darstellung ohne abgeschnittenen Text"). */
.validity-line { margin: .3rem 0 0; font-size: .82rem; line-height: 1.4; color: var(--text); overflow-wrap: break-word; }
.validity-line strong { color: var(--muted); font-weight: 600; }
.validity-active { color: var(--text); }
.validity-future { color: var(--accent); }
.validity-ended { color: var(--muted); }
.validity-unknown { color: var(--muted); font-style: italic; }

/* ── Zentrales Warnungsmodell (v1.9.0, siehe docs/warning-architecture.md) ── */
.warnings-section-muted { color: var(--muted); font-weight: 500; }
.warning-card.tone-information, .warning-card.tone-notice { border-left: 4px solid var(--warn); }
.warning-card.tone-warning { border-left: 4px solid var(--bad); }
.warning-card.tone-severe, .warning-card.tone-extreme { border-left: 4px solid var(--severe); }
.warning-card.tone-unknown { border-left: 4px solid var(--muted); }
.warning-card:focus { outline: 2px solid var(--accent); outline-offset: 2px; }
.warning-status-badge {
  margin-left: auto; font-size: .7rem; font-weight: 600; color: var(--text);
  background: var(--border); border-radius: 999px; padding: .1rem .6rem; white-space: nowrap;
}
.warning-multi-source-note { font-size: .8rem; color: var(--muted); margin: .5rem 0 0; font-style: italic; }
.warning-deeplink-history { border-left: 4px solid var(--accent); }
.warning-source-status {
  display: inline-block; font-size: .8rem; font-weight: 600; padding: .3rem .7rem; border-radius: 999px;
  margin-bottom: .8rem; border: 1px solid var(--border);
}
.warning-source-status-ok { color: var(--ok); border-color: var(--ok); }
.warning-source-status-degraded { color: var(--warn); border-color: var(--warn); }
.warning-source-status-unavailable { color: var(--bad); border-color: var(--bad); }
.warning-source-status-unknown { color: var(--muted); }

.install-hint { position: fixed; left: .8rem; right: .8rem; bottom: calc(.8rem + var(--safe-bottom)); background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: .9rem; box-shadow: 0 6px 24px rgba(0,0,0,.35); z-index: 50; }
.install-hint[hidden] { display: none; }
.install-hint p { margin: 0 0 .6rem; font-size: .85rem; }
.install-hint .actions { display: flex; gap: .5rem; flex-wrap: wrap; }

/* ── Benachrichtigungen (Web-Push, v1.4.0) ── */
.push-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: .8rem; padding: .5rem 0; border-bottom: 1px solid var(--border); }
.push-toggle-row:last-child { border-bottom: 0; }
.push-toggle-row .push-toggle-label { font-size: .9rem; }
.push-toggle-row input[type="checkbox"] { width: 1.3rem; height: 1.3rem; accent-color: var(--accent); }

@media (min-width: 720px) {
  .tabbar { position: static; }
}

@media (prefers-reduced-motion: no-preference) {
  .tab, button, .button { transition: background-color .15s ease, border-color .15s ease; }
}
@media (prefers-reduced-motion: reduce) {
  * { scroll-behavior: auto !important; }
}

/* ── Radar (v1.9.11, siehe docs/radar-map-architecture.md und docs/project-status-v1.9.11.md) ──
   Double-Buffering (zwei Leaflet-ImageOverlay-Layer statt vieler WMS-Kacheln) wird ausschließlich
   in JS gesteuert (pwa/js/app.js) - hier nur die Darstellung: größerer Kartenbereich, ruhige
   abgerundete Bedienleiste, deutliche Messung/Prognose-Trennung auf der Zeitleiste. */
.radar-toolbar {
  display: flex; align-items: center; gap: .8rem .6rem; flex-wrap: wrap; margin-bottom: .7rem;
  padding: .5rem .7rem; border: 1px solid var(--border); border-radius: 12px; background: var(--panel2);
  /* min-width: 0 ist am Container selbst wirkungslos, aber max-width verhindert, dass die
     Toolbar durch ein besonders breites Kind (z. B. den Regions-Select) ihren eigenen
     Elternrahmen sprengt. */
  max-width: 100%;
}
/* Bugfix "improve live observation selection and responsive Android radar controls" -
   bestaetigter Geraetebefund: "Region (Braunschweig–Wolfsburg–Helmstedt)" lief auf dem echten
   Android-Geraet rechts ueber den Kartenrand hinaus. Ursache: Flex-Kinder haben per Spezifikation
   einen impliziten "min-width: auto" (nicht 0) - dadurch durfte sich weder .radar-toolbar-group
   noch das <select> selbst unter seine INTRINSISCHE Inhaltsbreite (Laenge der laengsten
   <option>) verkleinern, obwohl .radar-toolbar bereits flex-wrap: wrap gesetzt hatte. Das
   erzwungene "min-width: 0" behebt das strukturell (nicht nur kosmetisch per Media Query). */
.radar-toolbar-group { display: flex; align-items: center; gap: .4rem; min-width: 0; max-width: 100%; }
.radar-select-label { font-size: .8rem; color: var(--muted); }
.radar-select {
  min-height: 2.4rem; padding: .3rem .5rem; border-radius: 8px; border: 1px solid var(--border);
  background: var(--panel); color: var(--text); font-size: .85rem;
  min-width: 0; max-width: 100%;
  /* Lange Optionstexte (z. B. "Region (Braunschweig–Wolfsburg–Helmstedt)") werden im
     geschlossenen Auswahlfeld mit Ellipsis abgeschnitten statt es zu ueberlaufen zu lassen -
     die aufgeklappte Optionsliste selbst bleibt davon unberuehrt (Browser-Standardverhalten). */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.radar-toggle { display: flex; align-items: center; gap: .4rem; font-size: .85rem; margin-left: auto; }
.radar-toggle input { width: 1.15rem; height: 1.15rem; accent-color: var(--accent); }
/* Radar-2.0-Block (Phase 6 "separater Gewittermodus"): eigene Ebenen-Werkzeugleiste, sowie ein
   dauerhaft deaktivierter Blitzdaten-Schalter (kein Provider konfiguriert, siehe
   docs/lightning-provider-architecture.md) - bewusst sichtbar statt versteckt, damit klar wird,
   dass die Ebene existiert, aber mangels freigegebener Quelle inaktiv ist. */
.radar-layer-toolbar { margin-top: .5rem; }
.radar-layer-toolbar .radar-toggle { margin-left: 0; }
.radar-toggle-disabled { opacity: .55; cursor: not-allowed; margin-left: .8rem; }
.radar-toggle-disabled input { cursor: not-allowed; }

/* 2026-08-15 (Realgeraete-Nachpruefung, Auftrag Abschnitt E): kompakte, standardmaessig
   eingeklappte Legende fuer die Gewitter-Kartensymbole - reines <details>/<summary>, kein Layout-
   Sprung waehrend die Karte laedt, ueberlaedt die Karte selbst nicht. */
.radar-thunderstorm-legend { margin-top: .4rem; }
.radar-thunderstorm-legend summary { cursor: pointer; }
.radar-thunderstorm-legend ul { margin: .4rem 0; padding-left: 1.1rem; }
.radar-thunderstorm-legend li { margin-bottom: .3rem; }
.radar-legend-swatch { display: inline-block; width: .9rem; height: .9rem; vertical-align: middle; margin-right: .2rem; }
.radar-legend-swatch-dot { border-radius: 50%; background: #e06666; }
.radar-legend-swatch-line { height: .18rem; width: 1.1rem; background: #e06666; }
.radar-legend-swatch-cone { border: 1px dashed #e06666; background: rgba(224, 102, 102, .12); }
.radar-legend-swatch-circle { border: 1px dashed #f0a63a; border-radius: 50%; background: transparent; }

/* Empfohlene mobile Struktur (Anforderung Phase 1): "Ausschnitt" (das breiteste Feld, mit dem
   laengsten Optionstext) bekommt auf schmalen Breiten eine eigene volle Zeile, Tempo/Schleife
   bleiben in der naechsten Zeile nebeneinander - vermeidet, dass drei ungleich breite Felder
   ineinander gequetscht werden. Deckt 320/360/390/412px vollstaendig ab (alle < 480px). */
@media (max-width: 480px) {
  /* Label ueber dem Auswahlfeld statt nebeneinander (Anforderung "Zeile 1: Label 'Ausschnitt' /
     Auswahlfeld darunter ueber volle Breite") - bei "Region (Braunschweig–Wolfsburg–Helmstedt)"
     bleibt sonst kaum Platz neben dem Label fuer den sichtbaren Optionstext. */
  .radar-toolbar-group-region { flex: 1 1 100%; flex-direction: column; align-items: stretch; gap: .2rem; }
  .radar-toolbar-group-region .radar-select { width: 100%; max-width: 100%; }
}

.radar-map-wrap {
  position: relative; width: 100%; height: 62vh; min-height: 360px; max-height: 620px;
  border-radius: 12px; overflow: hidden; background: var(--panel2);
}
.radar-map { width: 100%; height: 100%; }
.radar-map-controls-top { position: absolute; top: .6rem; right: .6rem; z-index: 500; display: flex; flex-direction: column; gap: .5rem; }
.radar-map-control {
  width: 2.6rem; height: 2.6rem; padding: 0; border-radius: 50%; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--panel) 88%, transparent); color: var(--text);
  font-size: 1.2rem; display: flex; align-items: center; justify-content: center; cursor: pointer;
  backdrop-filter: blur(2px);
}
.radar-map-control[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.radar-overlay-state {
  position: absolute; inset: 0; z-index: 600; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .6rem; text-align: center; padding: 1rem; background: color-mix(in srgb, var(--panel) 92%, transparent);
  color: var(--text);
}
/* v1.9.12: kurzer, sich selbst ausblendender Hinweis bei Erreichen der sinnvollen Zoomgrenze
   bzw. beim automatischen Wechsel zu einem schärferen Ausschnitt (siehe pwa/js/app.js). */
.radar-zoom-hint {
  position: absolute; left: 50%; bottom: .7rem; transform: translateX(-50%); z-index: 650;
  max-width: 88%; padding: .4rem .8rem; border-radius: 999px; font-size: .78rem; text-align: center;
  background: color-mix(in srgb, var(--panel) 90%, transparent); color: var(--text); border: 1px solid var(--border);
}
/* CARTO-Basiskarte fehlt (kein Env-Key konfiguriert, siehe app.js ensureMap()) - dieselbe
   Pill-Optik wie .radar-zoom-hint, aber am oberen statt unteren Kartenrand (bleibt dadurch klar
   getrennt vom transienten Zoom-Hinweis) und OHNE Auto-Hide, solange der Zustand anhaelt. top:3.5rem
   statt .6rem, damit die zentrierte Pill nicht mit den rechts oben fixierten Kartensteuerelementen
   (.radar-map-controls-top, 2.6rem Durchmesser) kollidiert, besonders auf schmalen Breiten. Bewusst
   gedaempft (--muted statt --text) - kein Alarmton, da Radar-/Gewitterdaten selbst normal
   funktionieren. */
.radar-basemap-hint {
  position: absolute; left: 50%; top: 3.5rem; transform: translateX(-50%); z-index: 650;
  max-width: 78%; padding: .4rem .8rem; border-radius: 999px; font-size: .78rem; text-align: center;
  background: color-mix(in srgb, var(--panel) 90%, transparent); color: var(--muted); border: 1px solid var(--border);
}
/* Zweistufiger Ladezustand, Stufe 2 (Ticket "Radar-Ladezustand verbessern"): #radarFrameLoadingHint
   erbt die Pill-Optik von .radar-basemap-hint (Basisregeln oben), wird aber am UNTEREN statt oberen
   Kartenrand positioniert - bleibt dadurch klar getrennt vom (seltener gleichzeitig sichtbaren)
   Basemap-Key-Hinweis oben und vom transienten .radar-zoom-hint direkt am unteren Rand (dieser
   Hinweis sitzt bewusst etwas hoeher, 3.2rem statt .7rem, damit sich beide im Ausnahmefall nicht
   ueberlappen). display:flex fuer Spinner+Text nebeneinander statt reinem Text. */
.radar-frame-loading-hint {
  top: auto; bottom: 3.2rem; display: flex; align-items: center; gap: .4rem;
}
/* Echter, kleiner Lade-Indikator statt reinem Text (Anforderung "kleiner Spinner/Progress-
   Indikator") - reine CSS-Rotation, kein Bild-Asset, keine "Fake"-Fortschrittsangabe (kein
   erfundener Prozentwert). prefers-reduced-motion respektiert, wie an anderer Stelle im Radar-UI
   bereits ueblich (siehe @media (prefers-reduced-motion: reduce) weiter unten). */
.radar-spinner {
  width: 1.1rem; height: 1.1rem; border-radius: 50%; flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, var(--text) 25%, transparent); border-top-color: var(--accent);
  animation: radar-spinner-rotate .8s linear infinite;
}
.radar-spinner-sm { width: .85rem; height: .85rem; border-width: 2px; }
@keyframes radar-spinner-rotate { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .radar-spinner { animation: none; border-top-color: color-mix(in srgb, var(--text) 25%, transparent); }
}
/* v1.9.12 (Anforderung 5 "Bilddarstellung optimieren"): Radar- und Basiskarten-Bilder nutzen
   bewusst den Browser-Standard (bilineare Skalierung, kein "pixelated"/"crisp-edges") - das
   erzeugt beim Hineinzoomen ein deutlich ruhigeres, weniger blockartiges Bild als eine
   Nächster-Nachbar-Skalierung, ohne kleine Regenzellen künstlich zu vergrößern oder zu verstärken
   (siehe docs/radar-map-architecture.md "Darstellungsauflösung versus Messgenauigkeit"). */
.leaflet-image-layer, .leaflet-tile { image-rendering: auto; }
/* v1.9.12 (Anforderung 6 "Standortmarker als saubere Vektorgrafik, Standortkreis oder dezenter
   Puls"): ersetzt den Standard-Leaflet-Pin (grosses Symbol, verdeckt teils das Radarbild) durch
   einen kleinen, ruhigen Punkt mit dezentem Puls-Ring - reine CSS-Vektorgrafik, kein Bild-Asset. */
.radar-location-marker { position: relative; width: 14px; height: 14px; }
.radar-location-marker .dot {
  position: absolute; inset: 3px; border-radius: 50%; background: var(--accent);
  border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,.25);
}
.radar-location-marker .pulse {
  position: absolute; inset: 0; border-radius: 50%; background: var(--accent); opacity: .45;
  animation: radar-location-pulse 2.2s ease-out infinite;
}
@keyframes radar-location-pulse {
  0% { transform: scale(.6); opacity: .5; }
  100% { transform: scale(2.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .radar-location-marker .pulse { animation: none; opacity: .25; }
}

.radar-status-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: .7rem; }
.radar-frame-badge { font-weight: 600; padding: .15rem .55rem; border-radius: 999px; border: 1px solid var(--border); font-size: .82rem; }
.radar-frame-badge-observation { background: var(--ok); color: #05241a; border-color: transparent; }
.radar-frame-badge-forecast { background: var(--warn); color: #3a2600; border-color: transparent; }
.radar-frame-time { font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* Sichtbarkeitsfreundliches "nur für Screenreader" - kein visuelles Layout, aber im Fokus/Vorlesefluss vorhanden. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Zeitleiste: die farbige Spur oben ist rein dekorativ (aria-hidden) - die eigentliche Bedienung
   bleibt der native, barrierefrei fokussierbare <input type="range"> darunter. Trennt Messung
   (links, ruhige Farbe) von Prognose (rechts, wärmere Farbe) klar sichtbar, mit einer "Jetzt"-Marke
   an der Grenze - Anforderung 7 "Messung und Prognose deutlich unterscheiden". */
.radar-timeline { margin-top: .9rem; }
.radar-timeline-track {
  position: relative; display: flex; height: .55rem; border-radius: 999px; overflow: hidden;
  border: 1px solid var(--border);
}
.radar-timeline-segment { flex: 0 0 auto; height: 100%; }
.radar-timeline-segment-observation { background: color-mix(in srgb, var(--ok) 55%, var(--panel2)); }
.radar-timeline-segment-forecast { background: color-mix(in srgb, var(--warn) 55%, var(--panel2)); }
.radar-timeline-now-marker {
  position: absolute; top: -.25rem; bottom: -.25rem; width: 2px; background: var(--text);
  transform: translateX(-1px);
}
.radar-timeline-labels { display: flex; justify-content: space-between; font-size: .72rem; color: var(--muted); margin: .3rem 0; }
.radar-timeline-now-label { font-weight: 700; color: var(--text); }
.radar-timeline-controls { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.radar-timeline-controls input[type="range"] { flex: 1 1 140px; min-width: 100px; accent-color: var(--accent); }
.radar-timeline-controls button { min-width: 2.6rem; min-height: 2.6rem; padding: .3rem; }

.radar-legend-row { display: flex; align-items: flex-start; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin-top: .9rem; }
.radar-legend-scale { display: flex; gap: .4rem; flex-wrap: wrap; margin: 0; }
.radar-legend-chip {
  padding: .2rem .6rem; border-radius: 999px; border: 1px solid var(--border); font-size: .75rem; color: var(--muted);
}
/* Bewusst KEINE eigenen Farbwerte, die eine bestimmte DWD-Intensitätsstufe behaupten würden - nur
   zunehmende Betonung (Rahmen/Gewicht) als Lesehilfe, die amtliche Farblegende bleibt maßgeblich.
   2026-08-15 (Realgeraete-Nachpruefung Teil B8): auf die tatsaechlich vier von
   INTENSITY_CLASS_THRESHOLDS berechneten Klassen reduziert (vorher sechs Chips inkl. eines nicht
   verdrahteten "Extremkern" - siehe docs/radar-thunderstorm-quality-model.md). */
.radar-legend-chip-0 { font-weight: 400; }
.radar-legend-chip-1 { font-weight: 500; border-width: 1.5px; color: var(--text); }
.radar-legend-chip-2 { font-weight: 600; border-width: 2px; color: var(--text); }
.radar-legend-chip-3 { font-weight: 700; border-width: 2px; color: var(--text); border-color: var(--accent); }
.radar-legend { font-size: .85rem; }
.radar-legend summary { cursor: pointer; font-weight: 600; }
.radar-legend img { display: block; margin-top: .5rem; max-width: 100%; height: auto; background: #fff; border-radius: 6px; }

/* ── Lokales Radar-Nowcasting (v1.10.0, siehe docs/radar-nowcasting-architecture.md) - bewusst
   ZURUECKHALTEND (keine rote Alarmoptik ohne amtliche Warnung, siehe Anforderung Abschnitt 10). ── */
.nowcast-details dl { display: grid; grid-template-columns: auto 1fr; gap: .25rem .8rem; font-size: .85rem; margin: .6rem 0 0; }
.nowcast-details dt { color: var(--muted); }
.nowcast-details dd { margin: 0; }
#nowcastStatusBadge { font-weight: 600; }

/* ── Wetterkameras (v1.9.17, siehe docs/weather-camera-evaluation.md) - kein automatisches Laden,
   Consent-Flow pro Sitzung, kein Proxying. ── */
.webcam-list { display: flex; flex-direction: column; gap: .8rem; margin-top: .6rem; }
.webcam-item { border: 1px solid var(--border); border-radius: 10px; padding: .8rem .9rem; background: var(--card-bg, transparent); }
.webcam-item h4 { margin: 0 0 .3rem; font-size: .95rem; }
.webcam-privacy-note { margin-top: .3rem; }
.webcam-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .6rem; }
.webcam-embed { margin-top: .6rem; }
.webcam-embed iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: 8px; }
.webcam-external-link { display: inline-flex; align-items: center; padding: .45rem .9rem; border-radius: 8px; text-decoration: none; }

/* ── Hilfe (v1.9.5, siehe docs/START_HERE.md; Lesbarkeit ueberarbeitet v1.12.1) ── */
.context-help {
  margin-bottom: .8rem; font-size: .95rem; border: 1px solid var(--border); border-radius: 8px;
  padding: .4rem .8rem; background: var(--card-bg, transparent);
}
.context-help summary { cursor: pointer; font-weight: 600; padding: .4rem 0; }
.context-help summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.context-help p { margin: .5rem 0 .7rem; color: var(--muted); line-height: 1.6; max-width: 68ch; }
.context-help a { color: var(--link-color); text-decoration: underline; }
/* Verhindert, dass die feste Reiterleiste (position: sticky) beim Sprung zu einem
   Handbuchabschnitt dessen Ueberschrift verdeckt (siehe jumpToHandbookSection() in app.js). */
.help-section { border-bottom: 1px solid var(--border); padding: .8rem 0; scroll-margin-top: 4.5rem; }
.help-section:last-child { border-bottom: none; }
.help-section summary {
  cursor: pointer; font-weight: 600; font-size: 1.05rem; padding: .4rem 0; line-height: 1.4;
}
.help-section summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.help-section[open] summary { margin-bottom: .2rem; }
.help-section p { margin: .7rem 0 0; font-size: 1rem; line-height: 1.65; max-width: 90ch; }
.help-section p + p { margin-top: .9rem; }
.help-section a { color: var(--link-color); text-decoration: underline; }
#helpCard > p.quality-note { max-width: 90ch; line-height: 1.6; }
@media (prefers-reduced-motion: reduce) {
  .context-help, .help-section { transition: none; }
}

/* ── Desktop-Breite fuer den Reiter "Mehr" (Hilfe & Handbuch, v1.12.1) ──
   "main" bleibt fuer alle anderen Reiter bei 640px (siehe oben) - nur waehrend der Reiter "Mehr"
   aktiv ist (body.wide-panel, gesetzt in app.js activateTab()), wird die Spalte auf Desktop auf
   eine fuer Fliesstext noch angenehme Breite vergroessert. Absatztext bleibt trotzdem auf ~68
   Zeichen begrenzt (siehe .help-section p oben), damit einzelne Zeilen nicht zu lang werden. */
@media (min-width: 860px) {
  body.wide-panel main { max-width: 900px; }
}

/* ── Radar-Embed-Modus fuer die native Android-App (?embed=android, siehe app.js) ──
   Ersetzt die vorherige komplette Web-Einbettung (voller Header/Hauptnavigation/alle Reiter
   sichtbar innerhalb der nativen WebView, "doppelte Navigation") - dieser Modus zeigt
   AUSSCHLIESSLICH den eigentlichen Radarinhalt. Bewusst reine CSS-Sichtbarkeitsregeln (kein
   fragiles DOM-Entfernen/-Neuaufbauen) - alle uebrigen Reiter/Skripte bleiben unveraendert
   vorhanden und funktionsfaehig, falls "embed=android" spaeter aus der URL entfernt wird (z. B.
   "Im Browser oeffnen"-Fallback in der App oeffnet bewusst OHNE diesen Parameter). */
body.embed-android .app-header,
body.embed-android .tabbar,
body.embed-android #statusRegion,
body.embed-android #updateBanner,
body.embed-android #installHint,
/* Reduzierte Radaransicht (Anforderung Phase 2 "darf nicht enthalten: Plattformhinweise
   ausserhalb des Radars, Warnungslisten ausserhalb des Radarbereichs") - die native App zeigt
   Gewittereinschaetzung/Webcams bereits an anderer Stelle (ThunderstormCard in "Aktuell"), eine
   zweite Kopie hier waere redundant/verwirrend. */
body.embed-android #panel-radar > details.context-help,
body.embed-android #nowcastCard,
body.embed-android #webcamCard,
/* Radar-2.0-Block: das neue Gewitterpanel (Phase 8) zeigt dieselbe /thunderstorm-Antwort wie
   die native ThunderstormCard in "Aktuell" - im Android-Embed waere es dieselbe Dopplung wie
   #nowcastCard/#webcamCard oben. */
body.embed-android #radarThunderstormPanel,
/* 2026-08-15 (Realgeraete-Nachpruefung): die Symbol-Legende erklaert dieselben Elemente, die die
   native ThunderstormCard bereits als eigene Zeilen (Entfernung/Richtung/Konfidenz) darstellt -
   dieselbe Dopplungslogik wie oben, daher ebenfalls im Embed ausgeblendet. */
body.embed-android .radar-thunderstorm-legend {
  display: none !important;
}
/* "main" traegt ausserhalb des Embed-Modus einen Sicherheitsabstand zur (hier ausgeblendeten)
   Tabbar/zum Header - im Embed-Modus soll die Karte den verfuegbaren Platz voll nutzen. */
body.embed-android main { padding-top: 0; max-width: none; }
body.embed-android #panel-radar { padding-top: .5rem; }

/* Radar-UX-Verdichtung (Geraetebefund: "Karte muss im ersten Viewport vollstaendig sichtbar
   sein, ohne dass der Nutzer scrollen muss" - der bisherige Aufbau aus zwei vollen
   .radar-toolbar-Bloecken (Region als eigene volle Zeile mit Label darueber, dann Tempo/Schleife,
   dann eine ZWEITE Werkzeugleiste fuer Gewitter/Blitzdaten) plus einer 62vh hohen Karte
   ueberschritt zusammen mit dem nativen nicht-scrollbaren WebView-Rahmen regelmaessig die
   verfuegbare Hoehe - das WebView scrollte dann INTERN, zusaetzlich zum aeusseren Compose-Screen
   ("doppelte Scroll-Logik"). Bewusst NUR im Android-Embed enger gefasst - die eigenstaendige
   PWA-Browseransicht behaelt ihr bisheriges, grosszuegigeres Layout unveraendert. */
body.embed-android .radar-toolbar {
  gap: .4rem; margin-bottom: .35rem; padding: .35rem .5rem;
}
/* Region bleibt IMMER ein kompakter Dropdown-Chip, auch unter 480px - die allgemeine PWA-Regel
   (Label ueber volle Breite) gilt hier bewusst NICHT: der Android-Embed ist ohnehin immer schmal
   (360-430dp, siehe Anforderung "Mobile First"), ein Extra-Zeilenumbruch nur fuer die
   Regionsauswahl kostet dort verhaeltnismaessig mehr Hoehe als auf einer breiteren mobilen
   Browseransicht. Der lange Optionstext bleibt durch die bestehende Ellipsis-Regel auf
   .radar-select trotzdem nie ueberlaufend sichtbar. */
body.embed-android .radar-toolbar-group-region {
  flex: 0 1 auto; flex-direction: row; align-items: center; gap: .3rem;
}
body.embed-android .radar-toolbar-group-region .radar-select { width: auto; max-width: 11rem; }
body.embed-android .radar-select-label { display: none; }
body.embed-android .radar-select { min-height: 1.9rem; padding: .2rem .4rem; font-size: .8rem; }
body.embed-android .radar-toggle { font-size: .8rem; }
body.embed-android .radar-toggle input { width: 1rem; height: 1rem; }
/* Die zweite Werkzeugleiste (Gewitter/Blitzdaten) ruecht direkt an die erste heran statt einen
   eigenen, fast identisch gestalteten Kartenrahmen darunter zu bilden - beide zusammen wirken so
   als EINE zusammenhaengende Steuerzeile statt zwei getrennte Bloecke (Anforderung 1). */
body.embed-android .radar-layer-toolbar { margin-top: .25rem; }
/* "Blitzdaten ausgegraut bzw. verborgen, wenn keine Quelle existiert" - der erklaerende
   Klammertext ("keine Quelle") kostet im engen Embed-Kontext eine ganze Wortbreite mehr als er
   dort traegt; die Erklaerung bleibt ueber das bestehende title-Attribut (Tooltip/Screenreader)
   vollstaendig erhalten, nur der sichtbare Text wird auf das Nötigste verdichtet. */
body.embed-android .radar-toggle-disabled .small.muted { display: none; }

/* Kartenhoehe im Android-Embed - Root-Cause-Fix des Realgeraete-Regressionsbefunds (Build 45,
   Pixel 7 Pro): `height: 88vh` bezog sich auf 88% der GESAMTEN WebView-Viewporthoehe, OBWOHL im
   selben Dokument bereits zwei Werkzeugleisten, die Statuszeile, die komplette Zeitleiste
   (Slider/Buttons/Hinweistext) und die Legende zusaetzlichen Platz beanspruchen - 88vh Karte PLUS
   all dieser weitere Inhalt UEBERSCHREITET damit rechnerisch immer 100% des WebView-Viewports,
   unabhaengig von der nativen Android-Hoehe. Das WebView (kein `overflow:hidden` auf body) scrollte
   dadurch INTERN, um den ueberschuessigen Inhalt trotzdem erreichbar zu machen - fuer den Nutzer
   sichtbar als abgeschnittene Karte plus ein zweiter, gegen die aeussere Compose-Seite arbeitender
   Scrollbereich (verifiziert per echtem Pixel-Screenshot, nicht durch invalidateSize()/
   ResizeObserver behebbar, da das ein rein CSS-/Layout-Problem ist, keine Leaflet-Kartengroesse).
   Fix: die Kartenhoehe haengt jetzt AUSSCHLIESSLICH von der eigenen Breite ab (aspect-ratio), nicht
   mehr vom WebView-Viewport oder vom Inhalt der Geschwisterelemente - dadurch ist die GESAMTE
   Dokumenthoehe (Werkzeugleisten + Karte + Status + Zeitleiste + Legende) ein deterministischer,
   von aussen messbarer Wert (siehe reportRadarContentHeight() in app.js), den RadarScreen.kt per
   JavaScript-Bridge abfragt und dem WebView-Container 1:1 als Android-Hoehe zuweist - kein
   WebView-internes Scrollen mehr moeglich, weil WebView-Containerhoehe == tatsaechliche
   Dokumenthoehe (siehe RadarScreen.kt "BensaRadarHeightBridge"). */
body.embed-android .radar-map-wrap {
  height: auto; aspect-ratio: 4 / 5; min-height: 320px; max-height: 520px;
}
/* Statuszeile unter der Karte bleibt einzeilig-kompakt statt eigener Kartenoptik - die
   ausfuehrliche Interpretation zeigt ohnehin bereits die native RadarThunderstormCard direkt
   unter dem eingebetteten WebView (siehe RadarScreen.kt), eine zweite, groessere Statusflaeche
   INNERHALB der Seite waere hier redundant. */
body.embed-android .radar-status-row { padding: .3rem .1rem; font-size: .8rem; }

/* html/body duerfen im Embed NIE selbst vertikal scrollen (siehe Kommentar oben) - die Hoehe des
   WebView-Android-Containers wird stattdessen per Bridge exakt an document.scrollHeight
   angeglichen. `overflow-x: hidden` bleibt als reine Absicherung gegen horizontalen Overflow
   (z. B. durch die feste 4:5-Kartenbreite auf extrem schmalen Geraeten), NICHT als Ersatz fuer die
   Hoehenberechnung. */
body.embed-android html, body.embed-android body {
  overflow-x: hidden; overflow-y: visible;
}

@media (max-width: 400px) {
  .radar-map-wrap { height: 52vh; min-height: 280px; }
  .radar-toolbar { gap: .5rem; }
  .radar-toggle { margin-left: 0; }
}
/* Die schmalbreiten-Regel oben (< 400px, height: 52vh) gilt bewusst NUR fuer die eigenstaendige
   PWA-Browseransicht - im Android-Embed hat die aspect-ratio-Regel weiter oben (nach dieser
   Media Query im Dokument, daher hoehere CSS-Spezifitaet durch Deklarationsreihenfolge bei
   gleicher Spezifitaet reicht hier NICHT sicher aus) Vorrang, deshalb hier explizit erneut gesetzt. */
@media (max-width: 400px) {
  body.embed-android .radar-map-wrap { height: auto; aspect-ratio: 4 / 5; min-height: 280px; max-height: 460px; }
}
@media (orientation: landscape) and (max-height: 500px) {
  .radar-map-wrap { height: 74vh; }
  body.embed-android .radar-map-wrap { height: auto; aspect-ratio: 3 / 2; min-height: 200px; max-height: 380px; }
}
:fullscreen .radar-map-wrap, .radar-map-wrap:fullscreen { height: 100vh; max-height: none; border-radius: 0; }
@media (prefers-reduced-motion: reduce) {
  .radar-map-control, .leaflet-image-layer { transition: none !important; }
}

/* ── Mehrtagesausblick (v1.16.0, siehe docs/multi-day-outlook.md) ──
   Wiederverwendung bestehender Bausteine (.card, .status-badge-Farblogik) statt eines neuen,
   fremden Designs. Segmentierte Umschalter statt verschachtelter Tabs (Abschnitt H/I), horizontal
   scrollbar auf schmalen Bildschirmen statt Umbruch in winzige Spalten (Abschnitt J). */
#outlookSection { margin-top: 1.2rem; }
.outlook-switchers { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .6rem; }
.segmented {
  display: flex; gap: .3rem; overflow-x: auto; padding-bottom: .1rem;
  -webkit-overflow-scrolling: touch;
}
.segmented-btn {
  flex: 1 1 auto; min-width: 4.5rem; min-height: 44px; padding: .5rem .6rem; border: 1px solid var(--border);
  border-radius: 10px; background: var(--panel2); color: var(--text); font-size: .82rem; cursor: pointer;
  white-space: nowrap;
}
.segmented-btn[aria-checked="true"] { background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 600; }
.segmented-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.outlook-trend { font-size: .9rem; }
.outlook-trend[hidden] { display: none; }

/* Mobil: vertikale Liste (statt horizontalem Wischen) - konsistent mit den bestehenden
   Tagesabschnitts-/Warnungskarten dieser App, kein Konflikt mit der Seiten-Wischnavigation. */
#outlookDaysList { display: flex; flex-direction: column; gap: .7rem; }
.outlook-day-card { padding: .9rem 1rem; }
.outlook-day-card.is-today { border-color: var(--accent); }
.outlook-day-head {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .5rem;
}
.outlook-day-head h3 { margin: 0; font-size: .95rem; }
/* Premium-Tagesicon (Ticket "Einheitliches Premium-Wettericon-System"), Ueberschrift ruecht davor
   nach rechts (margin-right:auto), Badge bleibt am Zeilenende. */
.outlook-day-icon { width: 2.2rem; height: 2.2rem; object-fit: contain; flex: 0 0 auto; order: -1; }
.outlook-day-head h3 { margin-right: auto; }
.outlook-day-summary { margin: 0 0 .5rem; color: var(--text); }
.outlook-day-values { margin: 0; }
.outlook-day-values dt { font-size: .75rem; color: var(--muted); margin-top: .35rem; }
.outlook-day-values dd { margin: 0 0 .1rem; }
/* Tagesvorhersage: Aenderung gegenueber Vortag (UI-Polish, 2026-08-24) - bewusst kompakt/klein
   (kleiner als outlook-day-summary), damit die Zusatzinfo die bestehende Kartenhoehe nicht
   unnoetig aufblaest (Betreiber-Vorgabe "kompakt bleiben"). */
.outlook-day-comparison { margin: .2rem 0 0; font-size: .78rem; color: var(--muted); }
.outlook-limitation { font-size: .78rem; color: var(--muted); margin-top: .4rem; }

/* Qualitaetsstufen (Abschnitt D/K): IMMER Text, Farbe ist nur eine Zusatzinformation, nie die
   einzige (siehe outlookAgreementMeta in pwa-data-lib.js - liefert stets shortLabel + className). */
.agreement-badge { display: inline-flex; align-items: center; gap: .3rem; padding: .25rem .6rem; border-radius: 999px; font-size: .78rem; font-weight: 600; border: 2px solid var(--border); white-space: nowrap; }
.agreement-badge.agree-good { border-color: var(--ok); color: var(--ok); }
.agreement-badge.agree-medium { border-color: var(--warn); color: var(--warn); }
.agreement-badge.agree-divergent { border-color: var(--warn); color: var(--warn); background: rgba(245,185,66,.12); }
.agreement-badge.agree-limited { border-color: var(--muted); color: var(--muted); }
.agreement-badge.agree-none, .agreement-badge.agree-unknown { border-color: var(--bad); color: var(--bad); }

/* Tagesabschnitte (nur horizonDay 0-3) - kompakte Unterliste innerhalb der Tageskarte, keine
   zweite Kartenebene (kein Tab-in-Tab, Abschnitt I). */
.outlook-day-periods { display: grid; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr)); gap: .4rem; margin-top: .6rem; padding-top: .6rem; border-top: 1px dashed var(--border); }
.outlook-period { background: var(--panel2); border-radius: 8px; padding: .4rem .5rem; font-size: .75rem; }
.outlook-period .outlook-period-label { display: block; color: var(--muted); margin-bottom: .15rem; }
/* Cross-Platform-Paritaets-Fund 2026-08-16: Regenwahrscheinlichkeit/-menge je Abschnitt, dieselben
   Rohfelder wie Android (DayDetailModel.kt) - siehe pwa-data-lib.js enrichDayPeriodsWithPrecipitation. */
.outlook-period .outlook-period-rain, .outlook-period .outlook-period-rain-amount { display: block; margin-top: .15rem; color: var(--accent, var(--muted)); }
.outlook-period .outlook-period-rain-amount { color: var(--muted); }

/* Desktop (Abschnitt J): Kartenraster statt einer einzelnen langen Spalte, mit sinnvoller
   Maximalbreite (main bleibt bei 640px begrenzt, siehe oben) - fuer 16 Tage trotzdem KEINE
   unlesbar schmalen Spalten, deshalb ein Grid mit Mindestbreite je Karte statt fester Spaltenzahl. */
@media (min-width: 680px) {
  #outlookDaysList { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .8rem; }
}
@media (prefers-reduced-motion: reduce) {
  .segmented { scroll-behavior: auto; }
}

/* ── Wetter-E-Mails (v1.23.0, siehe docs/email-subscription-architecture.md) - eigenes,
   konsistentes Abstandssystem statt verstreuter Einzelwerte; zwei klar getrennte Unterbereiche
   ("Neu anmelden"/"Bereits angemeldet") innerhalb einer gemeinsamen Karte. ── */
.email-sub-card {
  --email-sub-gap-xs: .35rem;
  --email-sub-gap-sm: .6rem;
  --email-sub-gap-md: 1rem;
  --email-sub-gap-lg: 1.4rem;
}
.email-sub-intro { margin-top: -.1rem; margin-bottom: var(--email-sub-gap-md); }

.email-sub-subcard {
  display: block; background: var(--panel2); border: 1px solid var(--border); border-radius: 12px;
  padding: 1rem 1.1rem 1.2rem;
}
.email-sub-subcard + .email-sub-subcard { margin-top: var(--email-sub-gap-lg); }
.email-sub-subcard h4 { margin: 0 0 var(--email-sub-gap-xs); font-size: 1rem; }
.email-sub-subcard > .quality-note { margin-top: var(--email-sub-gap-xs); max-width: 60ch; }
.email-sub-subcard > .quality-note:first-of-type { margin-top: var(--email-sub-gap-xs); }

.email-sub-form { display: flex; flex-direction: column; gap: var(--email-sub-gap-md); margin-top: var(--email-sub-gap-md); max-width: 30rem; }

.email-sub-field { display: flex; flex-direction: column; gap: var(--email-sub-gap-xs); }
.email-sub-field label { font-weight: 600; font-size: .88rem; }

.email-sub-input {
  width: 100%; min-height: 48px; padding: .75rem .9rem; border-radius: 10px;
  border: 1.5px solid var(--border); background: var(--panel); color: var(--text);
  font-size: 1rem; font-family: inherit; appearance: none;
}
.email-sub-input::placeholder { color: var(--muted); opacity: 1; }
.email-sub-input:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.email-sub-input[aria-invalid="true"] { border-color: var(--bad); }
.email-sub-input:disabled { opacity: .6; }

/* Checkbox: die gesamte Zeile ist das Label (natives <label for>), grosszuegiges Innenpolster
   sorgt fuer ein Touch-Ziel deutlich ueber 44x44px, auch wenn nur die Checkbox selbst kleiner ist. */
.email-sub-consent {
  display: flex; align-items: flex-start; gap: .7rem; cursor: pointer;
  padding: .5rem .4rem; margin: 0 calc(var(--email-sub-gap-xs) * -1); border-radius: 8px;
  min-height: 44px;
}
.email-sub-consent input[type="checkbox"] {
  width: 1.4rem; height: 1.4rem; min-width: 1.4rem; margin-top: .1rem; accent-color: var(--accent); cursor: pointer;
}
.email-sub-consent input[type="checkbox"]:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.email-sub-consent-text { display: flex; flex-direction: column; gap: .2rem; }
.email-sub-consent-main { font-size: .95rem; line-height: 1.4; }
.email-sub-consent-hint { font-size: .8rem; color: var(--muted); }
.email-sub-privacy-link { margin: 0; font-size: .82rem; }
.email-sub-privacy-link a { color: var(--link-color); }

.email-sub-btn-primary, .email-sub-btn-secondary { width: 100%; }

.email-sub-status {
  margin: 0; padding: .6rem .8rem; border-radius: 8px; font-size: .88rem; line-height: 1.5;
  display: flex; gap: .5rem; align-items: flex-start;
  background: rgba(61, 207, 142, .12); border: 1px solid var(--ok); color: var(--text);
}
.email-sub-status::before { content: "✓"; color: var(--ok); font-weight: 700; flex: 0 0 auto; }
.email-sub-status-error {
  background: rgba(240, 106, 106, .12); border-color: var(--bad);
}
.email-sub-status-error::before { content: "⚠"; color: var(--bad); }
.email-sub-status[hidden] { display: none; }

@media (min-width: 480px) {
  .email-sub-manage-row { flex-direction: row; flex-wrap: wrap; align-items: flex-end; }
  .email-sub-manage-row .email-sub-field { flex: 1 1 12rem; }
  .email-sub-manage-row .email-sub-btn-secondary { width: auto; flex: 0 0 auto; min-height: 48px; }
  .email-sub-manage-row .email-sub-status,
  .email-sub-manage-row .email-sub-status-error { flex-basis: 100%; }
}

/* Desktop: die beiden Unterkarten nebeneinander statt einer langen Spalte, sobald die Karte
   selbst genug Breite hat (siehe body.wide-panel main im Reiter "Mehr", oben). */
@media (min-width: 760px) {
  .email-sub-card { display: grid; grid-template-columns: 1fr 1fr; column-gap: var(--email-sub-gap-lg); }
  .email-sub-card h3, .email-sub-card .email-sub-intro { grid-column: 1 / -1; }
  .email-sub-subcard + .email-sub-subcard { margin-top: 0; }
}
