/*
 * Heizwarte — Grundstile. Der Wurzelblock ist dunkel (Dennis ist extrem lichtempfindlich): Wo kein prefers-color-scheme
 * gemeldet wird, bleibt es dunkel. Moderne Browser melden immer hell oder dunkel (Chromium kennt kein no-preference mehr);
 * wer dunkel will, stellt das System oder in den Einstellungen „Dunkel“. Hell gibt es nur, wenn das System es
 * meldet oder die Einstellungen es wählen (BAUPLAN Abschnitt 8, Theme ab M3):
 * zwei wortgleiche Blöcke unter :root, einmal per @media (prefers-color-scheme: light) ohne data-theme="dark",
 * einmal für data-theme="light". Die hellen Temperaturfarben (tcol, ANCH_LIGHT) stehen in chart.js; app.js wählt das Schema.
 * Alle Größen in rem, einzige Ausnahme sind die 48-Pixel-Tippflächen und der Seitenrand.
 * Keine Animationen, kein style-Attribut im Markup (CSP, Abschnitt 8): Zustände laufen über Klassen und hidden.
 */

/* ---------------------------------------------------------------------------------------------
   Schrift: Atkinson Hyperlegible 400 und 700, selbst gehostet (SIL Open Font License, assets/fonts/OFL.txt).
   Je Stärke zwei Teilmengen mit den unicode-range-Werten der Startseite (latin-ext zuerst, latin danach):
   latin endet bei U+00FF, ohne latin-ext fielen ą ę ł ś ź ż ć ń und ş ğ İ mitten im Wort auf die Rückfallschrift.
   font-display swap: erst der Systemstapel (--body), dann tauscht der Browser, sobald die Datei da ist.
   Kyrillisch, Devanagari und CJK hat die Schrift nicht, dort greift der Systemrückfall.
   --------------------------------------------------------------------------------------------- */
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url("../assets/fonts/atkinson-hyperlegible-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-display: swap;
  font-weight: 400;
  src: url("../assets/fonts/atkinson-hyperlegible-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url("../assets/fonts/atkinson-hyperlegible-latin-ext-700-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Atkinson Hyperlegible";
  font-style: normal;
  font-display: swap;
  font-weight: 700;
  src: url("../assets/fonts/atkinson-hyperlegible-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  color-scheme: dark;

  /* Flächen und Text, Werte von Bürg (index:20–36); --faint 55 % → 62 % wegen WCAG 4,5:1 für Kleintext */
  --bg: oklch(17% 0.018 252);
  --surface: oklch(21.5% 0.02 252);
  --line: oklch(31% 0.022 252);
  --fg: oklch(95% 0.008 250);
  --muted: oklch(72% 0.02 250);
  --faint: oklch(62% 0.02 250);

  /* Rand von Eingabefeldern und Knöpfen: mindestens 3:1 gegen den Grund (WCAG 1.4.11), --line wäre zu leise */
  --edge: oklch(58% 0.03 252);

  /* Hauptknopf: gedämpftes Blau mit dunkler Schrift, kein Weiß auf Schwarz (Dennis ist lichtempfindlich) */
  --accent: oklch(74% 0.1 235);
  --on-accent: oklch(16% 0.02 252);

  /* aktuelle Temperaturfarbe, app.js setzt sie per style.setProperty (CSSOM, mit der CSP vereinbar) */
  --t: oklch(85% 0.05 210);

  /* Ampel */
  --ok: oklch(76% 0.15 152);
  --warn: oklch(85% 0.16 92);
  --alarm: oklch(73% 0.17 55);
  --crit: oklch(66% 0.21 25);

  /* Wettersymbole (Bürg index:250–260, als Variablen, damit das Hell-Theme sie überschreiben kann) */
  --ic-sun: oklch(86% 0.15 85);
  --ic-moon: oklch(85% 0.05 250);
  --ic-cloud: oklch(78% 0.02 250);
  --ic-cloud-dark: oklch(66% 0.02 250);
  --ic-fog: oklch(72% 0.02 250);
  --ic-rain: oklch(72% 0.11 240);
  --ic-snow: oklch(92% 0.03 230);
  --ic-bolt: oklch(86% 0.16 92);

  /* Kurve (Bürg index:459–477, fest kodiert in drawChart): Nachtband, Gitter, Regenbalken (die Deckkraft setzt die
     Kurve je Balken per fill-opacity), MOSMIX-Linie */
  --chart-night: oklch(12% 0.02 260 / 0.55);
  --chart-grid: oklch(31% 0.022 252);
  --chart-rain: oklch(62% 0.09 240);
  --chart-mos: oklch(72% 0.02 250);

  /* Schriften: Text in Atkinson Hyperlegible (oben per @font-face), Rückfall Segoe UI und Systemschrift;
     Display (h1, große Zahl) und Mono kommen aus dem System. Zahlen laufen über tabular-nums am body. */
  --display: "Avenir Next", "Segoe UI", system-ui, sans-serif;
  --body: "Atkinson Hyperlegible", "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, monospace;
}

/* Hell (Abschnitt 8, Theme ab M3). Die zwei Blöcke sind wortgleich: der erste folgt dem System, solange die Einstellungen
   nicht „Dunkel“ gewählt haben, der zweite gilt, wenn sie „Hell“ gewählt haben. Werte laut Plan: Flächen und Text,
   Ampel (alle über 4,5:1 auf --bg und --surface; tests/contrast.test.js prüft Ampel und Textfarben beider Themes).
   Alles andere hier ist ein Entwurf. --edge, --accent und --on-accent haben im Plan keinen Hell-Wert und sind so gewählt, dass der Rand über
   3:1 und die Schrift auf dem Hauptknopf über 4,5:1 liegt. --t ist nur der Rückfall vor dem ersten Rendern. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;

    --bg: #F3F3F6;
    --surface: #FFFFFF;
    --line: #DFE0ED;
    --fg: #1C1D27;
    --muted: #4A4D5E;
    --faint: #5F6275;

    --edge: oklch(55% 0.03 252);

    --accent: oklch(48% 0.12 240);
    --on-accent: oklch(98% 0.005 250);

    --t: oklch(45% 0.06 210);

    --ok: oklch(48% 0.14 152);
    --warn: oklch(50% 0.13 92);
    --alarm: oklch(52% 0.16 55);
    --crit: oklch(50% 0.20 25);

    --ic-sun: oklch(63% 0.15 70);
    --ic-moon: oklch(60% 0.07 260);
    --ic-cloud: oklch(64% 0.02 250);
    --ic-cloud-dark: oklch(52% 0.02 250);
    --ic-fog: oklch(60% 0.02 250);
    --ic-rain: oklch(58% 0.13 240);
    --ic-snow: oklch(62% 0.07 230);
    --ic-bolt: oklch(66% 0.16 80);

    --chart-night: oklch(40% 0.04 260 / 0.1);
    --chart-grid: oklch(84% 0.012 270);
    --chart-rain: oklch(55% 0.11 240);
    --chart-mos: oklch(50% 0.03 250);
  }

  /* Umgekehrte Farben bei hellem System (Sehhilfen, 31.10.2026): die Anhebungen für die dunkle Umkehr ganz unten
     gelten hier nicht, die hellen Werte bleiben. Steht in DIESER @media, damit es bei genau einer Abfrage nach
     prefers-color-scheme bleibt (tests/theme.test.js). */
  :root[data-vision="invert"]:not([data-theme]) {
    --faint: #5F6275;
    --alarm: oklch(52% 0.16 55);
    --crit: oklch(50% 0.20 25);
  }
}

:root[data-theme="light"] {
  color-scheme: light;

  --bg: #F3F3F6;
  --surface: #FFFFFF;
  --line: #DFE0ED;
  --fg: #1C1D27;
  --muted: #4A4D5E;
  --faint: #5F6275;

  --edge: oklch(55% 0.03 252);

  --accent: oklch(48% 0.12 240);
  --on-accent: oklch(98% 0.005 250);

  --t: oklch(45% 0.06 210);

  --ok: oklch(48% 0.14 152);
  --warn: oklch(50% 0.13 92);
  --alarm: oklch(52% 0.16 55);
  --crit: oklch(50% 0.20 25);

  --ic-sun: oklch(63% 0.15 70);
  --ic-moon: oklch(60% 0.07 260);
  --ic-cloud: oklch(64% 0.02 250);
  --ic-cloud-dark: oklch(52% 0.02 250);
  --ic-fog: oklch(60% 0.02 250);
  --ic-rain: oklch(58% 0.13 240);
  --ic-snow: oklch(62% 0.07 230);
  --ic-bolt: oklch(66% 0.16 80);

  --chart-night: oklch(40% 0.04 260 / 0.1);
  --chart-grid: oklch(84% 0.012 270);
  --chart-rain: oklch(55% 0.11 240);
  --chart-mos: oklch(50% 0.03 250);
}

* {
  box-sizing: border-box;
}

/* Ein Bildschirm mit hidden darf nie von einer display-Regel überstimmt werden. */
[hidden] {
  display: none !important;
}

html {
  background: var(--bg);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 1.125rem/1.5 var(--body);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: 44rem;
  margin: 0 auto;
  padding-inline: 16px;
  padding-block: 1.25rem 3rem;
}

h1,
h2,
h3 {
  margin: 0;
  line-height: 1.2;
}

h1 {
  font-family: var(--display);
  font-size: 1.75rem;
}

h2 {
  font-size: 1.375rem;
}

h3 {
  font-size: 1.125rem;
}

p {
  margin: 0;
}

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

/* Tippflächen und Fokus (Abschnitt 8): mindestens 48 px, Trefferliste 64 px, Fokusring nie weg */
button,
.hit,
select,
input,
summary,
a.footer-link {
  min-height: 48px;
  min-width: 48px;
}

.hit {
  min-height: 64px;
}

a.footer-link {
  display: inline-block;
}

:focus-visible {
  outline: 3px solid var(--fg);
  outline-offset: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------------------------
   Kopf und Bildschirme
   --------------------------------------------------------------------------------------------- */

header {
  margin-bottom: 1.25rem;
}

/* Kopfzeile: Name links, rechts daneben „Installieren“ (Nachtrag 30.10.2026). Der Knopf erscheint erst,
   wenn der Browser die Installation anbietet (app.js, renderInstall), und fehlt in der installierten App. */
.headline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

/* Hinweise zum Speicher: der Satz trägt die Bedeutung, der Rahmen nur die Auffälligkeit */
.notes p {
  margin-top: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 2px solid var(--warn);
  border-radius: 0.625rem;
}

/* Schrittzähler der Einrichtung; leer, wenn kein Zähler gilt */
.step {
  margin-top: 0.25rem;
  color: var(--muted);
}

.screen {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* ---------------------------------------------------------------------------------------------
   Knöpfe
   --------------------------------------------------------------------------------------------- */

button {
  font: inherit;
  line-height: 1.25;
  color: var(--fg);
  background: var(--surface);
  border: 2px solid var(--edge);
  border-radius: 0.75rem;
  padding: 0.625rem 1rem;
  text-align: center;
  cursor: pointer;
}

@media (hover: hover) {
  button:hover {
    border-color: var(--fg);
  }
}

button.primary {
  min-height: 56px;
  font-weight: 700;
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

/* Gesperrt wird nur per aria-disabled, nie per disabled: der Knopf behält den Fokus (Abschnitt 6) */
button[aria-disabled="true"] {
  opacity: 0.7;
  cursor: progress;
}

/* Textknöpfe: „Zurück“ und „Keine passt?“ sehen wie Links aus und sind trotzdem 48 px hoch */
button.back,
button.plain {
  align-self: flex-start;
  background: transparent;
  border-color: transparent;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  padding-inline: 0.5rem;
}

.actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.actions button {
  width: 100%;
}

/* ---------------------------------------------------------------------------------------------
   Felder und Fehler
   --------------------------------------------------------------------------------------------- */

form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

label {
  font-weight: 700;
}

input[type="text"],
input[type="number"] {
  width: 100%;
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 2px solid var(--edge);
  border-radius: 0.625rem;
  padding: 0.625rem 0.75rem;
}

input[aria-invalid="true"] {
  border-color: var(--crit);
}

/* Fehlertext: ein div mit role="alert", leer solange nichts schiefgegangen ist */
.err {
  padding: 0.75rem 1rem;
  border: 2px solid var(--crit);
  border-radius: 0.75rem;
  background: color-mix(in oklch, var(--crit) 12%, var(--bg));
}

.err:empty {
  display: none;
}

.err p + p {
  margin-top: 0.25rem;
}

.err-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Ohne sichtbaren Ausweg nimmt die Zeile auch keinen Abstand weg */
.err-actions:not(:has(button:not([hidden]))) {
  display: none;
}

/* ---------------------------------------------------------------------------------------------
   S3 Trefferliste
   --------------------------------------------------------------------------------------------- */

.hits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.hit {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
  padding: 0.75rem 1rem;
  text-align: left;
}

.hit-label {
  font-weight: 700;
}

.hit-line,
.hit-kind {
  color: var(--muted);
}

/* ---------------------------------------------------------------------------------------------
   S4 Bestätigen
   --------------------------------------------------------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1rem;
}

.card-title {
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.2;
}

.elev {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
}

.elev .field {
  width: 100%;
}

/* ---------------------------------------------------------------------------------------------
   S5 Heizart: das Eingabefeld deckt die ganze Karte ab, so ist die Tippfläche mindestens 64 px hoch
   --------------------------------------------------------------------------------------------- */

.choices {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.choice {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.875rem;
  min-height: 64px;
  padding: 0.875rem 1rem;
  background: var(--surface);
  border: 2px solid var(--edge);
  border-radius: 0.75rem;
  font-weight: 400;
  cursor: pointer;
}

.choice input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

/* Die Wahl zeigt sich als gefüllter Punkt (Form), der Rahmen kommt nur dazu */
.choice .dot {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.125rem;
  border: 2px solid var(--muted);
  border-radius: 50%;
}

.choice input:checked ~ .dot {
  border-color: var(--accent);
  background: radial-gradient(circle, var(--accent) 0 45%, transparent 50%);
}

.choice:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in oklch, var(--accent) 12%, var(--surface));
}

.choice:has(input:focus-visible) {
  outline: 3px solid var(--fg);
  outline-offset: 2px;
}

/* Ohne :has() sitzt der Fokusring am Punkt */
@supports not selector(:has(*)) {
  .choice input:focus-visible ~ .dot {
    outline: 3px solid var(--fg);
    outline-offset: 2px;
  }
}

.choice-body {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.choice-title {
  font-weight: 700;
}

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

/* ---------------------------------------------------------------------------------------------
   Hauptbildschirm: Kopfzeile, Jetzt, Ampel, Warnungen, drei Tage
   --------------------------------------------------------------------------------------------- */

/* Ortszeile und die zwei Textknöpfe; bricht auf schmalen Handys um, nie ein Zahnrad allein */
.place-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.place-name {
  font-weight: 700;
}

/* Ortsnamen bis 40 Zeichen, auch ohne Leerzeichen: lieber mitten im Wort umbrechen als quer scrollen (Fall 3).
   overflow-wrap: anywhere senkt auch die Mindestbreite im Flex-Layout; die 48-px-Regel der Knöpfe bleibt unberührt. */
.place-name,
.choice-hint,
.place-confirm button,
#settingsHeatPlace {
  overflow-wrap: anywhere;
}

/* Ein <select> ist so breit wie seine längste Option und bricht nicht um: Kasten und Feld dürfen deshalb nie
   breiter werden als die Zeile, sonst schiebt ein langer Ortsname die Seite über 360 px hinaus (Fall 3) */
.place-pick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  max-width: 100%;
}

.head-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

select {
  max-width: 100%;
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 2px solid var(--edge);
  border-radius: 0.625rem;
  padding: 0.5rem 0.75rem;
}

.notice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border: 2px solid var(--edge);
  border-radius: 0.75rem;
}

/* Statuszeile (Abschnitt 8, Block 2): der Stand in der Zweitfarbe; „⚠ Veraltet“ trägt Symbol und Wort, die Farbe
   kommt nur dazu */
#status {
  color: var(--muted);
}

#status .status-warn {
  color: var(--warn);
}

/* Jetzt: die Temperatur trägt die Farbe der Außentemperatur (--t), der Rest bleibt in Textfarben */
.now {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.25rem 1rem;
  border-radius: 1.25rem;
  background: radial-gradient(120% 140% at 0% 0%, color-mix(in oklch, var(--t) 20%, transparent), transparent 62%), var(--surface);
}

.now-body {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.5rem 1.25rem;
  align-items: center;
}

.now-temp {
  font: 800 clamp(3rem, 14vw, 5rem) / 0.95 var(--display);
  letter-spacing: -0.03em;
  color: var(--t);
}

.now-meta {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  color: var(--muted);
}

.now-cond {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--fg);
  font-weight: 700;
}

.icon {
  display: inline-flex;
  flex: none;
}

.icon svg {
  display: block;
}

@media (max-width: 420px) {
  .now-body {
    grid-template-columns: 1fr;
  }
}

/* Ampel: vier Lampen sind Zierde (aria-hidden), Stufe, Wort und Satz stehen als Text daneben.
   Die Stufenfarbe liegt in --lv (per style.setProperty gesetzt), die Lampen haben je eine eigene. Ohne Stufe
   (keine Daten, Daten zu alt) fehlt --lv, dann bleibt die Ampel neutral statt grün getönt. */
.verdict {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.875rem;
  align-items: start;
  padding: 1rem;
  border-radius: 1.125rem;
  border: 1px solid var(--line);
  border-left: 6px solid var(--lv, var(--line));
  background: color-mix(in oklch, var(--lv, var(--line)) 9%, var(--bg));
}

.lamp {
  display: flex;
  flex-direction: column;
  gap: 0.3125rem;
  padding: 0.4375rem;
  border-radius: 0.75rem;
  background: oklch(12% 0.01 252);
}

.lamp i {
  width: 0.875rem;
  height: 0.875rem;
  border-radius: 50%;
  background: oklch(28% 0.01 252);
}

.lamp .l0 { --c: var(--ok); }
.lamp .l1 { --c: var(--warn); }
.lamp .l2 { --c: var(--alarm); }
.lamp .l3 { --c: var(--crit); }

.lamp i.on {
  background: var(--c);
  box-shadow: 0 0 0.75rem var(--c);
}

.verdict-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

.verdict-body h2 {
  color: var(--lv, var(--fg));
}

.verdict-action {
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.25;
}

.reasons {
  margin: 0;
  padding-left: 1.25rem;
  color: var(--muted);
}

/* Warnungen des Deutschen Wetterdienstes: Wortlaut unverändert, der Rahmen nur zur Auffälligkeit */
.alerts {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.alert-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.alert-item {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  padding: 0.875rem 1rem;
  border-radius: 0.875rem;
  border: 1px solid color-mix(in oklch, var(--crit) 50%, transparent);
  background: color-mix(in oklch, var(--crit) 16%, var(--bg));
}

.alert-item h3 {
  font-family: var(--display);
}

.alert-time {
  font-weight: 700;
}

.alert-text {
  white-space: pre-line;
}

/* Heute und die nächsten zwei Tage: eine Spalte auf dem Handy, ab 720 px drei nebeneinander */
.days-box {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.days {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.625rem;
}

@media (min-width: 720px) {
  .days {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.day {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
  padding: 0.875rem;
  border-radius: 1rem;
  background: var(--surface);
}

.day-date {
  color: var(--muted);
}

.day-cond {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.day-range {
  font-weight: 700;
}

.day-note {
  color: var(--muted);
}

/* Heizfahrplan: eine Karte je Nacht, untereinander in jeder Breite (die Sätze sind länger als bei den Tageskarten).
   Der Hinweis „Start fällig“ oder „optional“ steht als Wort im Rahmen, nie als Farbe allein. */
.plan-box {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.plan {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.plan-item {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
  padding: 0.875rem;
  border-radius: 1rem;
  background: var(--surface);
}

.plan-when {
  font-family: var(--display);
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1.25;
}

.plan-tag {
  align-self: flex-start;
  padding: 0.125rem 0.625rem;
  border: 2px solid var(--edge);
  border-radius: 1rem;
  font-weight: 700;
}

.plan-strength {
  font-weight: 700;
}

.plan-meta {
  color: var(--muted);
}

/* ---------------------------------------------------------------------------------------------
   Mehr anzeigen (Abschnitt 8, Blöcke 8 bis 10): ein Knopf über die ganze Breite, 56 px hoch; darunter, erst nach dem
   Druck, die Kurve und das Lüften. Der Zustand steht im Wort („Mehr“ oder „Weniger anzeigen“) und in
   aria-expanded, nie in einem Pfeil allein. Das beste Lüftungsfenster trägt sein Wort im Rahmen.
   Die Kurve selbst ist ein SVG, das chart.js baut; ihre Farben kommen aus den Variablen --chart-* und --t (je Theme),
   die Schrift in der Zeichnung ist in Zeichnungseinheiten gesetzt (font-size am <svg>), damit sie mit der Kurve skaliert.
   --------------------------------------------------------------------------------------------- */

.more-btn {
  width: 100%;
  min-height: 56px;
  font-weight: 700;
}

.chart-box,
.air-box {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.chart-legend:empty,
.chart-summary:empty {
  display: none;
}

.chart-legend {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.chart-legend-item {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  color: var(--muted);
}

/* Farbmuster vor dem Legendentext, rein dekorativ: der Text daneben sagt dasselbe */
.legend-swatch {
  flex: none;
  display: inline-block;
  width: 1.5rem;
  height: 0.25rem;
  border-radius: 0.125rem;
}

.legend-swatch.is-main {
  background: var(--t);
}

.legend-swatch.is-second {
  background: repeating-linear-gradient(90deg, var(--chart-mos) 0 0.25rem, transparent 0.25rem 0.4375rem);
}

.legend-swatch.is-rain {
  width: 0.625rem;
  height: 0.625rem;
  margin-inline: 0.4375rem;
  background: var(--chart-rain);
}

.chart-wrap {
  position: relative;
}

/* pan-y: senkrecht scrollt die Seite weiter, waagerechtes Ziehen führt den Zeiger über die Kurve */
.chart-svg {
  display: block;
  width: 100%;
  height: auto;
  touch-action: pan-y;
  font-family: var(--body);
}

/* Kasten über der Kurve beim Berühren; die Lage links setzt chart.js per CSSOM */
.chart-tip {
  position: absolute;
  top: 0.375rem;
  left: 0;
  transform: translateX(-50%);
  min-width: 9.5rem;
  max-width: calc(100% - 0.5rem);
  box-sizing: border-box;
  padding: 0.5rem 0.625rem;
  border: 1px solid var(--edge);
  border-radius: 0.75rem;
  background: var(--surface);
  color: var(--fg);
  font-size: 0.875rem;
  line-height: 1.35;
  pointer-events: none;
}

.chart-tip b {
  font: 700 1.125rem var(--display);
}

.chart-tip-head,
.chart-tip-line,
.chart-tip-feels {
  color: var(--muted);
}

.chart-tip-feels {
  margin-inline-start: 0.5rem;
}

/* Farbskala unter der Kurve: der Verlauf kommt aus chart.scaleCss() (app.js setzt ihn per CSSOM), die Marken stehen auf
   ihrer Temperatur (−10 bis 32 Grad über die ganze Breite) */
.scale-box {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.scale {
  height: 0.625rem;
  border-radius: 99px;
}

.scale-labels {
  position: relative;
  height: 1.25rem;
  color: var(--faint);
  font-size: 0.75rem;
}

.scale-labels span {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
}

.scale-labels span:nth-child(1) {
  left: 0;
  transform: none;
}

.scale-labels span:nth-child(2) {
  left: 23.81%;
}

.scale-labels span:nth-child(3) {
  left: 47.62%;
}

.scale-labels span:nth-child(4) {
  left: 66.67%;
}

.scale-labels span:nth-child(5) {
  left: 83.33%;
}

.scale-labels span:nth-child(6) {
  left: 100%;
  transform: translateX(-100%);
}

.air-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.air-slot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding: 0.75rem 0.875rem;
  border-radius: 1rem;
  background: var(--surface);
}

.air-tag {
  padding: 0.125rem 0.625rem;
  border: 2px solid var(--edge);
  border-radius: 1rem;
  font-weight: 700;
}

.air-slot.best .air-text {
  font-weight: 700;
}

/* ---------------------------------------------------------------------------------------------
   Einstellungen (Abschnitt 8): Ortsliste, Heizart als Karten (.choice von S5), drei Stepper, Höhe.
   Ein Stepper ist Knopf „−“, Zahl mit Einheit, Knopf „+“; beide Knöpfe 48 px, kein Schieberegler.
   --------------------------------------------------------------------------------------------- */

.set-block {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.place-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.place-item {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1rem;
}

/* Löschen mit Rückfrage: der zweite Knopf trägt die Frage als Text, „Abbrechen“ daneben */
.place-del {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
}

.place-confirm {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.5rem;
  width: 100%;
}

button.danger {
  border-color: var(--crit);
}

.step-field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.step-label {
  font-weight: 700;
}

.stepper {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.step-btn {
  flex: none;
  min-width: 48px;
  min-height: 48px;
  padding: 0;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
}

/* Am Rand des Bereichs bleibt der Knopf fokussierbar (aria-disabled), sieht aber gedämpft aus */
.step-btn[aria-disabled="true"] {
  cursor: default;
}

.stepper output {
  min-width: 5.5rem;
  text-align: center;
  font-size: 1.375rem;
  font-weight: 700;
}

/* „Für Fortgeschrittene“ (Abschnitt 7): zugeklapptes <details> mit den acht Schwellen-Steppern. Das Dreieck der
   Zusammenfassung bleibt das eingebaute; sie ist mindestens 48 px hoch (Regel oben) und trägt den Fokusring. */
.advanced {
  padding: 0 1rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 1rem;
}

.advanced summary {
  padding: 0.75rem 0;
  font-weight: 700;
  cursor: pointer;
}

.advanced-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-bottom: 1rem;
}

/* ---------------------------------------------------------------------------------------------
   Fußzeile (Abschnitt 8): zehn Absätze mit Quellen und Lizenzen, drei davon ganz als Link.
   Der Link trägt Unterstreichung, nie Farbe allein; a.footer-link und .visually-hidden stehen oben.
   --------------------------------------------------------------------------------------------- */

footer {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  font-size: 1rem;
}

footer p + p {
  margin-top: 0.75rem;
}

footer a.footer-link {
  color: var(--fg);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* ---------------------------------------------------------------------------------------------
   Sehhilfen der Werkstatt (31.10.2026): Hoher Kontrast, Farbenblind, Umgekehrte Farben.
   Eine Wahl für alle Werkzeuge (werkstatt.darstellung, siehe boot.js). data-theme trägt hell/dunkel, data-vision
   contrast, cvd oder invert. Die Theme-Blöcke oben bleiben unverändert; Hoher Kontrast und Farbenblind kommen immer
   mit festem data-theme, deshalb braucht es hier keine weitere Abfrage nach prefers-color-scheme.
   Die Temperaturfarben (tcol) laufen über eigene Ankertabellen in chart.js (hc-dark, hc-light, inv-dark).
   --------------------------------------------------------------------------------------------- */

/* Hoher Kontrast dunkel: Schwarz, Schrift #E0E0E0 (15,91:1), jede Textfarbe 7:1 auf Schwarz. Die Ampel hält das im
   Dunkeln schon, nur Kritisch steigt von 6,10 auf 7,20. */
:root[data-vision="contrast"][data-theme="dark"] {
  --bg: #000000;
  --surface: #000000;
  --line: #A0A0A0;
  --fg: #E0E0E0;
  --muted: #C4C4C4;
  --faint: #ADADAD;
  --edge: #A0A0A0;
  --crit: #FF635F;
  --chart-grid: #6E6E6E;
}

/* Hoher Kontrast hell: Weiß, Schrift Schwarz, Ampel und Akzent auf 7:1 nachgedunkelt (gleicher Farbton) */
:root[data-vision="contrast"][data-theme="light"] {
  --bg: #FFFFFF;
  --surface: #FFFFFF;
  --line: #585757;
  --fg: #000000;
  --muted: #2B2B2B;
  --faint: #474747;
  --edge: #585757;
  --accent: #005C8A;
  --ok: #006531;
  --warn: #6A5500;
  --alarm: #894500;
  --crit: #B2001B;
  --chart-grid: #8A8A8A;
}
:root[data-vision="contrast"] .card { border-width: 2px; }
/* Der Ampel-Kasten ist sonst mit 9 % der Stufenfarbe getönt; darauf hielte der Stufensatz im Hellen nur 6,23:1 */
:root[data-vision="contrast"] .verdict { background: var(--surface); border-width: 2px; }
:root[data-vision="contrast"] .lamp i.on { box-shadow: none; }
:root[data-vision="contrast"] :focus-visible { outline: 3px solid var(--fg); outline-offset: 2px; }

/* Farbenblind: die Ampel in Okabe-Ito-Tönen, die bei Rot-Grün- und Blau-Gelb-Schwäche auseinanderzuhalten sind:
   Blau, Gelb, Orange, Rotviolett. Die Stufe steht ohnehin immer als Text da (Stufe, Zahl, Wort, Satz). */
:root[data-vision="cvd"][data-theme="dark"] {
  --ok: #56B4E9;
  --warn: #F0E442;
  --alarm: #E69F00;
  --crit: #CC79A7;
}
:root[data-vision="cvd"][data-theme="light"] {
  --ok: #0072B2;
  --warn: #946500;
  --alarm: #A54700;
  --crit: #8C3F6C;
}

/* Umgekehrte Farben wie der Farbfilter von Windows. Umdrehen erhält den WCAG-Kontrast nicht: im Dunkeln kämen Alarm,
   Kritisch und die leiseste Schrift umgedreht auf 3,51, 2,05 und 3,46. Leicht angehoben halten sie 4,6 gegen beide
   Grundtöne; bei hellem System setzt die @media oben die hellen Werte zurück. */
:root[data-vision="invert"] {
  filter: invert(1);
  --faint: #909BA6;
  --alarm: #FF9847;
  --crit: #FF8E86;
}
:root[data-vision="invert"] :is(img:not([src*=".svg"]), video, [data-echt]):not([data-echt] *) { filter: invert(1); }
@media print {
  :root[data-vision="invert"],
  :root[data-vision="invert"] :is(img:not([src*=".svg"]), video, [data-echt]):not([data-echt] *) { filter: none; }
}
