/*
 * TS-007. Self-hosted, no external requests, no build step (AC-1/AC-2).
 *
 * Mobile-first: everything below is written for a 320 px phone and widened with min-width
 * queries, never the other way round (AC-5). Both themes are first-class (AC-6): the palette is
 * the only thing that changes, and every text pair in it clears 4.5:1 (AC-20).
 */

/* ---------------------------------------------------------------- palette */

:root {
    --grund: #f4f4f1;
    --flaeche: #ffffff;
    --flaeche-2: #ececea;
    --schrift: #191917;
    --gedaempft: #5a5a54;
    --linie: #dedbd4;
    --akzent: #1f6b47;
    --akzent-schrift: #ffffff;
    --gut: #1c6b45;
    --gut-flaeche: #e3f1e9;
    --warnung: #8a5400;
    --warnung-flaeche: #f8eed8;
    --fehler: #a11f1f;
    --fehler-flaeche: #f8e3e3;
    --neutral: #4f5560;
    --neutral-flaeche: #e9eaec;
    /* TS-007 AC-27: the shaded column behind a bucket with no reading at all. Muted enough
       to read as "nothing here", distinct enough that it can never be mistaken for a zero. */
    --luecke-flaeche: #f0efeb;
    /* TS-007 AC-42/AC-50: the price bands, taken from the HHC PHP page so the colours mean here
       what the family has read them to mean for years. Absolute, never relative to the day. */
    --preis-gratis: #7c3aed;
    --preis-sehr-guenstig: #059669;
    --preis-guenstig: #22c55e;
    --preis-ok: #f59e0b;
    --preis-teuer: #ef4444;
    --preis-suendteuer: #991b1b;
    /* The outline on the quarter-hour under way (AC-44) — contrast against every band above. */
    --preis-rand: #111827;
    --schatten: 0 1px 2px rgb(0 0 0 / 6%), 0 4px 12px rgb(0 0 0 / 4%);
    --radius: 12px;
    --raster: 1rem;
}

/* The dark palette, defined once and applied from two places: the system preference below,
   and the manual override further down, which must win in both directions (AC-6). */
@media (prefers-color-scheme: dark) {
    :root:not([data-thema="hell"]) {
        color-scheme: dark;
        --grund: #131519;
        --flaeche: #1b1e23;
        --flaeche-2: #23272e;
        --schrift: #eaeae6;
        --gedaempft: #a2a49e;
        --linie: #2e333b;
        --akzent: #6cc394;
        --akzent-schrift: #10231a;
        --gut: #6cc394;
        --gut-flaeche: #16321f;
        --warnung: #e6b552;
        --warnung-flaeche: #35290f;
        --fehler: #f08a8a;
        --fehler-flaeche: #3a1c1c;
        --neutral: #a8adb6;
        --neutral-flaeche: #262a31;
        --luecke-flaeche: #1e2127;
        /* Same bands, lifted off a dark background: #991b1b and #059669 go nearly black there,
           and a band that cannot be seen is a band that cannot be read (AC-50). */
        --preis-gratis: #a78bfa;
        --preis-sehr-guenstig: #10b981;
        --preis-guenstig: #4ade80;
        --preis-ok: #fbbf24;
        --preis-teuer: #f87171;
        --preis-suendteuer: #dc2626;
        --preis-rand: #f5f5f0;
        --schatten: none;
    }
}

:root[data-thema="dunkel"] {
    color-scheme: dark;
    --grund: #131519;
    --flaeche: #1b1e23;
    --flaeche-2: #23272e;
    --schrift: #eaeae6;
    --gedaempft: #a2a49e;
    --linie: #2e333b;
    --akzent: #6cc394;
    --akzent-schrift: #10231a;
    --gut: #6cc394;
    --gut-flaeche: #16321f;
    --warnung: #e6b552;
    --warnung-flaeche: #35290f;
    --fehler: #f08a8a;
    --fehler-flaeche: #3a1c1c;
    --neutral: #a8adb6;
    --neutral-flaeche: #262a31;
    --luecke-flaeche: #1e2127;
    --preis-gratis: #a78bfa;
    --preis-sehr-guenstig: #10b981;
    --preis-guenstig: #4ade80;
    --preis-ok: #fbbf24;
    --preis-teuer: #f87171;
    --preis-suendteuer: #dc2626;
    --preis-rand: #f5f5f0;
    --schatten: none;
}

/* ---------------------------------------------------------------- basis */

* {
    box-sizing: border-box;
}

html {
    /* iOS zooms a form field below 16px and never zooms back out. */
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    background: var(--grund);
    color: var(--schrift);
    font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    font-variant-numeric: tabular-nums;
    /* AC-5: nothing may push the page sideways at 320 px. Wide content scrolls in its own box. */
    overflow-x: hidden;
}

h1 {
    margin: 0 0 0.25rem;
    font-size: 1.4rem;
    letter-spacing: -0.01em;
}

h2 {
    margin: 2rem 0 0.75rem;
    font-size: 1.05rem;
    letter-spacing: -0.005em;
}

h3 {
    margin: 0 0 0.5rem;
    font-size: 0.95rem;
}

a {
    color: var(--akzent);
    text-underline-offset: 2px;
}

:focus-visible {
    outline: 2px solid var(--akzent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ---------------------------------------------------------------- gerüst */

.kopf {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.9rem;
    background: var(--flaeche);
    border-bottom: 1px solid var(--linie);
}

.marke {
    font-weight: 650;
    letter-spacing: -0.02em;
    color: var(--schrift);
    text-decoration: none;
    font-size: 1.05rem;
}

.kopf-rechts {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/*
 * Wraps rather than scrolls. A horizontally scrolling nav put Einstellungen off the right edge
 * of a 375 px phone with nothing to suggest it was there — and AC-7's "nothing more than two
 * taps away" is not met by a destination you have to discover by swiping a strip.
 */
.navi {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem;
    padding: 0.4rem 0.6rem;
    background: var(--flaeche);
    border-bottom: 1px solid var(--linie);
}

.navi a {
    flex: 0 0 auto;
    padding: 0.35rem 0.6rem;
    border-radius: 999px;
    color: var(--gedaempft);
    text-decoration: none;
    font-size: 0.88rem;
    white-space: nowrap;
}

@media (min-width: 700px) {
    .navi a {
        padding: 0.35rem 0.75rem;
        font-size: 0.92rem;
    }
}

.navi a:hover {
    background: var(--flaeche-2);
    color: var(--schrift);
}

.navi a[aria-current="page"] {
    background: var(--akzent);
    color: var(--akzent-schrift);
    font-weight: 550;
}

.inhalt {
    padding: 1rem 0.9rem 3rem;
    max-width: 62rem;
    margin: 0 auto;
}

.seitenkopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}

.untertitel {
    color: var(--gedaempft);
    font-size: 0.88rem;
    margin: 0;
}

@media (min-width: 700px) {
    .kopf,
    .navi,
    .inhalt {
        padding-inline: 1.25rem;
    }
}

/* ---------------------------------------------------------------- kacheln */

.kacheln {
    display: grid;
    /* Single column under 700 px is the default, not a breakpoint (AC-5). */
    grid-template-columns: 1fr;
    gap: var(--raster);
}

@media (min-width: 700px) {
    .kacheln {
        grid-template-columns: repeat(2, 1fr);
    }
    .kachel.breit {
        grid-column: 1 / -1;
    }
}

@media (min-width: 1000px) {
    .kacheln.drei {
        grid-template-columns: repeat(3, 1fr);
    }
}

.kachel {
    background: var(--flaeche);
    border: 1px solid var(--linie);
    border-radius: var(--radius);
    box-shadow: var(--schatten);
    padding: 0.9rem 1rem 1rem;
    min-width: 0;
}

.kachel-kopf {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
}

.kachel-titel {
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--gedaempft);
    margin: 0;
}

/* The one number the tile exists for. */
.wert {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    font-size: 2rem;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.15;
}

.wert .einheit {
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--gedaempft);
    letter-spacing: 0;
}

.wert.klein {
    font-size: 1.35rem;
}

/* AC-9: a price is never shown without saying which price it is. */
.wert-art {
    font-size: 0.78rem;
    color: var(--gedaempft);
    margin-top: 0.15rem;
}

.nebenwert {
    color: var(--gedaempft);
    font-size: 0.85rem;
    margin-top: 0.35rem;
}

.fussnote {
    color: var(--gedaempft);
    font-size: 0.8rem;
    margin: 0.6rem 0 0;
}

/* ---------------------------------------------------------------- zustände */

.abzeichen {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.12rem 0.5rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
}

.abzeichen::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentColor;
    flex: 0 0 auto;
}

.z-GUT {
    color: var(--gut);
    background: var(--gut-flaeche);
}

.z-WARNUNG {
    color: var(--warnung);
    background: var(--warnung-flaeche);
}

.z-FEHLER {
    color: var(--fehler);
    background: var(--fehler-flaeche);
}

.z-NEUTRAL {
    color: var(--neutral);
    background: var(--neutral-flaeche);
}

.z-INFO {
    color: var(--neutral);
    background: var(--neutral-flaeche);
}

/* Calendar source states use the same vocabulary as the jobs page. */
.z-OK {
    color: var(--gut);
    background: var(--gut-flaeche);
}

.z-DISABLED,
.z-NEVER_RUN {
    color: var(--neutral);
    background: var(--neutral-flaeche);
}

.z-DEGRADED {
    color: var(--warnung);
    background: var(--warnung-flaeche);
}

.z-FAILED {
    color: var(--fehler);
    background: var(--fehler-flaeche);
}

/* The job health strip (AC-11). Its colour is the first thing on the page. */
.streifen {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    padding: 0.7rem 0.9rem;
    border-radius: var(--radius);
    border: 1px solid transparent;
    margin-bottom: var(--raster);
    font-size: 0.9rem;
}

.streifen.z-GUT {
    border-color: color-mix(in srgb, var(--gut) 30%, transparent);
}

.streifen.z-WARNUNG {
    border-color: color-mix(in srgb, var(--warnung) 40%, transparent);
}

.streifen.z-FEHLER {
    border-color: color-mix(in srgb, var(--fehler) 40%, transparent);
}

.streifen .zusammenfassung {
    color: var(--schrift);
}

.streifen .mehr {
    margin-left: auto;
    font-size: 0.85rem;
}

/* AC-17: a gap says what it is. It never renders as a value. */
.keine-daten {
    color: var(--gedaempft);
    font-style: italic;
    font-size: 0.92rem;
}

.kachel.leer .wert {
    color: var(--gedaempft);
    font-size: 1.05rem;
    font-weight: 500;
    font-style: italic;
}

.veraltet {
    color: var(--warnung);
}

/* TS-004 AC-7a: shown exactly once, so it has to be readable and selectable on a phone —
   monospace, wrapping at any character, and never truncated with an ellipsis. */
.feed-url {
    display: block;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
    user-select: all;
    padding: 0.5rem 0.6rem;
    border-radius: 6px;
    background: var(--flaeche-2, rgba(127, 127, 127, 0.12));
}

/* ---------------------------------------------------------------- diagramme */

.diagramm-huelle {
    /* uPlot sizes itself to this box; without the clip a phone scrolls sideways. */
    width: 100%;
    overflow: hidden;
}

/* The band legend above the chart is the colour key (AC-43); uPlot's own legend keeps its hover
   readout but loses its swatches, which would claim one colour for a six-colour series. */
.preis-diagramm .u-marker {
    display: none;
}

/* AC-43: the bands, in words. The bar colour is a judgment, and a judgment has to be legible
   without the reader having learnt the palette. */
.preis-legende {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 0.85rem;
    margin-bottom: 0.6rem;
    font-size: 0.8rem;
    color: var(--gedaempft);
}

.preis-schluessel {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}

.preis-tupfer {
    width: 0.75rem;
    height: 0.75rem;
    border-radius: 3px;
    flex: none;
}

.preis-tupfer-jetzt {
    background: transparent;
    border: 2px solid var(--preis-rand);
}

/* The same reduction the canvas applies to a provisional bar (AC-47). */
.preis-tupfer-vorlaeufig {
    background: var(--preis-teuer);
    opacity: 0.45;
}

/* AC-3: every chart has a text form. It is collapsed, not absent. */
.tabellenform {
    margin-top: 0.75rem;
    font-size: 0.85rem;
}

.tabellenform > summary {
    cursor: pointer;
    color: var(--gedaempft);
    padding: 0.3rem 0;
}

.tabellen-rolle {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-height: 22rem;
}

.uplot,
.u-wrap {
    max-width: 100%;
}

.u-legend {
    font-size: 0.82rem;
    color: var(--gedaempft);
}

.u-legend .u-marker {
    border-radius: 2px;
}

/* ---------------------------------------------------------------- tabellen */

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

th,
td {
    text-align: left;
    padding: 0.45rem 0.6rem;
    border-bottom: 1px solid var(--linie);
    white-space: nowrap;
}

th {
    font-weight: 600;
    font-size: 0.78rem;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--gedaempft);
    position: sticky;
    top: 0;
    background: var(--flaeche);
}

td.zahl,
th.zahl {
    text-align: right;
}

td.text {
    white-space: normal;
}

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

tr.hervorgehoben td {
    background: var(--gut-flaeche);
}

/* ---------------------------------------------------------------- formulare */

label {
    display: block;
    margin: 0.9rem 0 0.25rem;
    font-size: 0.85rem;
    color: var(--gedaempft);
}

input[type="text"],
input[type="password"],
input[type="number"],
input[type="date"],
select {
    width: 100%;
    padding: 0.55rem 0.6rem;
    border: 1px solid var(--linie);
    border-radius: 8px;
    background: var(--flaeche);
    color: var(--schrift);
    font-size: 1rem;
    font-family: inherit;
}

.ankreuz {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    margin: 0.9rem 0;
    color: var(--schrift);
}

.ankreuz input {
    width: auto;
}

button,
.knopf {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.5rem 0.9rem;
    border: 1px solid transparent;
    border-radius: 8px;
    background: var(--akzent);
    color: var(--akzent-schrift);
    font: inherit;
    font-size: 0.92rem;
    font-weight: 550;
    cursor: pointer;
    text-decoration: none;
    /* A 44 px target is the difference between usable and infuriating on a phone. */
    min-height: 2.6rem;
}

button.zweitrangig {
    background: var(--flaeche);
    color: var(--schrift);
    border-color: var(--linie);
}

button.gefaehrlich {
    background: var(--fehler-flaeche);
    color: var(--fehler);
    border-color: color-mix(in srgb, var(--fehler) 35%, transparent);
}

button.link {
    background: none;
    border: 0;
    color: var(--akzent);
    padding: 0.2rem;
    min-height: 0;
    text-decoration: underline;
    font-size: 0.85rem;
}

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

.knopfreihe {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 1rem;
}

.inline {
    display: inline;
}

fieldset {
    border: 1px solid var(--linie);
    border-radius: var(--radius);
    padding: 0.5rem 1rem 1rem;
    margin: 0 0 1rem;
    min-width: 0;
}

legend {
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--gedaempft);
    padding-inline: 0.35rem;
}

/* Chips for the "cheapest N hours" control. */
.wahl {
    display: flex;
    gap: 0.35rem;
    flex-wrap: wrap;
}

.wahl a {
    padding: 0.3rem 0.7rem;
    border: 1px solid var(--linie);
    border-radius: 999px;
    font-size: 0.85rem;
    text-decoration: none;
    color: var(--gedaempft);
    background: var(--flaeche);
}

.wahl a[aria-current="true"] {
    background: var(--akzent);
    border-color: var(--akzent);
    color: var(--akzent-schrift);
    font-weight: 550;
}

/* ---------------------------------------------------------------- hinweise */

.hinweis {
    color: var(--gedaempft);
    font-size: 0.88rem;
}

.meldung {
    padding: 0.6rem 0.8rem;
    border-radius: 8px;
    font-size: 0.9rem;
    margin: 0 0 1rem;
}

.meldung.fehler {
    background: var(--fehler-flaeche);
    color: var(--fehler);
}

.meldung.warnung {
    background: var(--warnung-flaeche);
    color: var(--warnung);
}

.meldung.gut {
    background: var(--gut-flaeche);
    color: var(--gut);
}

/* ---------------------------------------------------------------- anmeldung */

.zentriert {
    display: grid;
    place-items: center;
    min-height: 100vh;
    min-height: 100dvh;
    padding: 1rem;
}

.karte {
    width: min(23rem, 100%);
    padding: 1.75rem;
    background: var(--flaeche);
    border: 1px solid var(--linie);
    border-radius: var(--radius);
    box-shadow: var(--schatten);
}

/* ---------------------------------------------------------------- htmx */

/* A refresh in flight is visible but does not make the page jump. */
.htmx-request.aktualisiert,
.htmx-request .aktualisiert {
    opacity: 0.55;
    transition: opacity 120ms ease-in;
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        animation: none !important;
    }
}

/* Present for a screen reader, absent for the eye — table captions and skip labels (AC-20). */
.nur-lesbar {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* --------------------------------------------- vorläufige Preise (TS-010 AC-20) */

/* An early figure must never look like a billed one. Colour alone would not do it —
   the marker carries a glyph and a title, so it survives greyscale and a screen reader. */
.vorlaeufig {
    color: var(--warnung);
    font-weight: 600;
}

tr.vorlaeufig-zeile td {
    background: var(--warnung-flaeche);
}

.quelle-fussnote {
    color: var(--gedaempft);
    font-size: 0.8rem;
    margin-top: 0.6rem;
}

/* TS-007 AC-30: one row per Zählpunkt — the Zählpunkt, its name, its order, save. A table put
   the number field and the button off the right edge on anything narrower than a laptop, and
   wrapping flex rows say what a table was only pretending to say here. */
.zaehlpunkt-liste {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.zaehlpunkt-zeile {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.7rem;
    background: var(--flaeche-2);
    border-radius: var(--radius);
}

.zaehlpunkt-zeile code {
    flex: 1 1 100%;
    font-size: 0.78rem;
    color: var(--gedaempft);
    word-break: break-all;
}

.zaehlpunkt-zeile input[type="text"] {
    flex: 1 1 12rem;
    min-width: 0;
    margin: 0;
}

.zaehlpunkt-zeile input[type="number"] {
    flex: 0 0 4.5rem;
    margin: 0;
}

.zaehlpunkt-zeile button {
    flex: 0 0 auto;
}

/* ------------------------------------------------------- Termine (TS-015) */

/*
 * The month grid degrades rather than shrinks (AC-7). At 320 px a seven-column table gives each
 * day about 45 px, and titles in this data run to 100 characters — there is no truncation of one
 * that is readable in 45 px. So below 700 px a cell carries the day number and one dot per
 * appointment, and the agenda underneath does the reading. Both forms are in the DOM and the CSS
 * picks; the whole month is at most a few dozen rows, so that costs nothing worth a script.
 */

.monatsleiste {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin: 0.4rem 0 0.6rem;
}

.monatstitel {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    text-align: center;
    white-space: nowrap;
}

/*
 * At 320 px "← davor" and "danach →" wrapped into two-line slabs that dwarfed the month they were
 * navigating, and pushed "August 2026" onto two lines between them. The words are dropped rather
 * than shrunk: an arrow beside a month name needs no label, and the accessible name below keeps
 * the meaning for anyone not reading the glyph.
 */
.monatsleiste .knopf {
    white-space: nowrap;
}

.monatsleiste .wort {
    display: none;
}

@media (min-width: 480px) {
    .monatsleiste .wort {
        display: inline;
    }
}

/* Keeps the title centred when one of the two arrows is gone at the edge of the stored span. */
.knopf.zweitrangig.leer {
    visibility: hidden;
}

.kalender-huelle {
    overflow-x: auto;
}

/* -------------------------------------------------- Calendar sources (TS-018) */

.quellenfilter {
    display: flex;
    align-items: end;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin: 0.7rem 0 1rem;
}

.quellenfilter label {
    margin: 0;
    flex: 0 0 auto;
}

.quellenfilter select {
    width: auto;
    min-width: 12rem;
    flex: 1 1 14rem;
}

.quellenfilter .knopf {
    flex: 0 0 auto;
}

.quellenstatus {
    margin: 0 0 1rem;
    padding: 0.7rem 0.8rem;
    border: 1px solid var(--linie);
    border-radius: var(--radius);
    background: var(--flaeche-2);
}

.quellenstatus h2 {
    margin: 0 0 0.45rem;
    font-size: 0.82rem;
    color: var(--gedaempft);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.quellenstatus-zeile {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
    padding: 0.3rem 0;
    font-size: 0.82rem;
    color: var(--gedaempft);
}

.quellenstatus-zeile + .quellenstatus-zeile {
    border-top: 1px solid var(--linie);
}

.quellenstatus-zeile strong {
    color: var(--schrift);
}

.quellenstatus-zeile.veraltet strong {
    color: var(--warnung);
}

.kalender {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
}

.kalender th {
    padding: 0.3rem 0.2rem;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--gedaempft);
    text-align: center;
}

.kalender td {
    height: 3rem;
    padding: 0;
    border: 1px solid var(--linie);
    vertical-align: top;
    background: var(--flaeche);
}

.kalender td.fremd {
    background: var(--luecke-flaeche);
}

.kalender td.heute {
    outline: 2px solid var(--akzent);
    outline-offset: -2px;
}

.tag-nummer {
    display: block;
    padding: 0.2rem 0.3rem 0;
    font-size: 0.75rem;
    color: var(--gedaempft);
}

.kalender td.heute .tag-nummer {
    color: var(--akzent);
    font-weight: 650;
}

.tag-zelle {
    display: block;
    height: 100%;
    text-decoration: none;
    color: inherit;
}

.tag-zelle:hover {
    background: var(--flaeche-2);
}

.tag-zelle:focus-visible {
    outline: 2px solid var(--akzent);
    outline-offset: -2px;
}

/* AC-8: never colour alone. A dot is filled, hollow or struck; the chip repeats it in words, and
   the cell's aria-label says it outright. */
.tag-punkte {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 0.15rem 0.3rem 0.3rem;
}

.punkt {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--akzent);
}

.punkt.vorlaeufig {
    background: transparent;
    border: 1.5px solid var(--warnung);
}

.punkt.abgesagt {
    background: var(--fehler);
    opacity: 0.45;
}

.punkt-mehr {
    font-size: 0.62rem;
    line-height: 1;
    color: var(--gedaempft);
}

.tag-chips {
    display: none;
}

.chip {
    display: block;
    margin: 1px 2px;
    padding: 1px 4px;
    border-radius: 4px;
    background: var(--gut-flaeche);
    border-left: 3px solid var(--akzent);
    font-size: 0.7rem;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chip.vorlaeufig {
    background: var(--warnung-flaeche);
    border-left-color: var(--warnung);
    border-left-style: dashed;
}

.chip.abgesagt {
    background: var(--fehler-flaeche);
    border-left-color: var(--fehler);
    text-decoration: line-through;
}

.chip-zeit {
    font-variant-numeric: tabular-nums;
    color: var(--gedaempft);
}

.chip-quelle {
    display: inline;
    margin-left: 0.25rem;
    color: var(--gedaempft);
    font-size: 0.64rem;
}

.chip-mehr {
    display: block;
    padding: 1px 6px;
    font-size: 0.68rem;
    color: var(--gedaempft);
}

@media (min-width: 700px) {
    .kalender td {
        height: 5.5rem;
    }

    .tag-punkte {
        display: none;
    }

    .tag-chips {
        display: block;
    }
}

/* -------------------------------------------------------------- the agenda */

.agenda {
    margin-top: 1.2rem;
}

.agenda-tag {
    padding-top: 0.8rem;
    /* The anchor target sits under a sticky-free header, but a little breathing room keeps the
       heading off the very top edge when a chip jumps here. */
    scroll-margin-top: 0.8rem;
}

.agenda-datum {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 0.35rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--gedaempft);
    border-bottom: 1px solid var(--linie);
    padding-bottom: 0.25rem;
}

/* AC-12: the past recedes, it does not disappear — it is the history this page exists for. */
.agenda-tag.vergangen .termin {
    opacity: 0.62;
}

.agenda-tag.heute .agenda-datum {
    color: var(--akzent);
}

.termin {
    display: flex;
    gap: 0.7rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid var(--linie);
}

.termin:last-child {
    border-bottom: none;
}

.termin-zeit {
    flex: 0 0 5.2rem;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
    color: var(--gedaempft);
    white-space: nowrap;
}

.termin-haupt {
    min-width: 0;
    flex: 1 1 auto;
}

.termin-titel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    font-weight: 550;
}

.termin.abgesagt .termin-titel > span:first-child {
    text-decoration: line-through;
}

.termin-rand {
    margin: 0.1rem 0 0;
    font-size: 0.8rem;
    color: var(--gedaempft);
}

.termin-beschreibung {
    margin: 0.15rem 0 0;
    font-size: 0.82rem;
    color: var(--gedaempft);
    white-space: pre-line;
}

.quelle-abzeichen {
    font-size: 0.7rem;
}

/* --------------------------------------------- Wetterkarte (TS-016) */

/*
 * A static SVG basemap as a background-image with the stations positioned on top in percent.
 * No map library and no script: the theme swap below is the whole of the "interactivity",
 * and it is three CSS rules (AC-1, AC-5).
 */
.karte {
    position: relative;
    /* Matches the generated viewBox exactly — if one changes the other must (AC-3). */
    aspect-ratio: 1440 / 580;
    width: 100%;
    margin: 0 0 0.6rem;
    border: 1px solid var(--linie);
    border-radius: var(--radius);
    background-color: var(--flaeche);
    background-image: url("../img/weltkarte-hell.svg");
    background-repeat: no-repeat;
    background-size: 100% 100%;
}

/* Both themes are first-class, and the manual override has to win in both directions (AC-6). */
@media (prefers-color-scheme: dark) {
    :root:not([data-thema="hell"]) .karte {
        background-image: url("../img/weltkarte-dunkel.svg");
    }
}

:root[data-thema="dunkel"] .karte {
    background-image: url("../img/weltkarte-dunkel.svg");
}

:root[data-thema="hell"] .karte {
    background-image: url("../img/weltkarte-hell.svg");
}

.karte-marker {
    position: absolute;
    /* The inline style carries left/top only, so the centring transform stays here. */
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.15rem;
    box-sizing: border-box;
    text-decoration: none;
    font-variant-numeric: tabular-nums;
    /* Lifted off both basemaps: a ring in the surface colour, not a shadow that vanishes on
       one of the two themes. */
    box-shadow: 0 0 0 2px var(--flaeche);
}

/* Under 700 px a world map is ~288 px wide and a labelled badge cannot fit five times over.
   The markers become dots and the tiles below carry the numbers (TS-007 AC-5). */
.karte-marker {
    width: 12px;
    height: 12px;
    border-radius: 50%;
}

.karte-marker .karte-grad,
.karte-marker .karte-symbol,
.karte-marker .karte-wind,
.karte-marker .karte-name {
    display: none;
}

/* AC-19: the visible dot stays 12 px so neighbours do not merge, while the tap target is the
   full 44 px. Transparent, centred on the dot, and above nothing else that is clickable. */
.karte-marker::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
}

@media (min-width: 700px) {
    .karte-marker {
        width: auto;
        height: auto;
        padding: 0.15rem 0.4rem;
        border-radius: 999px;
        font-size: 0.8rem;
        font-weight: 600;
        line-height: 1.35;
    }

    .karte-marker .karte-grad,
    .karte-marker .karte-symbol,
    .karte-marker .karte-wind {
        display: inline-flex;
    }

    .karte-marker::before {
        display: none;
    }

    .karte-symbol {
        width: 0.95em;
        height: 0.95em;
        flex: none;
    }

    .karte-wind {
        font-size: 0.85em;
        line-height: 1;
        opacity: 0.85;
    }

    /* The station name sits under the badge rather than inside it, so the badge stays a
       consistent size and the names never widen a cluster.
       Selector matches the hide rule's specificity above — `.karte-name` alone loses to
       `.karte-marker .karte-name` and every marker stays anonymous. */
    .karte-marker .karte-name {
        display: block;
        position: absolute;
        top: calc(100% + 2px);
        left: 50%;
        transform: translateX(-50%);
        padding: 0 0.2rem;
        border-radius: 4px;
        background: var(--flaeche);
        color: var(--schrift);
        font-size: 0.68rem;
        font-weight: 500;
        white-space: nowrap;
        pointer-events: none;
    }
}

/* AC-9: the ramp only tints the marker — the temperature is printed on it and repeated in
   aria-label, so colour is never the sole carrier. Every pair below clears 4.5:1 on white. */
.karte-marker.grad-eisig { background: #4c5fd7; color: #fff; }
.karte-marker.grad-sehr-kalt { background: #2f6fc0; color: #fff; }
.karte-marker.grad-kalt { background: #1f6b86; color: #fff; }
.karte-marker.grad-mild { background: #2f7d4f; color: #fff; }
.karte-marker.grad-warm { background: #9c5c0c; color: #fff; }
.karte-marker.grad-heiss { background: #a52a1f; color: #fff; }

/* AC-13: no reading is its own state — neutral, never a temperature colour. */
.karte-marker.grad-unbekannt {
    background: var(--neutral-flaeche);
    color: var(--gedaempft);
    border: 1px dashed var(--neutral);
}

.karte-marker.gewaehlt {
    box-shadow: 0 0 0 2px var(--flaeche), 0 0 0 4px var(--akzent);
    z-index: 3;
}

.karte-marker:hover,
.karte-marker:focus-visible {
    z-index: 4;
}

/* AC-12: a fanned marker keeps a dot at the station's real position and a line back to it.
   Without these two the map would be quietly wrong about where a station is. */
.karte-anker {
    position: absolute;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--gedaempft);
    transform: translate(-50%, -50%);
    z-index: 1;
}

.karte-leine {
    position: absolute;
    height: 2px;
    /* The inline style supplies rotate(), so the vertical centring has to be a margin —
       a transform here would overwrite it. */
    margin-top: -1px;
    transform-origin: 0 50%;
    background: var(--gedaempft);
    opacity: 0.75;
    z-index: 1;
}

.karte-fussnote {
    margin-top: 0;
}
