/* ═══════════════════════════════════════════════════════════════════════════════
   team.junaspin — App-Shell

   Die Tokens stammen aus dem junaspin-PIM und sind bewusst unverändert übernommen,
   damit beide Anwendungen als eine Familie lesbar sind. Herleitung und Messwerte:
   docs/PIM-ANALYSE.md §3.

   ⛔ DIE FARBWERTE HIER SIND NUR DIE VORBELEGUNG. Die gültigen Werte stehen in
   app_settings.design und werden von views/layout.html als :root-Block DAHINTER
   ausgegeben. Wer eine Farbe ändern will, tut das im Admin-UI, nicht hier.

   Die Regeln, gegen die jede Zeile prüfbar ist:
    1 Höchstens eine Primäraktion pro Seite.
    2 Farbe ist Bedeutung, nie Dekoration.
    3 Ziffern tabellarisch, rechtsbündig, Einheiten grau.
    4 Schriftgrößen nur über Tokens — keine Pixelzahl in einer font-size.
    5 Schatten trennen FLÄCHEN, sie schmücken nichts. Eine Karte liegt auf dem
      Grund und wirft deshalb einen Hauch (--sh-karte); was sich hebt, wirft
      mehr (--sh-hoch). Eine Zeile und ein Icon werfen nie einen.

      ⛔ EINE AUSNAHME, UND SIE IST GEZÄHLT: die PRIMÄRAKTION einer Seite trägt
      --sh-primaer, den Schatten in ihrer eigenen Markenfarbe. Hier stand einmal
      „ein Knopf wirft nie einen". Der Satz hielt die Fläche ruhig und nahm der
      einen Handlung, auf die es je Seite ankommt, ihr Gewicht: zwischen „Kommen"
      und „Abmelden" entschied allein die Füllfarbe. Der Schatten hebt genau
      einen Knopf je Seite — Regel 1 begrenzt ihn von selbst. Jeder ANDERE Knopf
      wirft weiterhin keinen, außer für den Moment unter dem Zeiger.
   ═══════════════════════════════════════════════════════════════════════════════ */

:root {
  --rail-w: 244px;
  --h-topbar: 56px;
  /* Die Leiste am unteren Rand auf schmalen Fenstern: Ikone und Wort, dazu das Fingermaß. */
  --unten-h: 64px;

  /* ⛔ „Inter" STEHT VORNE, DIE SYSTEMSCHRIFT BLEIBT DAHINTER STEHEN — sie ist nicht Beiwerk,
     sondern das, was in der ersten halben Sekunde und auf jedem Gerät ohne die Datei zu lesen ist
     (`font-display: swap`). Die @font-face-Regeln stehen weiter unten mit ihrer Begründung.
     ⛔ `--f-mono` TRÄGT BEZEICHNER, KEINE ZAHLEN — Farbwerte, die PIN-Eingabe. (Die Schlüssel unter
     Einstellungen trugen sie bis zum 08.10.2026; seitdem stehen dort Klartext-Beschriftungen.)
     Die tickenden Laufzeiten stehen seit dem 03.10.2026 in Inter mit `tabular-nums`: jede Ziffer
     hat dort dieselbe Breite, und nichts wackelt — die Festbreitenschrift daneben las sich wie ein
     Fremdkörper. */
  --f-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --f-mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, "Liberation Mono", monospace;

  /* Typo-Skala aus dem PIM. Die Erweiterungen stehen darunter, jede mit ihrem Grund;
     `--fs-terminal` ist die erste: eine Lagerhalle liest keine 28 px aus zwei Metern. */
  --fs-micro: 11px; --fs-dense: 13px; --fs-ui: 14px;
  --fs-body: 15px;  --fs-sect: 17px;  --fs-title: 22px; --fs-kpi: 28px;
  --fs-icon: 10px;  --fs-terminal: 64px;
  /* Die Uhr im Ruhebild des Terminals: sie ist das, was man im Vorbeigehen aus zwei, drei Metern
     abliest. Mit der Fensterhöhe skaliert, weil das Lagertablet kleiner sein kann als ein Monitor. */
  --fs-terminal-uhr: clamp(88px, 17vh, 168px);

  /* Zwei Erweiterungen gegenüber dem PIM, beide mit einem Grund:
     --fs-h1  Die Seitenüberschrift lag mit 22 px nur fünf Pixel über jedem
              Kartentitel (17 px). Fünf Pixel sind keine Rangfolge — man sah
              nicht, wo eine Seite anfängt. 26 und nicht 28: --fs-kpi bleibt
              die größte Zahl der Startseite, und das soll eine Zahl sein.
     --fs-feld Nur für schmale Fenster. iOS zoomt bei JEDEM Fokus in ein
              Eingabefeld unter 16 px hinein und danach nicht wieder heraus —
              wer eine Zeit nachträgt, zoomt sonst bei jedem Feld von Hand zurück. */
  --fs-h1: 26px;    --fs-feld: 16px;

  /* Die dritte Erweiterung, und die letzte: --fs-hero für die Zahl im Fortschrittsring.
     --fs-kpi (28px) trägt die Kennzahlkarten daneben; die Ringzahl in derselben Größe wäre die
     vierte gleich große Zahl der Seite und damit keine Rangfolge mehr. Sie ist die eine, die
     jemand im Vorbeigehen liest — im Lager aus zwei Metern, im Büro über die Schulter. */
  --fs-hero: 44px;

  /* Ein Zeilenmaß für Fließtext, überall. 780 px sind bei 15 px rund 95 Zeichen.
     ⛔ Gilt NUR für Fließtext — Tabellen und Raster haben es absichtlich nicht. */
  --measure: 780px;

  /* Das Flächenmaß, nicht zu verwechseln mit --measure: das begrenzt ZEILEN,
     dieses begrenzt die FLÄCHE. Auf einem 34-Zoll-Monitor lief der Inhalt sonst
     über 2400 px und zwei Kennzahlen standen so weit auseinander, dass man den
     Kopf drehen musste, um sie zu vergleichen. */
  --bahn: 1360px;

  /* ⛔ EINE HOEHE FUER JEDES BEDIENELEMENT. Knopf, Eingabefeld, Auswahl und Aufklapper standen
     mit 38, 34 und der nativen Hoehe nebeneinander — in einem Formular sieht das aus wie drei
     verschiedene Bausaetze. Auf schmalen Fenstern und auf jedem Zeigegeraet ohne Maus geht der
     Wert auf 48 px (Fingermass), und zwar an EINER Stelle statt in acht Regeln. */
  --control-h: 38px;

  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;

  /* ⛔ DIE SKALA BLEIBT AUFSTEIGEND, UND DIE KARTE SITZT AUF --r-4.
     Der Auftrag schrieb „--r-3: 14px" und meinte damit die Kartenkante. Die Karte trägt in
     diesem Haus aber --r-4; --r-3 auf 14 zu setzen hätte die dritte Stufe über die vierte
     (12 px) gehoben und damit eine Skala erzeugt, in der die kleinere Zahl den größeren Radius
     meint. Umgesetzt ist deshalb die ABSICHT: --r-4 auf 14 px — und alles, was eine Karte ist
     (Karte, Kennzahlkachel, Aktionskarte, Menüblatt, großer Knopf), wird davon von selbst
     runder, ohne dass eine einzige Vorlage angefasst werden muss. */
  --r-1: 3px; --r-2: 6px; --r-3: 10px; --r-4: 14px; --r-full: 999px;

  /* Vier Höhen, vier Aufgaben — siehe Regel 5 im Kopf.
     --sh-karte  eine Karte auf dem Grund. Zwei Lagen, beide sehr schwach: die weiche trägt den
                 Raum, die harte zeichnet die Unterkante nach. Man soll ihn nicht als Schatten
                 lesen, sondern nur die Kante als Kante.
     --sh-hoch   was sich beim Zeigen hebt und was über dem Inhalt schwebt (Aufklapper,
                 Schubfach, klebende Leiste). ⛔ OHNE DEN RING aus der warmen Fassung
                 (`0 0 0 1px`): auf kühlem Grund zeichnete der eine sichtbare zweite Kante um
                 jedes Blatt, und ein Aufklapper mit zwei Kanten sieht aus wie zwei Aufklapper.
                 Die Trennung trägt jetzt der weiche Versatz nach unten.
     --sh-pop / --sh-modal  auf die kühlen Neutralen nachgezogen. */
  --sh-karte: 0 1px 3px 0 rgb(0 0 0 / .05), 0 1px 2px -1px rgb(0 0 0 / .03);
  --sh-hoch:  0 10px 15px -3px rgb(0 0 0 / .08), 0 4px 6px -4px rgb(0 0 0 / .04);
  --sh-pop:   0 4px 12px rgb(15 23 42 / .10), 0 0 0 1px rgb(15 23 42 / .05);
  --sh-modal: 0 16px 48px rgb(15 23 42 / .24);

  /* ⛔ DIE PRIMÄRAKTION TRÄGT IHREN SCHATTEN IN IHRER EIGENEN FARBE, UND ZWAR GERECHNET.
     Ein fester Wert `rgba(44,95,133,.25)` wäre die Markenfarbe ein zweites Mal — und --primary
     kommt im Betrieb aus `app_settings.design`. Nach dem ersten Wechsel unter Einstellungen →
     Design läge ein blauer Schatten unter einem grünen Knopf. Die erste Zeile ist der Rückfall
     für Browser ohne `color-mix`; die zweite überschreibt sie überall, wo es sie gibt. */
  --sh-primaer: 0 2px 6px rgb(15 23 42 / .18);
  --sh-primaer: 0 2px 6px color-mix(in srgb, var(--primary) 28%, transparent);

  /* ⛔ DIE NEUTRALEN SIND KÜHL — UND DAS IST DIE UMKEHR EINER FRÜHEREN ENTSCHEIDUNG.
     Hier stand bis zum 30.08.2026 das Gegenteil: warme Neutrale, damit das gedeckte Stahlblau
     der Marke Präsenz bekommt. Der Satz stimmte für sich genommen und war trotzdem der falsche
     Handel. Auf einem großen Bildschirm las sich die warme Fläche nicht als „warm", sondern als
     vergilbt — und die Kante zwischen Karte und Grund verschwand, weil beide Töne dicht
     beieinanderlagen. Das gedeckte Blau verliert auf kühlem Grund nichts, was es nicht über den
     KONTRAST zurückbekommt: Weiß auf --primary steht bei 6,81:1, --primary als Text auf der
     Karte ebenfalls. Wer die warme Fassung wiederhaben will, ändert diesen Block — nicht
     einzelne Werte an dreißig Stellen.

     Alle Werte liegen auf einer gemeinsamen kühlen Achse, damit sie sich untereinander nicht
     beißen. Die gemessenen Verhältnisse stehen bei --text und bei den Badge-Familien;
     `test/farbkontrast.test.js` rechnet sie bei jedem Lauf nach. */
  --canvas: #FFFFFF;
  --sunken: #F8FAFC;
  --table-head: #F1F5F9;
  --hover: #F1F5F9;
  --selected: #E8F1FA;
  --border: #E2E8F0;
  --row-line: #EDF2F7;

  /* ⛔ ZWEI KANTEN, ZWEI AUFGABEN — und die zweite ist nachgemessen.
     --border trägt Haarlinien und die Kante eines Knopfes: dort ist die Fläche schon sichtbar,
     die Linie schließt sie nur ab. --border-strong trägt die Kante eines EINGABEFELDES, und die
     ist der einzige Hinweis darauf, wohin jemand tippt. WCAG 2.1 (1.4.11, Nicht-Text-Kontrast)
     verlangt dafür 3:1 gegen die Nachbarfläche; die alte warme Kante #CFCAC1 kam auf 1,48:1 und
     verfehlte das seit jeher. #8995AE ist der HELLSTE Wert auf der kühlen Achse, der 3:1 gegen
     Weiß hält (gemessen 3,01:1) — dunkler als modisch, und genau so hell wie erlaubt. */
  --border-strong: #8995AE;

  /* ⛔ DIE KARTENKANTE IST EIN EIGENES TOKEN UND NICHT --border.
     Sie ist hier erstmals ein fester Wert und kein rgba mehr: auf kühlem Grund liegt die Karte
     so dicht am Papier, dass eine nur abdunkelnde Kante je nach Untergrund verschieden stark
     ausfiel — im Schubfach anders als auf der Arbeitsfläche. Im Dunkel-Theme bleibt sie
     aufhellendes rgba, weil die Karte dort ÜBER dem Grund liegt. */
  --karte-rand: #E2E8F0;

  --text: #0F172A;        /* 17,85:1 auf der Karte · 17,06:1 auf dem Grund */
  --text-muted: #475569;  /*  7,58:1 / 7,24:1 — Labels, Sekundärwerte */
  --text-faint: #8595AA;  /*  3,05:1 — NUR Platzhalter/Einheiten/disabled. Nie auf einem Wert. */

  /* Marke: das junaspin-Logo ist gedecktes Stahlblau #5B7F9E. --primary ist daraus auf
     Kontrast gezogen (Weiß darauf 6,81:1). ⛔ Diese vier kommen im Betrieb aus
     `app_settings.design` und werden von layout.html überschrieben — was hier steht, ist die
     Vorbelegung für den ersten Start und für die Tests. */
  --primary: #2C5F85;
  --primary-hover: #234E6E;
  --focus: #2C5F85;

  /* ⛔ DIE SCHRIFT AUF DER MARKENFLAECHE IST EIN TOKEN UND KEIN FESTES WEISS.
     Sie stand an fuenf Stellen als `color: #fff` — am Primaerknopf, an der Schrittnummer, im
     Ansicht-Balken und an dessen Rueckweg. Im Hellen stimmt Weiss (6,81:1). Im DUNKELN ist
     --primary die aufgehellte Fassung (#6BA3D0), und Weiss darauf kommt auf 2,70:1 — unter
     jedem Schwellwert, und zwar seit es das Dunkel-Theme gibt. Ein Token loest das an einer
     Stelle statt an fuenfen.
     ⛔ WAS ES NICHT LOEST: --primary kommt aus app_settings.design. Waehlt jemand dort eine
     sehr helle Marke, faellt auch im Hellen der Kontrast — dagegen hilft nur eine Pruefung im
     Einstellungsformular, und die ist eine eigene Aufgabe. */
  --auf-primary: #FFFFFF;

  /* Ampel — auf dem kühlen Grund nachgemessen: good 6,73:1 · warn 5,43:1 · bad 6,62:1 auf der
     Karte, 6,44 / 5,19 / 6,33 auf dem Grund. Sie gehört dem Tagesstatus und dem Urlaubskonto.
     Kein Button trägt sie. */
  --good: #12693F;
  --warn: #B54708;
  --bad:  #B32318;

  /* ══════════════════════════════════════════════════════════════════════════════════════════
     DIE HANDLUNGSFARBEN AN DER STEMPELUHR — EINE EIGENE ACHSE, UND ZWAR AUS EINEM GRUND.

     ⛔ HIER STAND „KEIN KNOPF TRÄGT FARBE", UND DER SATZ IST JETZT GENAUER STATT WEG.
     Der Wunsch nach einem grünen „Kommen" war zweimal abgelehnt, und das Argument war richtig:
     um 8:00 steht die Ampel auf grau, und zwölf Pixel daneben leuchtete Grün — zwei Grün mit
     zwei Bedeutungen, danach heißt Grün nichts mehr. Was das Argument NICHT trägt, ist der
     Schluss, dass die drei Knöpfe deshalb gleich aussehen müssen. Sie bedeuten drei verschiedene
     Dinge, und im Lager wird mit Handschuhen und aus zwei Metern getroffen.

     Aufgelöst wird der Widerspruch über die BEDEUTUNGSEBENE, nicht über den Farbton:
       • Die AMPEL (`--good/--warn/--bad`) sagt, in welchem ZUSTAND jemand ist.
       • Diese Achse sagt, welche HANDLUNG ein Knopf auslöst.
     Zwei Ebenen, zwei Familien — und die Handlungsfamilie meidet das Ampelgrün ausdrücklich:
     „du arbeitest" (grün) und „fang an zu arbeiten" (Petrol) dürfen nicht gleich aussehen.

     ⛔ DIE PAUSE IST `--warn` SELBST, UND DAS IST KEIN VERSEHEN. Auf dieser Karte bedeutet
     Bernstein bereits „Pause" — an der Ampel, am Streifen der Karte und am Ring. Ein zweiter,
     leicht anderer Amberton daneben wäre die Frage wert, was denn der Unterschied ist; es gibt
     keinen. „Farbe ist Bedeutung" ist damit eingehalten, nicht gebrochen.
     ⛔ SIE IST DESHALB EIN `var(--warn)` UND KEIN EIGENER HEXWERT. Genau der stand hier einmal
     (`#B45309` neben `--warn: #B54708`), und der Kommentar behauptete trotzdem, es sei derselbe
     Ton. Als Verweis zieht ein Wechsel unter Einstellungen → Design beide mit — und die Zusage
     lässt sich nicht mehr durch eine geänderte Ziffer brechen.

     ⛔ GEHEN IST SCHIEFER UND NICHT ROT. Rot ist `--bad` und heißt in diesem Haus „Verstoß";
     Feierabend ist keiner. Der ruhige Slate-Ton ist der Schlussstrich unter den Tag.

     ⛔ UND SIE STEHEN NICHT IN `app_settings.design`. Die Ampel ist dort änderbar, weil sie zur
     Marke gehört; diese drei tragen eine Zusage, die `test/farbkontrast.test.js` nachrechnet —
     Weiß darauf lesbar, und die Handlung vom Zustand unterscheidbar. Ein Regler, an dem sich
     beide Familien angleichen lassen, wäre die Zusage ohne den Test.

     Nachgemessen: --auf-akt auf kommen 5,47:1 · gehen 10,35:1; auf der Pause gilt der Wert der
     Ampel selbst (Vorbelegung 5,19:1), und `test/farbkontrast.test.js` rechnet ihn nach. */
  --akt-kommen: #0F766E;  --akt-kommen-hover: #0B5F59;
  --akt-gehen:  #334155;  --akt-gehen-hover:  #1E293B;
  --auf-akt: #FFFFFF;

  /* ⛔ DER TAG IST EINE KARTE, UND DER HEUTIGE TRÄGT DIE MARKE (20.10.2026, Vorbild: die Zeitentabelle in zeitkumpel).
     Balken, Säulen, Zeitleiste und der Ring am Zwischenstand bleiben im Markenblau (`--primary`, Mehrarbeit `--primary-hover`); das Plus einer Differenz
     trägt dieselbe Marke, das Minus den Schiefer von `--akt-gehen` – NIE Rot und nie Grün (CLAUDE.md, „Ein Diagramm trägt keine Ampelfarbe“).
     Die Karte des heutigen Tages nimmt die vorhandene Fläche `--selected` und eine Kante, gemischt aus der Marke: beides folgt einem anderen Ton unter
     Einstellungen → Design von selbst, im Dunkeln ebenso (die Marke ist dort die helle Fassung). Die Schiene ist immer dunkel, ihr Merkzeichen deshalb
     ein fester, heller Ton aus dem Logo (`--logo-pfeil-hell`). */
  --heute-bg: var(--selected);
  --heute-rand: #B4CDE3;
  --heute-rand: color-mix(in srgb, var(--primary) 32%, var(--canvas));
  --rail-akzent: #8DB3D4;

  /* ⛔ DIE PAUSE IST `--warn` SELBST — NICHT EIN ZWEITER AMBERTON DANEBEN.
     Hier stand `#B45309` neben `--warn: #B54708`, und der Kommentar darüber behauptete, die Pause
     TEILE den Bernstein der Ampel. Sie tat es nicht: zwei Werte, wenige Pixel auseinander auf
     derselben Karte (der Streifen links nimmt `--warn`, der Knopf daneben nahm den eigenen Ton).
     Genau der „zweite, leicht andere Amberton", den der Kommentar selbst als Fehler benennt — und
     im Dunkel-Theme waren beide zufällig gleich, die Themes widersprachen sich also auch
     untereinander.
     Jetzt ist es EIN Wert. Damit zieht ein Wechsel unter Einstellungen → Design den Knopf mit;
     vorher trüge der Streifen den neuen Amber und der Knopf den alten.
     ⛔ DER HOVER WIRD GERECHNET, NICHT NOTIERT — aus demselben Grund wie bei `--sh-primaer`.
     Die erste Zeile ist der Rückfall für Browser ohne `color-mix`. */
  --akt-pause: var(--warn);
  --akt-pause-hover: #92400E;
  --akt-pause-hover: color-mix(in srgb, var(--warn) 82%, black);

  /* ⛔ VIER FAMILIEN, UND SIE TRAGEN MEHR ALS NUR PILLEN: an ihnen hängen auch die
     `.hinweis`-Kästen. Wer hier eine Zahl ändert, ändert beide — das ist Absicht, denn
     „freigegeben" muss in der Pille und im Kasten dasselbe Grün sein.
     Die Familien waren schon vorher kühl; sie sind der Grund, warum der Rest des Hauses jetzt
     zu ihnen passt und nicht umgekehrt. Nachgemessen (WCAG 2.1):
     ok 7,29 · warn 6,84 · err 7,60 · neutral 6,92 — alle über AAA für Fließtext. */
  --badge-ok-bg: #ECFDF5;   --badge-ok-bd: #A7F3D0;   --badge-ok-fg: #065F46;
  --badge-warn-bg: #FFFBEB; --badge-warn-bd: #FDE68A; --badge-warn-fg: #92400E;
  --badge-err-bg: #FEF2F2;  --badge-err-bd: #FECACA;  --badge-err-fg: #991B1B;
  --badge-neu-bg: #F1F5F9;  --badge-neu-bd: #CBD5E1;  --badge-neu-fg: #475569;

  /* ⛔ DIE ZÄHLKAPSEL IST EINE EIGENE FAMILIE UND KEINE DER VIER OBEN.
     „7 Anträge" ist keine Konsequenz, sondern eine Menge — in Warn-Gelb stünde an jedem
     Montagmorgen eine Warnung, die keine ist, und nach zwei Wochen sähe niemand mehr hin.
     Ein ruhiges Markenblau sagt „hier liegt etwas", ohne zu behaupten, dass etwas schiefgeht.
     Gemessen 6,16:1. Der EINE Fall, der wirklich eine Konsequenz ist — ein offener Klärfall,
     der den Monatsabschluss blockiert —, trägt weiterhin den Warnton über `data-art`. */
  --zahl-bg: #EFF6FF; --zahl-bd: #BFDBFE; --zahl-fg: #1D4ED8;

  /* ⛔ DIE SCHIENE IST SEIT DEM 29.09.2026 TIEFES STAHLBLAU — und ihr Wert kommt aus der Datenbank.
     `--rail` wird von layout.html aus `app_settings.design.railLight` überschrieben; Migration 035
     zieht den gespeicherten Wert mit. Die helle Schiene trennte Menü und Inhalt nur über eine
     Haarlinie, und die Marke stand nirgends auf der Seite. Jetzt trägt die Schiene die Marke.
     ⛔ DIE SCHRIFT DARAUF IST HELL, ALSO MUSS DIE SCHIENE DUNKEL BLEIBEN. Die Design-Seite weist
     einen Ton ab, auf dem `--rail-text` nicht lesbar wäre (`routes/einstellungen.js`).
     ⛔ HOVER UND AKTIV WERDEN AUS `--rail` GEMISCHT, damit sie einem anderen Ton unter
     Einstellungen → Design folgen. Der Hexwert davor ist die Vorbelegung, die
     `test/farbkontrast.test.js` nachrechnet — dasselbe Muster wie bei `--sh-primaer`. */
  --rail: #12304A;
  --rail-hover: #1C3F5E;
  --rail-hover: color-mix(in srgb, var(--rail) 86%, white);
  --rail-active: #25506F;
  --rail-active: color-mix(in srgb, var(--rail) 72%, white);
  --rail-border: #0B2233;
  --rail-text: #D5E1EC;        /* auf der Schiene gut 11:1 */
  --rail-text-active: #FFFFFF;
  --rail-section: #8EA8BF;     /* rund 5,5:1 — tritt zurück und bleibt lesbar */

  /* Das Logo (views/_logo.html): Spiralpfeil und Schriftzug getrennt einfärbbar. Auf dunkler
     Fläche — Schiene, Markenfläche, Dunkel-Theme — die hellen Fassungen. */
  --logo-pfeil: #5A7D9A;
  --logo-schrift: #0F172A;
  --logo-pfeil-hell: #8DB3D4;
  --logo-schrift-hell: #FFFFFF;

  --toast-bg: #0F172A;
  --toast-fg: #E8EDF4;

  color-scheme: light;
}

/* Dark: EIN Block, EIN Selektor. Kein zusätzlicher `prefers-color-scheme`-Block —
   im PIM war das toter Code und eine Falle: 24 Token-Zeilen, die jemand von Hand
   synchron halten musste, und beim Palettenwechsel liefen sie auseinander.
   `data-theme` wird vor dem ersten Paint gesetzt (layout.html).

   ⛔ DIESER BLOCK SCHLÄGT AUCH DEN AUS DER DATENBANK. `<style id="marke">` schreibt ein
   `:root { --primary: … }` (Spezifität 0,1,0); dieser Selektor hier liegt bei 0,2,0 und gewinnt.
   Das ist gewollt und der eigentliche Grund, warum die Farben als `:root`-REGEL und nicht als
   Inline-Style ausgegeben werden: die hellen Markenwerte wären auf dunklem Grund zu dunkel. */
:root[data-theme="dark"] {
  --canvas: #1B222C; --sunken: #131922; --table-head: #232B36;
  --hover: #262F3B; --selected: #1E3B54;
  --border: #2E3846; --border-strong: #636C7E; --row-line: #262E3A;
  /* Im Dunkeln liegt --canvas ÜBER --sunken; die Kante zeichnet deshalb nach oben auf
     und nicht nach unten ab. Hier bleibt sie rgba — anders als im Hellen: die Karte liegt im
     Dunkeln auf verschieden hellen Gründen (Seite, Schubfach), und eine aufhellende Kante passt
     sich jedem davon an. */
  --karte-rand: rgb(255 255 255 / .08);
  --text: #E8EDF4; --text-muted: #A3AFC0; --text-faint: #6E7A8C;
  --primary: #6BA3D0; --primary-hover: #82B5DD; --focus: #8CBEE2;
  --auf-primary: #0F172A;
  --good: #45C08A; --warn: #E5A34C; --bad: #F0655A;
  /* Die Handlungsfarben kippen wie die Marke: heller Grund, dunkle Schrift. ⛔ `--auf-akt` MUSS
     mitkippen — als festes Weiß käme es auf dem aufgehellten Petrol auf 1,9:1 und wäre auf einem
     Knopf unlesbar, den jemand morgens im Halbdunkel des Lagers trifft. Genau dieser Fehler ist
     in diesem Haus schon einmal passiert (siehe --auf-primary). */
  --akt-kommen: #5EC7BC; --akt-kommen-hover: #7BD6CC;
  --akt-gehen:  #94A3B8; --akt-gehen-hover:  #B0BCCC;
  --auf-akt: #0F172A;
  /* Die Pause bleibt auch hier `--warn` selbst. Der Hover hellt auf statt abzudunkeln: im Dunkeln
     liegt die Fläche über dem Grund, und „heller" ist dort die Bewegung nach vorn. */
  --akt-pause: var(--warn);
  --akt-pause-hover: #F0B76E;
  --akt-pause-hover: color-mix(in srgb, var(--warn) 82%, white);
  --badge-ok-bg: #0F2C1E; --badge-ok-bd: #1F5637; --badge-ok-fg: #6EDCA6;
  --badge-warn-bg: #2C2415; --badge-warn-bd: #5A4520; --badge-warn-fg: #F0BE6B;
  --badge-err-bg: #31191A; --badge-err-bd: #63302B; --badge-err-fg: #F58B80;
  --badge-neu-bg: #212936; --badge-neu-bd: #333D4D; --badge-neu-fg: #A9B5C4;
  --zahl-bg: #17263C; --zahl-bd: #24405F; --zahl-fg: #93C5FD;
  --rail: #0F141B; --rail-hover: #1A212B; --rail-active: #233040;
  --rail-border: #1E2530; --rail-text: #A9B5C4; --rail-text-active: #FFFFFF;
  --rail-section: #737E93;
  --logo-pfeil: #8DB3D4; --logo-schrift: #E8EDF4;
  --toast-bg: #E8EDF4; --toast-fg: #131922;
  /* Im Dunkeln trägt der Schatten wenig — die Tiefe entsteht daran, dass
     --canvas HELLER ist als --sunken. Der Hauch bleibt trotzdem: er zeichnet die
     Unterkante nach, die sonst mit dem Grund verschwimmt. */
  --sh-karte: 0 1px 3px rgb(0 0 0 / .45);
  --sh-hoch:  0 10px 15px -3px rgb(0 0 0 / .55), 0 4px 6px -4px rgb(0 0 0 / .4);
  --sh-pop: 0 4px 12px rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .07);
  --sh-modal: 0 16px 48px rgb(0 0 0 / .62);
  --sh-primaer: 0 2px 6px rgb(0 0 0 / .4);
  --sh-primaer: 0 2px 6px color-mix(in srgb, var(--primary) 34%, transparent);
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   DIE HAUSSCHRIFT — LOKAL, NICHT AUS EINEM NETZ.

   ⛔ KEIN GOOGLE FONTS UND KEIN CDN. Ein `<link>` auf fonts.googleapis.com schickt die IP-Adresse
   jedes Mitarbeiters bei jedem Seitenaufruf an einen Dritten in die USA — LG München I,
   20.01.2022, 3 O 17493/20, und dort ging es um einen Besucher, nicht um eine Belegschaft, die
   dazu verpflichtet ist, diese Seite zu benutzen. Die Dateien liegen deshalb unter
   `public/fonts/`. Es ist dieselbe Regel, aus der eine Mail hier nichts nachlädt.

   ⛔ EINE VARIABLE SCHRIFT UND NICHT VIER SCHNITTE. Das Haus benutzt 400, 500 und 600; als
   Einzeldateien wären das drei Abrufe und drei Gelegenheiten, einen davon zu vergessen. Die
   `wght`-Achse deckt jedes Gewicht ab, das jemals hinzukommt.

   ⛔ ZWEI SUBSETS MIT `unicode-range`, UND DAS ZWEITE KOSTET IM REGELFALL NICHTS. Der Browser
   lädt `latin-ext` (74 kB) nur, wenn auf der Seite tatsächlich ein Zeichen daraus steht — bei
   einem Nachnamen wie „Nowaczyk" oder „Şahin". Ohne dieses Subset fiele genau dieser eine
   Buchstabe auf die Systemschrift zurück, mitten im Wort.
   Das Minuszeichen aus `stdUhr` (U+2212, nicht der Bindestrich) liegt im Latin-Subset — sonst
   stünde jede Minusstunde in einer anderen Schrift als die Zahl dahinter.

   ⛔ WAS BEWUSST NICHT ABGEDECKT IST: die Pfeile ← und → (U+2190/U+2192) der Monatsnavigation.
   Das Latin-Subset trägt nur ↑ und ↓. Sie fallen damit auf die Systemschrift zurück — und das ist
   hier hinnehmbar, weil ein Pfeil ein Symbol ist und kein Buchstabe: er steht allein vor seinem
   Wort, nicht mitten darin. Ein drittes Subset dafür wären 40 kB für zwei Zeichen. Wer sie
   angleichen will, ersetzt sie durch die Ikonen aus `_ikonen.html` — nicht durch ein Subset.

   ⛔ `font-display: swap`. Ein Mitarbeiter, der um 8:00 stempeln will, wartet nicht auf eine
   Schriftdatei: der Text steht sofort in der Systemschrift da und wird danach ersetzt. Die
   Alternative (`block`) hielte den Knopf für bis zu drei Sekunden unsichtbar — das ist derselbe
   Gedanke, aus dem das Stempeln ohne JavaScript funktioniert.

   ⛔ OHNE `?v=`. Eine Schriftdatei ändert ihren Inhalt nicht; ändert sie ihn doch, ändert sich
   ihr Name. Die Versionsregel des Hauses gilt Dateien, die sich unter gleichem Namen ändern —
   Stylesheet und Skripte —, und `test/views.test.js` prüft genau die.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-latin.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: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-latin-ext.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;
}

/* ⛔ DER GRUND IST --sunken, NICHT --canvas. Vorher trugen Seite und Karte dieselbe
   Farbe; sichtbar war eine Karte nur an ihrer Haarlinie, und eine Seite las sich als
   eine lange Liste ohne Anfang und ohne Ende.

   Die Rollen sind ab hier fest: --sunken ist der Grund (Arbeitsfläche, Anmeldeseite,
   Wochenende im Kalender), --canvas ist alles, was DARAUF liegt oder eine Eingabe
   annimmt (Karte, Topbar, Knopf, Feld). Im Dunkel-Theme kippt das von selbst richtig,
   weil --canvas dort heller ist als --sunken.

   ⛔ DER GRUND IST KÜHL (#F8FAFC), UND HIER STAND EINMAL DAS GEGENTEIL.
   Der alte Satz lautete „KEIN KÜHLES #F8FAFC" und begründete das mit der Präsenz der Marke auf
   warmem Grund. Die Begründung war richtig und die Folge trotzdem falsch: auf einem großen
   Bildschirm las sich das warme Beige als vergilbt, und Karte und Grund lagen so dicht
   beieinander, dass die Karte ihre Kante verlor. Die Marke holt sich ihre Präsenz jetzt über den
   Kontrast statt über die Temperatur (6,81:1 gegen Weiß). Die vollständige Herleitung steht oben
   im Token-Block bei den Neutralen. */
body {
  margin: 0;
  background: var(--sunken);
  color: var(--text);
  font: 400 var(--fs-body)/1.5 var(--f-ui);
  -webkit-text-size-adjust: 100%;
}

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
/* ⛔ EIN LINK IM FLIESSTEXT TRÄGT SEINEN STRICH. Die Markenfarbe liegt neben dem gedämpften Text eines
   Hinweises bei 1,11:1 (hell) — „Postausgang ansehen" sah aus wie ein Wort des Satzes. In Tabellen,
   Menüs und Kapseln trägt der Ort den Link; im Satz trägt ihn nur der Strich (WCAG 1.4.1). */
.karte-hinweis a:not(.knopf):not(.pill), .hinweis a:not(.knopf):not(.pill),
.feld-hinweis a:not(.knopf):not(.pill) { text-decoration: underline; text-underline-offset: 2px; }

/* ⛔ EIN SPRUNGZIEL LANDET UNTER DER KLEBENDEN TOPBAR, NICHT DAHINTER. `#eintragen`, `#minijob`,
   `#lohnexport`: die Kartenüberschrift stand bei 21 px, die Leiste reicht bis 57. */
html { scroll-padding-top: calc(var(--h-topbar) + var(--sp-3)); }

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

/* ── SHELL ─────────────────────────────────────────────────────────────────── */
.app { display: grid; grid-template-columns: var(--rail-w) 1fr; min-height: 100vh; }

.rail {
  background: var(--rail);
  border-right: 1px solid var(--rail-border);
  padding: var(--sp-4) var(--sp-2) var(--sp-6);
  display: flex; flex-direction: column; gap: 2px;
}
.rail-brand {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3) var(--sp-5);
  color: var(--rail-text-active); text-decoration: none;
}
.rail-brand:hover { text-decoration: none; }
.rail-brand .logo { width: 148px; height: auto; }
.rail-brand small {
  padding-left: 2px; color: var(--rail-section);
  font: 600 var(--fs-micro)/1 var(--f-ui); letter-spacing: .22em; text-transform: uppercase;
}
.rail, .marke-flaeche { --logo-pfeil: var(--logo-pfeil-hell); --logo-schrift: var(--logo-schrift-hell); }
.logo-pfeil { fill: var(--logo-pfeil); }
.logo-schrift { fill: var(--logo-schrift); }
.logo, .logo-marke, .logo-wort { display: block; }

/* Die Gruppenüberschrift trennt, ohne selbst gelesen werden zu wollen: klein, weit
   gesperrt, gedeckt. Getrennt wird über den Abstand DAVOR und nicht über eine Linie —
   die wäre der sechste waagerechte Strich auf einer Seite, die schon genug davon hat. */
.rail-section {
  margin-top: var(--sp-3); padding: var(--sp-4) var(--sp-3) var(--sp-2);
  border-top: 1px solid color-mix(in srgb, var(--rail-text-active) 8%, transparent);
  font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .09em; text-transform: uppercase; color: var(--rail-section);
}
/* Die erste Gruppe steht unter der Marke, ohne Linie davor. */
.rail-brand + .rail-section { margin-top: 0; padding-top: var(--sp-1); border-top: 0; }
.rail-section:first-of-type { padding-top: var(--sp-1); }

/* ⛔ DER AKTIVE EINTRAG IST EINE PILLE, KEIN RANDSTRICH MEHR. Der 3-px-Streifen saß am
   äußersten linken Rand, außerhalb der Trefferfläche, und war auf einem Tablet in der
   Halle bei Schräglicht kaum zu sehen. Eine gefüllte Fläche ist aus zwei Metern
   erkennbar. Die Ikone daneben trägt keine eigene Farbe — sie erbt über currentColor
   und stimmt damit in Hell, Dunkel, aktiv und im Ausdruck ohne eine einzige Regel. */
.rail a {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: var(--control-h); padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-3);
  color: var(--rail-text); font-size: var(--fs-ui); font-weight: 500; text-decoration: none;
  transition: background-color .15s ease-in-out, color .15s ease-in-out;
}
.rail a > .ikone { flex: none; opacity: .7; transition: opacity .15s ease-in-out, color .15s ease-in-out; }
.rail a:hover { background: var(--rail-hover); color: var(--rail-text-active); text-decoration: none; }
.rail a:hover > .ikone { opacity: 1; }
/* 20.10.2026: Die Pille ist leiser geworden – eine zarte helle Fläche über der Schiene statt des Blocks, dazu ein Merkzeichen am linken Rand und die
   Ikone in hellem Markenblau: „hier bist du“. Die Fläche wird aus der Schriftfarbe gemischt (hell wie dunkel); die erste Zeile
   ist der Rückfall ohne `color-mix`. */
.rail a:hover { background: color-mix(in srgb, var(--rail-text-active) 7%, transparent); }
.rail a[aria-current="page"] {
  background: var(--rail-active); color: var(--rail-text-active); font-weight: 600;
}
.rail a[aria-current="page"] { background: color-mix(in srgb, var(--rail-text-active) 12%, transparent); }
.rail a[aria-current="page"]::before {
  content: ''; position: absolute; left: 0; top: 9px; bottom: 9px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--rail-akzent);
}
.rail a[aria-current="page"] > .ikone { opacity: 1; color: var(--rail-akzent); }

/* Die Schiene bleibt stehen. Fünfzehn Einträge scrollten sonst auf der Mitarbeiterliste
   oder im Änderungsprotokoll aus dem Bild, und der Weg zurück führte über das Ende der
   Seite. `height: 100vh` statt `align-self: start`: sonst hörte die Schienenfarbe bei
   kurzem Inhalt auf halber Höhe auf und darunter stünde der Seitengrund.

   ⛔ NICHT, WENN DER ANSICHT-BALKEN STEHT — derselbe Grund wie bei der Topbar: der Balken
   klebt selbst bei top:0, und die Schiene liefe unter ihm hindurch. */
.app:not(.mit-ansicht) .rail {
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}

.main { display: flex; flex-direction: column; min-width: 0; }

/* Die Leiste klebt oben: auf der Mitarbeiterliste und im Änderungsprotokoll stünde der
   Weg zurück sonst tausend Pixel weiter oben. */
.topbar {
  min-height: var(--h-topbar); flex: none;
  display: flex;
  border-bottom: 1px solid var(--border);
  background: var(--canvas);
  position: sticky; top: 0; z-index: 30;
}
/* Die Leiste läuft über die volle Breite, ihr INHALT steht in derselben Bahn wie die
   Seite darunter. Ohne das stünde auf einem 34-Zoll-Monitor der Abmeldeknopf einen
   halben Meter rechts neben der letzten Karte. */
.topbar-bahn {
  display: flex; align-items: center; gap: var(--sp-4);
  width: 100%; min-height: var(--h-topbar);
  max-width: calc(var(--bahn) + 2 * var(--sp-5));
  margin-inline: auto; padding: 0 var(--sp-5);
}
/* Auf schmalen Fenstern blendet die Querleiste die Wortmarke aus (.rail-brand). Ohne
   diese hier stünde die Anwendung auf dem Telefon ohne jeden Namen da. */
.topbar-marke { display: none; align-items: center; gap: var(--sp-2); }
.topbar-marke .logo-marke { height: 22px; width: auto; }
.topbar-marke .logo-wort { height: 18px; width: auto; }
.topbar-marke small {
  color: var(--text-muted); font: 600 var(--fs-micro)/1 var(--f-ui);
  letter-spacing: .18em; text-transform: uppercase;
}
/* ⛔ AUSSER, WENN DER ANSICHT-BALKEN STEHT. Der klebt selbst bei top:0 (z-index 50);
   zwei klebende Leisten an derselben Kante schöben sich übereinander, und ausgerechnet
   der Hinweis „du siehst fremde Daten" läge dann halb unter der Topbar. */
.app.mit-ansicht .topbar { position: static; }
.topbar .rechts { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }
.topbar .uhr { font: 500 var(--fs-dense)/1 var(--f-mono); color: var(--text-muted); }
/* ⛔ AUF DEM TELEFON HAT DIE UHR VORRANG VOR DEM SCHRIFTZUG. Marke, laufende Stempelleiste, Umschalter
   und Konto brauchten zusammen 480 px; auf 390 px rollte die ganze Seite waagerecht, und mit ihr der
   Stempelknopf halb aus dem Bild. Wo die Leiste oder die Testphasen-Kapsel steht, bleibt deshalb
   nur das Zeichen der Marke. Die Kapsel selbst weicht der Leiste: sie ist eine Erinnerung für die
   Verwaltung und steht auf der Startseite (ohne Leiste) weiter da — die Uhr ist eine Pflicht. */
@media (max-width: 520px) {
  .topbar-bahn:has(.leiste-uhr) .topbar-marke :is(.logo-wort, small),
  .topbar-bahn:has(.testphase-kapsel) .topbar-marke :is(.logo-wort, small) { display: none; }
  .topbar-bahn:has(.leiste-uhr) .testphase-kapsel { display: none; }
  .menue > summary { padding: 0 var(--sp-2); }
}

/* ⛔ DIE BAHN IST GEDECKELT UND ZENTRIERT. Ohne Deckel zog auto-fit auf einem breiten
   Monitor aus zwei Kennzahlen sechs Spalten und schob sie so weit auseinander, dass der
   Vergleich einen Kopfdreh kostete. Der Deckel sitzt an .inhalt und nicht an einem neuen
   Element: ein Wrapper hätte in neunundzwanzig Vorlagen ergänzt werden müssen — und die
   dreißigste hätte ihn beim nächsten Mal nicht. */
.inhalt {
  padding: var(--sp-6); flex: 1; min-width: 0;
  width: 100%;
  max-width: calc(var(--bahn) + 2 * var(--sp-6));
  margin-inline: auto;
}
.seitenkopf { margin-bottom: var(--sp-5); }
.seitenkopf h1 {
  margin: 0 0 var(--sp-1);
  font: 600 var(--fs-h1)/1.2 var(--f-ui);
  letter-spacing: -.015em;
}
.seitenkopf p { margin: 0; color: var(--text-muted); max-width: var(--measure); }

/* ── BAUSTEINE ─────────────────────────────────────────────────────────────── */
/* ⛔ REINWEISS AUF WARMEM GRUND, KANTE NUR ANGEDEUTET, SCHATTEN IN ZWEI LAGEN.
   Die Karte hebt sich über die FLÄCHE ab (--canvas gegen --sunken) und nicht über eine
   Linie — die Linie ist nur da, damit die Kante an der Stelle, wo der Schatten nichts
   mehr trägt, nicht ausfranst. Genau diese Reihenfolge unterscheidet eine ruhige
   SaaS-Oberfläche von einer Maske aus umrandeten Kästen. */
.karte {
  background: var(--canvas);
  border: 1px solid var(--karte-rand);
  border-radius: var(--r-4);
  box-shadow: var(--sh-karte);
  padding: var(--sp-5);
  margin-bottom: var(--sp-4);
}
.karte > h2 { margin: 0 0 var(--sp-3); font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.karte > p { max-width: var(--measure); }
.karte-hinweis { color: var(--text-muted); font-size: var(--fs-ui); }

.raster { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* ⛔ DIE BESCHRIFTUNG STEHT ÜBER DEM WERT — über order, nicht über einen Umbau der
   Vorlagen. Vierzehn Kennzahlen in fünf Dateien schreiben alle erst den Wert und dann
   das Wort; sie umzustellen hieße, vierzehn Stellen richtig zu erwischen. Und der
   Live-Timer schreibt in #istHeute.firstChild — die Zahl MUSS der erste Kindknoten
   bleiben, sonst tickt die Tagessumme in einen Leerraum (public/js/stempeluhr.js). */
.kennzahl { display: flex; flex-direction: column; gap: var(--sp-2); }
.kennzahl .beschriftung {
  order: -1;
  font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}
.kennzahl .wert {
  font: 600 var(--fs-kpi)/1.1 var(--f-ui);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.kennzahl .einheit { color: var(--text-faint); font-size: var(--fs-dense); font-weight: 400; }

/* ⛔ DIE SEKUNDÄRE KANTE IST --border UND NICHT MEHR --border-strong.
   --border-strong ist seit dem Kontrastumbau die Kante eines EINGABEFELDES und liegt bei
   3:1 gegen Weiß — an einem Knopf gezogen umrandete sie jede „Abbrechen"-Fläche so schwer,
   dass die Nebenhandlung genauso laut war wie die Hauptsache. Ein Knopf hat eine Füllung
   und eine Beschriftung; seine Kante schließt sie nur ab. */
.knopf {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--control-h); padding: 0 var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-2);
  background: var(--canvas); color: var(--text);
  font: 500 var(--fs-ui)/1 var(--f-ui); cursor: pointer;
  /* ⛔ DIE EIGENSCHAFTEN STEHEN EINZELN DA UND NICHT ALS `all`. Der Auftrag schrieb
     `transition: all .15s`; `all` animiert auch Breite, Höhe und Position — auf einem
     Lagertablet ruckelt danach jeder Knopf, der beim Zeigen umbricht, und der Übergang
     läuft im Hauptthread statt im Compositor. `transform` steht deshalb NAMENTLICH
     daneben: das Anheben unter dem Zeiger ist dasselbe Bild, nur ohne die Nebenwirkung. */
  transition: background-color .15s ease-in-out, border-color .15s ease-in-out,
              color .15s ease-in-out, box-shadow .15s ease-in-out,
              transform .15s ease-in-out;
}
/* Der Zeiger hebt den Knopf einen Hauch an — und zwar sichtbar: der Schatten allein
   war auf einem hellen Grund kaum zu bemerken. Ein Pixel ist genug; zwei sähen aus,
   als spränge die Zeile. */
.knopf:hover {
  background: var(--hover); border-color: var(--border-strong);
  box-shadow: var(--sh-karte); text-decoration: none;
  transform: translateY(-1px);
}
/* ⛔ DIE PRIMÄRAKTION IST DIE EINE AUSNAHME VON REGEL 5 (siehe Dateikopf). Ihr Schatten
   steht in ihrer EIGENEN Farbe und ist aus --primary gerechnet — nicht als fester
   rgba-Wert notiert, sonst läge er nach dem ersten Wechsel unter Einstellungen → Design
   in Blau unter einem grünen Knopf. */
.knopf-primaer {
  background: var(--primary); border-color: var(--primary); color: var(--auf-primary);
  box-shadow: var(--sh-primaer);
}
.knopf-primaer:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
/* Der Druck nimmt die Höhe wieder weg: die Rückmeldung „ich habe getroffen" entsteht
   daran, dass sich etwas SENKT, und nicht an einer zweiten Farbe. */
.knopf:active { box-shadow: none; transform: none; }
.knopf[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; transform: none; }
/* ⛔ WER BEWEGUNG ABGESTELLT HAT, BEKOMMT KEINE — auch nicht die neue Hebung. Der Zustand
   bleibt trotzdem sichtbar: Fläche, Kante und Schatten wechseln weiterhin, sie springen
   nur, statt zu blenden. */
@media (prefers-reduced-motion: reduce) {
  .knopf { transition: none; }
  .knopf:hover { transform: none; }
}

/* Ohne Rahmen und ohne Fläche — für Nebensächliches in der Topbar. Ein Umschalter für
   Hell und Dunkel, der aussieht wie „Abmelden", macht die eine Handlung, die man nicht
   versehentlich auslösen will, zur auffälligsten der Oberfläche. */
.knopf-leise { border-color: transparent; background: none; }
/* ⛔ DER LEISE KNOPF BLEIBT LEISE, AUCH UNTER DEM ZEIGER. `.knopf:hover` setzt seit dem
   SaaS-Politur-Umbau Kante und Schatten; beides muss hier zurückgenommen werden, sonst
   springt der Umschalter für Hell und Dunkel beim Zeigen zu einem vollen Knopf auf und
   ist damit wieder so auffällig wie „Abmelden" daneben. */
.knopf-leise:hover { background: var(--hover); border-color: transparent; box-shadow: none; transform: none; }
/* ⛔ UND ER HEBT SICH AUCH NICHT. Ein Umschalter für Hell und Dunkel, der beim Zeigen
   hochspringt, zieht genau den Blick auf sich, den die Regel oben ihm nehmen wollte. */
.knopf-leise { box-shadow: none; }
.knopf-rund { width: var(--control-h); padding: 0; }

/* Ikonen erben Farbe und Größe von ihrem Text. Die einzige Regel, die sie brauchen,
   ist die gegen das Schrumpfen im Flexkasten. */
.ikone { flex: none; }
.ikone-chevron { transition: transform .15s ease; }
@media (prefers-reduced-motion: reduce) { .ikone-chevron { transition: none; } }

.feld { display: block; margin-bottom: var(--sp-4); }
/* ⛔ OHNE DIESE ZEILE WIRKT [hidden] NICHT. `display: block` darüber ist eine
   Autorenregel und schlägt das UA-Stylesheet — antrag.js setzt `grundFeld.hidden`,
   um bei einer Krankmeldung nicht nach der Diagnose zu fragen, und das Feld blieb
   trotzdem stehen. Der Wert wurde geleert, die Einladung blieb: ein Freitextfeld
   neben „Krankheit" ist genau das Gesundheitsdatum, das hier nicht anfallen soll. */
.feld[hidden] { display: none; }
.feld > span { display: block; margin-bottom: var(--sp-1); font-size: var(--fs-dense); color: var(--text-muted); }
/* ⛔ EINE AUFZÄHLUNG VON TYPEN WAR DIE FALSCHE BAUFORM — UND SIE HAT EINEN TYP VERLOREN.
   Hier stand `[type="text"], [type="password"], [type="number"], select`, und dreihundert
   Zeilen weiter unten stand dieselbe Regel noch einmal für `[type="date"]` und `[type="email"]`.
   Zwei Fassungen derselben Sache — und `[type="time"]` stand in keiner von beiden. Die sechs
   Zeitfelder im Nachtrag-Formular (`_tagesdetail.html`, `meinezeiten.html`) trugen deshalb gar
   keine Kante: im Hellen ein Systemfeld zwischen gestalteten, im Dunkeln ein HELLES Kästchen auf
   dunkler Karte. Aufgefallen ist es beim Durchzählen der Typen, nicht beim Ansehen der Seite.

   ⛔ DESHALB JETZT ÜBER AUSSCHLÜSSE. Ein neuer Feldtyp ist damit von selbst gestaltet; die
   Aufzählung wäre wieder die Liste, in der der nächste fehlt. Ausgenommen sind genau die vier,
   die eine eigene Bauform haben: Haken und Auswahlknopf (`min-height` machte daraus einen
   Kasten), der Farbwähler (`.farbfeld`) und die Dateiauswahl (der Knopf darin gehört dem System).
   Die Mobilregel weiter unten arbeitet seit jeher so — sie war das Vorbild.
   `test/farbkontrast.test.js` hält die Bauform fest.

   ⛔ UND DIE AUSSCHLÜSSE STEHEN IN `:where()`. Das ist keine Schreibweise, sondern die Reparatur
   eines Fehlers, den die erste Fassung dieser Regel hatte: `:not()` ZÄHLT für die Spezifität. Vier
   davon machten aus `.feld input` (0,1,1) plötzlich (0,5,1) — und damit gewann die Grundregel gegen
   jede Verfeinerung darunter. Gemessen im Browser: `.feld input[inputmode="numeric"] { width: 12ch }`
   (0,2,1) verlor, und das Zahlenfeld für die PIN-Länge zog sich wieder über 227 statt 12 Zeichen.
   Aufgefallen ist es der Browser-Prüfung „keine Karte ist zerrissen", nicht dem Auge.

   `:where()` hat die Spezifität null. Die Regel steht damit wieder auf (0,1,1) — genau so tief, wie
   eine GRUNDregel stehen muss, damit alles Genauere sie überstimmt. */
.feld input:where(:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"])),
.feld select {
  width: 100%; min-height: var(--control-h); padding: 0 var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  background: var(--canvas); color: var(--text);
  font: 400 var(--fs-ui)/1 var(--f-ui);
}
.feld input:focus-visible, .feld select:focus-visible { border-color: var(--focus); }

/* Farbwähler: der native Picker daneben, der Hexwert daneben lesbar — man muss den
   Wert abtippen können, ohne ihn aus dem Picker zu erraten. */
.farbfeld { display: flex; align-items: center; gap: var(--sp-3); }
.farbfeld input[type="color"] {
  width: 44px; height: 38px; padding: 2px;
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  background: var(--canvas); cursor: pointer;
}
.farbfeld input[type="text"] { width: 10ch; font-family: var(--f-mono); }

/* ── AUFKLAPPER IN DER TOPBAR ───────────────────────────────────────────────
   ⛔ EIN <details>, KEIN JAVASCRIPT-MENÜ. Es öffnet, schließt und ist tastaturbedienbar,
   ohne dass eine Zeile Skript geladen sein muss — dieselbe Bauform, die im Haus schon
   viermal steht (Verlauf, Feinheiten, Terminal). Escape und der Klick nach außen sind
   Aufwertung im Skriptblock von layout.html, nicht Voraussetzung.

   ⛔ KEIN aria-expanded UND KEIN role="menu". Den Zustand meldet der Browser am
   <details> von selbst; ein zweites Attribut daneben liefe irgendwann auseinander. Und
   role="menu" verpflichtet zur Pfeiltastenbedienung, die man dann doch in JS bauen
   müsste — für eine Liste aus Links ist das die falsche Rolle. */
.menue { position: relative; }
.menue > summary {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: var(--control-h); padding: 0 var(--sp-3);
  border: 1px solid transparent; border-radius: var(--r-2);
  font: 500 var(--fs-ui)/1 var(--f-ui); color: var(--text);
  cursor: pointer; list-style: none;
}
.menue > summary::-webkit-details-marker { display: none; }
.menue > summary:hover { background: var(--hover); }
.menue[open] > summary { background: var(--hover); border-color: var(--border); }
.menue[open] > summary > .ikone-chevron { transform: rotate(180deg); }
.menue > summary > .ikone-chevron { color: var(--text-muted); }

.menue-blatt {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  min-width: 15rem; max-width: calc(100vw - 2 * var(--sp-4));
  max-height: min(70vh, 30rem); overflow-y: auto;
  padding: var(--sp-2);
  background: var(--canvas); border: 1px solid var(--border);
  border-radius: var(--r-4); box-shadow: var(--sh-hoch);
}
.menue-blatt a, .menue-blatt button {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; min-height: 40px; padding: 0 var(--sp-3);
  border: 0; border-radius: var(--r-2); background: none;
  color: var(--text); font: 400 var(--fs-ui)/1.3 var(--f-ui);
  text-align: left; text-decoration: none; cursor: pointer;
}
.menue-blatt a:hover, .menue-blatt button:hover { background: var(--hover); text-decoration: none; }
.menue-blatt form { margin: 0; }
.menue-titel {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .09em; text-transform: uppercase; color: var(--text-muted);
}
.menue-trenner { height: 1px; margin: var(--sp-2) calc(-1 * var(--sp-2)); background: var(--row-line); }
/* ⛔ DER SATZ ÜBER DAS PROTOKOLL STEHT IM AUFKLAPPER, NICHT IN EINER HILFESEITE.
   Wer weiß, dass sein Blick festgehalten wird, schaut aus einem Grund und nicht aus
   Neugier — und ein Aufklapper auf jeder Seite senkt genau diese Schwelle. Derselbe
   Hinweis steht an der Einstiegsstelle in mitarbeiter_detail.html. */
.menue-fuss {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
  color: var(--text-muted); font-size: var(--fs-micro); line-height: 1.45;
}
.menue-name { font-weight: 500; }
/* ⛔ DER WÄHLER IM ANSICHT-BALKEN STEHT AUF DER MARKENFARBE, nicht auf --canvas. Nur der
   Auslöser: das aufgeklappte Blatt bleibt eine normale Fläche, sonst stünde eine
   Namensliste in Weiß auf Blau und sähe aus wie Teil des Hinweises. */
.menue-auf-marke > summary { color: var(--auf-primary); border-color: currentColor; border-color: color-mix(in srgb, currentColor 55%, transparent); }
.menue-auf-marke > summary > .ikone-chevron { color: inherit; color: color-mix(in srgb, currentColor 80%, transparent); }
.menue-auf-marke > summary:hover,
.menue-auf-marke[open] > summary { background: none; background: color-mix(in srgb, currentColor 15%, transparent);
  border-color: currentColor; border-color: color-mix(in srgb, currentColor 55%, transparent); }

.hinweis {
  border: 1px solid var(--border); border-left-width: 3px;
  border-radius: var(--r-2); padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4); max-width: var(--measure);
  font-size: var(--fs-ui);
}
.hinweis-ok   { background: var(--badge-ok-bg);   border-color: var(--badge-ok-bd);   border-left-color: var(--good); }
.hinweis-warn { background: var(--badge-warn-bg); border-color: var(--badge-warn-bd); border-left-color: var(--warn); }
.hinweis-bad  { background: var(--badge-err-bg);  border-color: var(--badge-err-bd);  border-left-color: var(--bad); }
.hinweis-neu  { background: var(--badge-neu-bg);  border-color: var(--badge-neu-bd);  border-left-color: var(--text-faint); }

/* ⛔ TABELLARISCHE ZIFFERN GELTEN DER GANZEN TABELLE, NICHT NUR DER SPALTE `.zahl`.
   Sie hingen an `.zahl` und damit an einer Aufzählung: Datum, Uhrzeit „08:15" und die Kalenderzahl
   standen daneben in proportionalen Ziffern, und eine 1 ist dort schmaler als eine 8 — untereinander
   gelesen franst die Spalte aus. Eine Grundregel an der Tabelle deckt jede Spalte ab, auch die, die
   morgen dazukommt; `.zahl` behält den Rechtsbündigkeitsteil, für den es da ist.
   Auf Buchstaben wirkt `tabular-nums` nicht — es gibt also nichts auszunehmen. */
.gitter { width: 100%; border-collapse: collapse; font-size: var(--fs-ui); font-variant-numeric: tabular-nums; }
/* Der Kopf war 13 px und genauso schwer gewichtet wie die Zelle darunter (14 px) —
   zwei Ebenen, die sich nicht unterscheiden. Als gesperrtes Versalien-Etikett tritt er
   zurück und ordnet trotzdem. Dasselbe Muster wie .rail-section und .kennzahl. */
.gitter th {
  background: var(--table-head); text-align: left;
  font: 600 var(--fs-micro)/16px var(--f-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
  padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border);
}
.gitter td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--row-line); }
.gitter tr:hover td { background: var(--hover); }
/* Regel 3: Ziffern rechtsbündig — sonst tanzen die Kommastellen. Tabellarisch sind sie schon,
   das trägt die Grundregel an `.gitter` weiter oben. */
.gitter .zahl { text-align: right; }

.schritte { counter-reset: schritt; list-style: none; padding: 0; margin: 0; }
.schritte > li {
  counter-increment: schritt;
  position: relative; padding: 0 0 var(--sp-5) var(--sp-8);
  border-left: 1px solid var(--border); margin-left: 13px;
}
.schritte > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.schritte > li::before {
  content: counter(schritt);
  position: absolute; left: -14px; top: 0;
  width: 26px; height: 26px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--primary); color: var(--auf-primary);
  font: 600 var(--fs-dense)/1 var(--f-ui);
}
.schritte h3 { margin: 2px 0 var(--sp-1); font: 600 var(--fs-ui)/1.35 var(--f-ui); }
.schritte p { margin: 0 0 var(--sp-2); max-width: var(--measure); }
.schritte .merke {
  font-size: var(--fs-dense); color: var(--text-muted);
  border-left: 2px solid var(--border-strong); padding-left: var(--sp-3);
}

/* ── ANMELDESEITE ──────────────────────────────────────────────────────────── */
.anmelden {
  min-height: 100vh; display: grid; place-items: center;
  background: var(--sunken); padding: var(--sp-4);
}
.anmelden-karte {
  width: 100%; max-width: 380px;
  background: var(--canvas); border: 1px solid var(--border);
  border-radius: var(--r-4); box-shadow: var(--sh-pop);
  padding: var(--sp-8);
}
.anmelden-karte h1 { margin: 0 0 var(--sp-5); font: 600 var(--fs-title)/1.2 var(--f-ui); }
.anmelden-karte .knopf { width: 100%; }

/* ── STEMPELUHR ─────────────────────────────────────────────────────────────
   Die einzige Fläche, die jeder Mitarbeiter täglich benutzt. Drei Regeln:

   1 Der Zustand steht VOR den Knöpfen. Wer nicht weiß, ob er eingestempelt ist,
     drückt aufs Geratewohl — und das erzeugt genau die Doppelbuchungen, gegen
     die die Datenbank sich dann wehren muss.
   2 Nur mögliche Knöpfe werden gezeigt. Kein ausgegrautes „Pause beenden", das
     erst beim Drücken erklärt, warum es nicht geht.
   3 Genau eine Primäraktion: der nächste Schritt im Tagesablauf. „Gehen" steht
     immer daneben, aber nie als der auffälligere von beiden — sonst endet der
     Tag beim Griff nach der Pause.

   Die Zielgrößen sind fürs Lager gerechnet: 56 px hohe Knöpfe lassen sich mit
   Arbeitshandschuhen auf einem Tablet treffen. */
/* ⛔ DIE KARTE TRÄGT DIE AMPELFARBE, NICHT DER KNOPF. Der Auftrag wollte einen großen
   grünen „Kommen"-Knopf. Der wäre aus zwei Gründen falsch:

     1. Um 8:00 steht die Ampel in .stempel-lage auf grau („keine Buchung"), und zwölf
        Pixel daneben leuchtete Grün. Zwei Grün mit zwei Bedeutungen auf einer Karte —
        danach heißt Grün nichts mehr. Die Hausregel sagt es kürzer: die Ampel gehört dem
        Tagesstatus, sie ist keine Dekoration für Knöpfe.
     2. Bliebe der Knopf immer grün, passierte beim Einstempeln optisch NICHTS — und das
        ist der eine Moment, auf den es hier ankommt.

   Stattdessen springt die ganze Karte um: der Streifen an ihrer linken Kante ist grau,
   solange nichts läuft, grün beim Arbeiten, gelb in der Pause. Dieselbe Farbe, dieselbe
   Bedeutung, sehr viel größere Fläche — und der Knopf bleibt die eine Primäraktion in
   Markenblau. Grün wird verdient, nicht vergeben. */
.stempeluhr {
  display: grid; gap: var(--sp-5);
  position: relative; overflow: hidden;
  padding: var(--sp-6);
}
.stempeluhr::before {
  content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: 4px;
  background: var(--text-faint);
}
.stempeluhr[data-lage="arbeit"]::before { background: var(--good); }
.stempeluhr[data-lage="pause"]::before  { background: var(--warn); }

.stempel-lage { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
/* Die Ampel gehört dem Tagesstatus — hier, nicht an einem Knopf. */
.stempel-lage .ampel {
  position: relative;
  flex: none; width: 12px; height: 12px; border-radius: var(--r-full);
  background: var(--text-faint);
}
.stempel-lage[data-lage="arbeit"] .ampel { background: var(--good); }
.stempel-lage[data-lage="pause"]  .ampel { background: var(--warn); }
.stempel-lage .text { font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.stempel-lage .seit { color: var(--text-muted); font-size: var(--fs-ui); }

/* ⛔ DER PULS HOLT SEINE FARBE ÜBER `inherit`, NICHT AUS DEM KEYFRAME. Die Ampelfarben
   stehen in app_settings.design und werden von layout.html gesetzt; ein Farbwert im
   Keyframe wäre eine zweite Kopie, die beim nächsten Speichern unter Einstellungen →
   Design auseinanderliefe. Animiert werden nur transform und opacity — beides läuft im
   Compositor und kostet auf einem Lagertablet nichts. */
.stempel-lage .ampel::after {
  content: ''; position: absolute; inset: 0;
  border-radius: inherit; background: inherit;
  animation: ampel-puls 2.4s cubic-bezier(.22, .61, .36, 1) infinite;
}
.stempel-lage[data-lage="frei"] .ampel::after { display: none; }
@keyframes ampel-puls {
  0%       { transform: scale(1);   opacity: .5; }
  70%, 100% { transform: scale(2.8); opacity: 0; }
}
/* ⛔ display:none UND NICHT animation:none. Ohne Bewegung fröre der Ring mitten in der
   Skalierung bei opacity .5 ein — das sähe aus wie ein Anzeigefehler, nicht wie Ruhe. */
@media (prefers-reduced-motion: reduce) {
  .stempel-lage .ampel::after { display: none; }
}

.stempel-knoepfe { display: flex; gap: var(--sp-4); flex-wrap: wrap; }
.stempel-knoepfe form { margin: 0; }
.knopf-gross {
  min-height: 56px; padding: 0 var(--sp-6);
  font: 600 var(--fs-sect)/1 var(--f-ui); border-radius: var(--r-4);
}
.knopf-gross > .ikone { margin-right: var(--sp-1); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   DIE HANDLUNGSFARBE AM STEMPELKNOPF.

   ⛔ EINE REGEL, DREI FARBEN — die Farbe kommt über `--akt` aus dem `data-aktion` daneben und
   steht nicht dreimal in einer Regel. Käme morgen ein vierter Stempelvorgang, bräuchte er eine
   Zeile im Token-Block und keine vierte Knopfregel.

   ⛔ DIE RANGFOLGE TRÄGT WEITERHIN DIE FLÄCHE, NICHT DIE FARBE. Regel 1 des Hauses („höchstens
   eine Primäraktion je Seite") gilt unverändert: nur der ERSTE Knopf — die nächste Handlung im
   Tagesablauf — ist gefüllt und wirft seinen Schatten. Die anderen tragen dieselbe Farbe als
   Kante und Schrift auf der Kartenfläche. Wären alle drei gefüllt, stünden drei gleich laute
   Antworten nebeneinander, und der Tag endete beim Griff nach der Pause.

   ⛔ UND DER SCHATTEN IST AUS DER FARBE GERECHNET, wie bei `--sh-primaer`. Ein fester rgba-Wert
   wäre der blaue Schatten unter dem petrolfarbenen Knopf.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
[data-aktion="kommen"]     { --akt: var(--akt-kommen); --akt-hover: var(--akt-kommen-hover); }
[data-aktion="pause_start"],
[data-aktion="pause_ende"] { --akt: var(--akt-pause);  --akt-hover: var(--akt-pause-hover); }
[data-aktion="gehen"]      { --akt: var(--akt-gehen);  --akt-hover: var(--akt-gehen-hover); }

/* Der gefüllte Knopf: die eine Primäraktion. ⛔ Er steht NACH `.knopf-primaer` im Stylesheet und
   gewinnt damit gegen dessen Markenblau — beide Klassen stehen gemeinsam am ersten Knopf, damit
   `test/views.test.js` seine Kette `knopf knopf-gross knopf-primaer` weiterhin findet und die
   Regel „genau eine Primäraktion" an einer Klasse prüfbar bleibt. */
.knopf-akt[data-aktion] {
  background: var(--akt); border-color: var(--akt); color: var(--auf-akt);
  box-shadow: 0 2px 6px rgb(15 23 42 / .18);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--akt) 30%, transparent);
}
.knopf-akt[data-aktion]:hover { background: var(--akt-hover); border-color: var(--akt-hover); }

/* Die Nebenhandlungen: dieselbe Farbe, aber als Kante und Schrift. ⛔ KEIN SCHATTEN — die
   gezählte Ausnahme von Regel 5 gilt der Primäraktion und nur ihr. */
.knopf-akt[data-aktion]:not(.knopf-primaer) {
  background: var(--canvas); border-color: var(--akt); color: var(--akt);
  box-shadow: none;
}
.knopf-akt[data-aktion]:not(.knopf-primaer):hover {
  background: var(--hover); border-color: var(--akt); color: var(--akt);
}

/* Ein laufendes Segment hat kein Ende — der Gedankenstrich in der Endespalte sähe
   aus wie ein fehlender Wert. Stattdessen steht dort, was tatsächlich der Fall ist. */
.gitter .laeuft { color: var(--good); font-weight: 600; }
.gitter .geschaetzt { color: var(--warn); }

/* ── FORMULARE UND LISTEN ───────────────────────────────────────────────────
   Ein Muster für alle Antrags- und Stammdatenformulare. Drei Regeln:
   Zeitraum zuerst, Besonderheiten in ein <details>, genau eine Primäraktion. */
.antrag { max-width: var(--measure); }
.antrag .knopf + .knopf, .antrag .knopf + a.knopf { margin-left: var(--sp-3); }

/* Zwei Felder nebeneinander, solange Platz ist. Auf dem Handy untereinander — nicht
   zwei je 160 px, in denen kein Datum mehr lesbar steht. */
.feldpaar { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 var(--sp-4); }

/* ⛔ HIER STAND DIE ZWEITFASSUNG DER FELDREGEL — für `[type="date"]` und `[type="email"]`, mit
   denselben sechs Eigenschaften wie oben. Beide Typen sind jetzt vom Ausschluss-Selektor gedeckt.
   Übrig bleibt, was das Textfeld WIRKLICH anders macht: es ist mehrzeilig. */
.feld textarea {
  width: 100%; padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  background: var(--canvas); color: var(--text); font: 400 var(--fs-ui)/1.45 var(--f-ui);
  min-height: 72px; resize: vertical;
}
.feld-hinweis { display: block; margin-top: var(--sp-1); color: var(--text-muted); font-size: var(--fs-dense); }
.feld-schalter { display: grid; grid-template-columns: auto 1fr; gap: 0 var(--sp-2); align-items: baseline; }
.feld-schalter .feld-hinweis { grid-column: 2; }
.feld-schalter > span { margin: 0; font-size: var(--fs-ui); color: var(--text); }

/* Eingabe und Knopf in einer Zeile — für Kleinigkeiten wie „PIN setzen", die kein
   eigenes Formularfeld mit Beschriftung rechtfertigen. */
.reihenform { display: flex; gap: var(--sp-2); align-items: center; }
.reihenform input[type="text"],
.reihenform select {
  min-height: var(--control-h); padding: 0 var(--sp-3); min-width: 12ch;
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  background: var(--canvas); color: var(--text); font: 400 var(--fs-ui)/1 var(--f-ui);
}
.aktionsreihe { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-4); }
/* Die Summenzeile einer Tabelle steht abgesetzt unter den Menschen, nicht als einer von ihnen. */
.gitter tfoot td { border-top: 1px solid var(--border-strong); background: var(--table-head); font-weight: 600; }
.aktionsreihe form { margin: 0; }

.karte-kopf { display: flex; align-items: baseline; gap: var(--sp-4); margin-bottom: var(--sp-4); }
.karte-kopf > h2 { margin: 0; font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.karte-kopf > .knopf, .karte-kopf > a.knopf { margin-left: auto; }

/* ⛔ EINE TABELLE ROLLT IN IHREM EIGENEN KASTEN, NICHT IM BODY. Fünf Spalten auf 360 px
   schieben sonst die ganze Seite waagerecht — und mit ihr den Stempelknopf aus dem Bild. */
/* ⛔ `position: relative`, SONST ENTKOMMT, WAS ABSOLUT STEHT. Ein `.nur-vorlesen` im Tabellenkopf
   (position: absolute) bezog sich auf die Seite statt auf den Rollkasten, stand am rechten Ende
   der breiten Tabelle — und schob auf dem Telefon die ganze Seite um 218 px nach rechts. */
.gitter-rolle { overflow-x: auto; position: relative; }
/* ⛔ EIN ROLLKASTEN ZEIGT, DASS ER ROLLT. Die Auswertung war bei 1440 px breiter als ihre Karte, und
   nichts sagte, dass rechts die Spalte „Stand" wartete. Ein Schatten an der Kante, hinter der noch
   etwas liegt — er verschwindet, sobald dort nichts mehr ist (`local` deckt ihn mit der Fläche zu).
   Nur in einer Karte: die Deckfläche trägt `--canvas`, und auf einem anderen Grund stünde sie als
   Streifen da. Im Druck rollt nichts, und Hintergründe druckt der Browser ohnehin nicht.
   ⛔ DIESELBE REGEL FÜR DIE SÄULEN (Round Table, 09.10.2026): auf dem Telefon rollte der Monat dort
   ebenso, und nichts sagte, dass rechts die zweite Monatshälfte lag. */
.karte .gitter-rolle,
.karte .saeulen-rolle {
  background:
    linear-gradient(to right, var(--canvas) 40%, transparent) left center / 28px 100% no-repeat local,
    linear-gradient(to left, var(--canvas) 40%, transparent) right center / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) left center / 10px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) right center / 10px 100% no-repeat scroll;
}
.gitter td > a { font-weight: 500; }
.zeile-zusatz { display: block; color: var(--text-muted); font-size: var(--fs-dense); }
/* Farbe ist Bedeutung: rot steht hier für „hier fehlt etwas, das gebraucht wird". */
.fehlt { color: var(--bad); font-weight: 500; }

.fehlerliste { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); }
.fehlerliste li + li { margin-top: var(--sp-1); }

/* Der fertige Text ans Lohnbuero. ⛔ AUF --sunken UND NICHT AUF --canvas: er liegt IN einer
   Karte und muss sich von ihr abheben — dieselbe Rollenverteilung wie ueberall, nur eine
   Ebene tiefer. Monospace, weil Berater- und Lohnartnummern darin stehen und Ziffern in einer
   Proportionalschrift beim Abtippen verrutschen. */
.brieftext {
  margin: var(--sp-3) 0 0;
  padding: var(--sp-4);
  background: var(--sunken);
  border: 1px solid var(--border);
  border-radius: var(--r-2);
  font: 400 var(--fs-dense)/1.55 var(--f-mono);
  color: var(--text);
  /* Der Text wird zum Weiterleiten markiert — er darf umbrechen statt seitwaerts zu laufen. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 26rem; overflow-y: auto;
}

/* ⛔ DER ZUGANGSCODE ERSCHEINT GENAU EINMAL. Er darf deshalb nicht aussehen wie ein Hinweis,
   den man wegliest — groß, einzeilig, in Monospace, damit er sich abtippen und vorlesen lässt. */
.code-karte { border-left: 3px solid var(--primary); }
.code-karte .code {
  font: 600 var(--fs-kpi)/1.2 var(--f-mono);
  letter-spacing: .08em; margin: var(--sp-3) 0;
  -webkit-user-select: all; user-select: all;   /* Safari braucht den Praefix — und iOS ist Zielgeraet. */
}

/* ⛔ DAS FINGERMASS HÄNGT AM ZEIGEGERÄT UND NICHT NUR AN DER BREITE.
   Das Kiosk-Tablet im Lager steht quer und ist damit breiter als 780 px — nach der Breitenregel
   allein bekäme es 38-Pixel-Knöpfe, und genau dort wird mit Arbeitshandschuhen getippt.
   `pointer: coarse` fragt danach, WOMIT gezeigt wird, und nicht danach, wie breit das Fenster ist.
   Beide Regeln setzen denselben Wert; welche zuerst greift, ist damit gleichgültig. */
@media (pointer: coarse) {
  :root { --control-h: 48px; }
}

/* ── SCHMALE FENSTER ───────────────────────────────────────────────────────── */
/* Die Schiene wird zur waagerechten Leiste. Kein Overlay mit Umschalter: für M0 ist
   das eine Abhängigkeit von JavaScript, die die Stempeluhr sich nicht leisten soll. */
@media (max-width: 780px) {
  /* 38 px liegen unter dem Fingermass. ⛔ 48 px UND NICHT MEHR 44: 44 war das Minimum aus den
     Apple-Richtlinien; 48 kommt aus Material Design. ⛔ NICHT AUS DEN WCAG — hier stand einmal
     „2.5.8, Target Size", und das ist falsch herum zitiert: jene Regel verlangt 24 px (AA, WCAG
     2.2). Die Zahl hier ist also strenger als die Norm und keine Ableitung daraus. Der Grund steht
     daneben und trägt allein: im Lager wird mit Arbeitshandschuhen getippt, und vier Pixel sind an
     einem Pausenknopf der Unterschied zwischen Treffen und Danebentippen. */
  :root { --control-h: 48px; }

  .app { grid-template-columns: 1fr; }
  /* ⛔ AUF DEM TELEFON GIBT ES KEINE SCHIENE, SONDERN DIE LEISTE UNTEN (`.unten`). Die Schiene
     wurde hier bis zum 29.09.2026 zur waagerecht rollenden Querleiste — bei der Verwaltung mit
     achtzehn Einträgen, von denen drei ins Bild passten. */
  .rail { display: none; }
  .inhalt { padding: var(--sp-4); padding-bottom: calc(var(--unten-h) + var(--sp-6) + env(safe-area-inset-bottom)); }
  .topbar-bahn { padding: 0 var(--sp-3); gap: var(--sp-2); }
  .topbar-marke { display: flex; }
  /* Der Name weicht der Ikone: auf 360 px sind „Ansicht wechseln" und ein voller Name
     eine Zeile zu viel, und der Aufklapper öffnet trotzdem dasselbe.
     ⛔ NICHT display:none. Das nähme dem Aufklapper seinen zugänglichen Namen — übrig
     bliebe ein Knopf aus zwei Bildern, den eine Sprachausgabe nur als „Details" ansagen
     kann. Der Text bleibt im Dokument und verlässt nur die Fläche. */
  /* ⛔ NICHT DER AVATAR — er ist selbst ein <span>, und bis zum 29.09.2026 verschwand er hier mit:
     auf dem Telefon stand oben rechts nur ein Pfeil ohne Kopf. */
  .menue > summary > span:not(.avatar) {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  /* ⛔ EINGABEFELDER BRAUCHEN 16 px, SONST ZOOMT iOS BEI JEDEM FOKUS HINEIN — und
     danach nicht wieder heraus. Wer eine Zeit nachträgt, zoomt sonst bei jedem Feld
     von Hand zurück.
     ⛔ DIE HÖHE STEHT HIER NICHT MEHR. Sie kommt aus `--control-h`, und das Token steht in
     diesem Block ohnehin auf 48 — ein 44er-Literal daneben hätte es überstimmt, und genau so
     war der runde Umschalter in der Topbar 48 breit und 44 hoch. Hier bleibt, was das Token
     NICHT trägt: die Schriftgröße.
     ⛔ Haken und Auswahlknöpfe bleiben außen vor: eine Mindesthöhe gilt auch für sie, und ein
     48 px hohes Kästchen ist kein besser treffbarer Haken, sondern ein Kasten. */
  .feld input:not([type="checkbox"]):not([type="radio"]),
  .feld select, .feld textarea, .reihenform input[type="text"] {
    font-size: var(--fs-feld);
  }
  .feld textarea { min-height: calc(var(--control-h) * 2); }

  /* Die Trefferfläche eines Aufklappers war die Textzeile — auf „Heutige Buchungen"
     der schwerste Treffer der Seite. */
  .verlauf > summary, .feinheit > summary { padding: var(--sp-3) 0; }

  /* Auf dem Telefon steht jeder Stempelknopf über die ganze Breite. Zwei Knöpfe
     nebeneinander sind auf 360 px so schmal, dass der Daumen zwischen sie gerät —
     und ein Fehlgriff kostet hier eine Korrektur mit Begründungspflicht. */
  .stempel-knoepfe { flex-direction: column; align-items: stretch; gap: var(--sp-4); }
  .stempel-knoepfe .knopf-gross { width: 100%; padding: 0 var(--sp-4); min-height: 64px; }
}

/* Was auf dem Bildschirm Orientierung gibt, ist auf Papier Ballast. */
@media print {
  /* ⛔ DIE TOKENS MÜSSEN ZURÜCKGESETZT WERDEN. Ohne diesen Block druckt die Seite im
     Dunkel-Theme hellgrauen Text auf weißem Papier — unlesbar, und es fällt erst am
     Drucker auf. Ein Stundenzettel wird unterschrieben; er muss immer gleich aussehen. */
  :root, :root[data-theme="dark"] {
    --canvas: #fff; --sunken: #fff; --table-head: #f0f0f0; --hover: #fff;
    --border: #999; --border-strong: #666; --row-line: #ccc;
    /* ⛔ AUCH DIE KARTENKANTE. Auf Papier trägt die Fläche nichts — --canvas und --sunken
       sind beide weiß —, und eine Kante bei 6 % Deckkraft druckt als gar nichts. Der
       Druckblock unten nimmt der Karte den Rahmen ohnehin ganz; das hier ist die Zusage
       für alles andere, was das Token trägt. */
    --karte-rand: #999;
    --text: #000; --text-muted: #333; --text-faint: #666;
    --primary: #000; --good: #000; --warn: #000; --bad: #000;
    /* Auf schwarzer Flaeche (die Schrittnummer druckt als gefuellter Kreis) bleibt nur Weiss. */
    --auf-primary: #fff;
    /* ⛔ AUCH DIE SCHATTEN. Ein box-shadow druckt als grauer Rand um jede Karte —
       auf einem Stundenzettel, der unterschrieben wird, sieht das aus wie ein Kasten,
       den jemand gezogen hat. */
    --sh-karte: none; --sh-hoch: none; --sh-pop: none; --sh-modal: none;
    /* ⛔ AUCH DER NEUE PRIMÄRSCHATTEN. Er steht in der Markenfarbe und druckt sonst als
       grauer Rahmen um genau den Knopf, den der Druckblock zwei Zeilen weiter ohnehin
       ausblendet — sichtbar bliebe der Schatten eines Elements, das nicht da ist. */
    --sh-primaer: none;
    /* ⛔ UND DIE ZÄHLKAPSEL. Sie liegt in der Schiene, die im Druck verschwindet — aber
       `--zahl-*` hängt inzwischen auch an Kapseln im Inhalt. Auf Papier trägt eine Zahl
       ihre Bedeutung im Text, nicht in einer Tönung. */
    --zahl-bg: #fff; --zahl-bd: #999; --zahl-fg: #000;
    color-scheme: light;
  }
  @page { size: A4 portrait; margin: 16mm 14mm; }
  .rail, .topbar, .stempel-knoepfe, .aktionsreihe, .knopf, .hinweis,
  .seitenkarten, .menue { display: none; }
  /* Ikonen sind Orientierung auf dem Bildschirm und Striche auf dem Papier. */
  .ikone { display: none; }
  .stempeluhr::before, .stempel-lage .ampel::after { display: none; }
  .app { display: block; }
  .inhalt { padding: 0; max-width: none; }
  .karte { border: none; padding: 0; margin: 0 0 var(--sp-4); box-shadow: none; }
  .gitter-rolle { overflow: visible; }
  /* Über einen Seitenumbruch hinweg wiederholt sich der Tabellenkopf — sonst steht auf
     Seite zwei eine Zahlenkolonne ohne Beschriftung. */
  .gitter thead { display: table-header-group; }
  .gitter tr { break-inside: avoid; }
  .gitter tr:hover td { background: none; }
  a[href]::after { content: none; }
}

/* Die Zahl an einem Schienen-Eintrag — eine Kapsel statt einer nackten Ziffer.
   ⛔ EINE MENGE IST KEINE WARNUNG („7 Anträge" sagt „hier liegt etwas", ohne etwas zu behaupten):
   ruhiger Markenton --zahl-*. Bis zum 08.10.2026 zählten offene Klärfälle mit und färbten die Zahl
   über `data-art="verstoss"` in den Warnton; seitdem zählt „Eingang" nur Entscheidungen
   (`src/navigation.js`), und die Zahl hat einen Ton. */
.rail-zahl {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; padding: 1px var(--sp-2);
  border-radius: var(--r-full);
  border: 1px solid var(--zahl-bd); background: var(--zahl-bg); color: var(--zahl-fg);
  font-variant-numeric: tabular-nums; font-size: var(--fs-micro); font-weight: 600;
  line-height: 1.5;
}

/* „Als Gehen werten" und „Pause eintragen" (`_tagesdetail.html`): unter der Tabelle, über die ganze Breite —
   in der Zelle lag der Aufklapper auf dem Telefon außerhalb des Bildes (Round Table, 08.10.2026). */
.als-gehen, .pause-eintragen { margin-top: var(--sp-3); }
.als-gehen > summary, .pause-eintragen > summary { list-style: none; display: inline-flex; }
.als-gehen > summary::-webkit-details-marker, .pause-eintragen > summary::-webkit-details-marker { display: none; }
.als-gehen[open] > summary, .pause-eintragen[open] > summary { margin-bottom: var(--sp-3); }

/* Die Rechnung unter einem Antragsformular: was kostet dieser Zeitraum? */
.antrag-rechnung {
  border-top: 1px solid var(--row-line); padding-top: var(--sp-3); margin: var(--sp-4) 0;
  font-size: var(--fs-ui); font-variant-numeric: tabular-nums; color: var(--text-muted);
}
.feinheit > summary {
  cursor: pointer; padding: var(--sp-2) 0;
  font-size: var(--fs-dense); color: var(--text-muted);
}
/* ⛔ EIN (i) STEHT NEBEN SEINEM WORT, NIE STATT DESSEN (views/_ikonen.html). Diese Regel gibt ihm
   nur seinen Abstand — sie macht das Wort nicht entbehrlich. Ein Aufklapper, dessen Beschriftung
   allein ein Icon wäre, ist für Tastatur und Sprachausgabe ein leerer Knopf; hinter diesen
   Aufklappern liegen Rechtsgrundlagen, und das wiegt hier schwerer als anderswo.
   `vertical-align` statt `inline-flex` am `summary`: die vorhandenen Aufklapper im Haus tragen
   reinen Text, und ein Flexkasten unter ihnen verschöbe deren Marker-Ausrichtung ohne Grund. */
.feinheit > summary > .ikone { margin-right: var(--sp-2); vertical-align: -2px; }

/* ── TEAM-RADAR ─────────────────────────────────────────────────────────────
   ⛔ FORM STATT FARBE. Die Ampel gehört dem eigenen Tagesstatus und dem
   Urlaubskonto; Anwesenheit ist kein Zustand von gut nach schlecht, und ein
   rotes Zeichen an einem Kollegen liest sich wie ein Vorwurf. Unterschieden
   wird über gefüllt / halb / offen — und die Gruppenüberschrift sagt dasselbe
   noch einmal in Worten, für alle, die die Form nicht unterscheiden. */
.radar-summe { font-size: var(--fs-dense); color: var(--text-muted); margin: 0 0 var(--sp-4); }
.radar-gruppe { margin-bottom: var(--sp-4); }
.radar-gruppe > h3 {
  margin: 0 0 var(--sp-2); font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-muted);
}
.radar-liste { display: flex; flex-wrap: wrap; gap: var(--sp-2); list-style: none; padding: 0; margin: 0; }
.person {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3); min-height: 32px;
  border: 1px solid var(--border); border-radius: var(--r-full);
  font-size: var(--fs-dense);
}
.person small { color: var(--text-muted); }
.person-mal { flex: none; width: 10px; height: 10px; border: 1.5px solid var(--text-muted); }
.person[data-lage="arbeit"] .person-mal { background: var(--text); border-color: var(--text); }
.person[data-lage="abwesend"] { color: var(--text-muted); border-style: dashed; }
.person[data-lage="abwesend"] .person-mal {
  background: linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
}

/* ── TEAM-KALENDER ──────────────────────────────────────────────────────────
   Zeilen sind Menschen, Spalten sind Tage. Kein 7×5-Raster: ein Balken liegt in
   einer Tabellenzeile und bricht nie um — im Wochenraster müsste jede mehrtägige
   Abwesenheit an jeder Wochengrenze zerlegt werden, und genau das ist ohne
   JavaScript die eigentliche Schwierigkeit. */
/* ⛔ DIE TABELLE NIMMT DIE GANZE KARTE (seit 08.10.2026). Bis dahin stand sie mit festen 22 px je Tag
   links in der Karte, und rechts daneben blieb ein Drittel leer — auf einem Arbeitsplatzmonitor ein
   zusammengequetschtes Raster neben weißer Fläche. Jetzt teilt sich die Breite auf die Tage auf:
   die Namensspalte nimmt, was ihr Inhalt braucht (`width: 1%` mit `nowrap`), jeder Tag mindestens
   24 px, auf einem breiten Fenster 28 px. Reicht die Breite nicht, rollt das Raster in seiner Karte —
   nie die Seite.
   ⛔ 28 PX ERST AB 1440 PX FENSTERBREITE. Mit 28 px überall brauchte der Monat 1009 px und die Karte
   bot bei 1280 px 946 — der 30. und 31. standen hinter dem Rollen (Prüfung als Mitarbeiter,
   08.10.2026). Mit 22 px passte es, mit 24 px passt es; ab 1440 px trägt die Bahn auch 28. */
.kalender-breit { overflow-x: auto; }
.kalender { border-collapse: collapse; font-size: var(--fs-micro); }
.kalender-breit .kalender { width: 100%; }
.kalender th, .kalender td { border: 1px solid var(--row-line); padding: 0; }
.kalender thead th { padding: var(--sp-1) 0; min-width: 24px; text-align: center; background: var(--table-head); }
@media (min-width: 1440px) { .kalender thead th { min-width: 28px; } }
.kalender th.kalender-name { width: 1%; }
.kalender-kurz { display: block; color: var(--text-muted); }
.kalender-zahl { display: block; font-variant-numeric: tabular-nums; }
/* ⛔ `z-index`, WEIL DIE ZELLEN POSITIONIERT SIND (`.kalender-zelle`, für die Klickfläche). Ohne ihn malt
   der Browser jede Zelle nach der festen Namensspalte — beim waagerechten Rollen lagen Flächen und
   Balken über den Namen, auch im Teamkalender jedes Mitarbeiters auf dem Telefon. */
.kalender-name {
  padding: var(--sp-1) var(--sp-3) !important; text-align: left; white-space: nowrap;
  font: 500 var(--fs-dense)/1.4 var(--f-ui); background: var(--canvas); position: sticky; left: 0;
  z-index: 1;
}
.kalender-zelle { height: 30px; position: relative; }
/* ⛔ WOCHENENDE UND FEIERTAG SIND ZWEI TÖNE, BEIDE NEUTRAL. Vorher trug der Feiertag `--hover` —
   denselben Wert wie der Tabellenkopf — und das Wochenende `--sunken`, das sich vom Weiß der Karte
   kaum abhob. Keine Farbe — ein freier Tag ist keine Kategorie, er ist der Hintergrund, vor dem die
   Kategorien stehen.
   ⛔ UND SIE SIND AUS DER FELDKANTE GEMISCHT, NICHT AUS DEM TABELLENKOPF. Mit `--table-head` lag das
   Wochenende bei 1,10:1 gegen die Karte (nachgerechnet am 08.10.2026) — eine Spalte, die man suchen
   musste. Gemischt aus `--border-strong` folgen beide Töne dem Theme und einer geänderten Palette;
   der Feiertag bleibt die tiefere Stufe. Den Namen eines Feiertags sagt die Zeile unter dem Raster. */
.kalender .wochenende { background: var(--border); }
.kalender .feiertag { background: color-mix(in srgb, var(--border-strong) 40%, var(--canvas)); }
/* Im Kopf trägt jede Spalte schon `--table-head` — das Wochenende setzt sich dort eine Stufe tiefer ab,
   sonst verschwände es genau in der Zeile, in der man die Wochentage liest. */
.kalender thead th.wochenende { background: color-mix(in srgb, var(--border-strong) 30%, var(--table-head)); }

/* Die Klickfläche einer freien Zelle (Urlaubsübersicht, nur mit `absence_approve`). Sie füllt die
   Zelle und zeigt erst unter dem Zeiger, dass sie etwas tut — ein Plus auf jeder der dreihundert
   freien Zellen wäre ein Raster aus Knöpfen statt eines Kalenders. */
.kalender-buchen { position: absolute; inset: 0; display: block; }
.kalender-buchen:hover, .kalender-buchen:focus-visible {
  background: var(--selected); outline: 1px solid var(--primary); outline-offset: -1px;
}
.kalender-buchen:hover::after, .kalender-buchen:focus-visible::after {
  content: "+"; position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--primary); font: 600 var(--fs-ui)/1 var(--f-ui);
}
.kalender .heute { outline: 2px solid var(--primary); outline-offset: -2px; }

.balken { display: block; height: 18px; margin: 5px 0; background: var(--selected); border: 1px solid var(--border-strong); }
/* ⛔ DIE INNEREN KANTEN ÜBER DIE BREITE, NICHT ÜBER `none`. `border-left: none` setzt den STIL, und
   `.balken.beantragt { border-style: dashed }` steht später und setzt ihn für alle vier Seiten zurück:
   ein beantragter Urlaub zerfiel in einzelne Tage mit einem Strich dazwischen. Eine Breite von null
   bleibt null, welcher Stil auch immer dazukommt. */
.balken.rand-start { border-radius: var(--r-full) 0 0 var(--r-full); border-right-width: 0; margin-left: 3px; }
.balken.rand-ende { border-radius: 0 var(--r-full) var(--r-full) 0; border-left-width: 0; margin-right: 3px; }
.balken.rand-mitte { border-radius: 0; border-left-width: 0; border-right-width: 0; }
.balken.rand-einzeln { border-radius: var(--r-full); margin: 5px 3px; }
/* Beantragt wird schraffiert, nicht eingefärbt — Farbe ist Bedeutung, und „noch nicht
   entschieden" ist keine Ampelstufe. */
.balken.beantragt {
  background: repeating-linear-gradient(45deg,
    var(--selected) 0 4px, var(--canvas) 4px 8px);
  border-style: dashed;
}

.kalender-schmal { display: none; }
.kalender-person { padding: var(--sp-3) 0; border-bottom: 1px solid var(--row-line); }
.kalender-person ul { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); font-size: var(--fs-ui); }
.kalender-person li.beantragt { color: var(--text-muted); font-style: italic; }

@media (max-width: 780px) {
  /* Ein Raster mit 31 Spalten ist auf 360 px unlesbar. Umgeschaltet wird über CSS
     und nicht über JavaScript: beide Ansichten stehen im selben DOM, damit es keine
     zweite Wahrheit gibt. */
  .kalender-breit { display: none; }
  .kalender-schmal { display: block; }
}

/* ── ÄNDERUNGSPROTOKOLL ─────────────────────────────────────────────────────
   Ein Eintrag je Änderung, nicht eine Tabellenzeile: Vorher und Nachher stehen
   nebeneinander, und der Grund gehört sichtbar dazu — ohne ihn ist ein
   Protokolleintrag im Streitfall nur die Feststellung, DASS etwas geschah. */
.protokoll-eintrag { padding: var(--sp-4) 0; border-bottom: 1px solid var(--row-line); }
.protokoll-eintrag:last-child { border-bottom: none; }
.protokoll-kopf { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: baseline; font-size: var(--fs-ui); }
.protokoll-wann { margin-left: auto; color: var(--text-muted); font-size: var(--fs-dense); }
.protokoll-grund {
  margin: var(--sp-2) 0; padding-left: var(--sp-3);
  border-left: 3px solid var(--border-strong);
  color: var(--text-muted); font-size: var(--fs-ui);
}
.protokoll-diff { margin-top: var(--sp-2); font-size: var(--fs-dense); }
/* ⛔ EIN LANGER WERT BRICHT UM, STATT DIE SEITE ZU VERBREITERN (08.10.2026): eine E-Mail-Adresse ohne
   Trennstelle machte das Protokoll auf dem Telefon 535 px breit (CLAUDE.md, „Auf dem Telefon rollt die
   Seite nie waagerecht"). `anywhere` zählt auch für die Mindestbreite der Spalte, `break-word` nicht. */
.protokoll-diff td { overflow-wrap: anywhere; }
/* Farbe ist auch hier Bedeutung: der alte Wert ist durchgestrichen, weil er nicht
   mehr gilt — nicht rot, weil er falsch gewesen wäre. */
.protokoll-vorher { color: var(--text-muted); text-decoration: line-through; }
.protokoll-nachher { font-weight: 500; }

/* ── NACHWEISE (ATTESTE) ────────────────────────────────────────────────────
   Die Löschfrist steht neben dem Link und nicht in einer Fußnote: sie ist der
   Grund, warum der Nachweis überhaupt befristet hier liegt. */
.nachweis-zeile {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
  padding: var(--sp-1) 0; font-size: var(--fs-dense);
}
.nachweis-frist { color: var(--text-muted); }

/* ── FEIERTAG, DER NICHT FÜR ALLE GILT ──────────────────────────────────────
   Seit zwei Bundesländern kann ein Tag in einer Region frei und in der anderen
   ein Arbeitstag sein. Der Kopf trägt dann das Kürzel als sichtbaren Text —
   ⛔ nicht als `title`: auf einem Touchgerät gibt es keinen Tooltip, und die
   Teilgeltung wäre ausgerechnet dort unsichtbar, wo der Kalender gelesen wird.
   Die Zellen bleiben unschattiert, weil der Tag eben nicht für alle frei ist. */
.kalender th.feiertag-teils { border-bottom: 2px solid var(--warn); }
.kalender-land {
  display: block;
  font-size: var(--fs-micro);
  color: var(--warn);
  font-weight: 600;
  letter-spacing: .02em;
}

/* ── DIE ENGPASS-ZEILE EINES BEREICHS ───────────────────────────────────────
   Wie viele Kräfte sind an diesem Tag verfügbar? Sie steht als `<tfoot>` unter
   dem Raster — eine Summe über die Spalte, und unten gelesen ist sie das
   Ergebnis statt einer Vorgabe.

   ⛔ DIE ZAHL STEHT SICHTBAR IN DER ZELLE. Eine bloß getönte Spalte wäre eine
   Ratefrage; getönt ist nur, was unter der Grenze liegt.

   ⛔ `--badge-warn-*` UND NICHT DIE AMPEL. Ein Engpass ist eine Planungsaufgabe
   und keine Bewertung eines Menschen — dieselbe Entscheidung wie bei den
   Kategorieflächen darüber. „droht" ist dieselbe Aussage eine Stufe leiser:
   die Grenze fällt erst, wenn die offenen Anträge genehmigt werden. Deshalb
   nur eine Kante und keine Fläche — sonst sähen beide gleich dringend aus. */
.kalender-besetzung th, .kalender-besetzung td { border-top: 2px solid var(--border-strong); }
.kalender-besetzung-zelle {
  text-align: center;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.kalender-besetzung-zelle[data-lage="engpass"] {
  background: var(--badge-warn-bg);
  color: var(--badge-warn-fg);
  font-weight: 700;
}
/* ⛔ „DROHT" IST EINE GESTRICHELTE LINIE IN DER SCHRIFTFARBE DES WARNTONS — nicht seine Kante. Die
   Kante lag bei 1,25:1 gegen die Karte und war nur zu sehen, wenn man wusste, wo. Gestrichelt wie
   „beantragt": dieselbe Aussage („wenn genehmigt wird"), dasselbe Muster. Ohne Kurzform
   `background`, damit der Ton eines Wochenendes darunter stehen bleibt. */
.kalender-besetzung-zelle[data-lage="droht"] {
  background-image: repeating-linear-gradient(90deg, var(--badge-warn-fg) 0 4px, transparent 4px 7px);
  background-size: 100% 3px; background-position: left bottom; background-repeat: no-repeat;
  color: var(--text);
}
.legende-engpass { background: var(--badge-warn-bg); border: 1px solid var(--badge-warn-fg); }
.legende-droht {
  background: var(--canvas) repeating-linear-gradient(90deg, var(--badge-warn-fg) 0 4px, transparent 4px 7px)
    left bottom / 100% 3px no-repeat;
  border: 1px solid var(--border);
}

/* ── DER MINIJOB-RECHNER ────────────────────────────────────────────────────
   Ein Kasten IN der Karte, abgesetzt auf dem Grund: er gehört zum Formular
   darunter, speichert aber nichts. `--sunken` ist der Grund, `--canvas` liegt
   darauf (CLAUDE.md) — ein Rechner, der wie eine zweite Karte aussähe, wäre
   eine zweite Handlung auf einer Seite, die genau eine hat.

   ⛔ `[hidden]` MUSS WIRKEN. Ohne Skript steht der Kasten nicht da; ein
   `display: grid` ohne die Ausnahme überstimmte das Attribut, und der Rechner
   wäre ausgerechnet dort sichtbar, wo er nicht rechnen kann. */
.minijob {
  margin-bottom: var(--sp-5);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-2);
  background: var(--sunken);
}
.minijob[hidden] { display: none; }
.minijob h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-sect); }

/* Zwei Ergebnisse nebeneinander. ⛔ Tabellenziffern, damit zwei Werte
   untereinander vergleichbar bleiben — dieselbe Regel wie in jeder Zahlspalte. */
.minijob-werte {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-5);
  margin: var(--sp-4) 0 var(--sp-3);
}
.minijob-werte dt { font-size: var(--fs-micro); color: var(--text-muted); }
.minijob-werte dd {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Der Saldo gegen das Budget. ⛔ „drüber" trägt den Badge-Warnton und nicht die
   Ampel: ob eine Wochenstundenzahl zu hoch ist, entscheidet ein Vertrag und
   nicht dieses Formular — gesperrt wird hier nichts. „drunter" bleibt ruhig:
   weniger als das Budget ist kein Mangel. */
.minijob-stand { margin: 0 0 var(--sp-3); font-size: var(--fs-ui); color: var(--text-muted); }
.minijob-stand[data-lage="drueber"] { color: var(--badge-warn-fg); font-weight: 600; }
.minijob-stand[data-lage="passt"] { color: var(--text); }

/* ── DIE MINIJOB-KARTE UNTER EINSTELLUNGEN → BETRIEB & ARBEITSZEIT ───────────
   Grenze und Faktor als Zahlen oben, die Minijobber darunter, der Rechner und
   das Formular am Fuß. ⛔ DIE ZAHLEN TRAGEN KEINE FARBE: eine Grenze ist kein
   Zustand. Getönt ist allein die Lage je Mensch, und zwar in den Badge-Tönen —
   „neue Fassung fällig" ist eine Aufgabe, keine Bewertung. */
.minijob-kopfzahlen {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  margin-bottom: var(--sp-4);
}
.minijob-kopfzahlen .kennzahl {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-3);
  background: var(--sunken);
}
.minijob-karte .gitter-rolle { margin-bottom: var(--sp-3); }
.minijob-karte .minijob { margin-top: var(--sp-4); }
.minijob-aendern { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-sect); }
/* Eine Kapsel, die ein Link ist, sieht aus wie eine Kapsel — nur der Zeiger verrät den Weg. */
a.pill:hover { text-decoration: none; filter: brightness(.97); }

/* ⛔ FELDER OHNE WIRKUNG STEHEN GESAMMELT IN EINEM AUFKLAPPER AM ENDE DER KARTE, MIT EINEM SATZ FÜR
   ALLE (`einstellungen.OHNE_WIRKUNG`, `_einstellungsgruppe.html`). In Worten, nicht in Farbe: sie sind
   nicht falsch, nur nicht angeschlossen — ein Warnton daran wäre eine Warnung, die nie verschwindet. */
.einstellungen-ohne-wirkung { margin-top: var(--sp-3); }
.einstellungen-ohne-wirkung > .feld:first-of-type { margin-top: var(--sp-2); }

/* ── DER POSTAUSGANG ─────────────────────────────────────────────────────────
   Der Fehler steht sichtbar in der Zeile (kein Tooltip), in der Schriftfarbe
   der Fehler-Kapsel: er ist die Auskunft, wegen der jemand die Seite öffnet. Das
   Muster einer Vorlage steht als Text auf dem Grund — es ist ein Beispiel, kein
   Formular, und soll nicht nach einer zweiten Karte aussehen. */
.postausgang-fehler { color: var(--badge-err-fg); overflow-wrap: anywhere; }
.postausgang td:first-child { white-space: nowrap; }
.postausgang-muster-titel { margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-sect); }
.postausgang-muster {
  margin: 0 0 var(--sp-3); padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-2);
  background: var(--sunken); color: var(--text);
  font: 400 var(--fs-ui)/1.6 var(--f-ui);
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* ── ANSICHT ALS MITARBEITER ────────────────────────────────────────────────
   ⛔ Klebt oben und läuft beim Scrollen mit. Ein Hinweis, der nach dem ersten
   Bildschirm verschwindet, ist genau dann weg, wenn jemand anfängt zu handeln.

   ⛔ NICHT in den Ampelfarben — die gehören dem Tagesstatus und dem
   Urlaubskonto. Ein Balken in Warn-Gelb ließe offen, ob die Anwendung etwas
   über die ARBEITSZEIT sagen will. Die Markenfarbe sagt „Systemzustand". */
.ansicht-balken {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  background: var(--primary);
  color: var(--auf-primary);
  font-size: var(--fs-ui);
  box-shadow: 0 1px 4px rgb(0 0 0 / .18);
}
.ansicht-text { flex: 1 1 16rem; }
.ansicht-zusatz { display: block; opacity: .85; font-size: var(--fs-dense); }
.ansicht-zurueck {
  flex: 0 0 auto;
  /* ⛔ Das Fingermaß aus `--control-h`: der Rückweg ist der eine Knopf, den man in Eile
     trifft — und auf dem Telefon mit dem Daumen. */
  min-height: var(--control-h);
  display: inline-flex;
  align-items: center;
  padding: 0 var(--sp-3);
  border: 1px solid currentColor;
  border-color: color-mix(in srgb, currentColor 55%, transparent);
  border-radius: var(--r-2);
  color: var(--auf-primary);
  text-decoration: none;
  font-weight: 500;
}
.ansicht-zurueck:hover, .ansicht-zurueck:focus-visible { background: none; background: color-mix(in srgb, currentColor 15%, transparent); }

/* ⛔ Im Dunkel-Theme bleibt es EIN Block, EIN Selektor — kein
   `prefers-color-scheme` daneben. Weiß auf --primary trägt in beiden Themes. */
:root[data-theme="dark"] .ansicht-balken { box-shadow: 0 1px 4px rgb(0 0 0 / .5); }
.seitenkopf-aktion { margin-top: var(--sp-2); }
.seitenkopf-aktion .zeile-zusatz { display: block; }

/* ── DASHBOARD: WAS OBERHALB DER FALZ STEHT ─────────────────────────────────
   ⛔ Die zwei Sekunden entscheiden sich nicht daran, WAS auf der Seite steht,
   sondern was oberhalb von ~530 px steht. Datum und Stand stehen deshalb in der
   Kopfzeile der Stempelkarte und nicht in einem eigenen Untertitel. */
.stempel-wann {
  color: var(--text-muted);
  font-size: var(--fs-dense);
}

/* ⛔ EIN MINUS IST HIER KEIN AMPELZUSTAND. Der Auftrag wollte Minus in Soft-Rot und
   Plus in Soft-Grün. Am 3. des Monats hat JEDER ein Minus — es sind erst drei Tage
   vorbei. Ein rotes Feld wäre ein Urteil über einen Monat, der noch läuft, und nach
   dem zweiten Mal glaubt es niemand mehr. Die Ampel gehört dem Tagesstatus und dem
   Urlaubskonto; hier arbeitet die FORM: ein Strich an der Kante, wo etwas fehlt, und
   das echte Minuszeichen (U+2212), das der Filter ohnehin schon setzt. */
/* ⛔ DIE REGEL SELBST STEHT WEITER UNTEN, BEI `.karte.kennzahl`. Sie hat dort die hoehere
   Spezifitaet und stand spaeter im Stylesheet — diese hier war seit dem Umbau der Kachel
   wirkungslos. Der Grund gehoert trotzdem hierher, wo man ihn sucht. */

/* ── AVATAR ─────────────────────────────────────────────────────────────────
   ⛔ DIE FARBE BEDEUTET "DIESER MENSCH", NICHT "DIESER ZUSTAND". Sie kommt aus
   einem Streuwert ueber den Namen (src/services/avatar.js) und niemals aus der
   Ampel. In "Wer ist da" ersetzt der Badge deshalb das .person-mal NICHT — der
   Status bleibt bei der FORM (gefuellt / halb / offen). Eine Kachel mit nur einem
   farbigen Kreis stellte Farbe implizit wieder an die Statusposition.

   Getoent statt gefuellt: der Kontrast haengt am Abstand der Helligkeiten und
   nicht am Farbton — Weiss auf einem gefuellten Kreis faellt bei Gelb und Gruen
   unter 4,5:1, bei Blau nicht. Derselbe Zahlenwert, dreifach verschiedene
   Wirkung. */
.avatar {
  flex: none; display: inline-grid; place-items: center;
  width: var(--avatar-gr, 32px); height: var(--avatar-gr, 32px);
  border-radius: var(--r-full);
  background: hsl(var(--avatar-hue) 40% 92%);
  color: hsl(var(--avatar-hue) 60% 24%);
  border: 1px solid hsl(var(--avatar-hue) 35% 78%);
  font: 600 var(--fs-micro)/1 var(--f-ui); letter-spacing: .02em;
}
:root[data-theme="dark"] .avatar {
  background: hsl(var(--avatar-hue) 30% 22%);
  color: hsl(var(--avatar-hue) 55% 78%);
  border-color: hsl(var(--avatar-hue) 28% 34%);
}
/* Auf Papier ist der Farbton Rauschen — die Initialen bleiben, der Ton geht. */
@media print { .avatar { background: none; color: var(--text); border-color: var(--border-strong); } }

/* ── ARBEITSZEITMODELL ALS WOCHENKARTE ──────────────────────────────────────
   Die Frage lautet "sieht die Woche plausibel aus?", nicht "wie viel am Mittwoch?".
   ⛔ DIE HOEHE IST EINE MENGE, KEIN ZUSTAND — deshalb --selected und kein Ampelton.
   ⛔ UND SIE IST FEST SKALIERT (--wt-max), nicht relativ zum groessten Tag: sonst
   saehe eine Halbtagswoche genauso aus wie eine Vollzeitwoche, und der Vergleich
   zwischen zwei Modellen waere wertlos. ⛔ Die Skala setzt die VORLAGE (`--wt-max` aus
   `arbeitszeit.hoechstarbeitszeitStunden`) — hier stand sie als Ziffer, passend zu einem
   `max` im Formular, das es nicht mehr gibt; das Modell darf die Grenze nicht überschreiten.
   Dieselbe Grafik steht unter „Meine Zeit → Dokumente" fuer das eigene Modell. */
/* Name und Badge in einer Tabellenzelle: der Badge darf die Zeile nicht hoeher machen.
   ⛔ DAS FLEX SITZT AM INNEREN ELEMENT, NICHT AN DER ZELLE. Eine Zelle mit `display: flex` ist
   keine Tabellenzelle mehr — ihre Unterkante lag zwei, drei Pixel neben der Linie der Nachbarzellen
   (gemessen am 08.10.2026 in der Mitarbeiterliste, in beiden Themes). */
.gitter td.mit-avatar > .mit-avatar-innen { display: flex; align-items: center; gap: var(--sp-2); }

.wochenkarte {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--sp-1);
  align-items: end; --wt-hoehe: 56px;
}
.wochentag { display: grid; gap: var(--sp-1); text-align: center; font-size: var(--fs-micro); }
.wochentag-balken {
  height: calc(var(--wt-h) / var(--wt-max) * var(--wt-hoehe)); min-height: 2px;
  background: var(--selected); border: 1px solid var(--border-strong);
  border-radius: var(--r-1) var(--r-1) 0 0;
}
/* Der freie Tag ueber die FORM, nicht ueber Farbe — dasselbe Muster wie .balken.beantragt. */
.wochentag[data-frei] .wochentag-balken { background: var(--sunken); border-style: dashed; }
.wochentag .std { font-variant-numeric: tabular-nums; color: var(--text); font-weight: 600; }
.wochentag[data-frei] .std { color: var(--text-faint); font-weight: 400; }
.wochentag .tag { color: var(--text-muted); }

/* ── "WER IST DA" ALS KACHELN ───────────────────────────────────────────────
   ⛔ KEIN box-shadow. Die Kachel liegt IN der .karte; eine zweite Hoehe waere eine
   zweite Karte, und die Tiefe verdoppelte sich ohne Bedeutung. */
.radar-liste.kacheln {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
}
.kacheln .person {
  align-items: flex-start; gap: var(--sp-3);
  min-height: 60px; padding: var(--sp-3);
  border-radius: var(--r-4); background: var(--canvas);
}
.kacheln .person-mal { margin-top: 5px; }
.person-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.person-name { font-size: var(--fs-ui); font-weight: 500; }
@media (max-width: 780px) { .radar-liste.kacheln { grid-template-columns: 1fr; } }

/* Die Landeswahl auf der Feiertagsseite: eine Karte, die nur ein Feld traegt. Ohne den Deckel
   liefe das <select> ueber die ganze Bahn — ein Bundesland ist kein Fliesstext. */
.landwahl { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--sp-3); }
.landwahl .feld { margin-bottom: 0; min-width: 18rem; }
.landwahl .karte-hinweis { flex-basis: 100%; margin: 0; }

/* Der Verlauf klappt zu. `summary` trägt eine <h2> — deshalb muss die
   Überschrift inline laufen, sonst springt das Dreieck in eine eigene Zeile. */
.verlauf > summary { cursor: pointer; list-style-position: inside; }   /* innen: aussen klebte der Pfeil an der Kartenkante */
.verlauf > summary > h2 { display: inline; font-size: var(--fs-sect); }
.verlauf[open] > summary { margin-bottom: var(--sp-3); }

/* ── STEMPELN NUR VOR ORT ────────────────────────────────────────────────────
   ⛔ KEIN `.hinweis`. Die Hinweisfarben stehen für „da stimmt etwas nicht"; hier ist alles in
   Ordnung, es ist nur woanders. Ein gelber Kasten an dieser Stelle läse sich für den Lagerkollegen
   jeden Morgen wie ein Vorwurf. Deshalb eine ruhige Fläche in Markenblau-Tönung — dieselbe Sprache,
   in der der Ansicht-Balken „Systemzustand" sagt. */
.stempel-vorort {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  margin: 0; padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-3);
  background: var(--selected); color: var(--text);
  font-size: var(--fs-ui); max-width: var(--measure);
}
/* Vertrauensarbeitszeit: das Stempeln liegt hinter einem Wort, nicht als großer Knopf da (Round Table,
   08.10.2026). Die Fläche zum Antippen hält das Fingermaß, auch wenn sie leise aussieht. */
/* ⛔ KEIN `display: flex` AM SUMMARY: es nahm das Dreieck weg, und „Heute doch stempeln" las sich
   wie ein Satz statt wie etwas zum Aufklappen. Das Fingermaß kommt aus dem Innenabstand. */
.stempel-doch > summary {
  width: fit-content; padding: var(--sp-3) 0;
  cursor: pointer; color: var(--text-muted); font-size: var(--fs-dense);
}
.stempel-doch[open] > summary { color: var(--text); }
.stempel-doch .stempel-knoepfe { margin-top: var(--sp-2); }
.stempel-vorort > .ikone { margin-top: 2px; color: var(--primary); }
.stempel-vorort b { display: block; }

/* ── DIE KAPSEL AN EINER ZEILE ───────────────────────────────────────────────
   Ein kurzes Etikett für einen Zwischenzustand („Storno beantragt", „ab 01.10.", „Modell fehlt").

   ⛔ SIE TRÄGT DIE BADGE-TÖNE UND NICHT DIE AMPEL SELBST. Die Ampel gehört dem Tagesstatus und dem
   Urlaubskonto; ein Etikett neben einem Namen ist eine Einordnung, keine Bewertung. Die
   `--badge-*`-Familie ist genau dafür da — getönt, mit eigener Kante, ohne die Leuchtkraft der
   Ampelfarbe. Und wo drei Töne nebeneinander stehen, gehört eine Legende dazu; drei Farben ohne
   sie sind eine Ratefrage.

   ⛔ `.marke` UND `.badge` SIND DIESELBE FORM MIT ZWEI NAMEN — und das ist kein Versehen.
   `.marke` steht seit jeher an einer Zeile; `.badge` ist der Name, unter dem eine Kapsel gesucht
   wird, wenn jemand eine neue Ansicht baut. Beide auf dieselbe Regel zu setzen ist billiger als
   eine Umbenennung in sechs Vorlagen — und es verhindert die zweite Pillenform, die sonst beim
   nächsten Mal daneben entsteht.

   ⛔ `inline-flex` UND NICHT `inline-block`. Eine Kapsel trägt oft eine Ikone oder eine Zahl neben
   ihrem Wort; ohne `align-items: center` säßen die beiden auf verschiedenen Grundlinien.
   `vertical-align: middle` hält sie dafür in der Textzeile, in der sie steht. */
/* ⛔ `.pill` IST DER DRITTE NAME FÜR DIESELBE FORM — und aus demselben Grund wie der zweite.
   Der Auftrag verlangt eine Klasse `.pill`. Eine eigene Regel dafür wäre die zweite Pillenform
   im Haus, und die erste Abweichung zwischen beiden fiele niemandem auf. Ein Alias am
   bestehenden Selektor kostet nichts und hält die Form bei EINER Definition.

   ⛔ DIE SCHRIFTGRÖSSE BLEIBT EIN TOKEN. Der Auftrag schrieb `.8rem` — das sind 12,8 px, und
   `--fs-dense` ist 13. Eine Pixelzahl in einer font-size bricht Regel 4 im Dateikopf, und der
   Unterschied wäre ein Fünftel Pixel. Maße, Gewicht und Abstand folgen dem Auftrag genau. */
.marke, .badge, .pill {
  display: inline-flex; align-items: center; gap: 6px;
  vertical-align: middle;
  padding: 4px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--badge-neu-bd); background: var(--badge-neu-bg); color: var(--badge-neu-fg);
  font: 600 var(--fs-dense)/1.35 var(--f-ui); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.marke-wartet, .badge-warn { border-color: var(--badge-warn-bd); background: var(--badge-warn-bg); color: var(--badge-warn-fg); }
.marke-kuenftig, .badge-neu { border-color: var(--badge-neu-bd); background: var(--badge-neu-bg); color: var(--badge-neu-fg); }
.badge-ok { border-color: var(--badge-ok-bd); background: var(--badge-ok-bg); color: var(--badge-ok-fg); }
.badge-bad { border-color: var(--badge-err-bd); background: var(--badge-err-bg); color: var(--badge-err-fg); }

/* ⛔ DER PUNKT IST EINE EIGENE KLASSE UND SITZT NICHT AN JEDER KAPSEL.
   Der Auftrag wollte ihn überall. „Farbe ist Bedeutung, nie Dekoration" (Regel 2) steht
   dagegen: an „Standard", „ab 01.11." oder „+2:00 h" bezeichnet ein Punkt keinen Zustand,
   er füllt nur Platz — und wo er an jeder Kapsel klebt, sagt er auch dort nichts mehr, wo
   er etwas sagen könnte. Er trägt deshalb `.badge-punkt` und steht an den Kapseln, die
   einen LAUFENDEN Zustand melden: anwesend, in Pause, nicht da.

   Er holt seine Farbe über `currentColor` aus der Familie, in der er steht — eine zweite
   Farbliste daneben liefe beim ersten Palettenwechsel auseinander. */
.badge-punkt::before {
  content: ''; flex: none;
  width: 6px; height: 6px; border-radius: var(--r-full);
  background: currentColor;
}
/* Mehrere Kapseln nebeneinander brechen um, statt die Karte zu sprengen. */
.badge-reihe { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: var(--sp-3) 0; }

/* ── DER FORTSCHRITTSRING DER STEMPELUHR ─────────────────────────────────────
   ⛔ DER RING TRÄGT DEN TAGESSTATUS UND KEINE EIGENE BEDEUTUNG. Grau, solange nichts läuft;
   grün beim Arbeiten; gelb in der Pause — dieselben drei Zustände wie der Streifen an der
   Kartenkante und wie die Ampel darüber, in derselben Farbe. Eine eigene Farbe für „Fortschritt"
   wäre ein zweites Grün mit einer zweiten Bedeutung; danach heißt Grün nichts mehr.

   ⛔ SVG UND TEXT LIEGEN IN DERSELBEN RASTERZELLE, nicht absolut positioniert übereinander.
   Nur so bleibt der Text an seinem Platz, wenn das SVG im Druck verschwindet — ein absolut
   gesetzter Block ohne Bezugsrahmen fiele dort in die linke obere Ecke der Seite.

   ⛔ DIE DREHUNG UM -90° STEHT AM SVG UND NICHT AN DEN KREISEN. Ein SVG-Kreis beginnt bei drei
   Uhr; ein Fortschritt, der rechts anfängt, wird als halb voll gelesen, bevor er begonnen hat.
   Am SVG dreht sie nur das Bild — der Text daneben in derselben Zelle bleibt aufrecht. */
.stempel-ring {
  display: grid; place-items: center;
  width: 10.5rem; aspect-ratio: 1; flex: none;
}
.stempel-ring > * { grid-area: 1 / 1; }
.stempel-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring-bahn { fill: none; stroke: var(--sunken); stroke-width: 14; }
.ring-wert {
  fill: none; stroke: var(--text-faint); stroke-width: 14; stroke-linecap: round;
  transition: stroke-dashoffset .6s cubic-bezier(.22, .61, .36, 1);
}
.stempel-ring[data-lage="arbeit"] .ring-wert { stroke: var(--good); }
.stempel-ring[data-lage="pause"]  .ring-wert { stroke: var(--warn); }
/* Ohne Bewegung springt der Bogen auf seinen Wert, statt dorthin zu laufen. Das ist hier die
   richtige Antwort — anders als beim Ampelpuls friert nichts auf halbem Weg ein. */
@media (prefers-reduced-motion: reduce) { .ring-wert { transition: none; } }

.ring-inhalt { display: grid; justify-items: center; gap: 2px; text-align: center; padding: 0 var(--sp-3); }
.ring-titel {
  font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .09em; text-transform: uppercase; color: var(--text-muted);
}
/* ⛔ IN DER HAUSSCHRIFT MIT TABELLARISCHEN ZIFFERN, NICHT MEHR IN FESTBREITE. Mit `tabular-nums` hat
   jede Ziffer dieselbe Breite, und beim Weiterzählen wandert nichts. Die Festbreitenschrift stand
   daneben wie ein Fremdkörper — das Terminal hat denselben Schritt am 29.09.2026 gemacht. */
.ring-zahl {
  font: 650 var(--fs-kpi)/1.05 var(--f-ui);
  font-variant-numeric: tabular-nums; letter-spacing: -.03em;
}
.ring-zahl .einheit { font: 400 var(--fs-ui)/1 var(--f-ui); color: var(--text-faint); }
.ring-spanne { font-size: var(--fs-dense); color: var(--text-muted); }

/* Der laufende Abschnitt unter dem Ring: ein Satz, keine zweite Kennzahl. */
.stempel-abschnitt {
  margin: 0; text-align: center;
  font-size: var(--fs-ui); color: var(--text-muted);
}
.stempel-abschnitt .laufzeit {
  font: 600 var(--fs-ui)/1 var(--f-ui);
  font-variant-numeric: tabular-nums; color: var(--text);
}
/* Seit wann der Tag läuft — vorn im Satz über den Abschnitt, etwas kräftiger als der Rest: es ist die
   Auskunft, die nach einer Pause sonst fehlte. */
.stempel-tagesbeginn { color: var(--text); }

/* Die nächste Handlung nimmt den meisten Platz, die anderen stehen daneben — die Rangfolge trägt
   die Fläche, nicht nur die Füllung. */
.stempeluhr .stempel-knoepfe .knopf-gross { flex: 1 1 10rem; }
.stempeluhr .stempel-knoepfe .knopf-primaer { flex: 2 1 14rem; }

@media (max-width: 780px) {
  /* Auf 360 px nimmt ein 15rem-Ring die halbe Bildschirmhöhe. Die Zahl bleibt lesbar, der Ring
     wird schmaler — er ist die Zugabe, nicht die Auskunft. */
  .stempel-ring { width: 9rem; }
  /* ⛔ UND DIE KARTE RÜCKT ENGER ZUSAMMEN. `--sp-5` zwischen fünf Blöcken sind hundert Pixel, die
     auf einem Telefon zwischen der Uhr und ihrem Knopf stehen — und der Knopf ist das, wofür die
     Karte da ist. Der Abstand bleibt vorhanden; er wird nur nicht mehr großzügig. */
  .stempeluhr { gap: var(--sp-4); padding: var(--sp-4); }
}

/* ⛔ AUF DEM SCHMALSTEN GERÄT WIRD DER RING NOCH EINMAL KLEINER. Bei 390 px Breite und einer
   stehenden Sitzungsmeldung darüber („Kommen erfasst") liegt der Knopf sonst unter der Falz —
   also genau nach dem Stempeln, wenn jemand prüfen will, ob es geklappt hat. Die Zahl in der
   Mitte behält ihre Größe: sie ist die Auskunft, der Bogen ist die Zugabe (so steht es auch im
   Druckblock, der den Bogen ganz weglässt und die Zahl behält).
   Gemessen auf 390 px: 8 rem sind 128 px, und die Zahl mit `--fs-kpi` steht darin frei. */
@media (max-width: 560px) {
  .stempel-ring { width: 8rem; }
  .ring-zahl { font-size: var(--fs-title); }
}

@media print {
  /* ⛔ DER RING WIRD NICHT GEDRUCKT, DIE ZAHL SCHON. Ein 12 px breiter Bogen druckt als grauer
     Reifen um eine Zahl und sieht auf einem unterschriebenen Stundenzettel nach einem Stempel
     aus, den niemand gesetzt hat. */
  .stempel-ring svg { display: none; }
  .stempel-ring { width: auto; aspect-ratio: auto; }
}

/* ── DER MONAT ALS BILD ──────────────────────────────────────────────────────
   Zwei Darstellungen mit zwei Fragen: der Balken beantwortet „wo stehe ich im Monat", die Säulen
   „welcher Tag war anders". Beide sind reines CSS — kein Diagrammpaket, kein Build-Schritt.

   ⛔ DIE AMPEL KOMMT HIER NICHT VOR. Sie gehört dem Tagesstatus und dem Urlaubskonto. Ein oranger
   Tag unter dem Soll wäre dasselbe wie das abgelehnte rote Monatsminus: am 3. des Monats hat jeder
   eines, weil erst drei Tage vorbei sind. Das Vorzeichen trägt die FORM — eine Säule, die unter
   ihrer Soll-Marke bleibt. Mehrarbeit trägt die dunklere Fassung des Markenblaus, kein Grün. */

.fortschritt {
  position: relative; height: 14px; margin-bottom: var(--sp-3);
  display: flex; overflow: hidden;
  border-radius: var(--r-full); background: var(--sunken);
  border: 1px solid var(--border);
}
.fortschritt-teil { display: block; height: 100%; }
.fortschritt-arbeit { background: var(--primary); }
/* Abgedeckt heißt abgedeckt und nicht gearbeitet. Dieselbe Fläche, andere Textur — die Schraffur
   trägt den Unterschied auch dort, wo Farbtöne nicht unterschieden werden. */
.fortschritt-gedeckt {
  background: repeating-linear-gradient(135deg,
    var(--selected) 0 6px, var(--canvas) 6px 12px);
}
/* ⛔ DIE MARKE IST DIE HÄLFTE DER AUSSAGE. Ohne sie sagt der Balken nur, wie viel vom Monat noch
   fehlt — am 3. also fast alles. `translateX(-50%)` setzt sie mittig auf ihren Prozentwert, sonst
   stünde sie bei 100 % einen Strich außerhalb. */
.fortschritt-marke {
  position: absolute; top: -2px; bottom: -2px; width: 2px;
  transform: translateX(-50%);
  background: var(--text); opacity: .55;
}
.fortschritt-text { margin: 0; font-size: var(--fs-ui); }

.saeulen-rolle { overflow-x: auto; padding-bottom: var(--sp-2); }
/* ⛔ `--saeulen-anzahl` KOMMT AUS DER VORLAGE, DAMIT DIE SPALTEN GLEICH BREIT BLEIBEN. Mit
   `auto-fit` verteilte ein Februar seine 28 Tage über dieselbe Breite wie ein Januar seine 31 —
   zwei Monate nebeneinander wären dann nicht vergleichbar. `minmax(18px, 1fr)` gibt jeder Säule
   eine Untergrenze und lässt den Kasten notfalls rollen. */
.saeulen {
  display: grid; gap: 3px; align-items: end;
  grid-template-columns: repeat(var(--saeulen-anzahl, 31), minmax(18px, 1fr));
  min-width: 100%;
}
.saeule { display: grid; justify-items: center; gap: 2px; }
.saeule-bahn {
  position: relative; width: 100%; height: 120px;
  border-radius: var(--r-1) var(--r-1) 0 0;
  background: var(--sunken);
}
.saeule[data-wochenende] .saeule-bahn,
.saeule[data-feiertag] .saeule-bahn { background: var(--hover); }

/* Alle drei Flächen wachsen von unten. Sie liegen übereinander, nicht nebeneinander: eine Säule
   ist EIN Tag, und zwei Balken nebeneinander lesen sich als zwei. */
.saeule-ist, .saeule-mehr, .saeule-gedeckt {
  position: absolute; left: 0; right: 0; bottom: 0; display: block;
}
.saeule-ist { background: var(--primary); border-radius: var(--r-1) var(--r-1) 0 0; }
/* Über dem Tages-Soll. Dunkler statt bunter — es ist mehr vom Gleichen, keine andere Sache. */
.saeule-mehr { background: var(--primary-hover); border-radius: var(--r-1) var(--r-1) 0 0; }
.saeule-gedeckt {
  border-radius: var(--r-1) var(--r-1) 0 0;
  background: repeating-linear-gradient(135deg,
    var(--selected) 0 5px, var(--canvas) 5px 10px);
}
/* ⛔ EIN STRICH UND KEINE FLÄCHE. Das Soll ist ein Ziel, kein Wert — als Fläche hinter der Säule
   wäre es von einem zweiten Messwert nicht zu unterscheiden. */
.saeule-soll {
  position: absolute; left: 0; right: 0; height: 2px;
  background: var(--border-strong);
}
.saeule-tag { font: 600 var(--fs-micro)/1.2 var(--f-ui); font-variant-numeric: tabular-nums; }
.saeule-kurz { font-size: var(--fs-micro); color: var(--text-faint); }
/* Ein Tag mit Soll, an dem nichts gebucht und nichts genehmigt ist. Der einzige, an dem die Form
   ein Fehlen zeigt — eine gestrichelte Bahn statt einer gefüllten. */
.saeule[data-art="offen"] .saeule-bahn {
  border: 1px dashed var(--border-strong); background: none;
}

.legende {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  list-style: none; margin: var(--sp-4) 0 0; padding: 0;
  font-size: var(--fs-dense); color: var(--text-muted);
}
.legende li { display: flex; align-items: center; gap: var(--sp-2); }
.legende-mal { width: 14px; height: 14px; border-radius: var(--r-1); flex: none; }
.legende-ist { background: var(--primary); }
.legende-mehr { background: var(--primary-hover); }
.legende-gedeckt {
  background: repeating-linear-gradient(135deg, var(--selected) 0 4px, var(--canvas) 4px 8px);
  border: 1px solid var(--border);
}
.legende-soll { height: 2px; border-radius: 0; background: var(--border-strong); }

@media (max-width: 780px) {
  /* Die Säulen bleiben, sie rollen nur. Ein Diagramm, das auf dem Telefon verschwindet, ist auf
     dem Gerät weg, auf dem die meisten es ansehen. */
  .saeule-bahn { height: 96px; }
  .saeule-kurz { display: none; }
}

@media print {
  /* Flächen drucken als graue Kästen; die Struktur bleibt trotzdem lesbar, weil die Höhen bleiben.
     Der Rollkasten muss aufgehen, sonst endet das Diagramm am Papierrand. */
  .saeulen-rolle { overflow: visible; }
}

/* ── DAS MONATSRASTER DER VERWALTUNG ─────────────────────────────────────────
   Es teilt sich Aufbau und Spaltenköpfe mit dem Teamkalender (`services/kalenderraster.js`) und
   unterscheidet sich in genau einem Punkt: hier steht, WARUM jemand fehlt.

   ⛔ DIE FLÄCHEN TRAGEN DIE BADGE-TÖNE, NICHT DIE AMPEL. Sie sind Kategorien und keine Bewertung.
   Die Ampel gehört dem Tagesstatus und dem Urlaubskonto; ein rot leuchtender Block am Namen eines
   Kollegen liest sich wie ein Vorwurf, auch in der Verwaltungssicht. Die `--badge-*`-Familie ist
   für genau das gebaut: getönt, mit eigener Kante, ohne die Leuchtkraft der Ampelfarbe.

   ⛔ UND DESHALB IST DIE LEGENDE PFLICHT. Drei Töne, die sich nur in der Sättigung unterscheiden,
   sind ohne sie eine Ratefrage — und für jemanden, der Farben schlecht unterscheidet, gar keine
   Auskunft. Die Schraffur für „beantragt" trägt zusätzlich, was keine Farbe trägt. */
/* ⛔ KRÄFTIGER SEIT DEM 08.10.2026 — UND WEITER IN DEN BADGE-TÖNEN. Die Fläche trug den hellsten Ton
   der Familie (`-bg`) mit der hellen Kante (`-bd`): auf weißem Grund ein Hauch, den man suchen
   musste. Jetzt trägt sie die Kantenfarbe als Fläche und die Schriftfarbe der Kapsel als Kante — die
   Kante allein hält 3:1 gegen die Karte (WCAG 1.4.11), und die Fläche bleibt ein Ton und keine Ampel. */
.balken[data-art="urlaub"] { background: var(--badge-ok-bd); border-color: var(--badge-ok-fg); }
.balken[data-art="krank"] { background: var(--badge-warn-bd); border-color: var(--badge-warn-fg); }
.balken[data-art="sonstige"] { background: var(--badge-neu-bd); border-color: var(--badge-neu-fg); }
/* ⛔ „BEANTRAGT" GEWINNT GEGEN DIE KATEGORIE. Beide Regeln standen gleich stark, und die Kategorie kam
   später: ein offener Antrag trug den Urlaubston und keine Schraffur — während die Legende daneben
   „beantragt" als schraffiertes Feld erklärte. Die Kante bleibt gestrichelt in der Kategoriefarbe.
   ⛔ DIE SCHRAFFUR TRÄGT DIE DUNKLE FARBE DER KATEGORIE, NICHT `--selected`. Ein offener Antrag ist
   die eine Fläche im Raster, die auf eine Entscheidung wartet — hellblau auf weiß sprang er nicht
   ins Auge. Dunkle Streifen auf dem Weiß der Karte tun es, und sie sagen weiter „noch nicht", weil
   die Fläche dazwischen leer bleibt. */
/* ⛔ NUR IM RASTER — DORT STEHT KEINE ZIFFER AUF DER FLÄCHE. Im eigenen Kalender auf `/urlaub`
   (`.monatsblatt`) liegt der Balken HINTER der Tageszahl, und die dunklen Streifen nahmen ihr den
   Kontrast (2,3:1 hell, 1,4:1 dunkel — Prüfung als Mitarbeiter, 08.10.2026). Dort bleibt die helle
   Schraffur; sie ist die Grundregel, die dunkle die Verfeinerung für `.kalender`. */
.balken.beantragt[data-art] {
  background: repeating-linear-gradient(45deg, var(--selected) 0 4px, var(--canvas) 4px 8px);
  border-style: dashed;
}
.kalender .balken.beantragt[data-art="urlaub"] {
  background: repeating-linear-gradient(45deg, var(--badge-ok-fg) 0 2px, var(--canvas) 2px 6px);
}
.kalender .balken.beantragt[data-art="krank"] {
  background: repeating-linear-gradient(45deg, var(--badge-warn-fg) 0 2px, var(--canvas) 2px 6px);
}
.kalender .balken.beantragt[data-art="sonstige"] {
  background: repeating-linear-gradient(45deg, var(--badge-neu-fg) 0 2px, var(--canvas) 2px 6px);
}
/* Der Teamkalender nennt keine Art (`team.kalender`) — sein beantragter Balken trägt dieselben
   Streifen in Neutral, wie die Legende daneben. Blasses Hellblau auf Weiß lag bei 1,14:1. */
.kalender .balken.beantragt:not([data-art]) {
  background: repeating-linear-gradient(45deg, var(--text-muted) 0 2px, var(--canvas) 2px 6px);
}

/* Der Name trägt seinen Badge. ⛔ Der Farbton bedeutet „dieser Mensch", nie einen Zustand
   (services/avatar.js) — er darf deshalb neben den Kategorieflächen stehen, ohne mit ihnen
   verwechselt zu werden: er ist rund, sie sind eckig. */
.kalender-person-kopf { display: flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
/* ⛔ DIE KAPSEL „AB …" / „BIS …" STEHT UNTER DEM NAMEN, NICHT DANEBEN. Daneben machte sie die
   Namensspalte so breit, dass der Monat bei 1440 px nicht mehr in die Karte passte und die letzten
   drei Tage ohne Hinweis hinter dem Rand lagen (Prüfung als Dominik, 08.10.2026). */
.kalender-person-kopf .marke {
  display: block; width: fit-content; margin: 2px 0 0;
  font-size: var(--fs-micro); padding-top: 0; padding-bottom: 0;
}

/* Tage vor dem Eintritt und nach dem Austritt sind keine freien Tage — sie gehören nicht dazu.
   Ohne diese Kennzeichnung sähe der Eintrittsmonat aus wie zwanzig Tage ohne Urlaub. */
/* ⛔ DIE SCHRAFFUR STEHT IN DER FELDKANTE (`--border-strong`, 3:1), NICHT IN `--sunken`. Mit `--sunken`
   auf `--canvas` lag sie bei 1,05:1 — im Raster und in der Legende praktisch unsichtbar, und der
   Eintrittsmonat sah wieder aus wie Tage ohne Urlaub. Dünne Linien, damit sie Fläche bleibt — und in
   der ANDEREN Richtung als „beantragt": in der Legende stehen beide als gestreiftes Quadrat nebeneinander. */
.kalender-zelle.ausserhalb {
  background: repeating-linear-gradient(-45deg,
    var(--border-strong) 0 1px, var(--canvas) 1px 6px);
}

/* Dieselben Töne wie die Flächen im Raster — die Legende ist keine zweite Fassung. */
.legende-urlaub { background: var(--badge-ok-bd); border: 1px solid var(--badge-ok-fg); }
.legende-krank { background: var(--badge-warn-bd); border: 1px solid var(--badge-warn-fg); }
.legende-sonstige { background: var(--badge-neu-bd); border: 1px solid var(--badge-neu-fg); }
.legende-beantragt {
  border: 1px dashed var(--text-muted);
  background: repeating-linear-gradient(45deg,
    var(--text-muted) 0 2px, transparent 2px 5px);
}

/* ── MITTEILUNGEN AUF DER STARTSEITE ─────────────────────────────────────────
   ⛔ EINE KACHEL IST EINE ZEILE, KEINE KARTE. Vier Karten mit Rand, Schatten und Innenabstand
   schöben die Stempeluhr aus dem Bild — und die ist der Grund, aus dem ein Mitarbeiter diese Seite
   öffnet. Der farbige Streifen links trägt die Dringlichkeit, der Rest ist ruhig.

   ⛔ DIESELBEN DREI TÖNE WIE BEI `.hinweis`, UND SIE BEDEUTEN DASSELBE. Rot: das blockiert den
   Monatsabschluss und wird sanktioniert (§ 22 ArbZG). Gelb: da wartet jemand. Neutral: es hat Zeit.
   Eine vierte Farbe für „Antrag" wäre eine Farbe für eine Kategorie statt für eine Konsequenz. */
.mitteilungen { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.mitteilung {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  background: var(--canvas);
  border: 1px solid var(--border); border-left-width: 3px;
  border-radius: var(--r-2);
}
.mitteilung[data-stufe="warn"] { border-color: var(--badge-warn-bd); border-left-color: var(--warn); }
.mitteilung[data-stufe="neu"]  { border-color: var(--badge-neu-bd);  border-left-color: var(--text-faint); }
.mitteilung-mal { flex: none; display: flex; color: var(--text-muted); }
.mitteilung-text { flex: 1 1 auto; min-width: 0; }
.mitteilung-text b { display: block; font: 600 var(--fs-ui)/1.35 var(--f-ui); }
/* ⛔ Der Halbsatz darunter wird NICHT abgeschnitten. Er trägt die gemessene Zahl („25 von 30
   Minuten"), und genau die sagt, was zu tun ist — ein Ellipsen-Punkt an ihrer Stelle machte aus
   einer Auskunft eine Ankündigung. */
.mitteilung-text small { display: block; color: var(--text-muted); font-size: var(--fs-dense); line-height: 1.4; }
.mitteilung > .knopf { flex: none; }
.mitteilungen-rest { margin: var(--sp-1) 0 0; font-size: var(--fs-dense); color: var(--text-muted); }

@media (max-width: 780px) {
  /* Auf 360 px steht der Knopf unter dem Text — nebeneinander bliebe für den Text eine Spalte von
     zwei Wörtern Breite. */
  .mitteilung { flex-wrap: wrap; }
  .mitteilung-text { flex-basis: calc(100% - 34px); }
  .mitteilung > .knopf { margin-left: auto; }
}
@media print { .mitteilungen { display: none; } }

/* ── EINSTELLUNGEN: DIE PAUSENSTAFFEL ────────────────────────────────────────
   Ein <fieldset> und keine Karte in der Karte: die Staffel gehört zur Gruppe „Arbeitszeit", sie ist
   kein eigener Bereich. Die <legend> trägt den Schlüsselnamen wie jedes andere Feld daneben. */
.staffel { border: 1px solid var(--border); border-radius: var(--r-2); padding: var(--sp-3) var(--sp-4) var(--sp-4); }
.staffel > legend { padding: 0 var(--sp-2); font-size: var(--fs-dense); color: var(--text-muted); }
.staffel .gitter { margin-bottom: var(--sp-2); }
/* ⛔ HIER STAND DIE SCHREIBMASCHINENSCHRIFT FÜR DIE SCHLÜSSELNAMEN (`pauseMindestabschnittMinuten`).
   Seit dem 08.10.2026 tragen die Felder Klartext (`services/einstellungen.js`, BESCHRIFTUNG) — ein
   deutscher Satz in Festbreite läse sich wie ein Wert und nicht wie eine Frage. Die Regel ist weg. */

/* ── EINSTELLUNGEN: DIE VERSANDART ───────────────────────────────────────────
   Die Karte der nicht gewählten Versandart tritt zurück — ohne Skript, über die Auswahl selbst.
   ⛔ AUSGEBLENDET, NICHT ENTFERNT: ihre Felder gehen weiter mit und behalten ihre Werte, damit ein
   Wechsel zurück nichts verliert. Ihr Geheimnisfeld wirkt dabei nicht (`einstellungen.mailPruefen`).
   ⛔ Wo `:has()` fehlt, stehen beide Karten da — jede mit ihrer Überschrift, also verständlich. */
form:has(select[name="methode"] option[value="graph"]:checked) .nur-smtp,
form:has(select[name="methode"] option[value="smtp"]:checked) .nur-graph { display: none; }

/* ── REITER ──────────────────────────────────────────────────────────────────
   Eine Leiste aus Links (`views/_reiter.html`), kein Umschalter. Jeder Reiter ist eine eigene
   Adresse — verlinkbar, als Lesezeichen ablegbar, mit der Zurück-Taste verlassbar.

   ⛔ DER AKTIVE REITER IST EINE PILLE, KEIN UNTERSTRICH. Derselbe Grund wie in der Schiene: ein
   3-px-Strich an der Unterkante ist auf einem Tablet bei Schräglicht kaum zu sehen, eine gefüllte
   Fläche schon. Und dieselbe Fläche wie dort — `--canvas` auf dem gedeckten Grund.

   ⛔ SIE ROLLT WAAGERECHT, STATT UMZUBRECHEN. Vier Reiter auf 360 px in zwei Zeilen sehen aus wie
   zwei Leisten. `scrollbar-width: none` nimmt nur die Leiste, nicht die Bedienbarkeit. */
.reiter {
  display: flex; gap: var(--sp-1);
  margin-bottom: var(--sp-5); padding: var(--sp-1);
  background: var(--table-head); border-radius: var(--r-3);
  overflow-x: auto; scrollbar-width: none;
}
.reiter::-webkit-scrollbar { display: none; }
.reiter a {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 34px; padding: 0 var(--sp-4); white-space: nowrap;
  border-radius: var(--r-2);
  color: var(--text-muted); font: 500 var(--fs-ui)/1 var(--f-ui); text-decoration: none;
}
.reiter a:hover { background: var(--hover); color: var(--text); text-decoration: none; }
.reiter a[aria-current="page"] {
  background: var(--canvas); color: var(--text); font-weight: 600; box-shadow: var(--sh-karte);
}
/* Die Grenze zwischen zwei Hälften einer Leiste (Einrichtung: Betrieb | System). ⛔ EINE LÜCKE MIT
   HAARLINIE, KEIN ZWEITER BALKEN — zwei Leisten übereinander läsen sich wie zwei Menüebenen. */
.reiter-trenner {
  flex: none; align-self: center;
  width: 1px; height: 20px; margin: 0 var(--sp-2);
  background: var(--border-strong);
}
/* Auf schmalen Fenstern trägt das Kürzel allein — „BW" statt „BW — Baden-Württemberg". Der lange
   Name bleibt im Dokument und verlässt nur die Fläche, damit eine Sprachausgabe ihn behält. */
@media (max-width: 780px) {
  .reiter-lang {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
}
@media print { .reiter { display: none; } }
/* Die Zahl an einem Schnellfilter (Auswertung): wie viele Zeilen er zeigt. Eine Menge und keine
   Warnung — sie trägt den gedämpften Ton und keine Kapsel (CLAUDE.md, „Eine Menge ist keine Warnung"). */
.reiter-zahl { color: var(--text-faint); font-variant-numeric: tabular-nums; font-weight: 500; }

/* ⛔ EIN KONTO OHNE LOHNBEZUG STEHT DEZENT DA — gedämpfter Text, keine Farbe. Es ist keine Lücke und
   kein Fehler, sondern eine Zeile, die in keine Summe gehört (services/auswertung.js). */
tr[data-ohne-lohn] td { color: var(--text-muted); }
/* ⛔ DIE MONATSÜBERSICHT HAT DREIZEHN SPALTEN — mit dem Polster der Grundregel war sie bei 1440 px
   breiter als ihre Karte, und die Spalte „Stand" lag angeschnitten hinter dem Rand (Prüfung als
   Dominik, 08.10.2026). Nur hier enger: eine Tabelle mit vier Spalten braucht die Luft. */
.gitter.auswertung-tabelle th, .gitter.auswertung-tabelle td { padding-left: var(--sp-2); padding-right: var(--sp-2); }
.auswertung-kennzahlen { margin-bottom: var(--sp-4); }
/* Der Monatsfortschritt (`views/auswertung.html`): zwei Bahnen in der Bauform des Tagesbalkens —
   Name, Bahn, Zahl. Die Zahl steht immer daneben; eine Bahn allein wäre eine Schätzaufgabe. */
.monatsfortschritt .fortschritt-zeile {
  display: grid; grid-template-columns: minmax(150px, max-content) 1fr auto;
  align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-2);
}
.fortschritt-name { font-size: var(--fs-ui); color: var(--text-muted); }
.fortschritt-wert { font-size: var(--fs-ui); font-variant-numeric: tabular-nums; }
.fortschritt-schritt { margin-top: var(--sp-3); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DIE STEMPELLEISTE IN DER TOPBAR — die Uhr, die es auf jeder Seite gibt.

   ⛔ SIE WIEDERHOLT DIE AMPEL DES TAGESSTATUS, SIE ERFINDET KEINE ZWEITE. Grau, solange nichts
   läuft; grün beim Arbeiten; gelb in der Pause — dieselben drei Bedeutungen wie auf der Leitkarte
   der Startseite. Die Regeln stehen bewusst NEBEN denen von `.stempel-lage` und nicht in einem
   gemeinsamen Selektor: die beiden sind verschieden groß, verschieden dicht und sitzen auf
   verschiedenem Grund. Ein geteilter Selektor hätte beim ersten Maßwechsel eine der beiden kaputt
   gemacht.

   ⛔ KEIN PULS. Der Ring auf der Startseite trägt die Bewegung; eine zweite pulsierende Ampel im
   Blickfeld jeder Seite ist Unruhe ohne Auskunft.

   ⛔ DER KNOPF WIRFT KEINEN SCHATTEN und trägt keine Ampelfarbe (siehe `.stempeluhr`): grün am
   „Kommen" wäre das zweite Grün mit einer zweiten Bedeutung.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.leiste-uhr {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--canvas);
}
.leiste-uhr .ampel {
  flex: none; width: 8px; height: 8px; border-radius: var(--r-full);
  background: var(--text-faint);
}
.leiste-uhr[data-lage="arbeit"] .ampel { background: var(--good); }
.leiste-uhr[data-lage="pause"]  .ampel { background: var(--warn); }

/* Ziffern in der dicktengleichen Schrift: eine Laufzeit, die im Sekundentakt die Breite wechselt,
   schiebt die Knöpfe daneben hin und her. */
.leiste-zeit { font: 600 var(--fs-dense)/1 var(--f-ui); font-variant-numeric: tabular-nums; }
.leiste-wort { font-size: var(--fs-micro); color: var(--text-muted); white-space: nowrap; }
.leiste-vorort { display: inline-flex; align-items: center; gap: var(--sp-1); }
/* ⛔ VOLLSTAENDIG, NICHT ERGAENZEND. Die Leiste trug frueher zusaetzlich `.stempel-knoepfe` und
   erbte damit auf schmalen Fenstern `flex-direction: column` — die zwei Knoepfe standen
   uebereinander und die klebende Topbar wuchs von 56 auf 95 Pixel, also rund ein Sechstel der
   Hoehe eines 360x640-Telefons. `flex: none` und `nowrap` halten die Knoepfe auch dann in einer
   Zeile, wenn die Topbar eng wird; ausweichen soll der erklaerende Text, nicht die Bedienung. */
.leiste-knoepfe {
  display: flex; flex-direction: row; flex-wrap: nowrap; flex: none;
  gap: var(--sp-1); margin: 0;
}
.leiste-uhr { flex: none; }
.leiste-knoepfe .knopf { padding: var(--sp-1) var(--sp-2); font-size: var(--fs-micro); }

/* Ab hier ist in der Topbar kein Platz mehr für Worte — die Ampel, die Ziffern und die Knöpfe
   bleiben, der erklärende Text weicht.

   ⛔ `display:none` NIMMT DEN TEXT AUCH AUS DEM BARRIEREFREIHEITS-BAUM. Der Knopf hieße für eine
   Sprachausgabe dann gar nichts mehr — und ein `title` heilt das nicht, er ist ein Tooltip und
   wird von Sprachausgaben unterschiedlich bis gar nicht gelesen. Die Beschriftung steht deshalb
   zusätzlich als `aria-label` am Knopf, genau wie beim Hell/Dunkel-Umschalter daneben. */
@media (max-width: 900px) {
  .leiste-uhr .leiste-wort { display: none; }
  .leiste-knoepfe .knopf-text { display: none; }
  /* ⛔ AUSSER BEI TERMINAL-PFLICHT OHNE LAUFENDE BUCHUNG (Round Table, 09.10.2026): dort blieb ein
     grauer Punkt ohne Wort — und genau dieser Stand ist der Grund für die Leiste („hat der Chip
     gezählt?"). Ohne Knöpfe ist Platz für ihn; läuft etwas, sagen es die Ziffern. */
  .leiste-uhr[data-vorort][data-lage="frei"] .leiste-wort:not(.leiste-vorort) { display: inline; }
}
@media (max-width: 560px) {
  .leiste-uhr { padding-left: var(--sp-2); }
  .leiste-zeit { font-size: var(--fs-micro); }
}

/* ⛔ IM AUSDRUCK HAT EINE BEDIENLEISTE NICHTS ZU SUCHEN. Auf einem ausgedruckten Stundennachweis
   stünde sonst ein toter „Gehen"-Knopf neben den Zahlen, die jemand unterschreiben soll. */
@media print { .leiste-uhr { display: none; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   EINSTELLUNGEN: FÜNFZEHN GRUPPEN, ZWEI SPALTEN.

   ⛔ `column-count` UND NICHT `grid`. Die Gruppen sind sehr unterschiedlich hoch — „Arbeitszeit"
   trägt eine Tabelle, „Betrieb" drei Zeilen. In einem Raster gibt die höchste Karte einer Reihe
   deren Höhe vor, und daneben stünde Leere. Spalten packen von selbst.

   ⛔ `break-inside: avoid` IST HIER KEINE FEINHEIT, SONDERN DIE BEDINGUNG. Ohne sie reißt der
   Umbruch eine Karte mitten im Formular auseinander: die Beschriftung stünde unten links, ihr
   Eingabefeld oben rechts, und der Speichern-Knopf gehörte sichtbar zu nichts.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  .einstellungen-spalten { column-count: 2; column-gap: var(--sp-4); }
  .einstellungen-spalten > .karte { break-inside: avoid; }
}

/* ⛔ EIN EINSTELLIGER WERT BRAUCHT KEINE 1300 PIXEL. `.feld input[type="text"]` trägt `width:100%`,
   und weil die Zahlenfelder aus dem oben genannten Grund `type="text"` sind (der Zahlentyp verwirft
   in manchen Browsern ein Komma still), zog sich `pinLaenge` über die halbe Bahn. Ein Feld, dessen
   Breite nichts über den erwarteten Wert sagt, ist eine Einladung, das Falsche hineinzuschreiben.

   Dasselbe Muster wie `.farbfeld input[type="text"] { width: 10ch }` auf der Design-Seite — dort
   stand die Antwort schon, nur an einer Stelle. */
.feld input[inputmode="decimal"],
.feld input[inputmode="numeric"] { width: 12ch; }

/* ⛔ `knopf-leise` UND `knopf-primaer` SCHLIESSEN EINANDER AUS — in dieser Reihenfolge im
   Stylesheet gewinnt `knopf-leise` mit `background: none`, während `knopf-primaer` seine Schrift
   auf `var(--auf-primary)` gesetzt hat
   gesetzt hat: weiße Schrift auf weißem Grund. Der Knopf ist dann im Markup vorhanden, im Bild
   aber nicht, und kein Test sieht das. Die Leiste vergibt deshalb genau eine der beiden Klassen. */
.leiste-knoepfe .knopf-primaer { border-color: var(--primary); }

/* Vier Kennzahlen nebeneinander. ⛔ Nicht `.raster` mit kleinerem Minimum überschreiben: das gilt
   für jedes Raster im Haus, und aus zwei Kennzahlen würden auf einem breiten Monitor vier. */
.raster-vier { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DER FORTSCHRITTSBALKEN IN DER TAGESZEILE.

   Dieselbe Aussage wie eine Säule, nur waagerecht und da, wo man ohnehin liest. ⛔ Und DIESELBEN
   drei Bedeutungen mit denselben drei Tönen: Markenblau bis zum Soll, die dunklere Fassung darüber,
   Schraffur für einen gedeckten Tag. Ein eigenes Vokabular hier hieße, dieselbe Sache zweimal zu
   erklären — und die Legende über der Tabelle gälte nur noch für die Hälfte der Seite.

   ⛔ MEHRARBEIT IST KEIN GRÜN. Der Grund steht bei `.saeule-mehr` und in CLAUDE.md: die Ampel
   gehört dem Tagesstatus und dem Urlaubskonto. Ein grüner Aufsatz an jeder langen Zeile wäre die
   dritte Bedeutung von Grün auf derselben Seite.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.spalte-balken { width: 34%; min-width: 140px; }

.tagesbalken { display: flex; align-items: center; gap: var(--sp-2); }

/* Die Bahn ist der Kasten, in dem alles bleibt (20.10.2026: gerundet und mit einer Kerbe fürs Soll – wie in zeitkumpel).
   ⛔ KEIN `overflow: hidden` MEHR: Die Kerbe ragt über die Bahn hinaus, und das ist ihr Zweck. Die Rundung tragen deshalb die Flächen selbst; wo zwei
   aneinanderstoßen (gedeckt → gearbeitet → darüber), ist die Naht gerade – sonst stünde dort ein Keil Bahn dazwischen. */
.tagesbalken-bahn {
  position: relative; flex: 1 1 auto; min-width: 60px;
  display: flex; height: 10px;
  background: var(--border);
  border-radius: var(--r-full);
}
.tb-gedeckt, .tb-ist, .tb-mehr { display: block; height: 100%; border-radius: var(--r-full); transition: width .2s; }
:is(.tb-gedeckt, .tb-ist):has(+ :is(.tb-ist, .tb-mehr)) { border-top-right-radius: 0; border-bottom-right-radius: 0; }
:is(.tb-gedeckt, .tb-ist) + :is(.tb-ist, .tb-mehr) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.tb-ist   { background: var(--primary); }
/* Über dem Tages-Soll. Dunkler statt bunter — es ist mehr vom Gleichen, keine andere Sache. */
.tb-mehr  { background: var(--primary-hover); }
.tb-gedeckt {
  background: repeating-linear-gradient(135deg,
    var(--selected) 0 5px, var(--canvas) 5px 10px);
}

/* ⛔ EIN STRICH UND KEINE FLÄCHE — wie bei den Säulen. Das Soll ist ein Ziel und kein Messwert;
   als Fläche wäre es von einem zweiten Wert nicht zu unterscheiden. Er steht nur dort, wo er etwas
   sagt: bei Untererfüllung liegt das Soll am Ende der Bahn, und ein Strich auf der Kante ist
   Rauschen. Die Vorlage lässt ihn dann weg. Er ist die Kerbe in Textfarbe. */
.tb-soll {
  position: absolute; top: -3px; bottom: -3px; width: 2px; border-radius: 1px;
  background: var(--text);
  transform: translateX(-1px);
}

/* Das Badge nennt die Stunden. ⛔ Im Neutral-Ton der Badges und nicht in Grün: „zwei Stunden mehr"
   ist eine Auskunft, keine Bewertung — am 3. des Monats hat sie noch niemand verdient und am 30.
   ist sie kein Lob. */
.marke-mehr {
  flex: none;
  font-variant-numeric: tabular-nums;
  border-color: var(--badge-neu-bd); background: var(--badge-neu-bg); color: var(--badge-neu-fg);
}

/* Auf schmalen Fenstern rollt die Tabelle ohnehin waagerecht; ein Balken, der dort auf 40 Pixel
   zusammenfällt, sagt nichts mehr und kostet eine Spalte Platz. */
@media (max-width: 700px) {
  .spalte-balken { display: none; }
}

/* Im Ausdruck bleibt er — ein Stundennachweis wird gelesen, nicht bedient. Aber ohne Farbfläche,
   die auf Schwarz-Weiß-Druckern zu einem grauen Klumpen wird. */
@media print {
  .tagesbalken-bahn { border: 1px solid #999; background: none; }
  .tb-ist { background: #999; }
  .tb-mehr { background: #444; }
  .tb-gedeckt { background: none; }
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════
   DIE ZEITLEISTE EINES TAGES — WANN, NICHT NUR WIE VIEL.

   ⛔ SIE IST NICHT DER TAGESBALKEN, UND DESHALB HAT SIE EIGENE KLASSEN. Der Balken darüber zeigt
   MENGEN (wie viel vom Soll ist erfüllt) und wächst von links; die Leiste zeigt LAGEN (wann lag
   was) und ihre Blöcke stehen frei auf einer Zeitachse. Beides in eine Familie zu zwingen hieße,
   dass eine Änderung an der einen die andere still verschiebt.

   ⛔ KEINE AMPEL. Ein Tag ist nicht gut oder schlecht: Arbeit trägt das Markenblau, die Pause den
   Bernstein der Badge-Familie (nicht `--warn`, das gehört dem Tagesstatus), und die Lücke ist die
   Bahn selbst — schraffiert, damit „hier war nichts" von „hier ist der Balken zu Ende" zu
   unterscheiden ist. Die Legende darunter benennt alle drei; drei Töne ohne sie wären eine
   Ratefrage.

   ⛔ DIE BLÖCKE SIND ABSOLUT POSITIONIERT UND NICHT GEFLEXT. Zwischen zwei Buchungen liegt Zeit,
   in der nichts lief; ein Flexkasten müsste dafür Füllelemente bekommen, und die entstünden in
   der Vorlage. Mit `left`/`width` aus dem Dienst trägt die Bahn die Lücken von selbst.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */
.tagesleiste { margin: var(--sp-2) 0 0; }
.tl-bahn {
  position: relative; height: 22px;
  border: 1px solid var(--border); border-radius: var(--r-2);
  background: var(--sunken);
  overflow: hidden;
}
.tl-block, .tl-luecke { position: absolute; top: 0; bottom: 0; }
.tl-block[data-art="arbeit"] { background: var(--primary); }
.tl-block[data-art="pause"] {
  background: var(--badge-warn-bd);
  /* Die Kante trennt Pause und Arbeit auch dann, wenn sie unmittelbar aneinanderstoßen — sonst
     liest sich der Übergang als ein einziger Block mit zwei Tönen. */
  box-shadow: inset 1px 0 0 var(--canvas), inset -1px 0 0 var(--canvas);
}
/* ⛔ EINE LAUFENDE BUCHUNG BEKOMMT EINE OFFENE KANTE. Ihr rechtes Ende ist „jetzt" und keine
   gebuchte Zeit; ein glatter Abschluss behauptete einen Feierabend, den es nicht gibt.
   Eine gestrichelte Kante und kein Farbverlauf: der Verlauf braucht `mask-image` mit Präfix und
   sähe auf einem Lagertablet ohne Unterstützung wie ein abgeschnittener Block aus — also genau
   wie das, wogegen er gebaut wäre. */
.tl-block[data-laeuft] { border-right: 2px dashed var(--canvas); }
.tl-luecke {
  background: repeating-linear-gradient(135deg,
    var(--border) 0 3px, transparent 3px 7px);
}
/* Die Stundenmarken. ⛔ `translateX(-50%)` an jeder Marke, damit die Beschriftung unter ihrem
   Strich steht und nicht daneben; die erste und die letzte laufen dadurch ein Stück über die Bahn
   hinaus — das ist richtig so, sie gehören zur Achse und nicht in den Kasten. */
.tl-marken {
  position: relative; height: 16px; margin-top: 2px;
  font-size: var(--fs-micro); color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.tl-marke { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }

.legende-tl-arbeit { background: var(--primary); }
.legende-tl-pause { background: var(--badge-warn-bd); }
.legende-tl-luecke {
  background: repeating-linear-gradient(135deg,
    var(--border) 0 3px, var(--sunken) 3px 7px);
  border: 1px solid var(--border);
}

/* ⛔ IM AUSDRUCK BLEIBT DIE LEISTE, ABER OHNE FLÄCHEN. Dieselbe Entscheidung wie beim Tagesbalken:
   ein Stundennachweis wird gelesen, und eine Farbfläche wird auf einem Schwarz-Weiß-Drucker zu
   einem grauen Klumpen. Unterschieden wird dann über die Füllung. */
@media print {
  .tl-bahn { border: 1px solid #999; background: none; }
  .tl-block[data-art="arbeit"] { background: #999; }
  .tl-block[data-art="pause"] { background: #ddd; box-shadow: inset 0 0 0 1px #999; }
  .tl-luecke { background: none; }
  /* ⛔ UND DIE LEGENDE ZEIGT, WAS DIE LEISTE ZEIGT. Ohne diese drei Zeilen trüge sie im Ausdruck
     weiterhin Markenblau und Bernstein, während die Leiste darüber grau und hellgrau druckt — eine
     Legende, die etwas anderes erklärt als das Bild, ist schlimmer als keine. */
  .legende-tl-arbeit { background: #999; }
  .legende-tl-pause { background: #ddd; border: 1px solid #999; }
  .legende-tl-luecke { background: none; border: 1px dashed #999; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DAS SCHUBFACH — ein Tag, ohne den Monat zu verlassen.

   ⛔ ES IST EIN ECHTES `<dialog>`. Escape, Fokusfalle, inerter Hintergrund und die Rücktaste des
   Telefons kommen damit vom Browser. Ein nachgebautes Overlay hätte davon im besten Fall die Hälfte.

   ⛔ ES SCHIEBT SICH VON RECHTS HEREIN UND NICHT VON UNTEN. Auf dem Telefon ist unten die
   Stempelleiste die wichtigste Fläche; ein Panel, das dort hochfährt, verdeckt sie im Moment des
   Öffnens. Unter 700 px wird daraus die volle Breite — ein 320 px breites Panel neben 40 px Rest
   ist keine Zweiteilung, sondern eine schlechte Vollseite.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.schubfach {
  margin: 0 0 0 auto;
  height: 100%;
  max-height: 100%;
  width: min(760px, 100%);
  max-width: 100%;
  padding: 0;
  border: none;
  border-left: 1px solid var(--border);
  background: var(--sunken);
  color: var(--text);
  box-shadow: var(--sh-hoch);
}

/* ⛔ `display` NUR AM GEÖFFNETEN DIALOG. Das Browser-Stylesheet setzt `dialog:not([open])` auf
   `display: none`; ein unbedingtes `display: flex` hier schlägt das und lässt das geschlossene
   Panel im Dokument stehen — mit `prefers-reduced-motion: reduce`, wo die Deckkraft-Regel unten
   nicht greift, sichtbar über der Seite. Gefunden hat das erst der Browser-Test: im Bild sah es
   richtig aus, weil die Deckkraft bei null lag. */
.schubfach[open] { display: flex; flex-direction: column; }
.schubfach::backdrop { background: rgb(16 22 30 / .38); }

/* ⛔ DIE BEWEGUNG HÄNGT AN `[open]` UND NICHT AN EINER KLASSE, die JavaScript setzt. `<dialog>`
   setzt das Attribut selbst; eine zweite Zustandsquelle daneben liefe beim Schließen über Escape
   auseinander — der Browser schlösse, und die Klasse bliebe stehen. */
@media (prefers-reduced-motion: no-preference) {
  .schubfach { transform: translateX(12px); opacity: 0; transition: transform .18s ease-out, opacity .18s ease-out; }
  .schubfach[open] { transform: none; opacity: 1; }
  .schubfach::backdrop { opacity: 0; transition: opacity .18s ease-out; }
  .schubfach[open]::backdrop { opacity: 1; }
}

.schubfach-kopf {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5);
  background: var(--canvas);
  border-bottom: 1px solid var(--border);
}
.schubfach-kopf h2 { margin: 0; font: 600 var(--fs-title)/1.25 var(--f-ui); flex: 1 1 auto; min-width: 0; }
/* ⛔ AUF DEM TELEFON BRICHT DER TITEL NICHT DREIZEILIG NEBEN „GANZE SEITE" UM: dort wird der Titel eine
   Stufe kleiner, und der Weg zur ganzen Seite trägt nur noch sein Wort ohne Polster. */
@media (max-width: 520px) {
  .schubfach-kopf { padding: var(--sp-3) var(--sp-4); }
  .schubfach-kopf h2 { font-size: var(--fs-sect); }
  .schubfach-wege .knopf-leise:not(.knopf-rund) { padding-left: var(--sp-2); padding-right: var(--sp-2); }
}
.schubfach-wege { display: flex; align-items: center; gap: var(--sp-2); flex: none; }
.schubfach-inhalt { padding: var(--sp-5); overflow-y: auto; flex: 1 1 auto; }
/* Die Karten im Schubfach liegen schon auf einer gehobenen Fläche — ein zweiter Schatten darauf
   macht daraus einen Stapel Papier. */
.schubfach-inhalt .karte { box-shadow: none; }

@media (max-width: 700px) {
  .schubfach { width: 100%; border-left: none; }
  .schubfach-inhalt { padding: var(--sp-4); }
}

/* Ein Schubfach ist Bedienung. Auf Papier hat es nichts zu suchen — und es ist beim Drucken
   ohnehin geschlossen. */
@media print { .schubfach { display: none; } }

/* Im Schubfach ist die Bahn schmaler als auf der Seite. ⛔ Ohne diese Zeile passen dort nur drei
   der vier Kennzahlen nebeneinander, und die vierte steht allein in einer zweiten Reihe — sie liest
   sich dann wie ein Nachtrag statt wie ein Viertel der Auskunft. */
.schubfach-inhalt .raster-vier { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DIE KENNZAHLKACHEL.

   Sie ist die erste Fläche, die auf jeder Übersichtsseite gelesen wird, und war bisher optisch
   dasselbe wie eine Textkarte. Jetzt trägt sie ihre eigene Form: weicher gerundet, mit einer
   ruhigen Kante links, die den Zustand führt.

   ⛔ DIE KANTE IST KEINE AMPEL. Sie steht im Markenblau, wenn es etwas zu zeigen gibt, und in der
   Grundlinie, wenn nicht — dieselbe Entscheidung wie beim Vorzeichen: die Ampel gehört dem
   Tagesstatus und dem Urlaubskonto, und ein grüner Rand an „gearbeitet: 148 h" wäre ein Urteil über
   eine Zahl, die keines verträgt.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.karte.kennzahl {
  border-radius: var(--r-4);
  padding: var(--sp-4) var(--sp-5);
  gap: 6px;
}
/* 20.10.2026: Die Kante links (3 px) ist einer Fläche gewichen: Die betonte Kachel (der Zwischenstand,
   die erste der Auswertung) trägt die zarte Fläche der Marke, die Kachel mit offenen Tagen die des Hinweises (Ocker). Beide sagen es auch in Worten:
   „Zwischenstand“ steht über der Zahl, „in der Tabelle markiert“ darunter. Ein Minus bekommt keine eigene Farbe (`data-vorzeichen` bleibt als Merkmal stehen). */
.karte.kennzahl[data-betont] { background: var(--heute-bg); border-color: var(--heute-rand); }

/* Der Zusatz unter dem Wert: eine Einordnung, kein zweiter Wert. ⛔ Kleiner und leiser als die
   Beschriftung darüber — zwei gleich laute Zeilen an einer Zahl sind eine zu viel. */
.kennzahl-zusatz {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  font: 600 var(--fs-micro)/1.5 var(--f-ui);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DAS GF-COCKPIT — DREI KACHELN ÜBER DER STEMPELUHR.

   Wer den Betrieb führt, soll ihn in unter einer Minute erfasst haben, ohne durch vier Menüpunkte
   zu klicken. Drei Fragen, drei Kacheln: wer ist da, was wartet auf mich, steht der Monat.

   ⛔ `auto-fit` MIT EINEM MINDESTMASS VON 20rem UND NICHT `repeat(3, 1fr)`. Bei zwei Kacheln (wer
   keinen Monatsabschluss fahren darf, bekommt die dritte gar nicht) blieben sonst 33 % der Bahn
   leer, und die Reihe sähe aus, als fehlte etwas. Auf einem Telefon fällt sie von selbst
   untereinander.

   ⛔ DIE KACHELN SIND `.karte` UND KEINE ZWEITE KARTENFORM. Sie erben Fläche, Kante, Rundung und
   Schatten von dort; was hier steht, ist nur die Anordnung. Eine eigene Kartenfassung liefe beim
   nächsten Design-Umbau von der ersten auseinander.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.gf-cockpit {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  margin-bottom: var(--sp-5);
  align-items: start;
}
.cockpit-kachel { margin-bottom: 0; }
/* ⛔ DER KOPF IST SEIT DEM AUFKLAPPER-UMBAU EIN ENKEL, KEIN KIND MEHR.
   Diese drei Regeln standen auf `> .karte-kopf` und trafen nach dem Einzug in das `<summary>`
   nichts mehr — die Kapsel rutschte an den Text heran, und der Kopf verlor seinen Abstand nach
   unten. Ein Selektor, der nichts trifft, meldet sich nicht; sichtbar war nur, dass die Kacheln
   „irgendwie enger" aussahen. */
.cockpit-kachel > summary > .karte-kopf { margin-bottom: var(--sp-3); align-items: center; }
.cockpit-kachel > summary > .karte-kopf > .badge,
.cockpit-kachel > summary > .karte-kopf > .pill { margin-left: auto; }
.cockpit-kachel .karte-hinweis { margin-bottom: 0; }
/* Der Weg am Fuß der Kachel — er steht nicht mehr im Kopf, weil ein Link in einem `<summary>`
   doppeldeutig ist (der Browser folgt ihm UND klappt um). */
.cockpit-wege { margin: var(--sp-3) 0 0; }

/* ── KACHEL 1: WER IST IM HAUS ──────────────────────────────────────────────
   ⛔ FORM STATT FARBE — dieselbe Regel wie bei „Wer ist da". Ein grüner Punkt am Namen eines
   Kollegen liest sich wie eine Bewertung dieses Menschen; die Ampel gehört dem Tagesstatus und dem
   Urlaubskonto. Unterschieden wird über gefüllt / halb / gestrichelt / offen, und die
   Gruppenüberschrift sagt dasselbe noch einmal in Worten — für alle, die die Form nicht
   unterscheiden. */
.puls-gruppe + .puls-gruppe { margin-top: var(--sp-4); }
.puls-gruppe > h3 {
  margin: 0 0 var(--sp-2);
  font: 600 var(--fs-micro)/1.4 var(--f-ui);
  letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}
.puls-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.puls-person {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) 0; min-width: 0;
}
/* ⛔ RUND UND NICHT ECKIG, ANDERS ALS IN „WER IST DA". Dort sitzt das Mal INNERHALB einer Pille und
   liest sich als Teil von ihr; hier steht es frei vor einem Namen, und ein leeres Quadrat an dieser
   Stelle sieht aus wie ein Haken, den jemand setzen soll. Die Unterscheidung bleibt dieselbe:
   gefüllt / halb / gestrichelt / offen — Form, keine Ampel. */
.puls-person .person-mal {
  flex: none; width: 10px; height: 10px;
  border: 1.5px solid var(--text-muted); border-radius: var(--r-full);
}
.puls-person[data-lage="arbeit"] .person-mal { background: var(--text); border-color: var(--text); }
/* Halb gefüllt: da, aber gerade nicht ansprechbar. */
.puls-person[data-lage="pause"] .person-mal {
  background: linear-gradient(90deg, var(--text) 50%, transparent 50%); border-color: var(--text);
}
.puls-person[data-lage="abwesend"] .person-mal {
  background: linear-gradient(135deg, var(--text-muted) 50%, transparent 50%); border-style: dashed;
}
.puls-name { font-size: var(--fs-ui); font-weight: 500; }
.puls-person[data-lage="nicht_da"] .puls-name { color: var(--text-muted); }

/* ── KACHEL 2: WAS AUF EINE ENTSCHEIDUNG WARTET ─────────────────────────────
   ⛔ DIE KNÖPFE STEHEN UNTER DEM TEXT UND NICHT DANEBEN. Nebeneinander sah es im Entwurf gut aus
   und im Betrieb nicht: die Kachel ist ein Drittel der Bahn breit, und neben zwei Knöpfen blieb für
   „Anna Arbeit · Urlaub" eine Spalte von einem Wort. Ein Name, der über sechs Zeilen läuft, ist
   keine Zusammenfassung mehr. Ein Raster aus zwei Spalten hält den Badge links und gibt Text und
   Knöpfen die volle Breite daneben.
   ⛔ KEIN `knopf-primaer`: die eine Primäraktion dieser Seite ist das Stempeln (Regel 1 im Kopf). */
.cockpit-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-3); }
.cockpit-posten {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-1) var(--sp-3);
  padding-bottom: var(--sp-3); border-bottom: 1px solid var(--row-line);
}
.cockpit-posten:last-child { padding-bottom: 0; border-bottom: none; }
.cockpit-posten > .avatar { grid-column: 1; grid-row: 1; margin-top: 2px; }
.cockpit-posten-text { grid-column: 2; min-width: 0; }
.cockpit-posten-text b { display: block; font: 600 var(--fs-ui)/1.35 var(--f-ui); }
.cockpit-posten-text small { display: block; color: var(--text-muted); font-size: var(--fs-dense); line-height: 1.4; }
.cockpit-posten-tun {
  grid-column: 2; display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
}
.cockpit-posten-tun form { margin: 0; }

/* ── KACHEL 3: WIE DER MONAT STEHT ──────────────────────────────────────────
   Der Satz trägt die Zahlen, die Kapseln darunter ihre Einordnung — und die Fußnote sagt, was
   „prüfbereit" hier wirklich geprüft hat. Eine Zahl, die mehr behauptet, als sie geprüft hat, ist
   beim zweiten Mal keine Zahl mehr. */
.cockpit-satz { margin: 0; font-size: var(--fs-ui); font-variant-numeric: tabular-nums; }
.cockpit-satz strong { font-weight: 600; }

/* Auf Papier hat ein Cockpit nichts zu suchen: es ist Bedienung, kein Nachweis. */
@media print { .gf-cockpit { display: none; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   ARBEITSZEITMODELLE: LISTE LINKS, EINE WOCHE RECHTS.

   ⛔ DAS AUSGEWÄHLTE MUSTER STEHT IN DER ADRESSE, NICHT IN JAVASCRIPT. Ein Klick lädt die Seite neu
   und der Stand steht im Verlauf des Browsers — man kann ihn verlinken, zurückgehen und ihn ohne
   Skript benutzen. Dieselbe Entscheidung wie beim Stempelformular: JS ist Aufwertung, nicht
   Voraussetzung.

   ⛔ AUF SCHMALEN FENSTERN FÄLLT DIE RECHTE SPALTE UNTER DIE LINKE und nicht daneben. Zwei Spalten
   zu je 170 px sind keine zwei Spalten, sondern zwei unlesbare Streifen.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.modell-split { display: grid; gap: var(--sp-4); grid-template-columns: minmax(16rem, 22rem) 1fr; align-items: start; }
.modell-liste { margin-bottom: 0; padding: var(--sp-3); }
.modell-liste > h2 { margin: var(--sp-2) var(--sp-2) var(--sp-3); font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.modell-wahl { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
/* Ein Eintrag ist ein Link auf dieselbe Seite mit anderem Suchteil. ⛔ `aria-current` und KEINE
   zweite Klasse daneben — zwei Behauptungen über denselben Zustand laufen beim ersten Umbau
   auseinander (dieselbe Regel wie in der Reiterleiste). */
.modell-wahl a {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3); border-radius: var(--r-3);
  color: var(--text); text-decoration: none;
  transition: background-color .15s ease-in-out;
}
.modell-wahl a:hover { background: var(--hover); text-decoration: none; }
.modell-wahl a[aria-current="true"] { background: var(--selected); }
.modell-wahl a[aria-current="true"] .modell-wahl-name { color: var(--rail-text-active); }
@media (prefers-reduced-motion: reduce) { .modell-wahl a { transition: none; } }
/* ⛔ `align-items: flex-start`. In einer Spalte streckt Flexbox jedes Kind auf die volle Breite —
   die Kapsel „Standard" wäre sonst ein Balken über den ganzen Eintrag statt einer Kapsel. */
.modell-wahl-text {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
}
.modell-wahl-name { font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.modell-wahl-text small { color: var(--text-muted); font-size: var(--fs-dense); line-height: 1.35; }
/* Die Kopfzahl: rechtsbündig und mit Tabellenziffern, damit zwei Modelle untereinander
   vergleichbar sind. Das Wort darunter, nicht daneben — sonst wandert die Zahl mit der Wortlänge. */
.modell-wahl-std {
  flex: none; display: flex; flex-direction: column; align-items: flex-end;
  font: 600 var(--fs-sect)/1.15 var(--f-ui);
  font-variant-numeric: tabular-nums; color: var(--text);
}
.modell-wahl-std small { color: var(--text-faint); font-weight: 400; font-size: var(--fs-micro); }

.modell-detail { margin-bottom: 0; }
/* ⛔ DIE WOCHE BEKOMMT EINEN DECKEL. Über die volle Breite der rechten Spalte gezogen sind die
   Balken so breit wie hoch — dann liest man Kästen und keine Mengen, und der Vergleich zwischen
   Montag und Mittwoch, für den die Grafik da ist, verschwindet. */
.modell-detail .wochenkarte { --wt-hoehe: 110px; margin: var(--sp-5) 0; max-width: 26rem; }
.modell-leute { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.modell-leute li { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-ui); }
.modell-leute .zeile-zusatz { display: inline; margin-left: auto; white-space: nowrap; }
/* Die Modelllosen hängen unter der Auswahlliste — der Kasten sitzt dort in einem <li> und braucht
   deshalb seinen Abstand von der Liste und nicht vom Fließtext. */
.modell-lose .hinweis { margin: var(--sp-3) 0 0; max-width: none; }
.modell-lose .modell-leute { margin-top: var(--sp-2); }

@media (max-width: 900px) {
  .modell-split { grid-template-columns: 1fr; }
  .modell-detail .wochenkarte { --wt-hoehe: 64px; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DIE EINRICHTUNGSLEISTE AN EINEM MITARBEITER.

   Drei Schritte, die vor dem ersten Arbeitstag stehen müssen: Stammdaten, Arbeitszeitmodell,
   Zugang. Bisher standen sie über die Liste verteilt — die Wochenstunden in der einen Spalte, das
   Passwort in der anderen —, und die Frage „ist der fertig eingerichtet?" beantwortete keine von
   beiden.

   ⛔ EIN ERLEDIGTER SCHRITT IST LEISE, EIN FEHLENDER NICHT. Drei gefüllte Kapseln an dreißig Zeilen
   sind dreißigmal dieselbe Auskunft und damit keine — was Arbeit macht, muss sich abheben.
   Erledigt tritt deshalb zurück, offen trägt den Warnton. Das ist eine Rangfolge, keine Ampel:
   die gehört dem Tagesstatus und dem Urlaubskonto.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
/* ── ABLEHNEN MIT BEGRÜNDUNG ────────────────────────────────────────────────
   ⛔ EIN <details> UND KEIN JAVASCRIPT. Die Maske öffnet und schließt wie jeder andere Aufklapper
   im Haus; die Prüfung selbst steht im Server, `required` ist nur die Bequemlichkeit davor.
   ⛔ GEÖFFNET NIMMT SIE DIE GANZE ZEILE. Nebeneinander bliebe für das Begründungsfeld eine Spalte
   von zwei Wörtern Breite — und eine Begründung, die nicht hineinpasst, wird keine. */
.ablehnen > summary { list-style: none; cursor: pointer; }
.ablehnen > summary::-webkit-details-marker { display: none; }
.ablehnen[open] { flex: 1 1 100%; }
.ablehnen[open] > summary { margin-bottom: var(--sp-2); }
.ablehnen > form { flex-wrap: wrap; }
.ablehnen > form input[type="text"] { flex: 1 1 18rem; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DAS REDESIGN VOM 30.08.2026 — DIE ANSICHTSBEZOGENEN BAUSTEINE

   Alles darueber ist der gemeinsame Bestand (Tokens, Karte, Knopf, Kapsel, Tabelle, Schiene).
   Was hier folgt, gehoert je einem Bereich der Anwendung und steht deshalb ZULETZT: mehrere dieser
   Regeln loesen eine Regel von weiter oben ab und gewinnen ausschliesslich ueber die Reihenfolge
   (die Formular-Controls und die Zaehlkapsel sind die beiden Faelle, an denen es haengt).
   ⛔ WER HIER ETWAS EINFUEGT, FUEGT ES ANS ENDE SEINES ABSCHNITTS EIN — nicht dazwischen.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */
/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   STARTSEITE — BEGRÜSSUNG, ZWEI-SPALTEN-RASTER, PULS ALS ZEILENKARTE, MONATSBALKEN

   Zum Einfügen in public/css/app.css, direkt beim Abschnitt „DAS GF-COCKPIT". Die Regeln setzen
   auf dem auf, was dort schon steht (.gf-cockpit, .cockpit-kachel, .puls-*, .cockpit-satz) und
   ersetzen nichts davon — außer den beiden am Ende ausdrücklich genannten Zeilen.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */


/* ── DIE BEGRÜSSUNG ÜBER DER SEITE ──────────────────────────────────────────────────────────────
   ⛔ DER ZWECK DER SEITE STEHT NEBEN DEM NAMEN UND NICHT DARUNTER. Der frühere Untertitel kostete
   rund 74 px und wurde genau deshalb entfernt (siehe Kommentar in views/dashboard.html). „Meine
   Zeit" muss trotzdem irgendwo stehen — sonst heißt die Seite für jeden Besucher nur noch „Guten
   Tag" und niemand weiß, was er hier vor sich hat. Auf einer gemeinsamen Grundlinie kostet der
   Zusatz keine einzige Zeile; erst wenn der Name zu lang wird, bricht er um.

   ⛔ 700 UND NICHT 600. Die Überschrift ist ab jetzt eine Ansprache und kein Etikett — sie darf
   fester stehen als jeder Kartentitel darunter. Die Größe bleibt --fs-h1: eine Ansprache ist keine
   Kennzahl. */
.seitenkopf-gruss {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3);
}
.seitenkopf-gruss > h1.gruss {
  margin: 0;
  font-weight: 700; letter-spacing: -.02em;
}
.seitenkopf-gruss > .gruss-zweck {
  margin: 0; color: var(--text-muted); font-size: var(--fs-ui);
}

/* ⛔ AUF DEM TELEFON IST DIE ANSPRACHE KLEINER — UND SIE BLEIBT STEHEN.
   Sie kostet dort mit `--fs-h1` (26 px) plus dem Abstand des Seitenkopfs rund fünfzig Pixel, und
   fünfzig Pixel sind auf einem 640-px-Schirm der Unterschied, ob der Stempelknopf noch im Bild
   ist. Sie ganz wegzublenden wäre die falsche Ersparnis: unter „Ansehen als" ist der Name die
   einzige Stelle, an der steht, WESSEN Seite man liest — die Zeile trägt eine Auskunft und nicht
   nur eine Begrüßung. Kleiner ja, weg nein. */
@media (max-width: 780px) {
  .seitenkopf-gruss { margin-bottom: var(--sp-3); }
  .seitenkopf-gruss > h1.gruss { font-size: var(--fs-title); }
}


/* ── DAS ZWEI-SPALTEN-RASTER DER STARTSEITE ─────────────────────────────────────────────────────
   Links, was den Betrieb betrifft; rechts, was den Menschen betrifft, der gerade davorsitzt.

   ⛔ DAS RASTER GILT NUR, WENN ES EIN COCKPIT GIBT — daher `[data-cockpit]` und keine Klasse für
   alle. Ein Mitarbeiter bekäme sonst eine 40-Prozent-Spalte mit seiner Uhr und 60 Prozent Leere
   daneben. Ohne das Attribut ist der Umschlag ein gewöhnlicher Block: die Seite steht dann Zeile
   für Zeile genau so, wie sie vorher stand — kein Grid, kein `gap`, keine verschobene Karte.

   ⛔ 900 px UND MIN-WIDTH. Darunter fällt alles untereinander, und zwar in der Reihenfolge des
   Markups: erst das Cockpit, dann die Uhr. Wer den Betrieb führt, öffnet die Seite wegen des
   Betriebs — das war schon die Entscheidung, als die Uhr unter das Cockpit rückte, und sie gilt
   auf einem Telefon unverändert weiter.

   ⛔ 3fr / 2fr UND NICHT 60% / 40%. Prozente rechnen den `gap` nicht mit; die Summe läge bei
   100 % + 20 px und die rechte Spalte liefe über die Bahn hinaus. */
@media (min-width: 900px) {
  .dashboard-raster[data-cockpit] {
    display: grid;
    grid-template-columns: 3fr 2fr;
    gap: var(--sp-5);
    align-items: start;
  }

  /* ⛔ IM RASTER STEHEN DIE DREI KACHELN UNTEREINANDER. `auto-fit` mit 20rem Mindestmaß ist für
     die volle Bahn gedacht; in einer 60-Prozent-Spalte zöge es auf einem breiten Monitor zwei
     Kacheln nebeneinander, und die schmalere von beiden bräche „Anna Arbeit · Urlaub" auf sechs
     Zeilen um. Die Überschreibung gilt deshalb ausschließlich INNERHALB des Rasters — außerhalb
     bleibt `auto-fit` das, was es war. */
  .dashboard-raster[data-cockpit] > .gf-cockpit {
    grid-template-columns: 1fr;
    margin-bottom: 0;
  }
}

/* Auf Papier ist das Cockpit ohnehin ausgeblendet; ohne diese Zeile bliebe im Ausdruck eine
   60-Prozent-Spalte stehen, in der nichts steht, und die Uhr stünde in der rechten Hälfte. */



/* ── DER TEAM-PULS ALS ZEILENKARTE ──────────────────────────────────────────────────────────────
   Name links, Zustand rechts. Die Kapsel trägt das Wort der Gruppenüberschrift, die Uhrzeit und
   den Ort — die drei Angaben, die die Frage „wen treffe ich gerade an?" vollständig beantworten.

   ⛔ DAS `.person-mal` BLEIBT STEHEN. Der Status hängt an der FORM (gefüllt / halb / gestrichelt /
   offen); die Kapsel kommt DAZU und ersetzt sie nicht. Dieselbe Zusage wie bei „Wer ist da".

   ⛔ UND DIE KAPSEL TRÄGT IMMER EIN WORT. Ein farbiger Punkt allein am Namen eines Kollegen liest
   sich wie eine Bewertung dieses Menschen — das Wort nimmt ihm die Zweideutigkeit. Die Töne sind
   die BADGE-Töne und nie die Ampel: die gehört dem Tagesstatus und dem Urlaubskonto. */
.puls-person { flex-wrap: wrap; }
/* ⛔ DAS MINDESTMASS AM NAMEN IST DAS, WAS DIE KAPSEL AUF SCHMALEN FENSTERN UMBRECHEN LÄSST.
   Ohne es schrumpft der Name (Flex-Elemente schrumpfen, bevor eine Zeile umbricht) und „Christian
   Schneider" stünde auf vier Zeilen neben einer Kapsel, die ganz bleibt. Mit ihm reißt die Zeile,
   die Kapsel rutscht darunter — und der Name, die Auskunft, die zuerst gelesen wird, bleibt heil. */
.puls-person > .puls-name { flex: 1 1 auto; min-width: 8rem; font-weight: 600; }
/* ⛔ RECHTSBÜNDIG ÜBER `margin-left: auto` UND NICHT ÜBER `justify-content: space-between`.
   Zwischen Mal, Avatar und Namen stehen feste Abstände; `space-between` verteilte die Reste auch
   dort und risse den Namen von seinem Bild los. */
.puls-kapsel { flex: none; margin-left: auto; max-width: 100%; }
/* Die zweite Uhrzeit (seit 08.10.2026): eine eigene Zeile UNTER der Kapsel, rechtsbündig wie sie —
   so liest sie sich als Zusatz zu ihr und nicht als Angabe zum Namen. */
.puls-zusatz { flex-basis: 100%; text-align: right; font-size: var(--fs-dense); color: var(--text-muted); }
/* ⛔ AUF DEM TELEFON DARF DIE KAPSEL UMBRECHEN. `.pill` hält ihren Inhalt sonst in einer Zeile —
   richtig für „Standard" oder „+2:00 h", falsch hier: „arbeitet seit 6:02 Uhr · Kommissionierung"
   trägt eine Kostenstelle, deren Länge in `app_settings` steht und nicht in dieser Datei. Über den
   Kartenrand hinauszulaufen ist die schlechtere Antwort als zwei Zeilen; die Kapselform bleibt. */
@media (max-width: 560px) {
  .puls-kapsel { white-space: normal; }
}


/* ── DER MONATSBALKEN ───────────────────────────────────────────────────────────────────────────
   ⛔ ALLE DREI ZUSTÄNDE ODER GAR KEIN BILD. Ein Balken, der nur „prüfbereit" füllt, behauptet für
   jedes abgeschlossene Konto ein Versäumnis — eine Anzeige, die einen Zustand verschweigt, lügt in
   einem Bild lauter als in einer Zahl. Prüfbereit, mit Klärfall und abgeschlossen teilen den Monat
   restlos auf; zusammen sind sie die Gesamtzahl.

   ⛔ BADGE-TÖNE, NICHT DIE AMPEL — und die Legende ist die `.badge-reihe` direkt darunter, mit
   denselben drei Tönen in derselben Reihenfolge. Drei Farben ohne Legende sind eine Ratefrage.

   ⛔ DIE BREITE KOMMT AUS `flex-grow` UND NICHT AUS EINEM PROZENTWERT. Die Vorlage gibt die
   ANZAHL mit (`--teil`), das Verhältnis rechnet der Browser. Eine Division in der Vorlage wäre
   eine Rechnung an einer Stelle, an der niemand nachrechnet — und bei null Konten eine durch
   null. Ein Segment mit dem Wert 0 bekommt `flex-grow: 0` und ist damit von selbst nicht da;
   deshalb steht hier auch kein `min-width`. */
.abschluss-balken {
  display: flex; overflow: hidden;
  height: 10px; margin-top: var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-full);
  background: var(--sunken);
}
.abschluss-balken > span { flex: var(--teil) 0 0%; }
.abschluss-balken > [data-art="bereit"]        { background: var(--badge-ok-bd); }
.abschluss-balken > [data-art="blockiert"]     { background: var(--badge-warn-bd); }
.abschluss-balken > [data-art="abgeschlossen"] { background: var(--badge-neu-bd); }
/* Der Balken sitzt zwischen Satz und Legende; ohne diese Zeile stünde die Legende doppelt so weit
   entfernt wie der Satz darüber und gehörte optisch nicht mehr dazu. */
.abschluss-balken + .badge-reihe { margin-top: var(--sp-2); }


/* ── FEINSCHLIFF IM COCKPIT ─────────────────────────────────────────────────────────────────────
   Untereinander gestellt fallen die Kartenköpfe auseinander: „Im Haus" trägt eine Kapsel (24 px),
   „Monat 07/2026" einen Knopf (38 px). Ein Mindestmaß am Kopf stellt die drei Überschriften auf
   dieselbe Grundlinie, ohne dass eine Kachel dafür Platz verschenkt. */
.cockpit-kachel > summary > .karte-kopf { min-height: 38px; }

/* ── DIE KACHEL ALS AUFKLAPPER ──────────────────────────────────────────────────────────────────
   ⛔ AUF DEM SCHREIBTISCH SIEHT MAN DAVON NICHTS. Der Kartenkopf war eine Überschrift und bleibt
   eine: kein Dreieck, kein Zeiger, kein Umbruch. Aufgeklappt ist der Regelfall, und das Skript in
   `dashboard.html` nimmt `open` nur auf schmalen Fenstern weg.

   ⛔ DER MARKER MUSS ZWEIMAL WEG. `list-style: none` deckt Firefox und die neueren Blink-Fassungen;
   `::-webkit-details-marker` ist der Weg für Safari, und Safari ist hier Zielgerät. Dieselbe
   Bauform wie bei `details.ablehnen`. */
.cockpit-kachel > summary { list-style: none; }
.cockpit-kachel > summary::-webkit-details-marker { display: none; }

/* Auf dem Telefon wird die Überschrift zum Bedienelement — und dann braucht sie auch das
   Fingermaß und einen sichtbaren Hinweis darauf, dass sich etwas öffnen lässt. */
@media (max-width: 780px) {
  .cockpit-kachel > summary { cursor: pointer; min-height: var(--control-h); }
  /* ⛔ EINE ZUGEKLAPPTE KACHEL IST EINE ZEILE, KEINE KARTE. Gemessen auf 390 px: mit dem Polster
     einer normalen Karte (`--sp-5` rundum) trug jede zugeklappte Kachel 90 px, die vier zusammen
     408 — mehr als die Uhr darunter. Zugeklappt gibt es nichts zu polstern: der Kopf IST der
     Inhalt. Die Trefferfläche bleibt trotzdem das Fingermaß, sie steckt in `min-height` am
     `<summary>` und nicht im Polster. */
  .cockpit-kachel:not([open]) { padding: 0 var(--sp-4); }
  .gf-cockpit { gap: var(--sp-2); }
  /* ⛔ EIN ZEICHEN UND KEINE IKONE. Die Ikonen des Hauses sind ein Nunjucks-Makro; ein Pfeil, der
     sich beim Aufklappen dreht, gehört zum Zustand des Elements und nicht in die Vorlage —
     dieselbe Entscheidung wie beim Chevron des Topbar-Menüs, nur ohne zweites Markup. */
  .cockpit-kachel > summary > .karte-kopf::after {
    content: '▾'; margin-left: var(--sp-2); color: var(--text-muted);
    transition: transform .15s ease; display: inline-block;
  }
  .cockpit-kachel[open] > summary > .karte-kopf::after { transform: rotate(180deg); }
  /* Zugeklappt ist der Kopf der ganze Inhalt — der Abstand darunter wäre dann Luft ohne Grund. */
  .cockpit-kachel:not([open]) > summary > .karte-kopf { margin-bottom: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .cockpit-kachel > summary > .karte-kopf::after { transition: none; }
}
/* Im Ausdruck steht alles offen — ein Papier klappt niemand auf. (`.gf-cockpit` wird ohnehin
   nicht gedruckt; die Regel steht hier für den Fall, dass sich das ändert.) */
@media print { .cockpit-kachel > summary > .karte-kopf::after { content: none; } }


/* ── DER KOLLISIONSHINWEIS AM ANTRAG ────────────────────────────────────────────────────────────
   ⛔ ER IST EIN `<small>` WIE DER RESTURLAUB DARÜBER UND KEINE EIGENE ZEILE MIT EIGENEM GEWICHT.
   Beide beantworten dieselbe Frage — „kann ich das genehmigen?" —, und zwei verschieden laute
   Antworten darauf lesen sich wie zwei verschiedene Wichtigkeiten.

   ⛔ DIE KAPSEL TRÄGT DEN TON, DER SATZ TRÄGT DIE AUSKUNFT. „Frei" bekommt den Grundton der
   Kapselform und keinen grünen: ein zweites Grün auf dieser Seite nähme dem Tagesstatus seines,
   und „niemand sonst ist weg" ist keine gute Nachricht über einen Menschen. Nur die Kollision hat
   eine Konsequenz und trägt deshalb den Warnton — dieselbe Unterscheidung wie bei der Zählkapsel
   in der Schiene („Eine Menge ist keine Warnung"). */
.kollision { display: block; margin-top: var(--sp-1); }
.kollision > .pill { margin-right: var(--sp-1); vertical-align: baseline; }
/* Eine Überschneidung in einem anderen Bereich kostet beim Genehmigen nichts — sie steht leise
   darunter, ohne Kapsel (`views/eingang.html`, seit 08.10.2026). */
.kollision[data-art="anderswo"] { color: var(--text-muted); }
.kollision-weg { display: block; margin-top: var(--sp-1); font-size: var(--fs-dense); }


/* ── DIE WOCHE DES TEAMS ────────────────────────────────────────────────────────────────────────
   Eine Zeile je Mensch: Bild, Name, Balken, Zahl, Lage. ⛔ SIE BORGT SICH DEN BALKEN AUS DER
   MONATSANSICHT (`.tagesbalken`, `.tb-*`) UND ERFINDET KEINEN ZWEITEN. Zwei Balkenfamilien mit
   denselben Tönen wären zwei Legenden für dasselbe Bild — und die eine, die jemand zu pflegen
   vergisst, wäre die falsche.

   ⛔ UND SIE BORGT SICH NICHT `.puls-person`. Die trägt über `.kacheln .person::after` ihre eigene
   Statuskapsel aus dem Stylesheet; hier stünde sie ein zweites Mal neben der echten. */
.wochenliste { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
.wochenzeile {
  display: flex; align-items: center; gap: var(--sp-3);
  padding-bottom: var(--sp-2); border-bottom: 1px solid var(--row-line);
}
.wochenzeile:last-child { padding-bottom: 0; border-bottom: none; }
.wochenzeile > .avatar { flex: none; }
/* ⛔ `min-width: 0` AM TEXTBLOCK. Ohne ihn wächst ein Flex-Element nicht unter seinen Inhalt, und
   die Kapsel rechts würde bei einem langen Namen aus der Karte geschoben statt umzubrechen. */
.wochenzeile-text { flex: 1 1 auto; min-width: 0; }
.wochenzeile-text b { display: block; font: 600 var(--fs-ui)/1.35 var(--f-ui); }
.wochenzeile-text small {
  display: block; color: var(--text-muted);
  font-size: var(--fs-dense); line-height: 1.4;
  font-variant-numeric: tabular-nums;
}
/* Der Balken sitzt zwischen Name und Zahl und bleibt schmal — er ist die Zugabe, die Zahl ist die
   Auskunft. Dieselbe Höhe wie in der Kennzahlkachel. */
.wochenzeile .tagesbalken { margin: 3px 0; }
.wochenzeile .tagesbalken-bahn { height: 6px; min-width: 0; }
.wochen-lage { flex: none; margin-left: auto; }
/* ⛔ AUF DEM TELEFON RUTSCHT DIE LAGE UNTER DEN NAMEN, statt ihn zu zerquetschen. Derselbe Grund
   wie bei `.puls-kapsel`: der Name ist die Auskunft, die zuerst gelesen wird. */
@media (max-width: 560px) {
  .wochenzeile { flex-wrap: wrap; }
  .wochen-lage { margin-left: 0; white-space: normal; }
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════
   IN app.css KÖNNEN DIESE BEIDEN REGELN ENTFALLEN — die Vorlage rendert `.puls-text` nicht mehr:
     .puls-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
     .puls-text small { color: var(--text-muted); font-size: var(--fs-dense); }
   Der Zusatz („seit 6:02 Uhr · Lager") steht jetzt in der Kapsel und nicht mehr in einem <small>
   unter dem Namen. `.puls-name` bleibt und bekommt oben sein Gewicht.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   MEINE ZEITEN — die vier neuen Bausteine der Monatsansicht.

   Einzufügen in public/css/app.css. Reihenfolge und Ort sind unten je Block genannt; keine der
   Regeln überschreibt eine bestehende, sie ergänzen sie.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */


/* ── 1. MEHRERE WEGE IM KARTENKOPF ──────────────────────────────────────────────
   Gehört direkt hinter `.karte-kopf > .knopf, .karte-kopf > a.knopf { margin-left: auto; }`.

   ⛔ `margin-left: auto` GILT JE KIND, NICHT EINMAL JE ZEILE. Mit zwei Knöpfen im Kartenkopf
   bekäme jeder von beiden seinen eigenen automatischen Rand, und der freie Platz verteilte sich
   zwischen ihnen — der erste stünde dann in der Mitte der Karte und sähe aus, als gehörte er zur
   Überschrift. Die Gruppe nimmt den Rand einmal und hält die Knöpfe beieinander.

   Auf einem schmalen Fenster bricht sie um, statt die Karte zu sprengen. */
.karte-kopf > .kopf-wege {
  margin-left: auto;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
}


/* ── 2. DER BALKEN IN DER KENNZAHL-KACHEL ───────────────────────────────────────
   Gehört hinter `.kennzahl-zusatz`.

   Es ist derselbe Balken wie in der Tageszeile — dieselben Klassen, dieselben drei Bedeutungen,
   dieselbe Legende. ⛔ EIN EIGENES VOKABULAR HIER WÄRE DIE ZWEITE ERKLÄRUNG FÜR DIESELBE SACHE:
   Markenblau bis zum Soll, die dunklere Fassung darüber, Schraffur für gedeckt. Er ist nur
   dünner, weil er unter einer Zahl steht und nicht neben ihr — als Achtpixel-Band zöge er den
   Blick von der Kennzahl weg, um die es auf der Kachel geht.

   Die Untergrenze der Bahn fällt weg: in einer Kachel gibt es keine Nachbarspalte, gegen die sie
   sich behaupten müsste, und mit 60 px Sockel bräche die Kachel auf dem Telefon um. */
.kennzahl .tagesbalken-bahn { height: 6px; min-width: 0; }


/* ── 3. DIE ZEITSPANNE EINES TAGES ──────────────────────────────────────────────
   Gehört hinter `.badge-punkt::before` — zu den Kapseln, deren Form sie teilt.

   ⛔ DIESELBE FORM, ABER KEIN BADGE-TON. Eine Uhrzeit ist eine Angabe und keine Bewertung. Die
   Badge-Töne sind auf dieser Seite dem Stand am Zeilenende vorbehalten (Abgeschlossen / Offen /
   Klärfall); ein blauer Chip in jeder der einunddreißig Zeilen wäre Farbe ohne Bedeutung, und
   danach fiele der Ton auch dort nicht mehr auf, wo er etwas sagt.

   ⛔ DER PUNKT NUR AM LAUFENDEN ABSCHNITT (seit 08.10.2026: „15:55 – jetzt"). `.badge-punkt` meldet
   einen laufenden Zustand; ein abgeschlossener Abschnitt ist keiner und trägt keinen. */
.zeitspanne {
  border-color: var(--border); background: var(--sunken); color: var(--text);
  font-weight: 500;
}

/* Datum, Spanne und der Zusatz darunter stehen übereinander. Nebeneinander wäre die Spalte
   doppelt so breit wie jede andere, und die Tabelle rollte auf jedem Laptop waagerecht.

   ⛔ DIE ZELLE SELBST BLEIBT EINE TABELLENZELLE. Ein `<td>` mit `display: flex` ist kein
   `table-cell` mehr und fällt aus der Spaltenberechnung; die Kopfzeile stünde danach über der
   falschen Spalte, und zwar nur in manchen Browsern. Die Kapsel nimmt sich ihre eigene Zeile
   deshalb selbst — `flex` statt `inline-flex` macht sie zum Block, `fit-content` hält sie
   trotzdem so schmal wie ihr Text. */
.tag-zelle .zeitspanne { display: flex; width: fit-content; margin-top: var(--sp-1); }

/* ⛔ SEIT DEM 08.10.2026 STEHEN DIE ABSCHNITTE SELBST DA, NICHT IHRE SPANNE (`zeitkonto.tagesabschnitte`).
   Untereinander und nicht nebeneinander — aus demselben Grund wie oben: drei Kapseln in einer Reihe
   machten die Tagesspalte breiter als die Tabelle. Ab vier stehen zwei da und der Rest hinter einem
   Aufklapper; so wird keine Zeile höher als drei Kapseln.
   ⛔ DIE PAUSE UNTERSCHEIDET SICH IN DER FORM, nicht im Ton: gestrichelte Kante, gedämpfte Schrift
   — und ihr Wort steht ohnehin davor. Eine Pause ist keine Bewertung, und ein Ton, der sie trüge,
   stünde in jeder zweiten Zeile des Monats. */
.tagesabschnitte { display: block; }
.tagesabschnitte .zeitspanne { margin-top: 2px; padding-top: 2px; padding-bottom: 2px; }
.tagesabschnitte .zeitspanne:first-child { margin-top: var(--sp-1); }
.zeitspanne[data-abschnitt="pause"] { border-style: dashed; border-color: var(--border-strong); color: var(--text-muted); }
.tagesabschnitte-mehr > summary {
  cursor: pointer; width: fit-content; margin-top: 2px;
  font-size: var(--fs-dense); color: var(--text-muted);
}

/* Auf Papier ist die Kapsel Dekoration: die Zeiten stehen dann in einer Tabelle mit Linien, und
   ein zweiter Rahmen um zwei Uhrzeiten druckt als grauer Kasten mitten in der Zeile. Der Text
   bleibt, die Form geht. */



/* ── 4. DAS SCHUBFACH FÜR DEN NACHTRAG ──────────────────────────────────────────
   Gehört hinter `.schubfach-inhalt .raster-vier`.

   Es teilt sich Form, Bewegung und Kopfzeile mit dem Tages-Schubfach — dieselbe Klasse
   `.schubfach`, dieselben Kinder. ⛔ NUR EINE ZEILE KOMMT DAZU: die Formularkarte wird beim
   Öffnen dorthin VERSCHOBEN und trägt ihren Kartenabstand mit; im Panel liegt sie aber schon auf
   einer gepolsterten Fläche, und der doppelte Rand ließe das Formular am unteren Rand kleben. */
#nachtragSchubfach .schubfach-inhalt > .karte { margin: 0; }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   URLAUB UND KALENDER — Nachtrag zu public/css/app.css.

   Die Regeln stehen in der Reihenfolge, in der sie in app.css eingefügt werden sollten:
   1) die Kalenderzellen  → direkt hinter den bestehenden `.balken`-Regeln (ca. Zeile 993),
   2) das Urlaubskonto    → hinter `.fortschritt-text` (ca. Zeile 1416),
   3) die Legendenfelder  → hinter den vorhandenen `.legende-*` (ca. Zeile 1477 bzw. 1524),
   4) der Druckblock      → als eigener `


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   2) DAS URLAUBSKONTO ALS BILD.

   ⛔ ES ZEIGT ALLE MENGEN, NICHT NUR „GENOMMEN". Wer drei genehmigte Wochen im November vor sich
   hat, sah im August einen fast leeren Balken — und plante danach. Vier Flächen, vier Zustände:
   genommen (angetreten), verplant (genehmigt, liegt noch vor uns), beantragt (noch nicht
   entschieden und deshalb noch nicht abgebucht) und frei.

   ⛔ KEINE AMPEL IN DEN FLÄCHEN, OBWOHL DAS URLAUBSKONTO SIE TRAGEN DÜRFTE. Die Ampel gehört dem
   KONTOSTAND, nicht seinen Bestandteilen: genommen, verplant und beantragt sind drei Mengen
   derselben Sache und keine Bewertung. Grün für „genommen" hieße, Urlaub sei gut und Rest schlecht.
   Unterschieden wird deshalb im Markenblau über die TEXTUR — dieselbe Entscheidung wie beim
   Monatsbalken, wo „gedeckt" die Schraffur von „gearbeitet" trägt.

   ⛔ UND „BEANTRAGT" TRÄGT GAR KEINE FARBE. „Noch nicht entschieden" ist keine Stufe von etwas,
   sondern das Fehlen einer Entscheidung — dieselbe Begründung wie bei `.balken.beantragt` im
   Kalender, nur mit dem Grauton, weil die Fläche hier nur 14 px hoch ist und ein heller
   Blauton auf `--sunken` darin nicht mehr zu erkennen wäre.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.urlaubskonto .fortschritt { margin-top: var(--sp-4); }

/* Dieselben vier Flächen zweimal: im Balken als `.fortschritt-teil`, in der Legende als
   `.legende-mal`. Eine gemeinsame Regel, damit die Legende nicht eines Tages etwas anderes
   erklärt, als der Balken zeigt. */
.konto-genommen { background: var(--primary); }
.konto-verplant {
  background: repeating-linear-gradient(135deg,
    var(--primary) 0 5px, var(--selected) 5px 10px);
}
.konto-beantragt {
  background: repeating-linear-gradient(135deg,
    var(--border-strong) 0 4px, var(--canvas) 4px 8px);
}
.konto-frei { background: var(--sunken); }
/* Die beiden hellen Felder brauchen in der Legende eine Kante — ohne sie steht dort auf der
   Karte (`--canvas`) ein unsichtbares Quadrat neben seinem Wort. Im Balken nicht: dort liegen
   sie in der Bahn und haben deren Kante. */
.legende-mal.konto-frei, .legende-mal.konto-beantragt { border: 1px solid var(--border); }


/* ── 3) DIE LEGENDENFELDER, DIE BISHER GEFEHLT HABEN ─────────────────────────
   ⛔ EINE LEGENDE NENNT ALLE ZUSTÄNDE DES BILDES, NICHT NUR DIE BUNTEN. Wochenende, Feiertag,
   „vor Eintritt" und „heute" sind Flächen wie jede andere — wer sie nicht erklärt bekommt,
   liest eine graue Spalte als Abwesenheit. Die Töne sind dieselben wie im Raster, damit die
   Legende keine zweite Fassung ist.

   ⛔ IM TEAMKALENDER GIBT ES DAZU KEINE GRUND-KATEGORIE. Er sagt „abwesend" und nie warum;
   Urlaub / Krankheit / anderes stehen ausschließlich in der Verwaltungsübersicht. Deshalb
   `legende-abwesend` als eigenes Feld und nicht `legende-urlaub` mit anderem Wort. */
.legende-abwesend { background: var(--selected); border: 1px solid var(--border-strong); }
.legende-wochenende { background: var(--border); border: 1px solid var(--border-strong); }
.legende-feiertag { background: color-mix(in srgb, var(--border-strong) 40%, var(--canvas)); border: 1px solid var(--border-strong); }
/* ⛔ DER PLANER AUF `/urlaub` HAT SEINE EIGENEN FLÄCHEN (`.monatsblatt td[data-frei]`, `[data-feiertag]`)
   — seine Legende trägt deren Töne, nicht die des Rasters. Die Legende ist keine zweite Fassung. */
.planer .legende-wochenende { background: var(--sunken); border: 1px solid var(--border); }
.planer .legende-feiertag { background: var(--hover); border: 1px solid var(--border); }
.planer .legende-beantragt {
  border: 1px dashed var(--border-strong);
  background: repeating-linear-gradient(45deg, var(--selected) 0 3px, transparent 3px 6px);
}
.legende-heute { background: var(--canvas); border: 2px solid var(--primary); }
.legende-ausserhalb {
  border: 1px solid var(--border-strong);
  background: repeating-linear-gradient(-45deg,
    var(--border-strong) 0 1px, var(--canvas) 1px 6px);
}

/* Unter 780 px steht das Raster nicht mehr da, sondern die Liste (`.kalender-schmal`).
   ⛔ Was dort keine Fläche mehr hat, hat auch keine Legende: ein Feld „Wochenende" neben einer
   Aufzählung erklärt ein Bild, das auf diesem Gerät gar nicht existiert. Die Balkenfelder
   bleiben nicht mehr: seit dem 08.10.2026 geht die Legende hier ganz (`legende-raster`), denn die
   Liste führt jeden Zustand in Worten und trägt keine Farbe (Round Table). */
@media (max-width: 780px) {
  .legende li.legende-nur-raster { display: none; }
  .legende.legende-raster { display: none; }
}


/* ── 4) AUF PAPIER ───────────────────────────────────────────────────────────
   Der Druck gibt Flächen standardmäßig nicht aus. Vom Urlaubsbalken bliebe ein leerer,
   gerundeter Kasten — und der liest sich wie „null von allem". Die Zahlen stehen ohnehin
   in der Legende daneben, deshalb geht auf Papier nichts verloren. */


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   ARBEITSZEITMODELLE — SAMMELDATEI (Abschnitt 5)

   Alles hier gehört in `public/css/app.css` in den Block „ARBEITSZEITMODELLE: LISTE LINKS, EINE
   WOCHE RECHTS" (dort ab `.modell-split`, heute Zeile ~2001). Vier Regeln ERSETZEN eine vorhandene
   Fassung — das steht jeweils über der Regel, samt dem Grund, warum die alte fiel. Der Rest kommt
   neu dazu. Der Druckblock am Ende gehört in den vorhandenen `


/* ── ERSETZT `.modell-wahl a[aria-current="true"]` ───────────────────────────
   Die Fläche allein trug den Zustand: `--selected` liegt nur wenige Prozent über dem Grund, und auf
   einem Lagertablet bei Schräglicht war die Auswahl schlicht nicht zu sehen. Der Ring zieht die
   Kante nach, die die Fläche nicht hergibt.

   ⛔ AM SELBEN SELEKTOR WIE DIE FLÄCHE — an `aria-current` und nicht an einer zweiten Klasse.
   Zwei Behauptungen über denselben Zustand laufen beim ersten Umbau auseinander; dieselbe Regel
   wie in der Reiterleiste, und `test/views.test.js` hält sie fest.

   ⛔ `var(--primary)` UND KEIN HEXWERT. Die Marke steht in `app_settings.design`; ein notierter
   Blauton bliebe nach dem ersten Wechsel unter Einstellungen → Design als einziger Rest der alten
   Marke stehen.

   ⛔ `inset`-SCHATTEN UND KEIN `outline`. Ein `outline` an diesem Selektor (0,2,1) schlüge die
   globale Fokusregel `:focus-visible` (0,1,0) — der ausgewählte Eintrag wäre dann der einzige ohne
   sichtbaren Tastaturfokus. Der Ring liegt innen und verschiebt deshalb auch nichts. */
.modell-wahl a[aria-current="true"] {
  background: var(--selected);
  box-shadow: inset 0 0 0 1px var(--primary);
}


/* ── ERSETZT `.modell-wahl-std` UND `.modell-wahl-std small` ─────────────────
   ⛔ DIE KOPFZAHL IST EINE MENGE UND TRÄGT JETZT DIE MENGEN-KAPSEL. Hier stand: „Das Wort darunter,
   nicht daneben — sonst wandert die Zahl mit der Wortlänge." Der Grund ist entfallen: das Wort ist
   in jeder Zeile dasselbe, und die Kapseln fluchten an ihrer RECHTEN Kante — ob 1 oder 12 darin
   steht, ändert nur, wo sie links beginnt. Geblieben ist die Aussage der Zahl: sie ist eine Menge
   und trägt deshalb `--zahl-*` und keinen Ampelton, genau wie `.rail-zahl`. „Sieben Mitarbeiter"
   ist weder gut noch schlecht.

   Maße, Gewicht und Abstand sind die der Kapselform (`.marke, .badge, .pill`) — eine zweite
   Pillenform im Haus wäre die erste Abweichung, die niemandem auffällt. */
.modell-wahl-std {
  flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px var(--sp-3); border-radius: var(--r-full);
  border: 1px solid var(--zahl-bd); background: var(--zahl-bg); color: var(--zahl-fg);
  font: 600 var(--fs-ui)/1.35 var(--f-ui);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Das Wort ist die Einheit der Zahl, kein zweiter Text: es erbt ihre Farbe und tritt nur im
   Gewicht zurück. Eine eigene Farbe daneben wären zwei Töne in einer Kapsel von drei Zentimetern. */
.modell-wahl-std small { color: inherit; font-weight: 500; font-size: var(--fs-micro); }


/* ── NEU: DER BEARBEITUNGSWEG IN DER RECHTEN SPALTE ──────────────────────────
   ⛔ ER IST BESCHRIFTET UND NICHT MEHR NUR EIN NAME. Hier stand je Mensch ein blauer Vorname;
   dass er auf das Änderungsformular führt, wusste nur, wer ihn schon einmal angeklickt hatte.
   Der Name bleibt der Weg zur Person, der Knopf daneben nennt die Handlung.

   ⛔ UND ER IST LEISE. Die Karte zeigt EIN Modell, das mehrere Menschen tragen — ein voller Knopf
   je Zeile wären fünf Hauptsachen untereinander, und die Seite hat keine (Regel 1: höchstens eine
   Primäraktion, und die liegt hier auf dem Änderungsformular, nicht in der Übersicht). */
.modell-detail .modell-leute .knopf {
  flex: none; margin-left: var(--sp-3);
  min-height: 30px; padding: 0 var(--sp-3);
  font-size: var(--fs-dense);
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DAS ÄNDERUNGSFORMULAR AM EINZELNEN MENSCHEN (`views/zeitmodell_detail.html`)
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die sieben Tage stehen in einem <fieldset class="feld staffel">: sie sind EINE Angabe in sieben
   Feldern. Ohne die Gruppe liest ein Screenreader siebenmal „Zahl" und nie die Frage dazu. */
.modell-tage {
  display: grid; gap: 0 var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
}
/* ⛔ DIE STUNDENFELDER FÜLLEN IHRE SPALTE. `.feld input[inputmode="decimal"]` ist im Haus 12 ch
   breit — richtig für ein einzelnes Feld im Fließtext, falsch für sieben nebeneinander: die Spalte
   ist schmaler als 12 ch, und die Felder ragten über ihre Zelle hinaus. */
.modell-tage .feld input[type="number"] { width: 100%; }
.modell-tage .feld { margin-bottom: var(--sp-3); }

/* ⛔ DIE LEGENDE DIESER STAFFEL IST KEIN SCHLÜSSELNAME. `.staffel > legend` steht im Haus in
   Schreibmaschinenschrift, weil die Pausenstaffel unter Einstellungen den DATENBANKSCHLÜSSEL trägt
   — dort ist die Schrift die Aussage „das ist ein Bezeichner, kein Satz". Hier steht ein deutscher
   Satz; in Monospace sähe er aus wie ein Feldname, den jemand zu übersetzen vergessen hat. */
.staffel.modell-woche > legend { font-family: var(--f-ui); }

/* Ein Hinweis, der zu der Tabelle darüber gehört, braucht seinen Abstand von ihr — `.hinweis`
   bringt nur einen nach unten mit. */
.modell-vorschau .hinweis { margin-top: var(--sp-4); }

/* Die Einheit hinter einer Zahl in einer Tabelle („40,00 h").
   ⛔ `--text-muted` UND NICHT `--text-faint`. `--text-faint` ist seit dem Kontrastumbau der Ton für
   PLATZHALTER — für Text, den man nicht liest, weil er noch keiner ist. Das „h" hinter der Zahl ist
   Teil der Aussage; in Platzhalterton gesetzt liest sich die Spalte, als fehlte dort etwas. */
.zahl-einheit { color: var(--text-muted); font-weight: 400; }


/* ── GEHÖRT IN DEN VORHANDENEN


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   MITARBEITER UND „WER IST DA" — die Regeln zu views/mitarbeiter.html,
   views/mitarbeiter_detail.html, views/mitarbeiter_formular.html und views/team.html.

   Einzufügen in public/css/app.css. Die Blöcke stehen in der Reihenfolge, in der sie im
   Stylesheet Sinn ergeben; jeder nennt oben, wohin er gehört.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [1] GEHÖRT ZU DEN KAPSELN — direkt hinter `.badge-ok` / `.badge-bad`.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ⛔ „LEISE" IST EINE EIGENE STUFE DER KAPSEL UND NICHT NUR EIN FALL DER EINRICHTUNGSLEISTE.
   Die Regel stand bisher als `.einrichtung .badge-fertig` und galt damit an genau einer Stelle.
   Gebraucht wird sie überall dort, wo ein Zustand ZUTRIFFT, aber nichts zu tun ist: „Aktiv" an
   achtundzwanzig von dreißig Zeilen. Gefüllt wäre das achtundzwanzigmal dieselbe Auskunft und
   damit keine — was Arbeit macht, muss sich abheben können.

   Gleiche Form, weniger Kontrast. Die Deklarationen sind wortgleich mit der bisherigen, engeren
   Fassung: bleibt jene stehen, ändert sich nichts. */
.badge-fertig {
  border-color: var(--border); background: transparent; color: var(--text-muted); font-weight: 400;
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [2] DIE EINRICHTUNGSLEISTE DER MITARBEITERLISTE GIBT ES SEIT DEM 08.10.2026 NICHT MEHR.
   Sie stand an jeder Zeile („1 Stammdaten · 2 Modell · 3 Zugang") und sagte dreißigmal „fertig".
   Was fehlt, steht jetzt als Warnkapsel in der Spalte, zu der es gehört (`routes/mitarbeiter.js`,
   `listenzeile`); die Regeln mit dem Zähler sind deshalb gelöscht und nicht stehengelassen.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die Zugangswege einer Zeile: kleine, ruhige Kapseln nebeneinander, die Warnung dahinter. */
.zugangswege { display: inline-flex; flex-wrap: wrap; gap: var(--sp-1); align-items: center; }
.zugangswege .pill { font-size: var(--fs-micro); }
.mitarbeiterliste-wert { font-variant-numeric: tabular-nums; }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [3] GEHÖRT ZUR MITARBEITERLISTE — hinter `.gitter td.mit-avatar`.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── DIE PERSONENZEILE ──────────────────────────────────────────────────────
   ⛔ ES BLEIBT EINE TABELLE. Sieben Spalten waren sieben gleich laute Auskünfte; wer eine Liste
   von dreißig Menschen liest, sucht aber zuerst den NAMEN und erst dann das Übrige. Rolle,
   Bereich, Anmeldename und Personalnummer stehen deshalb als zweite Zeile unter dem Namen — in
   derselben Zelle, nicht in vier eigenen Spalten. Was eine ZAHL ist (Wochenstunden), behält seine
   Spalte: Zahlen vergleicht man untereinander, nicht im Fließtext.

   Der Name trägt 600 und nicht die 500 aus `.gitter td > a`: er ist der Einstieg in die Zeile,
   der Rest ist Beiwerk. */
.personenzeile { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.personenzeile-name { font-size: var(--fs-ui); font-weight: 600; }

/* Mehrere Zustände an einem Menschen brechen um, statt die Spalte zu sprengen —
   „Anmeldung gesperrt" und „Scheidet aus" treten zusammen auf. */
.status-kapseln { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.gitter .status-kapseln .pill { font-size: var(--fs-micro); padding: 2px var(--sp-2); }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [4] GEHÖRT ZUR MITARBEITER-DETAILSEITE — hinter dem Kapsel-Block.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── DER PERSONENKOPF ───────────────────────────────────────────────────────
   Wessen Seite ist das? Der Name allein beantwortet die Frage erst beim Lesen; ein Bild
   beantwortet sie im Vorbeigehen. ⛔ DER FARBTON DES AVATARS BEDEUTET „DIESER MENSCH", NIE EINEN
   ZUSTAND — den tragen die Kapseln daneben, und zwar mit Wort. */
.personenkopf-oben { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }
.personenkopf-text { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.personenkopf-text > h1 { margin: 0; }
/* Der Weg in die Nur-Lese-Ansicht steht rechts und nimmt auf schmalen Fenstern die volle Zeile —
   der Satz über das Protokoll ist die eigentliche Aussage und darf nicht auf zwei Wörter Breite
   zusammenfallen. */
.personenkopf .seitenkopf-aktion { margin-left: auto; max-width: 24rem; }

/* ── DIE ECKDATEN ALS RASTER ────────────────────────────────────────────────
   ⛔ EIN RASTER UND KEINE TABELLE. Es sind Merkmale EINES Menschen, keine Zeilen, die man
   untereinander vergleicht — eine Tabelle mit einer Datenzeile behauptet einen Vergleich, den es
   nicht gibt. Beschriftung über dem Wert, weil die Werte verschieden lang sind und
   nebeneinandergesetzte Doppelpunkte sonst treppenförmig auseinanderlaufen. */
/* ⛔ `.eckdaten` UND NICHT `.datenraster` (seit 08.10.2026). Beide Bauformen hießen gleich: diese hier
   (Paare in `<div>`, Beschriftung über dem Wert) und die Liste aus Name und Wert weiter unten. Die
   zweite erbte von dieser den Spaltenabstand und den Abstand unter dem Namen — ihre Zeilenlinien
   rissen zwischen Name und Wert ab und lagen zwei Pixel versetzt (Postausgang, Resturlaub-Vorschau). */
.eckdaten {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  max-width: var(--bahn);
  margin: var(--sp-5) 0 0;
}
.eckdaten > div { min-width: 0; }
.eckdaten dt { font-size: var(--fs-dense); color: var(--text-muted); margin-bottom: 2px; }
.eckdaten dd { margin: 0; font-size: var(--fs-ui); font-weight: 500; overflow-wrap: anywhere; }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [5] GEHÖRT ZU „WER IST DA" — hinter `.kacheln .person-mal`.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── DAS WORT AN DER KACHEL ─────────────────────────────────────────────────
   ⛔ DIE KAPSEL STEHT IM STYLESHEET UND NICHT IN DER VORLAGE — und das ist keine Bequemlichkeit.
   Die Kachel wird an ZWEI Stellen gebaut: von `views/team.html` beim Seitenaufruf und von
   `public/js/radar.js` alle sechzig Sekunden neu. Stünde die Kapsel als Markup in der Vorlage,
   verschwände sie beim ersten Neuzeichnen — und niemand fände den Grund. Über `[data-lage]`
   hängt sie an dem einen Merkmal, das BEIDE Fassungen setzen; auseinanderlaufen können sie
   nicht.

   ⛔ SIE ERSETZT DAS `.person-mal` NICHT, sie kommt dazu. Der Status bleibt bei der FORM
   (gefüllt / halb / offen) — das ist die Zusage dieser Seite, seit es sie gibt. Das Wort ist für
   alle, die die drei Formen nicht auseinanderhalten, und für den flüchtigen Blick.

   ⛔ KEINE AMPEL UND KEIN GRÜN. Anwesenheit ist kein Zustand von gut nach schlecht; ein grünes
   „Anwesend" machte aus „nicht da" einen Vorwurf, und um 7:55 Uhr wäre die halbe Belegschaft rot.
   Unterschieden wird über den KONTRAST: anwesend steht am deutlichsten da, nicht da ruhig
   getönt, abwesend gestrichelt — dieselbe Rangfolge wie beim Mal daneben.

   ⛔ IMMER MIT WORT, NIE NUR EIN PUNKT. Ein farbiger Punkt ohne Wort ist eine Ratefrage; das
   Wort ist dasselbe wie in der Gruppenüberschrift darüber (ein Wort je Sache). */
.kacheln .person::after {
  content: "Nicht da";
  margin-left: auto; align-self: flex-start;
  display: inline-flex; align-items: center;
  padding: 2px var(--sp-2); border-radius: var(--r-full);
  border: 1px solid var(--badge-neu-bd); background: var(--badge-neu-bg); color: var(--badge-neu-fg);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); white-space: nowrap;
}
.kacheln .person[data-lage="arbeit"]::after {
  content: "Anwesend";
  border-color: var(--border-strong); background: var(--canvas); color: var(--text);
}
.kacheln .person[data-lage="abwesend"]::after {
  content: "Abwesend"; border-style: dashed;
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [6] GEHÖRT ZU DEN FORMULAREN — hinter `.reihenform input[type="text"]`.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ⛔ DER PLATZHALTER IST DIE EINE STELLE, AN DIE `--text-faint` GEHÖRT. Das Token trägt seinen
   Verwendungszweck im Namen und hatte bis hierher keine einzige Regel — der Platzhalter lief
   damit in der Browser-Vorgabe, und die ist im Dunkel-Theme fast so hell wie ein echter Wert.
   Ein Platzhalter, der aussieht wie ein Wert, ist ein ausgefülltes Feld, das keines ist. */
.feld input::placeholder,
.feld textarea::placeholder,
.reihenform input::placeholder { color: var(--text-faint); opacity: 1; }

/* ⛔ DIESELBE FOKUSKANTE AN ALLEN VIER CONTROLS. Sie galt bisher nur für `.feld input` und
   `.feld select`; `textarea` und die Felder der `.reihenform` — „Chip auflegen", „Terminal-PIN",
   der Sperrgrund — blieben beim ruhigen Grau. Der Fokusring aus `:focus-visible` liegt darüber;
   die Kante ist das, was beim Tippen stehen bleibt. */
.feld textarea:focus-visible,
.reihenform input:focus-visible,
.reihenform select:focus-visible { border-color: var(--focus); }

/* Das Kästchen ist ein Bedienelement und kein Schriftzeichen: 13 px sind auf einem Touchgerät
   kein Ziel. `accent-color` färbt den Haken in der Marke — dieselbe Farbe wie die Primäraktion,
   und keine der Ampel. */
.feld-schalter input[type="checkbox"] {
  width: 18px; height: 18px; margin: 0; accent-color: var(--primary);
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   [7] DIESE DREI ZEILEN GEHÖREN IN DEN BESTEHENDEN


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   MONATSABSCHLUSS UND LOHNEXPORT

   Neue Regeln für /abschluss, /abschluss/konto/:id und /lohnexport.
   Zum Einfügen in public/css/app.css. Kein Token wird hier definiert — alles kommt aus :root.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */


/* ── KARTENKOPF: DIE ERGÄNZUNGEN ────────────────────────────────────────────
   `.karte-kopf > .knopf` steht schon im Haus. Eine Kapsel rechts im Kopf gab es bisher nur an der
   Cockpit-Kachel (`.cockpit-kachel > .karte-kopf > .badge`) — dieselbe Absicht, nur enger gefasst
   als nötig. Sie gilt jetzt für jeden Kartenkopf: eine Zahl neben der Überschrift („12 Konten")
   ist dieselbe Sache wie ein Knopf daneben, nur ohne Handlung. */
.karte-kopf > .pill,
.karte-kopf > .badge,
.karte-kopf > .marke { margin-left: auto; }

/* ⛔ EIN KOPF MIT FORMULAR RICHTET MITTIG AUS, NICHT AUF DER GRUNDLINIE. `.karte-kopf` steht auf
   `baseline`, und das ist für Überschrift plus Knopf richtig. Sitzt rechts aber ein Formular mit
   beschrifteten Feldern („Jahr", „Monat"), legt `baseline` die Grundlinie der Überschrift auf die
   der Eingabefelder — die Überschrift rutscht sichtbar nach oben aus der Zeile. Der Umbruch ist
   Pflicht dazu: auf 360 px passt die Monatswahl nicht neben eine Überschrift. */
.karte-kopf.kopf-breit { align-items: center; flex-wrap: wrap; row-gap: var(--sp-3); }
.karte-kopf.kopf-breit > form { margin-left: auto; }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DER STAND EINES MONATS — KACHELN, BAHN, LEGENDE.

   Auf /abschluss und /lohnexport dieselbe Reihe: wie viele Konten stehen wo. Die Zahlen kommen aus
   der Route (`stand.teile`), gerechnet wird in dieser Datei nichts.

   ⛔ ALLE ZUSTÄNDE LIEGEN IN DER BAHN, NICHT NUR DER GUTE. Eine Bahn, die bei „12 von 30
   abgeschlossen" nur den fertigen Teil füllt und den Rest leer lässt, behauptet, der Rest sei
   gleichartig — er ist es nicht: prüfbereit und Klärfall sind zwei verschiedene Arbeiten. Dieselbe
   Begründung wie beim schraffierten Urlaubstag im Säulendiagramm: eine Anzeige, die einen Zustand
   verschweigt, lügt in einem Bild lauter als in einer Zahl.

   ⛔ BADGE-TÖNE UND NICHT DIE AMPEL. Das sind Kategorien einer Verwaltungsansicht und keine
   Bewertung; die Ampel gehört dem Tagesstatus und dem Urlaubskonto. Und drei Töne ohne Legende sind
   eine Ratefrage — sie steht deshalb unter jeder Bahn.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ⛔ DIE KACHELN LIEGEN AUF `--sunken`, OBWOHL SIE IN EINER KARTE STEHEN. Die Rollenverteilung
   bleibt dieselbe wie überall — der Grund liegt unter der Fläche —, nur eine Ebene tiefer: der
   Brieftext auf der Lohnexport-Seite macht es seit jeher genauso. Eine zweite Karte in der Karte
   wäre der Rahmen im Rahmen, und der macht aus einer Übersicht eine Maske aus Kästen. */
.stand-kacheln {
  display: grid; gap: var(--sp-3);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  margin-bottom: var(--sp-4);
}
/* ⛔ `align-items: flex-start`. In einer Spalte streckt Flexbox jedes Kind auf die volle Breite —
   die Kapsel „prüfbereit" wäre sonst ein Balken über die ganze Kachel statt einer Kapsel.
   (Dieselbe Falle wie bei `.modell-wahl-text`.) */
.stand-kachel {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  background: var(--sunken);
  border: 1px solid var(--karte-rand);
  border-radius: var(--r-3);
}
/* Die Zahl trägt die Kachel. ⛔ Die BESCHRIFTUNG ist hier die farbige Kapsel und nicht das kleine
   Versalien-Etikett der `.kennzahl`: sie benennt nicht nur, sie ordnet ein — und genau diese
   Einordnung führt die Bahn darunter fort. Zwei Beschriftungen an einer Zahl wären eine zu viel. */
.stand-wert {
  font: 600 var(--fs-kpi)/1.1 var(--f-ui);
  font-variant-numeric: tabular-nums; letter-spacing: -.02em;
}
.stand-zusatz { font-size: var(--fs-dense); color: var(--text-muted); line-height: 1.4; }

/* Die Bahn. Dieselbe Bauform wie `.fortschritt` im Mitarbeiterblatt — Abschnitte in einer Zeile,
   die Breite kommt als Prozentzahl aus der Route. ⛔ `overflow: hidden` ist keine Kosmetik: es ist
   die letzte Sicherung dagegen, dass ein gerundeter Prozentwert über die Kante schiebt. */
.standbalken {
  display: flex; height: 14px;
  border-radius: var(--r-full);
  background: var(--sunken);
  border: 1px solid var(--border);
  overflow: hidden;
}
/* ⛔ `flex: none`, SONST SCHRUMPFEN DIE ABSCHNITTE. Als normale Flex-Kinder gäben sie Breite ab,
   sobald die Trennkanten dazukommen — aus 40 % würden 39, und die Bahn zeigte andere Verhältnisse
   als die Kacheln darüber. Die Kante links trennt zwei Abschnitte, die sonst als einer gelesen
   würden; sie steht in der eigenen Tönung, damit sie im Dunkel-Theme mitkippt. */
.standbalken-teil { flex: none; height: 100%; border: 0 solid; border-left-width: 1px; }
.standbalken-teil:first-child { border-left-width: 0; }

/* Das Mal in der Legende trägt dieselbe Kante wie ein Balkenabschnitt — ohne sie verschwindet ein
   heller Ton auf weißem Grund, und die Legende erklärte dann ein leeres Quadrat. */
.legende-mal[data-art] { border: 1px solid; }

/* ⛔ EIN ZUSTAND, EIN TON, EINE STELLE. Kapsel, Balkenabschnitt und Legendenmal holen ihre Farbe
   aus derselben Regel — geführt über `data-art` und nicht über drei Klassennamen an drei Stellen.
   Getrennt gepflegt liefen sie beim ersten Palettenwechsel auseinander, und die Legende erklärte
   danach einen Ton, den die Bahn nicht mehr trägt. */
.pill[data-art="fertig"],
.standbalken-teil[data-art="fertig"],
.legende-mal[data-art="fertig"] {
  border-color: var(--badge-neu-bd); background: var(--badge-neu-bg); color: var(--badge-neu-fg);
}
.pill[data-art="bereit"],
.standbalken-teil[data-art="bereit"],
.legende-mal[data-art="bereit"] {
  border-color: var(--badge-ok-bd); background: var(--badge-ok-bg); color: var(--badge-ok-fg);
}
.pill[data-art="klaerfall"],
.standbalken-teil[data-art="klaerfall"],
.legende-mal[data-art="klaerfall"] {
  border-color: var(--badge-warn-bd); background: var(--badge-warn-bg); color: var(--badge-warn-fg);
}

/* ⛔ DER KLÄRFALL IST ZUSÄTZLICH SCHRAFFIERT — UND ZWAR NUR IN BAHN UND LEGENDE, NICHT IN DER
   KAPSEL. Drei Töne, die sich nur in der Sättigung unterscheiden, sind für jemanden, der Farben
   schlecht trennt, gar keine Auskunft; die Schraffur trägt, was keine Farbe trägt — dieselbe
   Antwort wie bei „beantragt" im Teamkalender. In der Kapsel steht ein Wort darauf: eine Schraffur
   unter Text macht ihn schwerer lesbar, und dort sagt das Wort ohnehin, was gemeint ist. */
.standbalken-teil[data-art="klaerfall"],
.legende-mal[data-art="klaerfall"] {
  background: repeating-linear-gradient(45deg,
    var(--badge-warn-bg) 0 4px, var(--badge-warn-bd) 4px 8px);
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DIE KLÄRLISTE — GRUND UND WEG, NICHT NUR DER GRUND.

   Bis hierher war das eine Aufzählung: „An 3 Tagen fehlt das Arbeitszeitmodell." Das sagt, was
   fehlt, und nicht, wo es einzutragen ist — bei dreißig Konten dreißigmal dieselbe Suche durchs
   Menü. Jeder Posten trägt jetzt seinen Weg; die Vorlage blendet ihn aus, wenn dem Angemeldeten
   das Recht dazu fehlt, statt ihn in eine 403 laufen zu lassen.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.klaerliste { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: grid; gap: var(--sp-2); }
.klaerliste > li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-2);
  font-size: var(--fs-dense); line-height: 1.45; color: var(--text-muted);
}
.klaer-person { color: var(--text); font-weight: 600; }
/* ⛔ Der Grund wird NICHT abgeschnitten. Er trägt die gemessene Angabe („An 3 Tagen …", „bis zum
   15.02."), und genau die sagt, was zu tun ist — ein Ellipsen-Punkt an ihrer Stelle machte aus
   einer Auskunft eine Ankündigung. `flex: 1 1 14rem` lässt ihn umbrechen statt kürzen. */
.klaer-grund { flex: 1 1 14rem; min-width: 0; }
.klaer-weg { white-space: nowrap; font-weight: 500; }

/* Dieselbe Liste auf einer ganzen Kartenbahn statt in einer Tabellenzelle: mehr Luft, Trennlinien
   und die Textgröße des Fließtexts. Die Struktur bleibt dieselbe — es ist eine Liste, keine zweite. */
.klaerliste-gross { gap: 0; margin-top: var(--sp-3); }
.klaerliste-gross > li {
  font-size: var(--fs-ui);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--row-line);
}
.klaerliste-gross > li:last-child { border-bottom: none; padding-bottom: 0; }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   WERTE, DIE JEMAND ABTIPPT.

   Beraternummer, Mandantennummer, Prüfsumme: Zahlen, die aus einer Mail der Steuerkanzlei kommen
   und in eine Mail zurückgehen. Eine vertippte Beraternummer bricht den Import nicht ab — sie
   schiebt die Datei in einen fremden Mandanten.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */
.wertliste { margin: var(--sp-3) 0 0; display: grid; gap: 0; }
.wertzeile {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--row-line);
}
.wertzeile:last-child { border-bottom: none; }
.wertzeile dt { flex: 0 0 12rem; font-size: var(--fs-ui); color: var(--text-muted); }
.wertzeile dd { margin: 0; display: flex; align-items: center; gap: var(--sp-2); }
/* ⛔ MONOSPACE UND GRÖSSER ALS DIE ZEILE. Es ist eine Ziffernfolge, die abgelesen und abgetippt
   wird; in einer Proportionalschrift verrutscht dabei genau die Stelle, an der 1 und 7 dicht
   beieinanderstehen. Derselbe Grund wie beim Zugangscode und beim Brieftext. */
.wertzeile code {
  font: 600 var(--fs-sect)/1.2 var(--f-mono);
  letter-spacing: .04em;
  -webkit-user-select: all; user-select: all;   /* Safari braucht den Präfix — und iOS ist Zielgerät. */
}

/* ⛔ DER KOPIERKNOPF STEHT NEBEN SEINEM WERT UND BLEIBT KLEIN. In einer Tabellenzeile verdoppelte
   ein Knopf in voller Höhe (38 px) die Zeilenhöhe des ganzen Protokolls. Er wird an einem
   Schreibtisch mit der Maus getroffen und nicht mit dem Daumen im Lager — das Fingermaß von 44 px
   gilt hier deshalb nicht, auch auf schmalen Fenstern nicht.
   ⛔ ER IST IM HTML `hidden` und wird von public/js/kopieren.js sichtbar gemacht: auf einem Gerät
   ohne Zugriff auf die Zwischenablage stünde er sonst da und täte beim Drücken nichts. */
.knopf-kopieren { min-height: 26px; padding: 0 var(--sp-2); font-size: var(--fs-micro); }
/* Wert und Knopf bleiben in einer Zeile — umgebrochen sähe der Knopf aus, als gehörte er zur
   nächsten Spalte. */
.spalte-kopierbar { white-space: nowrap; }
.spalte-kopierbar > code { margin-right: var(--sp-2); }


/* ── SCHMALE FENSTER ───────────────────────────────────────────────────────── */
@media (max-width: 780px) {
  /* Zwei Kacheln nebeneinander auf 360 px sind zwei Streifen. Die Zahl soll lesbar bleiben, also
     fällt die Reihe untereinander — dieselbe Antwort wie beim GF-Cockpit. */
  .stand-kacheln { grid-template-columns: 1fr; }
  /* Der Beschriftungsteil einer Wertzeile nimmt keine 12 rem mehr, sonst bleibt für die Zahl
     daneben eine Spalte von drei Ziffern. */
  .wertzeile dt { flex: 1 1 100%; }
}


/* ── DRUCK ─────────────────────────────────────────────────────────────────── */


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   ANTRÄGE, ZU TUN, PROTOKOLL — die Listenzeile und die Mengenkapsel.

   EINFÜGEN: hinter der Regel `.marke, .badge, .pill` (dort steht die Kapselform, auf der
   `.pill-zahl` aufsetzt) und vor dem globalen @media-print-Block wäre am saubersten — der
   print-Teil unten steht in einem eigenen @media und darf überall hin.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── DIE LISTENZEILE EINER ENTSCHEIDUNGSSEITE ───────────────────────────────────────────────────────
   ⛔ EINE ZEILE JE VORGANG, KEINE KARTE. Auf „Anträge" bekam bis hierhin jeder offene Antrag eine
   eigene `.karte` mit eigener Überschrift und einer vierzeiligen Tabelle darin. Bei sieben Anträgen
   waren das sieben Rahmen und sieben Überschriften für dieselbe Frage — die Seite las sich wie
   sieben Seiten, und die Reihenfolge, die dort die Dringlichkeit trägt, war nicht mehr zu sehen.
   Der Zweck der Seite ist eine Reihe von Entscheidungen; eine Reihe braucht Zeilen.

   ⛔ `.posten` STAND SEIT DEM ERSTEN ENTWURF IM MARKUP UND HATTE KEINE EINZIGE REGEL. Die Zeilen
   auf „Zu tun" sahen nur deshalb nach etwas aus, weil `.hinweis` danebenstand und seinen Kasten
   mitbrachte — die Nachtragszeile ohne ihn war ein Textabsatz. Was eine Klasse trägt, steht ab
   jetzt hier und nicht im Zufall.

   Drei Spalten: Farbmal des Menschen, was es ist, was zu tun ist. Die mittlere Spalte bekommt
   `minmax(0, 1fr)` und nicht `1fr` — sonst schiebt eine lange Begründung ohne Leerzeichen die
   Aktionsspalte aus der Karte, statt selbst umzubrechen. */
.posten {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: var(--sp-1) var(--sp-3);
  align-items: start;
}
/* Der Badge sitzt an der Oberkante des Namens und nicht an der der Zeile — dieselben zwei Pixel
   wie im Cockpit, aus demselben Grund: die Großbuchstaben darin haben oben mehr Luft als unten. */
.posten > .avatar { margin-top: 2px; }

/* ⛔ DIE TRENNLINIE NUR AN DER NACKTEN ZEILE. Ein Posten, der zugleich ein `.hinweis` ist (die
   Auffälligkeiten auf „Zu tun"), bringt Rahmen, Innenabstand und Außenabstand schon mit; eine
   zweite Linie darunter wäre ein doppelter Boden. `:not()` statt einer eigenen Klasse, weil sonst
   jede neue Zeile daran denken müsste, welche der beiden Fassungen sie ist. */
.posten:not(.hinweis) { padding: var(--sp-3) 0; border-bottom: 1px solid var(--row-line); }
.posten:not(.hinweis):last-child { padding-bottom: 0; border-bottom: none; }

/* ⛔ UND DER HINWEISKASTEN VERLIERT HIER SEINEN ZEILENDECKEL. `.hinweis` ist auf `--measure`
   begrenzt, weil er Fließtext trägt; diese Zeile trägt rechts eine Aktionsspalte, und die stünde
   dann mitten in der Karte statt an ihrem Rand. Zwei Maße, zwei Aufgaben — `--measure` begrenzt
   die Zeile, nicht die Fläche. */
.posten.hinweis { max-width: none; }

.posten-text { min-width: 0; }
/* Name, Art und Zustand stehen in einer Zeile und brechen gemeinsam um. */
.posten-kopf { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
/* ⛔ EINE ÜBERSCHRIFT UND KEIN FETTER TEXT — auch wenn sie wie fetter Text aussieht.
   Beim Umbau war aus dem `<h2>` je Antrag ein `<strong>` geworden: optisch dasselbe, und für eine
   Sprachausgabe der Unterschied zwischen „von Antrag zu Antrag springen" und „die ganze Seite
   durchlesen". Ein Posteingang ist eine Liste gleichrangiger Vorgänge; genau dafür sind
   Überschriften da. h3, weil die Karte darüber h2 trägt.

   ⛔ DIE KAPSEL STEHT IN DER ÜBERSCHRIFT, nicht daneben. Sie benennt den Vorgang mit — „Prüf Kraft,
   Urlaub" ist der Name des Antrags, nicht „Prüf Kraft". Daneben gestellt hieße die Überschrift nur
   noch nach dem Menschen, und bei zwei Anträgen derselben Person stünde zweimal dasselbe da.

   Die Größe bleibt --fs-ui: eine Überschrift ist hier eine Sprungmarke und keine Rangstufe. */
.posten-kopf > .posten-name {
  margin: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font: 600 var(--fs-ui)/1.35 var(--f-ui);
}
.posten-text > .zeile-zusatz { margin-top: 2px; }
/* Ein ganzer Satz in der Zeile — der über die Wirkung einer Stornierung etwa — bleibt auf
   Lesebreite. Er ist der einzige Fließtext hier drin. */
.posten-text > p { margin: var(--sp-2) 0 0; max-width: var(--measure); }

/* ⛔ DIE AKTIONEN RECHTS UND NICHT UNTER DEM TEXT — anders als im Cockpit, und der Unterschied
   ist die Breite. Die Cockpit-Kachel ist ein Drittel der Bahn breit; neben zwei Knöpfen bliebe
   dort für den Namen eine Spalte von einem Wort. Diese Seite hat die volle Bahn, und eine
   Warteschlange, in der alle Knöpfe an derselben Kante stehen, lässt sich von oben nach unten
   abarbeiten, ohne den Zeiger zu suchen.
   `flex` und nicht `grid`: die Ablehnungsmaske klappt mit `flex: 1 1 100%` in die volle Breite
   auf — das ist die Regel, die `.ablehnen[open]` schon mitbringt. */
.posten-tun {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
  gap: var(--sp-2);
}
.posten-tun form { margin: 0; }

/* Auf schmalen Fenstern fällt die Aktionsspalte unter die Zeile und beginnt links. Rechtsbündig
   unter einem linksbündigen Namen sähe aus, als gehörte sie zur nächsten Zeile. */
@media (max-width: 780px) {
  .posten { grid-template-columns: auto minmax(0, 1fr); }
  .posten-tun { grid-column: 1 / -1; justify-content: flex-start; }
}

/* ── DIE MENGENKAPSEL IM KARTENKOPF ────────────────────────────────────────────────────────────────
   Dieselbe Unterscheidung wie an der Schiene, nur eine Ebene weiter innen: eine MENGE („7 offen")
   trägt den ruhigen Markenton `--zahl-*` und sagt „hier liegt etwas", ohne etwas zu behaupten.
   Eine KONSEQUENZ — ein offener Klärfall, der den Monatsabschluss blockiert — trägt den Warnton
   über `data-art="verstoss"`. Wäre jede Zahl gelb, stünde an jedem Montagmorgen eine Warnung, die
   keine ist, und nach zwei Wochen sähe niemand mehr hin.
   ⛔ EIN AUFSATZ AUF `.pill` UND KEINE ZWEITE KAPSELFORM. Maße, Gewicht und Radius kommen von
   dort; hier stehen nur die drei Farben. */
.pill-zahl { border-color: var(--zahl-bd); background: var(--zahl-bg); color: var(--zahl-fg); }
.pill-zahl[data-art="verstoss"] {
  border-color: var(--badge-warn-bd); background: var(--badge-warn-bg); color: var(--badge-warn-fg);
}



/* ── WESSEN DATEN EINE PROTOKOLLZEILE BETRIFFT ─────────────────────────────────────────────────────
   Das Farbmal steht NEBEN dem Namen und nie statt seiner — es bedeutet „dieser Mensch" und trägt
   keine Aussage über die Zeile. In einer Liste aus achtzig Änderungen ist es das Einzige, woran
   sich „schon wieder derselbe" ohne Lesen erkennen lässt.
   `.protokoll-kopf` richtet an der Grundlinie aus; ein eigenes `inline-flex` hält Mal und Name
   trotzdem auf derselben Mitte. */
.protokoll-wer { display: inline-flex; align-items: center; gap: var(--sp-1); }


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   EINSTELLUNGEN · DOKUMENTE · KONTO · ANMELDUNG

   Neun Bausteine. Jeder ersetzt etwas, das vorher entweder als Inline-Style in einer Vorlage stand
   oder gar nicht dastand — siebzehn `style="…"` sind damit aus den Vorlagen verschwunden.

   ⛔ DIESER BLOCK GEHÖRT ANS ENDE VON app.css. Baustein 1 und 9 nehmen bestehende Regeln zurück
   (`.staffel input`, `.karte form > .feld > span`) und setzen sie enger neu. Sie haben dieselbe
   Spezifität wie die alten und gewinnen ausschließlich über die Reihenfolge — weiter oben
   eingefügt bewirken sie nichts, und zwar lautlos.

   ⛔ BEIM EINBAU IN app.css: zwei bestehende Regeln werden von hier abgelöst und können entfallen.
      Beide sind unten an ihrer Stelle namentlich genannt:
        · `.staffel input[type="text"]`      (Abschnitt „EINSTELLUNGEN: DIE PAUSENSTAFFEL")
        · `.farbfeld .probe`                 (Abschnitt „Farbwähler") — es gibt kein `.probe` im
          Markup; `views/_farbfeld.html` rendert keines. Tote Regel, seit es die Seite gibt.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */


/* ── 1 · EIN MASS FÜR ALLE BEDIENELEMENTE ────────────────────────────────────
   ⛔ DREI HÖHEN NEBENEINANDER WAREN ZWEI ZU VIEL. `.feld input` stand auf 38 px, die Felder in der
   Pausenstaffel auf 34, und die Sondertage-Tabelle trug überhaupt keine Regel — dort lieferte der
   Browser seine eigene Höhe und sein eigenes Kästchen. Auf einer Seite, die aus nichts als
   Eingabefeldern besteht, liest sich das als drei verschiedene Feldarten, und gemeint war keine
   davon.

   ⛔ DIE HÖHE IST EIN TOKEN UND KEINE ZIFFER AN FÜNF STELLEN. Die vierte Stelle wäre die, die beim
   nächsten Mal danebenliegt — dasselbe Argument, mit dem im Haus die Schriftgrößen aus dem Code
   verschwunden sind. Auf schmalen Fenstern wächst das Maß auf 44 px: dasselbe Fingermaß, das
   `.knopf` dort schon trägt, und derselbe Grund (ein Tablet im Lager, oft mit Handschuh). */

/* ⛔ UND HIER STAND DIE DRITTE AUFZÄHLUNG DERSELBEN TYPEN. Sie ist aus demselben Grund ersetzt wie
   die beiden oben: `[type="time"]` fehlte auch in ihr, und die sechs Zeitfelder im Nachtrag blieben
   auf ihrer Browserhöhe stehen — zwischen lauter Feldern, die das gemeinsame Maß tragen.
   `.farbfeld input[type="color"]` bleibt namentlich stehen: der Farbwähler ist genau der Fall, den
   der Ausschluss oben absichtlich auslässt, und er soll trotzdem dasselbe Maß haben. */
/* ⛔ UND HIER STAND DIE VIERTE. `.gitter-formular` zählte weiter `[type="text"]` auf, während
   die Regel darüber längst über Ausschlüsse geht — dieselbe Falle, nur eine Zeile tiefer. Sie
   schlug beim Monatsblatt zu (`views/schnellerfassung.html`): einunddreißig Zeilen mit je zwei
   `[type="time"]`-Feldern, und genau die blieben auf ihrer Browserhöhe stehen, neben einem
   Pausenfeld, das das Hausmaß trug. Ausschlüsse statt Aufzählung, damit ein neuer Feldtyp in
   einer Formulartabelle von selbst gestaltet ist.
   ⛔ `[type="hidden"]` KOMMT DAZU. Ein verstecktes Feld mit einer Mindesthöhe ist kein Fehler,
   solange es `display: none` trägt — aber es steht in dieser Aufzählung nur deshalb nicht,
   weil bisher keines in einer solchen Tabelle lag. */
.feld input:where(:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"])),
.feld select,
.gitter-formular input:where(:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]):not([type="hidden"])), .gitter-formular select,
.farbfeld input[type="color"] {
  min-height: var(--control-h);
}


/* ── 2 · EINE TABELLE, DIE EIN FORMULAR IST ──────────────────────────────────
   Pausenstaffel und Sondertage sind Tabellen, deren Zellen Eingabefelder tragen. An jedem einzelnen
   Feld stand `style="width:100%"` — achtmal dieselbe Anweisung, und die neunte fehlte bei der
   nächsten Zeile. Die Klasse steht deshalb an der TABELLE und nicht am Feld: was in einer solchen
   Zelle steht, füllt sie immer aus, und eine neue Spalte erbt das, ohne dass jemand daran denkt.

   ⛔ DIE SONDERTAGE-TABELLE HATTE BIS HIERHIN GAR KEINE KLASSE. Ihre Felder trugen die Kante des
   Browsers, nicht die des Hauses — auf derselben Seite, auf der die Pausenstaffel zwei Karten
   weiter die richtige trug.

   ⛔ KEIN ZEILEN-HOVER. `.gitter tr:hover td` hebt eine Zeile hervor, damit man sie beim Lesen
   nicht verliert. In einem Formular liest niemand Zeilen, und der Wechsel unter dem Zeiger sieht
   aus, als ließe sich die Zeile anklicken — sie lässt sich nicht. */
.gitter-formular td { padding: var(--sp-1) var(--sp-2); vertical-align: middle; }
.gitter-formular tr:hover td { background: none; }
.gitter-formular input:where(:not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]):not([type="hidden"])), .gitter-formular select {
  width: 100%; min-width: 8ch; padding: 0 var(--sp-2);
  border: 1px solid var(--border-strong); border-radius: var(--r-2);
  background: var(--canvas); color: var(--text);
  font: 400 var(--fs-ui)/1 var(--f-ui);
}
/* ⛔ EIN ZAHLENFELD BLEIBT SCHMAL, AUCH IN EINER TABELLE. Dieselbe Zusage wie bei
   `.feld input[inputmode="decimal"]`: ein Feld, dessen Breite nichts über den erwarteten Wert
   sagt, ist eine Einladung, das Falsche hineinzuschreiben. „30" in einem Kasten von einer halben
   Kartenbreite sieht aus, als fehle da noch etwas. */
.gitter-formular input[inputmode="decimal"],
.gitter-formular input[inputmode="numeric"] { width: 12ch; font-variant-numeric: tabular-nums; }

/* Eine Spalte nimmt den Rest der Breite, die anderen so viel, wie ihr Inhalt braucht. Ohne diese
   Zuweisung verteilt der Browser gleichmäßig — und dann ist das Feld für „Betriebsferien" so breit
   wie das für „12-24". Die Klasse sagt, WELCHE Spalte den Rest bekommt; feste Rem-Breiten an den
   übrigen wären dieselbe Aussage in drei Zahlen, die beim nächsten Spaltentitel nicht mehr passen. */
.gitter-formular th.weit { width: 100%; }

/* ⛔ AUCH IN DER TABELLE 16 px AUF SCHMALEN FENSTERN. Der Block bei 780 px kennt nur
   `.feld input` — die Sondertage-Tabelle steht außerhalb eines `.feld` und fiele als einzige
   Stelle der Anwendung wieder unter die Grenze, ab der iOS bei JEDEM Fokus hineinzoomt und danach
   nicht wieder heraus. Dominik pflegt die Betriebsferien auch vom Telefon aus. */
@media (max-width: 780px) {
  .gitter-formular input, .gitter-formular select { font-size: var(--fs-feld); }
}


/* ── 2b · DAS MONATSBLATT ────────────────────────────────────────────────────
   Eine Formulartabelle mit einunddreißig Zeilen (`views/schnellerfassung.html`): links der
   Papierzettel, rechts diese Tabelle. Sie erbt Höhe, Kante und Breite ihrer Felder von
   `.gitter-formular` — hier steht nur, was ein Blatt von einer Einstellungstabelle
   unterscheidet.

   ⛔ DER TAG OHNE SOLL TRÄGT DEN GRUND DER SEITE. Wochenende und Feiertag liegen auf
   `--sunken`, wie der Wochenendtag im Urlaubskalender — wer einunddreißig Zeilen abtippt,
   findet die Arbeitstage daran wieder, ohne die Wochentagskürzel zu lesen. Es ist KEIN
   Warnton: an einem freien Tag ist nichts falsch, und er bleibt ausfüllbar (wer am Samstag
   eingesprungen ist, steht auf dem Zettel).

   ⛔ UND KEINE AMPEL AN DER ZEILE. Die Spalte „Erfasst" sagt, was schon dasteht; ob das viel
   oder wenig ist, entscheidet nicht diese Seite (CLAUDE.md, „Eine Menge ist keine Warnung"). */
.blatt-tag {
  background: none; text-transform: none; letter-spacing: 0;
  font: 600 var(--fs-ui)/1.3 var(--f-ui); color: var(--text);
  white-space: nowrap;
}
.blatt-frei > th, .blatt-frei > td { background: var(--sunken); }
.blatt-stand { color: var(--text-muted); font-size: var(--fs-dense); }
/* Die Pausenspalte: „30" braucht keine Tabellenbreite. Dieselbe Zusage wie an
   `.gitter-formular input[inputmode="numeric"]`, nur enger — hier stehen höchstens drei
   Ziffern, und ein Feld, dessen Breite nichts über den erwarteten Wert sagt, ist eine
   Einladung, das Falsche hineinzuschreiben. */
.blatt input[inputmode="numeric"] { width: 6ch; }
/* ⛔ DIE ZEILE BLEIBT STEHEN, AUCH WENN SIE NICHTS AUFNEHMEN KANN. Ein fehlender Tag wäre ein
   Zählfehler beim Vergleich mit dem Zettel: wer „Mittwoch" sucht und den 15. nicht findet,
   verschiebt den Rest des Blatts um eine Zeile. Statt der Felder steht der Grund. */
.blatt-gesperrt { color: var(--text-faint); font-size: var(--fs-dense); font-style: italic; }


/* ── 3 · EIN FOKUSZUSTAND FÜR ALLE ───────────────────────────────────────────
   ⛔ `:focus-visible` UND NICHT `:focus`. Mit `:focus` leuchtet jedes Feld auch nach einem
   Mausklick auf; die Anzeige ist dann keine Auskunft mehr, sondern der Normalzustand.

   Der Ring selbst steht global im Kopf des Stylesheets und gilt Knopf, Link und Feld gleichermaßen
   — hier kommt nur die KANTE dazu, damit unter dem Ring auch das getroffene Feld als solches zu
   erkennen ist. Sie stand bisher an `.feld`-Feldern und sonst nirgends: in der Pausenstaffel, in
   der Sondertage-Tabelle und am Farbwähler blieb die Kante grau. */
.feld input:focus-visible, .feld select:focus-visible, .feld textarea:focus-visible,
.gitter-formular input:focus-visible, .gitter-formular select:focus-visible,
.farbfeld input:focus-visible {
  border-color: var(--focus);
}


/* ── 4 · HAKEN UND AUSWAHLKNÖPFE ─────────────────────────────────────────────
   Der native Haken ist in jedem Browser ein anderer: unter Windows ein blaues Quadrat, auf dem
   iPad ein Häkchen ohne Kasten, im Dunkel-Theme in der Systemfarbe statt in der Marke. Auf einer
   Seite, deren Felder alle dieselbe Kante und dieselbe Rundung tragen, ist er der einzige
   Fremdkörper.

   ⛔ 18 px UND NICHT GRÖSSER. Der Kasten steht neben einer 14-px-Zeile; ein 24er wäre kein besser
   treffbarer Haken, sondern ein Kasten. Die Trefferfläche ist ohnehin das <label> ringsum —
   `.feld-schalter` ist eines, über die ganze Zeile.

   ⛔ DAS HÄKCHEN IST AUSGESCHNITTEN UND KEIN BILD. Es trägt die Farbe der Fläche, auf der es liegt
   (`--canvas`), und stimmt damit in Hell, Dunkel und im Ausdruck ohne eine zweite Farbangabe —
   dieselbe Bauform wie bei den Ikonen mit `currentColor`.

   ⛔ DER AUSWAHLKNOPF STEHT HIER, OBWOHL ES HEUTE KEINEN GIBT. Er ist die zweite Hälfte derselben
   Form. Ohne ihn fiele das erste Einfachauswahlfeld auf den Systemhaken zurück — an einer Stelle,
   an der niemand mehr an dieses Stylesheet denkt, und neben einem Kästchen, das es nicht tut. */
.feld input[type="checkbox"], .feld input[type="radio"] {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; margin: 0;
  display: inline-grid; place-content: center;
  border: 1px solid var(--border-strong); border-radius: var(--r-1);
  background: var(--canvas); cursor: pointer;
}
.feld input[type="radio"] { border-radius: var(--r-full); }
.feld input[type="checkbox"]:checked, .feld input[type="radio"]:checked {
  background: var(--primary); border-color: var(--primary);
}
.feld input[type="checkbox"]::before {
  content: ''; width: 11px; height: 11px; transform: scale(0);
  background: var(--canvas);
  clip-path: polygon(14% 46%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 39% 71%);
}
.feld input[type="radio"]::before {
  content: ''; width: 8px; height: 8px; transform: scale(0);
  background: var(--canvas); border-radius: var(--r-full);
}
.feld input[type="checkbox"]:checked::before,
.feld input[type="radio"]:checked::before { transform: scale(1); }
.feld input[type="checkbox"]:disabled, .feld input[type="radio"]:disabled {
  opacity: .5; cursor: not-allowed;
}
/* Der Kasten sitzt auf der ERSTEN Zeile seiner Beschriftung und nicht in deren Mitte. „vereinbarung
   VorhandenSeit" bricht auf einer halben Bahn um; mittig ausgerichtet stünde der Haken dann
   zwischen den beiden Zeilen und gehörte sichtbar zu keiner. */
.feld-schalter { align-items: start; }
.feld-schalter > input[type="checkbox"], .feld-schalter > input[type="radio"] { margin-top: 2px; }


/* ── 5 · DIE FUSSZEILE EINER KARTE ───────────────────────────────────────────
   Die Gegenform zum `.karte-kopf`. Der Speichern-Knopf hing an jeder Karte etwas anders: mal
   direkt unter dem letzten Feld, mal mit einem `style="margin-top:…"` davor, in den Einstellungen
   in zwei Spalten nebeneinander. Genau dort ist „zu welcher Karte gehört dieser Knopf" eine echte
   Frage — eine Linie und ein gemeinsamer Abstand beantworten sie ohne ein Wort.

   ⛔ AUF PAPIER FÄLLT SIE WEG. Der Druckblock blendet `.knopf` aus; ohne diese Zeile bliebe ein
   leerer Streifen mit einer Linie darüber stehen — ein Kasten um nichts. */
.karte-fuss {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  justify-content: flex-end;
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--row-line);
}
/* Ein Hinweis in der Fußzeile steht links und schiebt die Handlung nach rechts. */
.karte-fuss > .karte-hinweis { margin: 0 auto 0 0; }
.karte-fuss form { margin: 0; }


/* ⛔ ZWEI KNÖPFE IM KARTENKOPF SIND EIN PAAR UND KEINE ZWEI EINZELNEN.
   `.karte-kopf > .knopf { margin-left: auto }` gilt jedem für sich; bei zweien verteilt Flexbox
   den freien Raum auf BEIDE Automargins, und der erste stünde in der Mitte der Kopfzeile — beim
   Jahreswechsel des Feiertagskalenders sähe „← 2025" aus wie eine zweite Überschrift. Die Hülle
   nimmt den Raum einmal und hält die beiden zusammen. */
.karte-kopf-tun { margin-left: auto; display: flex; flex-wrap: wrap; gap: var(--sp-2); }


/* ── 6 · DATENRASTER: NAME UND WERT, KEINE TABELLE ───────────────────────────
   „Beschäftigt seit — 01.03.2024" ist kein tabellarischer Zusammenhang, sondern ein Paar. Als
   <table> mit einer Kopfspalte links behauptete es eine Sortierung und einen Vergleich zwischen
   Zeilen, den es nicht gibt; die Etiketten standen in gesperrten Versalien da, als ließe sich
   danach gruppieren. Als <dl> ist es das, was es ist.

   ⛔ UND AUF DEM TELEFON FÄLLT ES UNTEREINANDER. Zwei Tabellenspalten auf 360 px sind zwei
   Streifen: links ein umgebrochenes Etikett, rechts ein umgebrochener Wert.

   ⛔ EIN PAAR BLEIBT AUF EINER SEITE. Diese Seite wird ausgedruckt („Was für mich gilt"); ein
   Wert, dessen Bezeichnung auf der Seite davor steht, ist keiner. */
.datenraster {
  display: grid; grid-template-columns: minmax(9rem, 15rem) 1fr; gap: 0;
  margin: 0; font-size: var(--fs-ui);
}
.datenraster > dt {
  margin: 0; padding: var(--sp-2) var(--sp-4) var(--sp-2) 0;
  font-size: var(--fs-dense); color: var(--text-muted);
  border-bottom: 1px solid var(--row-line);
  break-inside: avoid;
}
.datenraster > dd {
  margin: 0; padding: var(--sp-2) 0;
  min-width: 0; font-weight: 500; overflow-wrap: anywhere;
  border-bottom: 1px solid var(--row-line);
  break-inside: avoid;
}
.datenraster > dt:last-of-type, .datenraster > dd:last-of-type { border-bottom: none; }
/* Der Zusatz unter einem Wert ist schon als `.zeile-zusatz` definiert — er behält hier seinen
   Abstand nach oben, damit er nicht am Wert klebt. */
.datenraster > dd > .zeile-zusatz { margin-top: 2px; }

/* ⛔ 640 px UND NICHT DIE 780 DES HAUSES. Das ist hier kein Layoutwechsel der Hülle, sondern der
   Punkt, an dem neben einer 9-rem-Beschriftung kein lesbarer Wert mehr steht: „Wartezeit für den
   vollen Urlaubsanspruch" bricht dann dreizeilig um, und daneben stünde „6 Monate ab Eintritt" in
   einer Spalte von zwei Wörtern. Schon bei 780 gestapelt verschenkte die Seite auf einem kleinen
   Notebook dagegen die halbe Breite. */
@media (max-width: 640px) {
  .datenraster { grid-template-columns: 1fr; }
  .datenraster > dt { padding: var(--sp-3) 0 0; border-bottom: none; }
  .datenraster > dd { padding-top: 0; }
}


/* ── 7 · DIE ANMELDEKARTE ────────────────────────────────────────────────────
   Sie ist eine Karte wie jede andere — nur die einzige auf ihrer Seite. Also dieselbe Kante und
   dieselbe Rundung wie im Rest des Hauses, sonst ist die erste Fläche, die ein neuer Mitarbeiter
   sieht, die einzige, die anders aussieht.

   ⛔ `--sh-hoch` UND NICHT MEHR `--sh-pop`. `--sh-pop` bringt einen Ring mit (`0 0 0 1px`); auf dem
   kühlen Grund zeichnet der eine zweite, sichtbare Kante um die Karte, und eine Karte mit zwei
   Kanten sieht aus wie zwei Karten. Genau dieselbe Entscheidung ist bei `--sh-hoch` schon
   getroffen worden, als der Ring dort herausflog.

   ⛔ `--karte-rand` UND NICHT `--border`. `--border` trägt Haarlinien und Knopfkanten; die
   Kartenkante hat seit dem Kontrastumbau ihr eigenes Token, weil sie im Dunkel-Theme aufhellt
   statt abzudunkeln. Mit `--border` wäre die Anmeldekarte dort die einzige, die es nicht tut. */
.anmelden-karte { border-color: var(--karte-rand); box-shadow: var(--sh-hoch); }
/* Der Zusatz „team" hinter dem Firmennamen — dieselbe Bauform wie `.rail-brand small` und
   `.topbar-marke small`. Stand als Inline-Style in der Vorlage und trug damit als einzige der drei
   Stellen keine Schriftgröße aus der Skala. */
.anmelden-karte h1 small { color: var(--text-muted); font-weight: 500; font-size: var(--fs-dense); }
.anmelden-fuss { margin: var(--sp-5) 0 0; }


/* ── 8 · DIE FARBFELDER AUF DER DESIGN-SEITE ─────────────────────────────────
   ⛔ HIER STEHT NUR DIE DARSTELLUNG. Was gespeichert werden darf, entscheidet weiterhin allein die
   Prüfung im Server (`/^#[0-9a-fA-F]{6}$/`, routes/einstellungen.js) — eine zweite Prüfung im
   Stylesheet gäbe es nicht, und ein `pattern` im Markup ist Bequemlichkeit, keine Schranke.

   Der native Farbwähler zeichnet seine Probe mit einem eigenen Rand und einem Innenabstand: von
   44 × 38 px blieb ein Farbfleck übrig, umgeben von zwei Kanten — der des Browsers und der des
   Hauses. Auf der Seite, auf der man Farben BEURTEILT, ist das die falsche Reihenfolge: die Farbe
   soll die Fläche sein, die Kante nur ihr Abschluss.

   ⛔ BEIM EINBAU: `.farbfeld .probe` weiter oben kann entfallen — `views/_farbfeld.html` rendert
   kein `.probe`, die Regel hat nie etwas getroffen. */
.farbfeld input[type="color"] { padding: 2px; }
.farbfeld input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.farbfeld input[type="color"]::-webkit-color-swatch {
  border: none; border-radius: calc(var(--r-2) - 2px);
}
.farbfeld input[type="color"]::-moz-color-swatch {
  border: none; border-radius: calc(var(--r-2) - 2px);
}


/* ── 9 · DIE SCHREIBMASCHINENSCHRIFT GEHÖRT DEN SCHLÜSSELN ───────────────────
   ⛔ UND NUR IHNEN. `.karte form > .feld > span` setzt jede Feldbeschriftung in einer Karte mit
   Formular auf `--f-mono`. Gemeint waren die englischen Bezeichner aus `app_settings` — sie stehen
   bewusst so da, weil es die Namen sind, unter denen der Code sie liest. Getroffen hat die Regel
   aber auch „Bisheriges Passwort" und „Neues Passwort" im Konto: deutscher Fließtext in
   Schreibmaschinenschrift liest sich wie ein Wert und nicht wie eine Frage.

   Die Regel bekommt deshalb ihre Adresse — die Einstellungsgruppen. Zurückgenommen und einmal
   enger neu gesetzt, weil die alte Fassung in app.css oberhalb steht und nicht verschoben werden
   soll: sie erklärt an ihrer Stelle, warum es die Schrift überhaupt gibt. */
.karte form > .feld > span { font-family: inherit; }
/* ⛔ UND SEIT DEM 08.10.2026 AUCH UNTER EINSTELLUNGEN NICHT MEHR: dort stehen jetzt Klartext-
   Beschriftungen statt der Schlüssel, und für sie gilt dasselbe wie für das Konto. */

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DER DRUCK FUER DIE NEUEN BAUSTEINE — EIN BLOCK, NICHT ACHT.

   Die Tokens werden weiter oben im ersten @media print-Block zurueckgesetzt (Farben, Schatten);
   hier steht nur, was die neuen Bausteine auf Papier anders machen. Zwei Bloecke statt einem, weil
   der erste die TOKENS setzt und dieser die BAUSTEINE — und acht verstreute waeren die Fassung,
   bei der die neunte vergessen wird.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */
@media print {
  /* ── aus dashboard ── */
.dashboard-raster { display: block; }

  /* ── aus meinezeiten ── */
.zeitspanne { border: none; background: none; padding: 0; }

  /* ── aus urlaub ── */
  .urlaubskonto .fortschritt { display: none; }

  /* ── aus zeitmodelle ── */
  .modell-wahl a[aria-current="true"] { box-shadow: none; }

  /* ── aus mitarbeiter ── */
  /* Ein Weg, den man auf Papier nicht gehen kann. */
  .personenkopf .seitenkopf-aktion { display: none; }

  /* ── aus abschluss ── */
/* ⛔ DIE BAHN UND IHRE LEGENDE FALLEN WEG, DIE KACHELN BLEIBEN. Das ist kein verschwiegener
     Zustand: die Kacheln darüber tragen ALLE drei Zahlen mit ihren Wörtern, die Bahn trägt nur
     ihr Verhältnis. Auf Papier drucken drei blasse Tönungen als drei fast gleiche Graustufen —
     das Bild wäre dann eine Behauptung, die niemand mehr nachprüfen kann, und die Legende erklärte
     einen Ton, den man nicht sieht. */
  .standbalken, .legende-stand { display: none; }
  /* Eine Kachelreihe, die über einen Seitenumbruch fällt, ist auf Papier zweimal keine Übersicht. */
  .stand-kacheln { break-inside: avoid; }

  /* ── aus antraege ── */
/* ⛔ EINE AUFFÄLLIGKEIT IST KEIN BEDIENHINWEIS, SIE IST EIN BEFUND. Der Druckblock blendet
     `.hinweis` aus — richtig für Erklärkästen, falsch für diese Zeilen: auf Papier stand bisher
     „Arbeitszeitrecht: 3 offen" und darunter nichts. Die Zeile bleibt also stehen, ihre Tönung
     geht: Farbe ist auf Papier keine Bedeutung mehr, sondern ein grauer Kasten. */
  .posten.hinweis { display: grid; background: none; }
  /* Was man anklicken kann, gehört nicht auf Papier. */
  .posten-tun { display: none; }
  /* Eine Zeile, die über den Seitenumbruch fällt, verliert entweder ihren Namen oder ihren Grund. */
  .posten { break-inside: avoid; }

  /* ── aus einstellungen ── */
.karte-fuss { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   EINFÜHRUNG (29.09.2026) — Anmeldung, Zugangsbrief, Einrichtungsliste.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die Seiten vor der Anwendung (`views/schlicht.html`): links die Markenfläche, rechts die Karte.
   ⛔ DIE FLÄCHE TRÄGT DIE FARBE DER MENÜLEISTE (`--rail`), nicht eine eigene: wer sich anmeldet,
   landet danach in derselben Farbe — ein Haus, keine zwei. Der Verlauf kommt aus denselben Tokens. */
body.anmelden {
  display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  place-items: stretch; padding: 0; min-height: 100vh; background: var(--sunken);
}
.marke-flaeche {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; justify-content: center; gap: var(--sp-6);
  padding: var(--sp-8) clamp(32px, 7vw, 112px);
  background: linear-gradient(155deg, var(--rail-hover) 0%, var(--rail) 45%, var(--rail-border) 100%);
  color: var(--rail-text);
}
.marke-logo { width: min(420px, 82%); height: auto; position: relative; z-index: 1; }
.marke-zeile {
  position: relative; z-index: 1; margin: 0; max-width: 28rem;
  font: 500 var(--fs-sect)/1.5 var(--f-ui); color: var(--rail-text);
}
/* Der Spiralpfeil als Wasserzeichen: groß, hell, kaum sichtbar — Fläche, keine Aussage. */
.marke-wasserzeichen {
  position: absolute; right: -14%; bottom: -16%; width: 78%; opacity: .07; pointer-events: none;
  --logo-pfeil: var(--logo-schrift-hell);
}
.marke-wasserzeichen .logo-marke { width: 100%; height: auto; }
.anmelden-seite { display: grid; place-items: center; padding: var(--sp-6) var(--sp-4); }
.anmelden-karte { max-width: 400px; }
@media (max-width: 780px) {
  body.anmelden { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .marke-flaeche { padding: var(--sp-6) var(--sp-5); gap: var(--sp-3); }
  .marke-logo { width: 190px; }
  .marke-zeile { font-size: var(--fs-ui); }
  .marke-wasserzeichen { width: 55%; right: -8%; bottom: -30%; }
  .anmelden-seite { align-items: start; padding-top: var(--sp-5); }
}
.anmelden-wege {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  margin-top: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--row-line);
}

/* Der Zugangsbrief: auf dem Bildschirm Teil der Code-Karte, auf Papier das ganze Blatt. */
.zugangsbrief { margin-top: var(--sp-4); }
.zugangsbrief-gruss { font: 600 var(--fs-sect)/1.3 var(--f-ui); margin: 0 0 var(--sp-3); }
.code-wege { margin: var(--sp-4) 0 0; }
@media print {
  /* ⛔ LIEGT EIN ZUGANGSCODE AUF DER SEITE, DRUCKT NUR ER. Sonst käme das Mitarbeiterprofil mit aufs
     Blatt, das der Kollege in die Hand bekommt. */
  body:has(.code-karte) .inhalt > :not(.code-karte) { display: none; }
  .code-karte { border: none; }
  .code-karte .code { font-size: 32pt; letter-spacing: .12em; }
  .code-karte .code-einmal { display: none; }
}

/* Die Liste der Einrichtung — im Leitfaden-Fenster, auf /einrichtung und unter Einstellungen. */
.einrichtung-liste { list-style: none; margin: 0; padding: 0; }
.einrichtung-punkt {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-top: 1px solid var(--row-line);
}
.einrichtung-punkt:first-child { border-top: none; }
/* Dieselbe Rangfolge wie an der Einrichtungsleiste je Mitarbeiter: Erledigtes tritt zurück, Offenes
   trägt den Warnton der Badge-Familie — eine Rangfolge, keine Ampel. */
.einrichtung-mal {
  display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: 50%;
  border: 2px solid var(--badge-warn-bd); background: var(--badge-warn-bg); color: var(--badge-warn-fg);
}
.einrichtung-punkt[data-erledigt] .einrichtung-mal {
  border-color: var(--border); background: var(--sunken); color: var(--text-muted);
}
.einrichtung-punkt b { display: block; }
.einrichtung-punkt small { color: var(--text-muted); font-size: var(--fs-dense); }
.einrichtung-punkt[data-erledigt] b { color: var(--text-muted); font-weight: 500; }

/* ── DIE LEISTE AM UNTEREN RAND (nur schmale Fenster) ────────────────────────
   Die persönlichen Einträge unter dem Daumen, alles Weitere hinter „Mehr". Dieselben Einträge wie
   die Schiene, aus derselben Quelle (src/navigation.js). */
.unten { display: none; }
@media (max-width: 780px) {
  .unten {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    height: calc(var(--unten-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--canvas); border-top: 1px solid var(--border); box-shadow: var(--sh-pop);
  }
  .unten > .unten-eintrag, .unten-mehr { flex: 1 1 0; min-width: 0; }
  .unten-eintrag {
    position: relative; height: var(--unten-h);
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    color: var(--text-muted); font-size: var(--fs-micro); font-weight: 600; text-decoration: none;
    list-style: none; cursor: pointer;
  }
  .unten-eintrag::-webkit-details-marker { display: none; }
  .unten-eintrag span:not(.rail-zahl) { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .unten-eintrag[aria-current="page"], .unten-mehr[open] > .unten-eintrag { color: var(--primary); }
  .unten-eintrag[aria-current="page"]::before {
    content: ""; position: absolute; top: 0; left: 25%; right: 25%; height: 3px;
    border-radius: 0 0 var(--r-full) var(--r-full); background: var(--primary);
  }
  .unten-eintrag .rail-zahl { position: absolute; top: 6px; left: calc(50% + 6px); margin: 0; }
  .unten-blatt {
    position: fixed; left: var(--sp-3); right: var(--sp-3);
    bottom: calc(var(--unten-h) + env(safe-area-inset-bottom) + var(--sp-2));
    max-height: 70vh; overflow-y: auto; padding: var(--sp-2);
    background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-4);
    box-shadow: var(--sh-modal);
  }
  .unten-blatt a {
    display: flex; align-items: center; gap: var(--sp-3); min-height: var(--control-h);
    padding: 0 var(--sp-3); border-radius: var(--r-3); color: var(--text); text-decoration: none;
  }
  .unten-blatt a[aria-current="page"] { background: var(--selected); color: var(--primary); font-weight: 600; }
  .unten-blatt .rail-zahl { margin-left: auto; }
}
@media print { .unten { display: none; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   BETRIEBSSTART (03.10.2026) — Testdaten löschen, Echtbetrieb starten.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die Kapsel in der Kopfleiste. ⛔ DER WARNTON IST HIER EINE KONSEQUENZ, KEINE MENGE: solange sie
   steht, lässt sich jede Buchung restlos löschen. Sie führt dorthin, wo das endet. */
.testphase-kapsel { text-decoration: none; }
.testphase-kapsel:hover { text-decoration: none; filter: brightness(.97); }

.betriebsstart-raster { display: grid; gap: var(--sp-4); align-items: start; }
.betriebsstart-raster > .karte { margin-bottom: 0; }
@media (min-width: 1000px) { .betriebsstart-raster { grid-template-columns: 3fr 2fr; } }

.zweispaltig { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); margin-bottom: var(--sp-4); }
.kleintitel {
  margin: 0 0 var(--sp-2);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-muted);
}

/* Name links, Zahl rechts — eine Aufstellung, keine Tabelle. Eine Null tritt zurück: sie ist da,
   damit niemand fragt, ob die Tabelle vergessen wurde, und nicht, damit man sie liest. */
.mengenliste, .hakenliste { list-style: none; margin: 0; padding: 0; font-size: var(--fs-ui); }
.mengenliste li {
  display: flex; justify-content: space-between; gap: var(--sp-3);
  padding: 6px 0; border-bottom: 1px solid var(--row-line);
}
.mengenliste li b { font-variant-numeric: tabular-nums; }
.mengenliste li[data-leer] { color: var(--text-muted); }
.mengenliste li[data-leer] b { font-weight: 400; }
.hakenliste li { display: flex; align-items: flex-start; gap: var(--sp-2); padding: 6px 0; }
.hakenliste .ikone { margin-top: 2px; color: var(--text-muted); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DER LEITFADEN (03.10.2026) — Hilfe und Einrichtung im Fenster unten rechts.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Der Fuß der Menüleiste: zwei Wege, die keine Menüeinträge sind. Er sitzt unten, abgesetzt durch
   eine Linie in der Farbe der Leiste — wer ihn sucht, findet ihn dort, wo er in jeder Anwendung steht. */
.rail-fuss {
  margin-top: auto; padding-top: var(--sp-4);
  display: flex; flex-direction: column; gap: 2px;
  border-top: 1px solid color-mix(in srgb, var(--rail-text) 14%, transparent);
}
.rail-fuss .rail-zahl { font-weight: 600; }

/* Wer das System gebaut hat — ganz unten und leiser als jeder Menüeintrag: kleine Schrift im Ton der
   Gruppenüberschriften. Das Logo trägt seine eigene Farbe; auf der Leiste liegt sie bei gut 4,5:1. */
.rail a.rail-support {
  flex-direction: column; align-items: flex-start; gap: var(--sp-2);
  margin-top: var(--sp-3); padding: var(--sp-3);
  color: var(--rail-section); font-size: var(--fs-micro); line-height: 1.45;
}
.rail-support img { width: auto; height: 28px; }

/* ⛔ KEIN `showModal`, ALSO AUCH KEIN BACKDROP. Das Fenster liegt neben der Arbeit, nicht davor.
   Breit genug, dass eine Antwort nicht in Zeilen aus vier Wörtern zerfällt — an einem Rechner sieht
   man daneben noch die Seite, auf dem Telefon füllt es die Breite ohnehin. */
.leitfaden {
  position: fixed; inset: auto var(--sp-5) var(--sp-5) auto; z-index: 70;
  width: min(32rem, calc(100vw - 2 * var(--sp-4)));
  max-height: min(82vh, 52rem);
  margin: 0; padding: 0;
  display: none; flex-direction: column;
  background: var(--canvas); color: var(--text);
  border: 1px solid var(--karte-rand); border-radius: var(--r-4);
  box-shadow: var(--sh-modal);
  overflow: hidden;
}
.leitfaden[open] { display: flex; }
.leitfaden-kopf {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--row-line);
}
.leitfaden-kopf > h2 { margin: 0; font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.leitfaden-wege { display: flex; align-items: center; gap: 2px; margin-left: auto; }
/* Mit Reitern ersetzt die Reiterleiste die Überschrift — beide zusammen sagten dasselbe zweimal. */
.leitfaden-kopf:has(.leitfaden-reiter) > h2 {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%);
}
.leitfaden-reiter { display: flex; gap: 2px; padding: 3px; border-radius: var(--r-3); background: var(--sunken); }
.leitfaden-reiter a {
  padding: 6px var(--sp-3); border-radius: var(--r-2);
  color: var(--text-muted); font: 600 var(--fs-dense)/1.2 var(--f-ui); text-decoration: none;
}
.leitfaden-reiter a:hover { color: var(--text); text-decoration: none; }
.leitfaden-reiter a[aria-current="page"] { background: var(--canvas); color: var(--text); box-shadow: var(--sh-karte); }
.leitfaden-inhalt { overflow-y: auto; overscroll-behavior: contain; }
.leitfaden-inhalt[aria-busy="true"] { opacity: .55; }
.leitfaden-abschnitt { padding: var(--sp-4); }
.leitfaden-fuss {
  position: sticky; bottom: 0;
  padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--row-line); background: var(--canvas);
}
.leitfaden-fuss .knopf { width: 100%; }
/* Dieselben Bausteine als ganze Seite. */
.leitfaden-seite { max-width: 48rem; padding: 0; }
.leitfaden-seite .leitfaden-fuss { position: static; border-radius: 0 0 var(--r-4) var(--r-4); }
@media (max-width: 780px) {
  .leitfaden {
    inset: auto var(--sp-3) calc(var(--unten-h) + env(safe-area-inset-bottom) + var(--sp-2)) var(--sp-3);
    width: auto; max-height: 72vh;
  }
}
@media print { .leitfaden, .rail-fuss { display: none; } }

/* Der Stand als Ring und Satz — im Fenster, auf der Seite und unter Einstellungen. Die Markenfarbe
   und nicht die Ampel: ein halb eingerichtetes System ist kein Verstoß, nur noch nicht fertig. */
.einrichtung-stand { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.einrichtung-stand b { display: block; font-size: var(--fs-body); }
.einrichtung-stand small { color: var(--text-muted); font-size: var(--fs-dense); }
.einrichtung-ring { flex: none; width: 40px; height: 40px; transform: rotate(-90deg); }
.einrichtung-ring .ring-bahn { stroke-width: 4; }
.einrichtung-ring .ring-wert { stroke: var(--primary); stroke-width: 4; }
.einrichtung-gruppe {
  margin: var(--sp-5) 0 var(--sp-1);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-muted);
}
.einrichtung-text { min-width: 0; }
.einrichtung-text small { display: block; line-height: 1.4; }
/* Der nächste Schritt: dort, wohin der Knopf am Fuß führt. */
.einrichtung-punkt[data-naechster] {
  margin: var(--sp-1) calc(-1 * var(--sp-3)); padding-inline: var(--sp-3);
  border: 1px solid color-mix(in srgb, var(--primary) 40%, transparent);
  border-radius: var(--r-3); background: var(--selected);
}
.einrichtung-punkt[data-naechster] + .einrichtung-punkt { border-top: none; }
/* Unter Einstellungen: nur der Stand und der Weg dorthin. */
.einrichtung-kurz { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.einrichtung-kurz .einrichtung-stand { margin: 0; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   STARTSEITE (03.10.2026) — die Stempelkarte als Hauptkarte, daneben Stundenkonto und Urlaub.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Ohne Cockpit trägt die rechte Spalte die ganze Seite: die Karte links, die Konten rechts. Mit
   Cockpit steht beides untereinander in der schmaleren Spalte. */
.dashboard-uhr { display: grid; gap: var(--sp-4); align-items: start; }
.dashboard-uhr > .stempeluhr { margin-bottom: 0; }
@media (min-width: 1000px) {
  .dashboard-raster:not([data-cockpit]) > .dashboard-uhr { grid-template-columns: minmax(0, 1.65fr) minmax(0, 1fr); }
}
.dashboard-raster:not([data-cockpit]) { margin-bottom: var(--sp-4); }

.stempeluhr { gap: var(--sp-4); }
.stempel-kopf { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--sp-1) var(--sp-4); }
.stempel-lage .text { font: 650 var(--fs-title)/1.25 var(--f-ui); letter-spacing: -.01em; }

/* Der Ring und die Werte des Tages nebeneinander — auch auf dem Telefon: untereinander läge der
   Knopf eine Bildschirmhälfte tiefer, und um den geht es auf dieser Karte. */
.stempel-mitte { display: flex; align-items: center; gap: var(--sp-5); }
.stempel-werte { flex: 1; min-width: 0; display: grid; gap: var(--sp-3); margin: 0; }
.stempel-werte > div { display: grid; gap: 1px; padding-bottom: var(--sp-2); border-bottom: 1px solid var(--row-line); }
.stempel-werte > div:last-child { border-bottom: none; padding-bottom: 0; }
.stempel-werte dt {
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-muted);
}
.stempel-werte dd { margin: 0; font: 600 var(--fs-sect)/1.3 var(--f-ui); font-variant-numeric: tabular-nums; }
.stempel-werte dd .einheit { color: var(--text-faint); font-size: var(--fs-dense); font-weight: 400; }
.stempel-werte dd small { display: block; color: var(--text-muted); font-size: var(--fs-dense); font-weight: 400; }
.stempel-abschnitt { text-align: left; }

/* Der Tag bisher: dieselbe Leiste wie in der Tagesansicht, darunter jeder Abschnitt in einer Zeile. */
.stempel-heute { border-top: 1px solid var(--row-line); padding-top: var(--sp-4); }
.stempel-heute-kopf { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-2); }
.stempel-heute-kopf h3, .klaerfaelle-titel {
  margin: 0; font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-muted);
}
.stempel-heute-kopf a { font-size: var(--fs-dense); }
.stempel-heute .legende { margin-top: var(--sp-2); }
.abschnitte { list-style: none; margin: var(--sp-3) 0 0; padding: 0; font-size: var(--fs-ui); font-variant-numeric: tabular-nums; }
.abschnitte li { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--sp-3); padding: 4px 0; }
.abschnitt-art { min-width: 4.5rem; color: var(--text-muted); }
.abschnitte li[data-art="work"] .abschnitt-art { color: var(--text); font-weight: 500; }
.abschnitt-dauer { margin-left: auto; color: var(--text-muted); }
.abschnitte .zeile-zusatz { flex-basis: 100%; }

/* Die Seitenkarten: Auskunft und Weg in einem. */
.seitenkarten { display: grid; gap: var(--sp-4); align-content: start; }
.seitenkarten > .karte { margin-bottom: 0; }
.kurzkarte { display: grid; gap: var(--sp-3); }
.kurzkarte-kopf { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.kurzkarte-kopf > h2 { margin: 0; font: 600 var(--fs-sect)/1.3 var(--f-ui); }
.kurzkarte-kopf > a { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-dense); font-weight: 500; }
.kurzkarte-zeile { margin: 0; padding-top: var(--sp-3); border-top: 1px solid var(--row-line); font-size: var(--fs-ui); }
.kurzkarte-zeile .pill { margin-left: var(--sp-1); }
.kurzkarte-etikett {
  display: block; margin-bottom: 2px;
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}

/* Die Klärfälle in der Kachel „Zu entscheiden": eine Zeile je Fall, der Streifen trägt die Konsequenz. */
.klaerfaelle-titel { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-5); }
.klaerfaelle { list-style: none; margin: var(--sp-2) 0 0; padding: 0; }
.klaerfall {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2);
  border: 1px solid var(--row-line); border-left: 3px solid var(--text-faint); border-radius: var(--r-2);
}
.klaerfall[data-stufe="warn"] { border-left-color: var(--warn); }
.klaerfall-text { flex: 1; min-width: 0; }
.klaerfall-text b { display: block; font-size: var(--fs-ui); }
.klaerfall-text small { display: block; color: var(--text-muted); font-size: var(--fs-dense); line-height: 1.4; }

@media (max-width: 780px) {
  .stempel-lage .text { font-size: var(--fs-sect); }
  /* ⛔ IN DER SPALTE WIRKT `flex-basis` ALS HÖHE. Die Knöpfe stehen auf dem Telefon untereinander
     (siehe „Schmale Fenster"); ohne diese Zeile wurde „Pause starten" 14rem hoch. */
  .stempeluhr .stempel-knoepfe .knopf-gross { flex: none; }
  .stempel-mitte { gap: var(--sp-4); }
  .stempel-werte { gap: var(--sp-2); }
  .stempel-werte dd { font-size: var(--fs-ui); }
}

/* Die Hilfe im Leitfaden: Fragen als Aufklapper, die zur Seite oben, alles Weitere darunter. */
.hilfe-gruppe {
  margin: var(--sp-4) 0 var(--sp-2);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .09em; text-transform: uppercase;
  color: var(--text-muted);
}
.hilfe-gruppe:first-child { margin-top: 0; }
/* Jede Gruppe steht in ihrem eigenen Kasten (die Suche blendet ganze Gruppen aus) und ist damit dort
   das erste Kind — der Abstand zur Gruppe davor kommt deshalb von hier. */
.hilfe-block:not([hidden]) + .hilfe-block > .hilfe-gruppe { margin-top: var(--sp-4); }
.hilfe-titel { margin: var(--sp-3) 0 var(--sp-1); font: 600 var(--fs-ui)/1.35 var(--f-ui); }
.hilfe-frage { border-bottom: 1px solid var(--row-line); }
.hilfe-frage > summary {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  padding: var(--sp-2) 0; cursor: pointer; list-style: none;
  font-size: var(--fs-ui); color: var(--text);
}
.hilfe-frage > summary::-webkit-details-marker { display: none; }
.hilfe-frage > summary::before {
  content: ''; flex: none; width: 7px; height: 7px; margin-top: 7px;
  border-right: 1.75px solid var(--text-muted); border-bottom: 1.75px solid var(--text-muted);
  transform: rotate(-45deg); transition: transform .15s ease;
}
.hilfe-frage[open] > summary::before { transform: rotate(45deg); }
.hilfe-frage > p { margin: 0 0 var(--sp-2) calc(7px + var(--sp-2)); font-size: var(--fs-ui); color: var(--text-muted); line-height: 1.55; }
.hilfe-frage[open] { padding-bottom: var(--sp-1); }
.hilfe-thema { border: 1px solid var(--row-line); border-radius: var(--r-3); margin-bottom: var(--sp-2); }
.hilfe-thema > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3); cursor: pointer; list-style: none; font: 600 var(--fs-ui)/1.35 var(--f-ui);
}
.hilfe-thema > summary::-webkit-details-marker { display: none; }
.hilfe-thema[open] > summary { border-bottom: 1px solid var(--row-line); }
.hilfe-thema > .hilfe-frage { margin: 0 var(--sp-3); }
.hilfe-thema > .hilfe-frage:last-child { border-bottom: none; }
/* Dasselbe für die letzte SICHTBARE Frage, wenn die Suche die übrigen ausblendet — sonst stünde ihre
   Linie doppelt am Rahmen. Eigene Regel: wo `:has()` fehlt, fällt nur sie weg, nicht die darüber. */
.hilfe-thema > .hilfe-frage:not(:has(~ .hilfe-frage:not([hidden]))) { border-bottom: none; }
.hilfe-anzahl { color: var(--text-muted); font-size: var(--fs-micro); font-weight: 600; }
@media (prefers-reduced-motion: reduce) { .hilfe-frage > summary::before { transition: none; } }

/* Die Suche über der Hilfe. Ohne eigene `display`-Regel am Kasten — sonst wirkte `hidden` nicht, und
   ohne Skript stünde ein Feld da, das nichts tut. Die Lupe liegt im Feld und fängt keinen Klick. */
.hilfe-suche { margin-bottom: var(--sp-4); }
/* Während gesucht wird, behält das Fenster seine Höhe. Es hängt unten an; ohne das spränge seine
   Oberkante bei jedem Buchstaben mit der Zahl der Treffer auf und ab — samt dem Feld, in das man tippt. */
.leitfaden:has([data-hilfe][data-gesucht]) { height: min(82vh, 52rem); }
.hilfe-suche-feld { position: relative; margin-bottom: 0; }
.hilfe-suche-feld > .ikone {
  position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%);
  color: var(--text-muted); pointer-events: none;
}
.hilfe-suche-feld input { padding-left: calc(var(--sp-3) + 16px + var(--sp-2)); }
/* ⛔ DER STAND BLEIBT IM DOKUMENT, AUCH LEER. Eine Statusregion, die erst mit ihrem Text erscheint,
   wird von manchen Sprachausgaben nicht angesagt. Leer nimmt sie nur keinen Platz. */
.hilfe-suche-stand { margin: var(--sp-2) 0 0; font-size: var(--fs-dense); color: var(--text-muted); }
.hilfe-suche-stand:empty { margin: 0; }

/* Die Frage, auf die ein Fragezeichen gezeigt hat, leuchtet kurz auf — im Fenster über die Klasse aus
   `leitfaden.js`, auf der ganzen Seite über die Sprungmarke. Eine Farbe, die verblasst; keine
   Bewegung. Der Rand oben ist der Abstand, mit dem sie ins Bild rollt — auf der Seite steht dort die
   Topbar davor. */
@keyframes hilfe-hervor {
  from {
    background: color-mix(in srgb, var(--primary) 14%, transparent);
    box-shadow: 0 0 0 var(--sp-2) color-mix(in srgb, var(--primary) 14%, transparent);
  }
  to { background: transparent; box-shadow: 0 0 0 var(--sp-2) transparent; }
}
/* `--sp-2` UND NICHT MEHR: genau die Breite des Lichthofs. Darüber läge sonst ein angeschnittenes
   Stück der Zeile davor. */
.hilfe-frage { scroll-margin-top: var(--sp-2); border-radius: var(--r-1); }
.hilfe-frage.ist-hervorgehoben, .hilfe-frage:target { animation: hilfe-hervor 2s ease-out; }
.leitfaden-seite .hilfe-frage { scroll-margin-top: calc(var(--h-topbar) + var(--sp-3)); }

/* Wer weiterhilft, wenn die Hilfe es nicht tut — am Ende, unter einer Linie, auf dem Grund. */
.hilfe-kontakt {
  margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--row-line);
  font-size: var(--fs-dense); line-height: 1.5; color: var(--text-muted);
}
.hilfe-kontakt p { margin: 0 0 var(--sp-3); }
.hilfe-kontakt b { color: var(--text); }
.hilfe-kontakt-weg {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border-radius: var(--r-3); background: var(--sunken);
  color: var(--text-muted); text-decoration: none;
}
.hilfe-kontakt-weg:hover { background: var(--hover); text-decoration: none; }
.hilfe-kontakt-weg img { flex: none; width: auto; height: 28px; }
.hilfe-kontakt-adresse { color: var(--primary); font-weight: 600; white-space: nowrap; }
@media (max-width: 520px) { .hilfe-kontakt-weg { flex-direction: column; align-items: flex-start; } }
@media print { .hilfe-suche { display: none; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DAS FRAGEZEICHEN NEBEN EINER ZAHL ODER ÜBERSCHRIFT (04.10.2026) — `ikon.tipp()`, führt zur Frage
   im Leitfaden.

   Leise wie die Beschriftung, neben der es steht, bis man darauf zeigt. ⛔ KEIN `--control-h`: es
   steht IN einer Zeile — im Tabellenkopf, neben einer Beschriftung —, und 48 px lägen über dem Wert
   darunter; ein Tipp auf die Zahl öffnete die Hilfe. Sichtbar 24 px, die negativen Ränder halten die
   Höhe der Zeile; unter `pointer: coarse` wächst die Fläche unsichtbar auf 40 px (`::after`).
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */
.hilfe-tipp {
  display: inline-grid; place-items: center; vertical-align: middle;
  width: var(--sp-6); height: var(--sp-6); margin-block: -4px;
  border-radius: var(--r-full);
  color: var(--text-muted); text-decoration: none;
}
.hilfe-tipp:hover { background: var(--hover); color: var(--primary); text-decoration: none; }
.hilfe-tipp:focus-visible { color: var(--primary); border-radius: var(--r-full); }
@media (pointer: coarse) {
  .hilfe-tipp { position: relative; }
  .hilfe-tipp::after { content: ''; position: absolute; inset: calc(-1 * var(--sp-2)); border-radius: inherit; }
}
/* In einem Kopf aus Überschrift und Wegen gehört es zur Überschrift und nicht an den Rand: der Abstand
   des Kopfes gilt dem, was rechts steht. */
.karte-kopf > h2 + .hilfe-tipp,
.kurzkarte-kopf > h2 + .hilfe-tipp {
  display: inline-grid; align-self: center; margin: 0 0 0 calc(var(--sp-1) - var(--sp-4));
}
.kurzkarte-kopf > h2 + .hilfe-tipp { margin: 0 auto 0 calc(var(--sp-1) - var(--sp-3)); }
/* Im Tabellenkopf bleiben Wort und Fragezeichen zusammen — sonst rutscht es in einer schmalen Spalte
   allein in die zweite Zeile und steht dort wie eine eigene Überschrift. */
.gitter th:has(> .hilfe-tipp) { white-space: nowrap; }
/* Mit derselben Genauigkeit wie die Kopfregeln darüber — sonst bliebe im Ausdruck ein leerer Kasten. */
@media print { .hilfe-tipp, :is(.karte-kopf, .kurzkarte-kopf) > h2 + .hilfe-tipp { display: none; } }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   MEINE ZEITEN (03.10.2026) — der Kopf mit Monatswähler, die vierte Kachel, ruhigere Zeilen.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Für Sprachausgaben da, im Bild nicht: eine Spaltenüberschrift ohne sichtbares Wort. */
.nur-vorlesen {
  position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* Titel und Monat links, die Wege der Seite rechts — eine Zeile statt drei. Steht ein Satz darunter,
   bekommt er Luft zur Zeile. */
.seitenkopf-zeile + p { margin-top: var(--sp-2); }
.seitenkopf-zeile { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3) var(--sp-5); }
.seitenkopf-titel { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-5); }
.seitenkopf-titel > h1 { margin: 0; }
.seitenkopf-wege { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Der Monatswähler: zurück, der Monat, weiter — die Fläche dazwischen zeigt, wo man steht. */
.zeitwahl {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; border: 1px solid var(--karte-rand); border-radius: var(--r-full); background: var(--canvas);
  box-shadow: var(--sh-karte);
}
.zeitwahl .knopf-rund { min-height: calc(var(--control-h) - 6px); width: calc(var(--control-h) - 6px); }
.zeitwahl-wert { min-width: 9.5rem; padding: 0 var(--sp-2); text-align: center; font: 600 var(--fs-ui)/1 var(--f-ui); }
.zeitwahl-heute { margin: 0 var(--sp-2); font-size: var(--fs-dense); white-space: nowrap; }

/* Die vierte Kachel: was zu klären ist. Mit Klärfall trägt sie die Kante des Warntons — eine
   Konsequenz (er blockiert den Abschluss), keine Menge. Ohne steht der Haken als Form daneben. */
.karte.kennzahl[data-klaerung] { background: var(--badge-warn-bg); border-color: var(--badge-warn-bd); }
.kennzahl-vollstaendig .ikone { color: var(--text-muted); }

/* Die Zeilen: was noch kommt und was nichts zu sagen hat, tritt zurück. */
.tagesliste tr[data-kuenftig] td { color: var(--text-muted); }
.tagesliste tr[data-ruhig] td { color: var(--text-faint); padding-top: 4px; padding-bottom: 4px; }
.tagesliste tr[data-ruhig] .tag-zelle a { color: var(--text-muted); }
.tagesliste tr[data-klaerfall] .tag-zelle { box-shadow: inset 3px 0 0 var(--warn); }
.hinweis-zelle { min-width: 9rem; }
.hinweis-zelle > * + * { margin-left: var(--sp-2); }
.hinweis-zelle .zeile-zusatz { margin-left: 0; }
.hinweis-wort { color: var(--text); }
/* Die Kapseln brechen um, ohne sich zu berühren. */
.hinweis-zelle .pill { margin-block: 1px; }
/* ⛔ DIE BEGRÜNDUNG STEHT UNTER DEN KAPSELN, NICHT IN EINEM `title` (arbzg.hinweiseAmTag). Ihre Breite
   ist gedeckelt: geöffnet bestimmte sonst der längste Satz die Breite der Spalte, und die Tabelle
   finge an zu rollen. */
.hinweis-zelle .hinweis-gruende { display: block; margin-left: 0; max-width: 40ch; }
.hinweis-gruende > summary { padding: var(--sp-1) 0 0; }
.hinweis-gruende ul { margin: var(--sp-1) 0 0; padding-left: var(--sp-4); font-size: var(--fs-dense); color: var(--text-muted); }
.hinweis-gruende li + li { margin-top: var(--sp-1); }
/* ⛔ DAS FINGERMASS GILT AUCH FÜR DIE AUFKLAPPER DER ZEILE (CLAUDE.md, „Das Fingermaß hängt am
   Zeigegerät"). Die Regel für `.feinheit > summary` im Telefonblock steht weiter oben und würde von
   der engeren Fassung hier überstimmt — deshalb noch einmal, hier, für Telefon UND Tablet. */
@media (max-width: 780px), (pointer: coarse) {
  .hinweis-gruende > summary, .tagesabschnitte-mehr > summary { padding: var(--sp-3) 0; }
}
/* ⛔ AUF DEM TELEFON BRECHEN DIE KAPSELN DER ZEILE UM — wie `.puls-kapsel`. Sonst bestimmte die längste
   Kapsel („Pause 10:00 – 10:15 (15 min)") die Breite der Spalte, und die Tabelle rollte weiter als nötig. */
@media (max-width: 560px) {
  .tag-zelle .zeitspanne, .hinweis-zelle .pill { white-space: normal; }
}
.spalte-weg { width: 1%; white-space: nowrap; text-align: right; }
/* Der Weg einer Zeile ist ein kleiner Knopf, kein Textlink mehr (20.10.2026): „Korrigieren“ ein Stift, „Nachtragen“ eine Kapsel mit Plus.
   ⛔ DER STIFT STEHT NUR AM RECHNER ALLEIN – das Wort bleibt im Text (Sprachausgabe, Suche, Tastatur) und kommt auf dem Telefon wieder ins Bild:
   ein Stift allein wäre dort ein leerer Knopf, und der Daumen trifft die Kapsel besser. Auf einem Gerät mit Touch wächst der Stift auf Fingermaß. */
.zeilen-weg {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 32px; padding: 4px var(--sp-3) 4px 10px;
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--canvas);
  color: var(--primary);
  font-size: var(--fs-dense); font-weight: 600; white-space: nowrap;
  transition: background-color .15s ease-in-out, border-color .15s ease-in-out, color .15s ease-in-out, transform .15s ease-in-out;
}
.zeilen-weg:hover { background: var(--zahl-bg); border-color: var(--zahl-bd); color: var(--zahl-fg); text-decoration: none; }
.zeilen-weg:active { transform: scale(.96); }
.zeilen-weg .ikone { flex: none; }
@media (min-width: 781px) {
  .zeilen-weg-stift { width: 34px; height: 34px; padding: 0; border-color: transparent; background: none; color: var(--text-muted); }
  .zeilen-weg-stift > span {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .zeilen-weg-stift:hover { transform: translateY(-1px); }
}
@media (min-width: 781px) and (pointer: coarse) { .zeilen-weg-stift { width: 44px; height: 44px; } }
@media (max-width: 780px) {
  .seitenkopf-zeile { align-items: flex-start; }
  .zeitwahl-wert { min-width: 0; }
}
@media print { .seitenkopf-wege, .zeitwahl .knopf, .zeitwahl-heute, .spalte-weg { display: none; } }

/* ⛔ AUF DEM TELEFON WIRD DIE TAGESZEILE ZWEIZEILIG (Round Table, 08.10.2026). Die Tabelle war 655 px
   breit in einem 316-px-Kasten: „Hinweise" — wo „30 min Pause abgezogen" steht — und „Nachtragen"
   lagen hinter einem seitlichen Wischen, das niemand machte. Jetzt oben Tag, Ist und Differenz,
   darunter Hinweise und Weg. Pause, Soll und Balken treten zurück: die Pause steht als Abschnitt am
   Tag und als Kapsel, das Soll ergibt sich aus Ist und Differenz.
   ⛔ NUR CSS, KEIN ZWEITES MARKUP: zwei Fassungen derselben Zeile liefen beim nächsten Hinweis
   auseinander. ⛔ Das Wochenende und ein künftiger Tag ohne Eintrag fallen hier ganz weg — sie sagten
   nichts und machten die Seite 3700 px lang. Das Vorzeichen trägt die Differenz (`stdStand`), „Ist"
   steht vor seiner Zahl, weil der Tabellenkopf hier fehlt. */
@media (max-width: 640px) {
  /* 20.10.2026: Jeder Tag ist eine Karte (wie am Rechner), oben der Tag mit seinen Zeiten links und Ist und Differenz rechts, darunter der Balken in voller Breite,
     dann die Hinweise, unten der Weg und der Stand. Das Raster steht in diesem Block und in „Auf dem Telefon: der Stand“ weiter unten – die Farben der Karte stehen
     im Block „Meine Zeiten im Stil der Verkaufsseite“, getrennt für Telefon und Rechner. */
  .tagesliste thead { display: none; }
  .tagesliste, .tagesliste tbody { display: block; }
  .tagesliste tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "tag ist" "tag diff" "balken balken" "hinweis hinweis" "weg stand";
    column-gap: var(--sp-3); row-gap: 2px; align-items: center;
    margin: 0 0 var(--sp-2); padding: var(--sp-3);
  }
  .tagesliste td { display: block; padding: 0; border: 0; }
  .gitter.tagesliste tr:hover td { background: none; }
  .tagesliste .tag-zelle { grid-area: tag; align-self: start; padding: 0; }
  .tagesliste .spalte-ist { grid-area: ist; text-align: right; }
  .tagesliste .spalte-ist:not(:empty)::before { content: "Ist\00a0"; color: var(--text-muted); font-weight: 400; }
  .tagesliste .spalte-diff { grid-area: diff; text-align: right; padding: 0; }
  .tagesliste .spalte-pause, .tagesliste .spalte-soll { display: none; }
  .tagesliste .spalte-balken { grid-area: balken; width: auto; min-width: 0; margin-top: var(--sp-2); }
  .tagesliste .hinweis-zelle { grid-area: hinweis; min-width: 0; padding: 0; margin-top: var(--sp-1); }
  .tagesliste .hinweis-zelle .hinweis-gruende { max-width: none; }
  .tagesliste .spalte-weg { grid-area: weg; width: auto; text-align: left; padding: 0; margin-top: var(--sp-1); }
  .tagesliste tr[data-ruhig], .tagesliste tr[data-kuenftig-leer] { display: none; }
}
/* Vier Kennzahlen auf dem Telefon als zwei mal zwei: untereinander schob der Monat die Tabelle
   um vier Kartenhöhen nach unten, und die Zahlen sind kurz genug für die halbe Breite. */
@media (max-width: 780px) {
  .raster-vier { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
  .raster-vier .karte.kennzahl { padding: var(--sp-3); margin-bottom: 0; }
  .raster-vier .kennzahl .wert { font-size: var(--fs-title); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   URLAUB (03.10.2026) — oben Konto und „Als Nächstes", darunter Planen (zwei Monate und der Antrag),
   unten die eigenen Einträge und das Team.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ⛔ ZWEI REIHEN MIT JE EIGENEM RASTER, NICHT EINES ÜBER DIE GANZE SEITE. Ein gemeinsames Raster teilt
   die Zeilenhöhen: neben dem hohen Kalender stünde unter „Als Nächstes" eine leere Fläche. */
.urlaub-oben {
  display: grid; gap: var(--sp-4); align-items: start; margin-bottom: var(--sp-4);
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
}
.urlaub-oben > .karte { margin-bottom: 0; }
.urlaub-oben > .naechste { align-self: stretch; }
.urlaub-oben .urlaubskonto .fortschritt { height: 18px; }
.zeitwahl-jahr { min-width: 4.5rem; }

.naechste p { margin: 0; }
.naechste-art { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-ui); }
.naechste .naechste-zeitraum {
  margin-top: var(--sp-3);
  font: 600 var(--fs-title)/1.25 var(--f-ui); font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.naechste .naechste-abstand { margin-top: var(--sp-2); color: var(--text-muted); font-size: var(--fs-ui); }
.naechste-danach-titel {
  margin: var(--sp-5) 0 var(--sp-2); padding-top: var(--sp-4); border-top: 1px solid var(--row-line);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted);
}
.naechste-danach { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); font-size: var(--fs-ui); }
.naechste-danach li { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--sp-2); }
.naechste-danach-zeit { color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ── PLANEN ───────────────────────────────────────────────────────────────────────────────────── */
.planer > .karte-kopf { flex-wrap: wrap; align-items: center; }
.karte-kopf > .zeitwahl { margin-left: auto; }
/* Der Antrag steht rechts neben allem anderen und reicht über alle Zeilen; die letzte Zeile nimmt
   auf, was er länger ist. Ohne Feiertage oder Team bleibt deren Zeile leer — das kostet einen Abstand. */
.planer-flaeche {
  display: grid; gap: var(--sp-4) var(--sp-6); align-items: start;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 360px);
  grid-template-rows: auto auto auto 1fr;
  grid-template-areas: "monate antrag" "legende antrag" "feiertage antrag" "team antrag";
}
.planer-monate { grid-area: monate; }
.planer-legende { grid-area: legende; }
.planer-antrag { grid-area: antrag; }
.planer-feiertage { grid-area: feiertage; }
.planer-team { grid-area: team; }
.planer-nur-kalender { grid-template-columns: minmax(0, 1fr); grid-template-areas: "monate" "legende" "feiertage" "team"; }
.planer-monate {
  display: grid; gap: var(--sp-5) var(--sp-6); align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
}
.planer-antrag { padding-left: var(--sp-6); border-left: 1px solid var(--row-line); }
.planer-antrag > h3 { margin: 0 0 var(--sp-3); font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.planer-antrag .antrag { max-width: none; }

/* Das Monatsblatt. ⛔ KEINE ZELLKANTEN: eine Abwesenheit ist ein durchgehender Balken über ihre Tage,
   und eine Linie zwischen zwei Urlaubstagen zerlegte ihn wieder in einzelne. */
.monatsblatt { width: 100%; border-collapse: collapse; table-layout: fixed; font-variant-numeric: tabular-nums; }
.monatsblatt caption { text-align: left; padding: 0 0 var(--sp-2); font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.monatsblatt thead th {
  padding: 0 0 var(--sp-1); text-align: center;
  font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .04em; color: var(--text-muted);
}
.monatsblatt .mb-kw { width: 2.6em; text-align: center; font: 500 var(--fs-micro)/1 var(--f-ui); color: var(--text-muted); }
.monatsblatt td { position: relative; height: 40px; padding: 0; text-align: center; }
/* ⛔ „KEIN ARBEITSTAG" UND NICHT „WOCHENENDE": die Fläche kommt aus dem Arbeitszeitmodell
   (`urlaubskalender.js`). Wer Mo/Mi/Fr arbeitet, sieht seinen Dienstag so, wie er ihn plant. */
.monatsblatt td[data-frei] { background: var(--sunken); }
/* Der Feiertag trägt Fläche UND Form: `--hover` liegt zu dicht an `--sunken`, um allein zu tragen.
   Der Punkt unter der Zahl ist dasselbe Zeichen wie in der Legende. */
.monatsblatt td[data-feiertag] { background: var(--hover); }
.monatsblatt td[data-feiertag]::after,
.planer .legende-mal.legende-feiertag::after {
  content: ""; position: absolute; left: 50%; bottom: 5px; z-index: 2;
  width: 4px; height: 4px; margin-left: -2px; border-radius: var(--r-full); background: var(--primary);
}
.planer .legende-mal.legende-feiertag { position: relative; }
.planer .legende-mal.legende-feiertag::after { bottom: 2px; }

.mb-zahl {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;
  border-radius: var(--r-2); color: var(--text); font-size: var(--fs-ui); font-weight: 500;
}
a.mb-zahl:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); text-decoration: none; }
a.mb-zahl:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
.monatsblatt td[data-vergangen] .mb-zahl { color: var(--text-muted); }
.monatsblatt td[data-feiertag] .mb-zahl { color: var(--primary); font-weight: 700; }
.monatsblatt td[data-heute] .mb-zahl { box-shadow: inset 0 0 0 2px var(--primary); font-weight: 700; }

/* Die Abwesenheit liegt als Balken HINTER der Zahl — dieselbe Form und dieselben Badge-Töne wie im
   Teamkalender und in der Urlaubsübersicht (`.balken`, `[data-art]`), damit ein Urlaub überall
   gleich aussieht. Abgerundet wird nur am echten Anfang und Ende, nicht an der Wochengrenze. */
.monatsblatt .balken { position: absolute; inset: 5px 0; height: auto; margin: 0; z-index: 0; }
.monatsblatt .balken.rand-start { left: 4px; margin: 0; }
.monatsblatt .balken.rand-ende { right: 4px; margin: 0; }
.monatsblatt .balken.rand-einzeln { left: 4px; right: 4px; margin: 0; }
/* Ein halber Tag ist ein halb gefülltes Feld — über die Diagonale, damit es an jedem Rand gleich aussieht. */
.monatsblatt .balken[data-halb] { background-image: linear-gradient(135deg, transparent 50%, var(--canvas) 50%); }
.monatsblatt .balken.beantragt[data-halb] {
  background-image: linear-gradient(135deg, transparent 50%, var(--canvas) 50%),
    repeating-linear-gradient(45deg, var(--selected) 0 4px, var(--canvas) 4px 8px);
}
/* Dieselben Töne wie der Urlaubsbalken seit dem 08.10.2026 (Fläche `-bd`, Kante `-fg`). */
.legende-halb {
  border: 1px solid var(--badge-ok-fg);
  background: linear-gradient(135deg, var(--badge-ok-bd) 50%, var(--canvas) 50%);
}

/* Der gewählte Zeitraum. Die Ränder gefüllt, die Mitte getönt — und halb durchsichtig, damit ein
   Urlaub darunter sichtbar bleibt: wer über einen bestehenden Eintrag wählt, soll es sehen. */
.monatsblatt td[data-gewaehlt] .mb-zahl { background: color-mix(in srgb, var(--primary) 18%, transparent); border-radius: 0; }
.monatsblatt td[data-gewaehlt="rand"] .mb-zahl {
  background: var(--primary); color: var(--auf-primary); border-radius: var(--r-2); font-weight: 700;
}

.planer-legende { margin: 0; }
.planer-feiertage, .planer-team { padding-top: var(--sp-4); border-top: 1px solid var(--row-line); }
.planer-feiertage h3, .planer-team h3 { display: flex; align-items: center; gap: var(--sp-2); margin: 0 0 var(--sp-2); font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.planer-weg { margin-left: auto; font-weight: 500; }
.planer-team .personenliste { display: grid; gap: 0 var(--sp-6); grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.planer-feiertage ul {
  list-style: none; margin: 0; padding: 0; font-size: var(--fs-ui);
  display: grid; gap: var(--sp-1) var(--sp-6); grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}
.planer-feiertage li { display: flex; align-items: baseline; gap: var(--sp-3); }
.pf-datum { flex: none; min-width: 7.5em; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.pf-zusatz { color: var(--text-muted); }

/* ── UNTEN ────────────────────────────────────────────────────────────────────────────────────── */
.eintrag-art { display: inline-flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
.eintrag-zeitraum { white-space: nowrap; }
.personenliste { list-style: none; margin: 0; padding: 0; }
.personenliste li { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--row-line); }
.personenliste li:last-child { border-bottom: none; }
.planer-team .personenliste li:last-child { border-bottom: 1px solid var(--row-line); }
.personenliste-text { display: flex; flex-direction: column; min-width: 0; font-size: var(--fs-ui); }

@media (max-width: 1180px) {
  .planer-flaeche {
    grid-template-columns: minmax(0, 1fr); grid-template-rows: none;
    grid-template-areas: "monate" "legende" "antrag" "feiertage" "team";
  }
  .planer-nur-kalender { grid-template-areas: "monate" "legende" "feiertage" "team"; }
  .planer-antrag { padding: var(--sp-5) 0 0; border-left: none; border-top: 1px solid var(--row-line); }
}
@media (max-width: 900px) {
  .urlaub-oben { grid-template-columns: minmax(0, 1fr); }
}
@media print {
  .planer-antrag, .planer > .karte-kopf > .zeitwahl .knopf { display: none; }
  .planer-flaeche { grid-template-columns: minmax(0, 1fr); }
}

/* ── DIE TÖPFE DES URLAUBSKONTOS ────────────────────────────────────────────
   Gesetzlicher Mindesturlaub, vertraglicher Mehrurlaub, Übertrag, Zusatzurlaub
   — vier Mengen mit vier Fristen, in der Reihenfolge, in der sie abgebucht
   werden (`urlaub.toepfe()`).

   ⛔ KEINE EIGENEN MASSE, NUR EIN ABSTAND. Die Tabelle ist eine `.gitter` wie
   jede andere im Haus; eine zweite Tabellengestalt für vier Zeilen wäre die
   Zweitfassung, die bei der nächsten Änderung an `.gitter` danebenliegt. */
.toepfe { margin-top: var(--sp-4); }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   DER KONTOAUSZUG UNTER „MEINE ZEITEN" (M26, 16.10.2026).

   Oben die Rechnung „vor heute + heute = Zwischenstand", darunter die Tabelle mit dem Stand nach jedem Tag,
   den Wochenzeilen und den Zeilen für Berichtigung und Abschluss. Alles Zahlen kommen aus
   `services/kontoauszug.js`; dieses Stylesheet gestaltet nur.

   ⛔ KEINE AMPEL. Ein Minus am Zwischenstand ist am 3. des Monats für jeden Menschen da, weil erst drei Tage
   vorbei sind (CLAUDE.md, „Ein Diagramm trägt keine Ampelfarbe"). Das Vorzeichen trägt die ZAHL, nicht die Farbe.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die zwei Rechenzeichen sitzen an der Kachel, die sie anführt, in der Lücke zur vorigen. Bild, kein Inhalt:
   sie tragen `aria-hidden`, und die Vorlage legt für Sprachausgaben einen Satz dazu. */
.raster-stand .karte.kennzahl { position: relative; }
.rechenzeichen {
  position: absolute; z-index: 1; top: 50%; left: calc(-0.5 * var(--sp-4)); transform: translate(-50%, -50%);
  display: grid; place-items: center; width: 24px; height: 24px;
  border: 1px solid var(--karte-rand); border-radius: var(--r-full); background: var(--canvas);
  font: 600 var(--fs-body)/1 var(--f-ui); color: var(--text-muted); pointer-events: none;
}
/* Auf dem Telefon stehen die Kacheln zwei mal zwei: das „=" hätte keine Nachbarin vor sich. */
@media (max-width: 780px) {
  .rechenzeichen-gleich { display: none; }
  .rechenzeichen { left: calc(-0.5 * var(--sp-3)); }
}

/* Der Ring am Zwischenstand (`ring()` in `_tageszeile.html`): der Anteil von 40 Stunden. Bild, aria-hidden – die Zahl daneben sagt dasselbe. Die Marke für ein Plus,
   Schiefer für ein Minus, nie Rot. Er sitzt rechts in der Kachel und nimmt keinen Platz weg. */
.stand-ring { position: absolute; top: 50%; right: var(--sp-4); width: 60px; height: 60px; transform: translateY(-50%); pointer-events: none; }
.stand-ring svg { display: block; width: 100%; height: 100%; transform: rotate(-90deg); }
.stand-ring circle { fill: none; stroke-width: 12; stroke-linecap: round; }
.stand-ring .ring-bahn { stroke: var(--heute-rand); opacity: .55; }
.stand-ring .ring-wert { stroke: var(--primary); transition: stroke-dashoffset .3s ease-out; }
.stand-ring .ring-wert.ring-minus { stroke: var(--akt-gehen); }
@media (max-width: 780px) { .stand-ring { top: var(--sp-3); right: var(--sp-3); width: 34px; height: 34px; transform: none; } }
@media print { .stand-ring { display: none; } }

/* Die Spalte „Zwischenstand": die Zahl, auf die es ankommt, ohne Farbe — nur kräftiger als ihre Nachbarn. */
.spalte-stand { text-align: right; white-space: nowrap; font-weight: 600; font-variant-numeric: tabular-nums; }
.gitter th.spalte-stand { font-weight: 600; }

/* Die Zeilen zwischen den Tagen: Eröffnung, Woche, Berichtigung, Kontostand. Sie lesen sich wie Zwischenüberschriften —
   leiser als ein Tag. Ihre Flächen stehen im Block „Meine Zeiten als Karten“ (Rechner und Telefon getrennt). */
.tagesliste tr.zeile-eroeffnung td,
.tagesliste tr.zeile-woche td,
.tagesliste tr.zeile-buchung td,
.tagesliste tr.zeile-abschluss td {
  font-size: var(--fs-dense); color: var(--text-muted);
}
.tagesliste tr.zeile-eroeffnung td, .tagesliste tr.zeile-abschluss td { color: var(--text); }
.tagesliste tr.zeile-buchung td strong, .tagesliste tr.zeile-woche td strong { color: var(--text); }
.tagesliste tr.zeile-buchung .zeile-zusatz { display: inline; margin-left: var(--sp-2); }
.tagesliste tr.zeile-eroeffnung .zeile-zusatz { display: inline; margin-left: var(--sp-2); }

/* Der Strich im Fortschrittsbalken hat sein Wort in der Legende. */
.legende-marke { width: 2px; height: 14px; border-radius: 0; background: var(--text); opacity: .55; }

/* Die Fußzeile unter der Tabelle: Pause und Gedecktes, in einer Zeile. */
.tabellenfuss { margin: var(--sp-3) 0 0; }

/* ── DIE SÄULEN: LINK UND WERT ────────────────────────────────────────────────────────────────────── */
a.saeule { color: inherit; text-decoration: none; }
a.saeule:hover .saeule-bahn { outline: 2px solid var(--border-strong); outline-offset: 1px; }
a.saeule:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: var(--r-1); }
/* Ein Tag, der noch kommt, ist leiser — aber nicht gestrichelt wie ein versäumter (`data-art="offen"`). */
.saeule[data-kuenftig] { opacity: .7; }
.saeule[data-kuenftig][data-art="offen"] .saeule-bahn { border-style: solid; border-color: var(--border); }
/* Der Wert über dem Kopf: die kleine Schrift des Hauses, gedämpft, nie in der Farbe der Säule. Senkrecht, solange
   31 Spalten nebeneinander für eine waagerechte Zahl zu schmal sind; erst auf einem breiten Fenster waagerecht. */
.saeule-wert {
  display: block; min-height: 3.4em;
  font: 400 var(--fs-micro)/1.2 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--text-muted);
  writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap;
}
@media (min-width: 1100px) {
  .saeule-wert { min-height: 0; height: 1.2em; writing-mode: horizontal-tb; transform: none; text-align: center; }
}

/* ── AUF DEM TELEFON: DER STAND STEHT RECHTS IN DER WEGZEILE ──────────────────────────────────────── */
@media (max-width: 640px) {
  /* Der Stand steht unten rechts, in der Zeile des Weges (Raster oben: „weg stand“): Ohne Spalte „Zwischenstand“ bleibt dort nur der Weg. */
  .tagesliste .spalte-stand { grid-area: stand; padding: var(--sp-1) 0 0; text-align: right; align-self: center; justify-self: end; }
  .tagesliste .spalte-stand:not(:empty)::before { content: "Stand\00a0"; color: var(--text-muted); font-weight: 400; }
  /* Die Zeilen zwischen den Tagen laufen über die ganze Breite; der Stand einer Berichtigung steht rechts daneben. */
  .tagesliste tr.zeile-eroeffnung, .tagesliste tr.zeile-woche, .tagesliste tr.zeile-buchung, .tagesliste tr.zeile-abschluss {
    grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "text stand";
    padding: var(--sp-2) var(--sp-3);
  }
  .tagesliste tr.zeile-woche { grid-template-areas: "text text"; }
  .tagesliste tr.zeile-eroeffnung > td:first-child, .tagesliste tr.zeile-woche > td:first-child,
  .tagesliste tr.zeile-buchung > td:first-child, .tagesliste tr.zeile-abschluss > td:first-child { grid-area: text; }
  .tagesliste tr.zeile-eroeffnung > td:not(.spalte-stand):not(:first-child),
  .tagesliste tr.zeile-buchung > td:not(.spalte-stand):not(:first-child),
  .tagesliste tr.zeile-abschluss > td:not(.spalte-stand):not(:first-child) { display: none; }
  .tagesliste tr.zeile-eroeffnung td, .tagesliste tr.zeile-woche td,
  .tagesliste tr.zeile-buchung td, .tagesliste tr.zeile-abschluss td { background: none; }
}

/* ── DRUCK: DIE SPALTE UND DIE ZWISCHENZEILEN DRUCKEN MIT ─────────────────────────────────────────── */
@media print {
  .tagesliste tr.zeile-eroeffnung td, .tagesliste tr.zeile-woche td,
  .tagesliste tr.zeile-buchung td, .tagesliste tr.zeile-abschluss td { background: none; color: #000; }
  .rechenzeichen { display: none; }
}

/* ⛔ NEUN SPALTEN MÜSSEN IN DIE KARTE PASSEN (M26). Gemessen im Browser: mit der Spalte „Zwischenstand" war die Tabelle
   1098 px breit, die Karte bei einem Fenster von 1280 px 946 — „Weg" und „Hinweise" lagen hinter einem seitlichen
   Wischen, das niemand machte. Schmalere Zellränder, ein schmalerer Balken, ein Kopf, der in „Zwischen-/stand" bricht,
   und weniger Mindestbreite für die Hinweise. Auf dem Telefon gilt das Raster darüber (unter 640 px), auf dem Tablet
   rollt der Kasten weiter und sagt es mit seinem Randschatten. */
@media (min-width: 641px) {
  .gitter.tagesliste th, .gitter.tagesliste td { padding-left: var(--sp-2); padding-right: var(--sp-2); }
  .tagesliste .spalte-balken { width: 20%; min-width: 96px; }
  .tagesliste th.spalte-stand { white-space: normal; width: 5.5rem; }
  .tagesliste .hinweis-zelle { min-width: 7rem; }
}
/* Die Kapsel „+1:30 h" neben dem Balken sagt dasselbe wie die Spalte „Differenz" daneben; sie ist die breiteste Stelle
   der Zeile (Balken, Abstand, Kapsel) und hielt die Tabelle über der Karte. Unter 1440 px entfällt sie, die Zahl steht
   weiter in der Differenz. */
@media (max-width: 1439px) {
  .tagesliste .tagesbalken .marke-mehr { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   MEINE ZEITEN ALS KARTEN (20.10.2026)

   Vorbild ist die Zeitentabelle von zeitkumpel (dort aus der Tabelle „Meine Woche“ der Verkaufsseite entstanden): Jeder Tag liegt als eigene weiße Karte mit zarter Kante auf dem Grund,
   der heutige Tag trägt die Fläche der Marke und ein kleines „heute“, die Zeiten stehen als Kapseln mit Ikone, der Balken hat eine Kerbe fürs Soll.

   ⛔ DIE TABELLE BLEIBT EINE TABELLE. Tastatur, Sprachausgabe, Spalten, die Skripte (`data-tagesliste`, `data-zaehler`), die Suche im Browser und der Druck hängen daran.
   Die Zellen sehen nur aus wie Karten: `border-spacing` trennt die Zeilen, die erste und die letzte Zelle tragen die Rundung. Auf dem Telefon (bis 640 px) wird jede Zeile selbst
   zur Karte (Raster im Block „Auf dem Telefon wird die Tageszeile zweizeilig“ und im Block „Der Stand steht rechts in der Wegzeile“) – kein zweites Markup.
   ⛔ KEINE AMPEL: Plus und Minus der Differenz tragen die Marke und Schiefer, nie Grün und Rot (CLAUDE.md, „Ein Diagramm trägt keine Ampelfarbe“; ein Minus ist an einem
   Tag Vertrauensarbeitszeit kein Fehler). Das gilt für die Zahl am Tag so gut wie für den Stand im Monat.
   ⛔ DIE MARKE BLEIBT DEM, WAS MAN ANKLICKT UND WAS GEARBEITET HEISST: der Weg einer Zeile (Korrigieren, Nachtragen), der Link am Datum beim Zeigen, die Balken.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* Die Karte um die Tage trägt keine Fläche: jede Zeile ist selbst eine. Ihr Kopf („Tag für Tag“) und die Fußzeile stehen auf dem Grund der Seite. */
.karte.karte-tage { padding: 0; background: none; border: 0; box-shadow: none; }
.karte-tage > .karte-kopf { margin-bottom: var(--sp-2); }
.karte-tage > .karte-hinweis { margin: 0 0 var(--sp-3); }
.karte-tage > .tabellenfuss { margin: var(--sp-2) 0 0; padding-inline: var(--sp-1); }
/* Der Rollkasten zeigt auf dem Grund der Seite, nicht auf der Karte, dass er rollt (Regel bei `.gitter-rolle`). */
.karte-tage .gitter-rolle {
  background:
    linear-gradient(to right, var(--sunken) 40%, transparent) left center / 28px 100% no-repeat local,
    linear-gradient(to left, var(--sunken) 40%, transparent) right center / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) left center / 10px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) right center / 10px 100% no-repeat scroll;
}

/* ── Der Tag: Datum, „heute“ und die Zeiten als Kapseln ── */
.tagesliste .tag-zelle > a { font-size: var(--fs-body); font-weight: 700; color: var(--text); }
.tagesliste .tag-zelle > a:hover { color: var(--primary); }
.tag-heute {
  margin-left: var(--sp-1); padding: 1px 8px; vertical-align: 2px;
  border: 1px solid var(--heute-rand); border-radius: var(--r-full); background: var(--canvas); color: var(--primary);
  font: 650 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .02em;
}
/* Die Zeiten eines Tages stehen nebeneinander und brechen um, statt eine Zeile in drei hohe Kapseln zu zerlegen. */
.tagesliste .tagesabschnitte { display: flex; flex-wrap: wrap; gap: 4px 6px; margin-top: 6px; }
.tagesliste .tagesabschnitte .zeitspanne,
.tagesliste .tagesabschnitte .zeitspanne:first-child { margin: 0; padding: 2px 9px 2px 7px; }
.tagesliste .tagesabschnitte-mehr { flex: 1 0 100%; }
.zeitspanne { gap: 6px; }
.zeitspanne .ikone { flex: none; color: var(--primary); }
/* Die Pause trägt ihren Ocker nur im Zeichen; die Kapsel bleibt gestrichelt und ohne Ton (Begründung bei `.tagesabschnitte`). */
.zeitspanne[data-abschnitt="pause"] .ikone { color: var(--akt-pause); }

/* ── Die Zahlen: Ist fett, Pause und Soll leise, die Differenz in ihrem Ton ── */
.tagesliste td.spalte-ist { font-size: var(--fs-body); font-weight: 800; color: var(--text); }
.tagesliste tr[data-ruhig] td.spalte-ist { font-weight: 500; }
.tagesliste td.spalte-pause, .tagesliste td.spalte-soll { color: var(--text-muted); }
.diff { font-weight: 700; font-variant-numeric: tabular-nums; }
.diff-plus { color: var(--primary); }
.diff-minus { color: var(--akt-gehen); }
.diff-null { color: var(--text-muted); font-weight: 600; }
/* Die Wörter am Tag (Urlaub, Feiertag, gutgeschrieben, Gehen fehlt) sind abgerundete Kapseln wie die Hinweise daneben – nur ohne Ton. */
.hinweis-wort {
  display: inline-flex; align-items: center; margin-block: 1px; padding: 2px 10px;
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--sunken);
  font: 600 var(--fs-dense)/1.35 var(--f-ui); white-space: nowrap;
}
/* Die Woche trennt als Kapsel, nicht als graue Zeile. */
.tagesliste tr.zeile-woche td strong {
  display: inline-block; padding: 1px 10px;
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--canvas);
}

/* ── Am Rechner: Zellen als Karten ── */
@media (min-width: 641px) {
  .gitter.tagesliste { border-collapse: separate; border-spacing: 0 6px; margin-top: -6px; }
  .gitter.tagesliste th { background: none; border: 0; padding-block: var(--sp-1); }
  /* Der Tag bekommt den Platz, den seine Kapseln brauchen: so stehen zwei nebeneinander, statt dass jede Zeile drei Kapselhöhen misst. */
  .gitter.tagesliste thead th:first-child { width: 38%; }
  .gitter.tagesliste td {
    padding-block: var(--sp-3); vertical-align: middle;
    background: var(--canvas); border-block: 1px solid var(--karte-rand);
    transition: background-color .15s ease-in-out, border-color .15s ease-in-out;
  }
  .gitter.tagesliste td:first-child { border-left: 1px solid var(--karte-rand); border-radius: var(--r-3) 0 0 var(--r-3); }
  .gitter.tagesliste td:last-child { border-right: 1px solid var(--karte-rand); border-radius: 0 var(--r-3) var(--r-3) 0; }
  .gitter.tagesliste td:only-child { border-radius: var(--r-3); }
  .gitter.tagesliste tr:hover td { background: var(--canvas); border-color: var(--border-strong); }
  .gitter.tagesliste tr:hover td { border-color: color-mix(in srgb, var(--border-strong) 55%, var(--karte-rand)); }
  /* Was noch kommt, ist eine leise Karte ohne Fläche; was nichts zu sagen hat (Wochenende, freier Tag), hat gar keine. Der heutige Tag trägt die Petrol-Fläche,
     ein Tag, der den Abschluss aufhält, die des Hinweises – beide stehen zuletzt und gewinnen. */
  .gitter.tagesliste tr[data-kuenftig] td { background: transparent; border-color: var(--border); }
  .gitter.tagesliste tr[data-ruhig] td, .gitter.tagesliste tr[data-kuenftig-leer] td { background: transparent; border-color: transparent; padding-block: var(--sp-1); }
  .gitter.tagesliste tr[data-heute] td { background: var(--heute-bg); border-color: var(--heute-rand); }
  .gitter.tagesliste tr[data-klaerfall] td { background: var(--badge-warn-bg); border-color: var(--badge-warn-bd); }
  /* Die Zeilen zwischen den Tagen: Eröffnung, Berichtigung, Kontostand als flache Karten, die Woche als Trennlinie in Worten. */
  .gitter.tagesliste tr.zeile-eroeffnung td, .gitter.tagesliste tr.zeile-buchung td, .gitter.tagesliste tr.zeile-abschluss td {
    padding-block: var(--sp-2); background: var(--table-head); border-color: var(--border);
  }
  .gitter.tagesliste tr.zeile-woche td { padding-block: var(--sp-1); background: none; border-color: transparent; }
}

/* ── Auf dem Telefon: die Zeile ist die Karte ── */
@media (max-width: 640px) {
  .tagesliste tr { background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-3); }
  .tagesliste tr[data-kuenftig] { background: transparent; border-color: var(--border); }
  .tagesliste tr[data-heute] { background: var(--heute-bg); border-color: var(--heute-rand); }
  .tagesliste tr[data-klaerfall] { background: var(--badge-warn-bg); border-color: var(--badge-warn-bd); border-left: 3px solid var(--warn); }
  .tagesliste tr[data-klaerfall] .tag-zelle { box-shadow: none; }
  .tagesliste tr.zeile-eroeffnung, .tagesliste tr.zeile-buchung, .tagesliste tr.zeile-abschluss { background: var(--table-head); border-color: var(--border); }
  .tagesliste tr.zeile-woche { padding: var(--sp-1) var(--sp-1) 0; background: none; border: 0; }
}

/* Wer Bewegung abgestellt hat, bekommt keine: Flächen und Balken springen auf ihren Wert. */
@media (prefers-reduced-motion: reduce) {
  .gitter.tagesliste td, .zeilen-weg, .tb-gedeckt, .tb-ist, .tb-mehr, .stand-ring .ring-wert, .rail a, .rail a > .ikone { transition: none; }
  .zeilen-weg:hover, .zeilen-weg:active { transform: none; }
}

/* ── Im Ausdruck bleibt die Tabelle eine Tabelle: Linien statt Karten, keine Flächen ── */
@media print {
  .gitter.tagesliste { border-spacing: 0; margin-top: 0; }
  .gitter.tagesliste td, .gitter.tagesliste tr td {
    background: none !important; border-width: 0 0 1px !important; border-style: solid !important; border-color: #ccc !important; border-radius: 0 !important;
  }
  .tagesliste tr { background: none !important; border-radius: 0 !important; }
  .tag-heute { border-color: #999; color: #000; }
  .zeitspanne .ikone, .zeilen-weg { display: none; }
  .diff-plus, .diff-minus, .diff-null { color: #000; }
}

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   M28 TEIL A — ANTWORTEN MIT JE EINEM SATZ (21.10.2026)

   Die Einstellung „Wie sollen Nachträge behandelt werden?“ ist eine Entscheidung, die der Betrieb verstehen soll, BEVOR er sie trifft: eine Aufklappliste zeigt nur das Wort.
   Hier steht jede Antwort als eigene Zeile mit ihrem Satz dahinter (`einstellungen.AUSWAHL_ERKLAERT`); die Zahl der Antwort „Frist“ steht in ihr selbst.
   ⛔ Die gewählte Antwort ist an der Kante und am Punkt zu erkennen, nicht allein an einer Farbe (WCAG 1.4.1): die Kante der Karte wird kräftig, der Punkt ist gefüllt.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */
.feld-antworten { margin: 0 0 var(--sp-4); padding: 0; border: 0; min-width: 0; }
.feld-antworten > legend { padding: 0; margin-bottom: var(--sp-2); font-size: var(--fs-ui); font-weight: 650; color: var(--text); }
.antwort {
  display: grid; grid-template-columns: auto 1fr; gap: 0 var(--sp-3); align-items: start;
  margin-bottom: var(--sp-2); padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-3); background: var(--canvas); cursor: pointer;
}
.antwort:hover { border-color: var(--border-strong); }
.antwort:has(input[type="radio"]:checked) { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.antwort:has(input[type="radio"]:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.antwort > input[type="radio"] { margin: 3px 0 0; accent-color: var(--primary); }
.antwort-text { display: grid; gap: 2px; min-width: 0; }
.antwort-text > strong { font-size: var(--fs-ui); color: var(--text); }
.antwort-text > small { color: var(--text-muted); font-size: var(--fs-dense); line-height: 1.5; }
.antwort-zahl { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); font-size: var(--fs-dense); color: var(--text-muted); }
.antwort-zahl input { width: 6ch; }

/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   M28 TEIL B — „MEINE WOCHE“ (21.10.2026)

   Eine Tabelle, in die man tippt: Von, Bis, Pause je Tag, daneben Stunden, Differenz und der Balken mit der Kerbe fürs Soll (derselbe wie in „Tag für Tag“, `.tagesbalken`).
   ⛔ DIE TABELLE BLEIBT EINE TABELLE (Tastatur, Sprachausgabe, Tab von Feld zu Feld): `border-spacing` trennt die Zeilen, die erste und die letzte Zelle tragen die Rundung; am
   Telefon wird jede Zeile selbst zur Karte (Raster) – kein zweites Markup. Die Zeilen liegen auf dem Grund der Karte (`--sunken`), die Felder darin tragen `--canvas`.
   ⛔ KEINE AMPEL: die Differenz trägt ihre Form (`.diff-plus`, `.diff-minus`, `.diff-null`, oben beim Block „Meine Zeiten als Karten“), der Fehler beim Speichern ein Wort
   und die Warnfarbe – nie Rot als Urteil über einen Tag. ⛔ Die Fläche des heutigen Tages ist die der Marke (`--heute-bg`), wie in „Tag für Tag“.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */
.woche-karte { margin-bottom: var(--sp-5); }
.woche-kopf { flex-wrap: wrap; align-items: center; row-gap: var(--sp-2); }
.woche-kopf .zeitwahl { margin-left: auto; }
.woche-wert { white-space: nowrap; font-variant-numeric: tabular-nums; }
.woche-fehlerliste { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); }

.woche-tabelle { width: 100%; border-collapse: separate; border-spacing: 0 6px; margin-top: -6px; }
.woche-tabelle thead th {
  padding: var(--sp-1) var(--sp-3); text-align: left; background: none; border: 0;
  font: 600 var(--fs-dense)/1.3 var(--f-ui); color: var(--text-muted); white-space: nowrap;
}
.woche-tabelle thead th small { font-weight: 400; }
.woche-tabelle td, .woche-tabelle tbody th {
  padding: var(--sp-2) var(--sp-3); vertical-align: middle; text-align: left;
  background: var(--sunken); border-block: 1px solid var(--karte-rand);
}
.woche-tabelle tbody th:first-child, .woche-tabelle td:first-child { border-left: 1px solid var(--karte-rand); border-radius: var(--r-3) 0 0 var(--r-3); }
.woche-tabelle td:last-child { border-right: 1px solid var(--karte-rand); border-radius: 0 var(--r-3) var(--r-3) 0; }
.woche-tabelle tr[data-heute] td, .woche-tabelle tr[data-heute] th { background: var(--heute-bg); border-color: var(--heute-rand); }
.woche-tabelle tr[data-kuenftig] td, .woche-tabelle tr[data-kuenftig] th { background: transparent; border-color: var(--border); color: var(--text-muted); }
.woche-tabelle tr[data-ruhig] td, .woche-tabelle tr[data-ruhig] th { background: transparent; border-color: transparent; padding-block: var(--sp-1); color: var(--text-faint); }
.woche-tabelle tr[data-draussen] td, .woche-tabelle tr[data-draussen] th { background: transparent; border-color: transparent; color: var(--text-faint); }
.woche-tabelle tr[data-fehlerhaft] td, .woche-tabelle tr[data-fehlerhaft] th { border-color: var(--warn); }

.woche-tag { white-space: nowrap; font-weight: 400; }
.woche-tag abbr { text-decoration: none; font-size: var(--fs-body); font-weight: 700; color: var(--text); }
.woche-tag small { display: inline-block; margin-left: var(--sp-1); color: var(--text-muted); font-size: var(--fs-dense); }
.woche-wort {
  display: inline-flex; align-items: center; margin-block: 1px; padding: 1px 9px; margin-left: var(--sp-1);
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--canvas);
  font: 600 var(--fs-micro)/1.4 var(--f-ui); color: var(--text-muted); white-space: nowrap;
}

/* Die Felder: Zeit und Minuten. ⛔ 16 px auf schmalen Fenstern und am Zeigegerät ohne Maus (`--fs-feld`): iOS zoomt sonst bei jedem Fokus hinein. */
.woche-tabelle td input {
  width: 100%; min-width: 0; box-sizing: border-box; height: 34px; padding: 0 var(--sp-2);
  font: 500 var(--fs-ui)/1 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--text);
  background: var(--canvas); border: 1px solid var(--border-strong); border-radius: var(--r-2);
}
.woche-tabelle td input[type="time"] { min-width: 7.5ch; }
.woche-tabelle td input[data-feld="pause"] { max-width: 6ch; text-align: right; }
.woche-tabelle td input:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; border-color: var(--focus); }
.woche-tabelle td input[aria-invalid="true"] { border-color: var(--warn); }
.woche-fest { font-variant-numeric: tabular-nums; color: var(--text); }

.woche-stunden { white-space: nowrap; }
.woche-stunden > b { font-size: var(--fs-body); font-weight: 800; font-variant-numeric: tabular-nums; margin-right: var(--sp-2); }
.woche-stunden .diff { font-size: var(--fs-dense); margin-right: var(--sp-2); }
.woche-balken { display: inline-flex; vertical-align: middle; width: 64px; }
.woche-balken .tagesbalken-bahn { min-width: 0; height: 8px; }

/* Der Weg einer Zeile: Status („Gespeichert“), Wort („nachgetragen“, „gestempelt“) und Link nebeneinander, in der Mitte der Zeile – nicht ein Block über dem anderen. */
.woche-weg { min-width: 8rem; }
.woche-tabelle td.woche-weg { display: table-cell; }
.woche-weg > * { vertical-align: middle; }
.woche-status { display: inline-block; font-size: var(--fs-dense); color: var(--text-muted); }
.woche-status:empty { display: none; }
.woche-status[data-art="ok"] { color: var(--primary); font-weight: 600; }
.woche-status[data-art="fehler"] { color: var(--warn); font-weight: 600; }
.woche-quelle { margin-left: var(--sp-1); }
.woche-status + .woche-quelle, .woche-weg > :first-child { margin-left: 0; }

.woche-meldung { margin: var(--sp-2) 0 0; padding: var(--sp-2) var(--sp-3); border-radius: var(--r-2); background: var(--badge-warn-bg); border: 1px solid var(--badge-warn-bd); color: var(--text); font-size: var(--fs-dense); }
.woche-meldung[hidden] { display: none; }

/* Die Summen der Woche: Ist, Soll, Differenz, Zwischenstand – wie die Kennzahlen, nur kleiner. */
.woche-summe { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-6); margin-top: var(--sp-3); padding: var(--sp-3) var(--sp-3) 0; border-top: 1px solid var(--row-line); }
.woche-summe > div { display: flex; flex-direction: column; min-width: 5.5rem; }
.woche-summe .beschriftung { font-size: var(--fs-dense); color: var(--text-muted); }
.woche-summe b { font: 800 var(--fs-sect)/1.3 var(--f-ui); font-variant-numeric: tabular-nums; }
.woche-summe .einheit { font-size: var(--fs-micro); color: var(--text-muted); }
.woche-summe-stand b { color: var(--primary); }
.woche-wege { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.woche-vorwoche { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--row-line); }
.woche-vorwoche .feld-hinweis { margin: 0; flex: 1 1 18rem; }

/* ── Auf dem Telefon: die Zeile ist die Karte ── */
@media (max-width: 640px) {
  /* Die Wochenwahl bricht um statt zu überlaufen: der Link „Zur aktuellen Woche“ steht in einer eigenen Zeile. */
  .woche-kopf { display: block; }
  .woche-kopf > h2 { margin-bottom: var(--sp-2); }
  .woche-kopf .zeitwahl { display: flex; flex-wrap: wrap; max-width: 100%; margin-left: 0; border-radius: var(--r-3); }
  .woche-kopf .zeitwahl-wert { flex: 1 1 0; min-width: 0; white-space: normal; }
  .woche-kopf .zeitwahl-heute { flex: 1 0 100%; margin: 0 0 var(--sp-1); text-align: center; }
  .woche-tabelle thead { display: none; }
  .woche-tabelle, .woche-tabelle tbody { display: block; margin-top: 0; }
  /* ⛔ acht Spalten mit `minmax(0, 1fr)`: Tag und Weg teilen sich die obere Zeile je zur Hälfte, Von und Bis bekommen je drei Spalten (die Uhrzeit samt Zeichen soll hineinpassen),
     die Pause zwei. Ohne `minmax` dehnt ein langes Wort („nachgetragen“, „Korrigieren“) die Spalte, und die Karte ragt rechts heraus. */
  .woche-tabelle tr {
    display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: var(--sp-2) var(--sp-2);
    grid-template-areas: "tag tag tag tag weg weg weg weg" "von von von bis bis bis pause pause" "stunden stunden stunden stunden stunden stunden stunden stunden";
    margin-bottom: var(--sp-2); padding: var(--sp-3);
    background: var(--sunken); border: 1px solid var(--karte-rand); border-radius: var(--r-3);
  }
  .woche-tabelle tr[data-heute] { background: var(--heute-bg); border-color: var(--heute-rand); }
  .woche-tabelle tr[data-kuenftig], .woche-tabelle tr[data-draussen] { background: transparent; border-color: var(--border); }
  .woche-tabelle tr[data-ruhig] { display: none; }
  .woche-tabelle tr[data-fehlerhaft] { border-color: var(--warn); }
  .woche-tabelle td, .woche-tabelle tbody th, .woche-tabelle tr[data-heute] td, .woche-tabelle tr[data-heute] th, .woche-tabelle tr[data-kuenftig] td,
  .woche-tabelle tr[data-kuenftig] th, .woche-tabelle tr[data-draussen] td, .woche-tabelle tr[data-draussen] th {
    display: block; padding: 0; background: none; border: 0; border-radius: 0;
  }
  .woche-tabelle tbody th:first-child, .woche-tabelle td:first-child, .woche-tabelle td:last-child { border: 0; border-radius: 0; }
  .woche-tag { grid-area: tag; align-self: center; }
  .woche-tabelle td.woche-weg { display: block; grid-area: weg; min-width: 0; text-align: right; align-self: center; }
  .woche-tabelle td[data-label="Von"] { grid-area: von; }
  .woche-tabelle td[data-label="Bis"] { grid-area: bis; }
  .woche-tabelle td[data-label^="Pause"] { grid-area: pause; }
  .woche-tabelle td[data-label]::before { content: attr(data-label); display: block; margin-bottom: 2px; font-size: var(--fs-dense); color: var(--text-muted); }
  .woche-tabelle td input { font-size: var(--fs-feld); height: 44px; padding-inline: var(--sp-2); }
  .woche-tabelle td input[data-feld="pause"] { max-width: none; text-align: left; }
  /* Das Uhrzeichen im Zeitfeld nimmt am Telefon den Platz der Zahl (das Feld öffnet ohnehin beim Antippen seine eigene Auswahl). */
  .woche-tabelle td input[type="time"]::-webkit-calendar-picker-indicator { display: none; }
  .woche-tabelle td.woche-stunden { grid-area: stunden; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-3); }
  .woche-stunden > b::before { content: "Stunden\00a0"; font-weight: 400; color: var(--text-muted); font-size: var(--fs-dense); }
  .woche-stunden > b:empty::before { content: none; }
  .woche-balken { flex: 1 1 80px; width: auto; }
  .woche-summe { padding-inline: 0; }
}
@media (pointer: coarse) { .woche-tabelle td input { font-size: var(--fs-feld); } }
@media (prefers-reduced-motion: reduce) { .woche-karte .tb-gedeckt, .woche-karte .tb-ist, .woche-karte .tb-mehr { transition: none; } }

@media print { .woche-karte { display: none; } }


/* ═══════════════════════════════════════════════════════════════════════════════════════════════════
   M28 TEIL C — MEIN ARBEITSRHYTHMUS UND DIE BESETZUNG (21.10.2026, services/rhythmus.js)

   Vier Karten, im Markenblau (gearbeitet, `--primary`) und Schiefer (darunter) gezeichnet: die Wochentage als Balken, das Arbeitsfenster auf einer Achse, die Pause gegen ihre Kerbe, der Trend als Säulen.
   ⛔ KEINE AMPEL und kein Vorwurf: Ein Plus ist nicht „gut“, ein Minus nicht „schlecht“ — Plus Markenblau, Minus Schiefer, nie Grün und Rot. Jede Zeichnung ist aria-hidden und hat ihren Satz im Text.
   Die Besetzung ist eine Heatmap im Markenblau: die Stärke einer Zelle steckt in `--w` (0 bis 1), die Zahl steht in der Zelle — wer die Farbe nicht sieht, liest die Zahl.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */
.rhythmus-lead { margin: 0 0 var(--sp-4); }
.rhythmus-raster { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr)); gap: var(--sp-4); align-items: start; }
.rhythmus-karte > .karte-kopf h2 { display: flex; align-items: center; gap: var(--sp-2); }
.rhythmus-karte > .karte-kopf .ikone, .besetzung-karte > .karte-kopf .ikone { color: var(--primary); flex: none; }
.besetzung-karte > .karte-kopf h2 { display: flex; align-items: center; gap: var(--sp-2); }
.rhythmus-gross { margin: 0 0 var(--sp-3); font: 650 var(--fs-sect)/1.35 var(--f-ui); color: var(--text); }
.rhythmus-satz { margin-top: var(--sp-3); }
.rhythmus-leer { max-width: 44rem; }

/* Die Wochentage: Name, Balken, Wert, und — leise — die Beobachtung. */
.rhythmus-balken { display: grid; gap: var(--sp-2); margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
.rhythmus-balken li { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) 4.2rem; gap: 2px var(--sp-3); align-items: center; }
.rhythmus-name { font-weight: 650; }
.rhythmus-bahn { position: relative; display: block; height: 10px; border-radius: 5px; background: var(--sunken); box-shadow: inset 0 0 0 1px var(--border); }
.rhythmus-fuellung { position: absolute; inset: 0 auto 0 0; border-radius: 5px; background: var(--primary); }
.rhythmus-wert { font: 750 var(--fs-ui)/1.2 var(--f-ui); font-variant-numeric: tabular-nums; text-align: right; }
.rhythmus-marke { grid-column: 2 / -1; font: 600 var(--fs-micro)/1.3 var(--f-ui); color: var(--text-muted); }
.rhythmus-balken li[data-marke="längster Tag"] .rhythmus-fuellung { background: var(--primary-hover); }
.rhythmus-balken li[data-marke="früher Feierabend"] .rhythmus-fuellung, .rhythmus-balken li[data-marke="kürzester Tag"] .rhythmus-fuellung { background: var(--akt-gehen); }

/* Das Arbeitsfenster: ein Tag auf einer Achse, die Spanne von Kommen bis Gehen, der Beginn kräftiger. Die Marken stehen genau dort, wo ihre Stunde liegt. */
.rhythmus-fenster { margin: var(--sp-3) 0 var(--sp-2); }
.rhythmus-achse { position: relative; display: block; height: 16px; border-radius: 8px; background: var(--sunken); box-shadow: inset 0 0 0 1px var(--border); }
.rhythmus-tag { position: absolute; top: 3px; bottom: 3px; border-radius: 5px; background: color-mix(in srgb, var(--primary) 38%, var(--sunken)); }
.rhythmus-kommen { position: absolute; top: 0; bottom: 0; border-radius: 8px; background: var(--primary); }
.rhythmus-skala { position: relative; display: block; height: 14px; margin-top: 4px; font: 600 var(--fs-micro)/1 var(--f-ui); color: var(--text-muted); font-variant-numeric: tabular-nums; }
.rhythmus-skala > span { position: absolute; top: 0; transform: translateX(-50%); }

/* Die Pause: der Schnitt als Balken, das Vorgesehene als Kerbe. */
.rhythmus-pause .rhythmus-bahn { height: 12px; border-radius: 6px; margin: var(--sp-2) 0 var(--sp-3); }
.rhythmus-pause .rhythmus-fuellung { background: var(--akt-pause); border-radius: 6px; }
.rhythmus-kerbe { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--text); }

/* Der Trend: Säulen über und unter einer Mittellinie — Plus Markenblau, Minus Schiefer. */
.rhythmus-trend { display: grid; grid-template-columns: repeat(auto-fit, minmax(3.2rem, 1fr)); gap: var(--sp-2); margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
.rhythmus-trend li { display: grid; grid-template-rows: 7rem auto auto; justify-items: center; gap: 4px; }
.rhythmus-saeule { position: relative; display: block; width: 100%; max-width: 2.4rem; height: 100%; }
.rhythmus-saeule::before { content: ""; position: absolute; left: -4px; right: -4px; top: 50%; border-top: 1px solid var(--border-strong, var(--border)); }
.rhythmus-saeule-fuellung { position: absolute; left: 0; right: 0; bottom: 50%; max-height: 50%; border-radius: var(--r-1) var(--r-1) 0 0; background: var(--primary); }
.rhythmus-trend li[data-minus] .rhythmus-saeule-fuellung { top: 50%; bottom: auto; border-radius: 0 0 var(--r-1) var(--r-1); background: var(--akt-gehen); }
.rhythmus-trend li[data-laufend] .rhythmus-saeule-fuellung { opacity: .6; }
.rhythmus-saeule-wert { font: 750 var(--fs-dense)/1.2 var(--f-ui); font-variant-numeric: tabular-nums; }
.rhythmus-saeule-name { font: 600 var(--fs-micro)/1.2 var(--f-ui); color: var(--text-muted); }

/* Die Besetzung: Wochentag mal Stunde, die Farbe steckt in --w; die Kernzeit trägt eine Linie unter der Zahl. */
.besetzung { width: 100%; border-collapse: separate; border-spacing: 2px; table-layout: fixed; }
.besetzung thead th { padding: 0 0 2px; font: 600 var(--fs-micro)/1.2 var(--f-ui); color: var(--text-muted); text-align: center; font-variant-numeric: tabular-nums; }
.besetzung tbody th { width: 4.6rem; padding: 0 var(--sp-2) 0 0; text-align: left; font-weight: 700; white-space: nowrap; }
.besetzung tbody th abbr { text-decoration: none; }
.besetzung tbody th small { display: block; font: 600 var(--fs-micro)/1.2 var(--f-ui); color: var(--text-muted); }
.besetzung td {
  height: 2.4rem; padding: 0; border-radius: var(--r-1); text-align: center; font: 650 var(--fs-dense)/1 var(--f-ui); font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--primary) calc(var(--w, 0) * 70%), var(--sunken)); color: var(--text);
}
.besetzung td[data-leer] { background: var(--sunken); }
.besetzung td[data-kern] { box-shadow: inset 0 -3px 0 var(--text); }
/* Im Dunkeln ist --primary hell: Weiß auf der vollen Stärke (70 %) trüge keine 3:1. Mit 55 % bleibt auch die vollste Zelle so dunkel, dass die weiße Zahl über 4,5:1 liegt; im Hellen trägt die dunkle Zahl auf 70 % mehr als 4,5:1. */
:root[data-theme="dark"] .besetzung td { background: color-mix(in srgb, var(--primary) calc(var(--w, 0) * 55%), var(--sunken)); }
:root[data-theme="dark"] .besetzung td:not([data-leer]) { color: #fff; }

/* ⛔ AM TELEFON ROLLT DIE TABELLE IN IHREM KASTEN (`.gitter-rolle` zeigt den Schatten), STATT DIE ZAHLEN ZU QUETSCHEN: fünfzehn Stunden auf 320 px ließen jede Zelle in die
   Nachbarin ragen. Die Spalte der Wochentage bleibt beim Rollen stehen. */
@media (max-width: 640px) {
  .besetzung { min-width: 34rem; }
  .besetzung td { height: 2.2rem; }
  .besetzung tbody th { width: 3.4rem; position: sticky; left: 0; z-index: 1; background: var(--canvas); }
}
@media (max-width: 480px) {
  .rhythmus-balken li { grid-template-columns: 5.2rem minmax(0, 1fr) 3.8rem; }
  /* Sechs Wochen nebeneinander, auch auf 320 px: die Säulen werden schmaler, sie brechen nicht in eine zweite Zeile. */
  .rhythmus-trend { grid-template-columns: repeat(auto-fit, minmax(2.4rem, 1fr)); gap: var(--sp-1); }
}
@media print {
  .rhythmus-raster { display: block; }
  .rhythmus-karte { break-inside: avoid; margin-bottom: var(--sp-4); }
  .rhythmus-fuellung, .rhythmus-kommen, .rhythmus-tag, .rhythmus-saeule-fuellung, .besetzung td { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}


/* ═══════════════════════════════════════════════════════════════════════════════════════════════════
   M28 TEIL D — GESETZLICHE ARCHIVIERUNG: DIE QUARTALSSICHERUNG (21.10.2026, services/archiv.js)
   Ruhig und sachlich: ein Hinweis, eine Wahl, eine Aufzählung dessen, was in der Datei steht, ein Knopf. Die eine Primäraktion ist der Download.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */
.archiv-hinweis { max-width: 62rem; }
.archiv-offen { margin: 0 0 var(--sp-4); }
.archiv-karte > .karte-kopf h2 { display: flex; align-items: center; gap: var(--sp-2); }
.archiv-karte > .karte-kopf .ikone { color: var(--primary); flex: none; }
.archiv-wahl { display: flex; align-items: flex-end; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.archiv-wahl .feld { margin-bottom: 0; min-width: min(100%, 26rem); }
.archiv-wahl select { width: 100%; }
.archiv-unter { margin: var(--sp-4) 0 var(--sp-2); font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.archiv-liste { margin: 0 0 var(--sp-3); padding-left: var(--sp-5); max-width: var(--measure); }
.archiv-liste li { margin-bottom: var(--sp-2); }
.archiv-start { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-4); }
.archiv-start .karte-hinweis { margin: 0; flex: 1 1 18rem; }
.archiv-historie { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.archiv-historie li { padding: var(--sp-3) 0; border-top: 1px solid var(--row-line); }
.archiv-historie li:first-child { border-top: 0; }
.archiv-historie-kopf { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); font-size: var(--fs-ui); font-variant-numeric: tabular-nums; }
.archiv-historie-kopf > span { color: var(--text-muted); }
.archiv-summe { display: block; margin-top: var(--sp-1); font: 500 var(--fs-dense)/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; overflow-wrap: anywhere; color: var(--text-muted); }


/* ═══════════════════════════════════════════════════════════════════════════════════════════════════
   M29 — SCHNELLE WEGE FÜR DIE VERWALTUNG (22.10.2026)
   Kommen und Gehen nachtragen (Tagesansicht, `_tagesdetail.html`), der Weg „Zeiten“ in der Mitarbeiterliste und die Wochenkarte in der Sicht
   der Verwaltung (`_woche.html`, lesend oder – mit `time_edit_all` – buchend; sie nimmt die Klassen der Wochentabelle von oben).
   ⛔ KEINE AMPEL UND KEIN ZWEITER HAUPTKNOPF: die Karte „Kommen nachtragen“ ist eine Arbeitsfläche wie die Formulare darunter; die eine Primäraktion
   der Seite bleibt das Nachtragen unten (Regel 1). Die Töne tragen Wörter, nie allein die Farbe.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */
.live-karte > .karte-hinweis { margin: 0 0 var(--sp-4); max-width: var(--measure); }
/* Zwei Handlungen an einer laufenden Buchung nebeneinander, solange Platz ist – auf dem Telefon untereinander. */
.live-wege { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr)); gap: var(--sp-5) var(--sp-6); align-items: start; }
.live-wege .live-formular { max-width: none; }
.live-titel { margin: 0 0 var(--sp-2); font: 600 var(--fs-ui)/1.3 var(--f-ui); }
.live-formular .feld-hinweis { margin-top: var(--sp-2); }
.live-formular .knopf { margin-top: var(--sp-1); }

/* Die Spalte „Aktionen“ der Mitarbeiterliste: der Link bleibt in einer Zeile. */
.mitarbeiterliste .spalte-aktionen { white-space: nowrap; }

@media print { .live-karte, .mitarbeiterliste .spalte-aktionen, .woche-grund { display: none; } }

/* Die Wochenkarte der Verwaltung bucht: eine Begründung über der Tabelle, vorbelegt – „einfach buchen“ bleibt ein Tippen in der Zeile, und bei jeder Zeile steht trotzdem ein Grund im Protokoll.
   Das Feld ist ein gewöhnliches `.feld` (Kante, Höhe, Fingermaß kommen von der Grundregel); hier steht nur, wie breit die Zeile werden darf. */
.woche-grund { max-width: 38rem; margin: 0 0 var(--sp-3); }
.woche-grund .feld { margin-bottom: var(--sp-1); }
.woche-grund .feld-hinweis { margin: 0; }
/* „läuft“ neben dem leeren Bis einer laufenden Buchung; ein Wort mit eigener `display`-Regel würde `hidden` sonst überstimmen. */
.woche-wort[hidden] { display: none; }
.woche-laeuft { margin-left: 0; margin-top: var(--sp-1); }

/* Am Telefon bricht der Weg einer Wochenzeile um, statt über den Rand der Karte zu ragen: „Kommen nachtragen“ ist länger als die halbe Zeile. */
@media (max-width: 640px) {
  .woche-weg .zeilen-weg { white-space: normal; max-width: 100%; text-align: left; line-height: 1.25; }
}


/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   M30 — EINGANG, URLAUB UND MITARBEITER ALS KARTEN (23.10.2026)

   Vorbild ist „Meine Zeiten“ (M27, oben): jeder Vorgang liegt als eigene weiße Karte mit zarter Kante auf dem Grund der Seite (`--sunken`), nicht als Zeile in einer großen Karte.
   Drei Seiten bekommen dasselbe: der Eingang (Anträge, Rückgaben, Nachträge), „Meine Einträge“ unter Urlaub und die Mitarbeiterliste — dazu die ruhigeren Karten zum Urlaubskonto.

   ⛔ DIE TABELLEN BLEIBEN TABELLEN. `table.eintragsliste` und `table.mitarbeiterliste` tragen Tastatur, Sprachausgabe und die Prüfungen (Zeilen und Zellen werden gezählt, die `<tr>`
   haben keine Attribute): `border-spacing` trennt die Zeilen, die erste und die letzte Zelle tragen die Rundung. Wo der Platz nicht reicht (Tablet, Telefon), wird die Zeile selbst zur
   Karte (Raster, die Beschriftung kommt aus `data-label`) — kein zweites Markup, kein seitliches Wischen: bis dahin lagen „Entscheidung“ und „Zugang“ hinter dem Rand.
   ⛔ KEINE AMPEL UND KEIN NEUER TON: die Kapseln tragen die vorhandenen Badge-Töne mit ihrem Wort (wartet auf Entscheidung · genehmigt · storniert · zurückgenommen); Zahlen und Tage
   stehen in der neutralen Kapsel. Rot und Grün sagen hier nichts über einen Menschen. Die Marke bleibt dem, was man anklickt (Wege, Primäraktion).
   ⛔ DIE EINE PRIMÄRAKTION JE KARTE IST RUHIG: im Eingang steht „Genehmigen“ an jedem Vorgang; der Schatten der Primäraktion (Regel 5 im Dateikopf: „genau ein Knopf je Seite“) entfällt dort —
   fünf Schatten untereinander sind keine Hebung eines einzigen Knopfes mehr, sondern Lärm. Die Füllung trägt die Rangfolge allein.
   ═══════════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── DIE HÜLLE OHNE FLÄCHE ── */
.karte.karte-flach { padding: 0; background: none; border: 0; box-shadow: none; }
.karte-flach > .karte-kopf { margin-bottom: var(--sp-3); }
.karte-flach > .karte-hinweis { margin: 0 0 var(--sp-3); }
.karte-flach > h2 { margin: 0 0 var(--sp-3); }
/* Der Rollkasten zeigt auf dem Grund der Seite, nicht auf einer Karte, dass er rollt (Regel bei `.gitter-rolle`; dieselbe Fläche wie bei „Tag für Tag“). */
.karte-flach .gitter-rolle {
  background:
    linear-gradient(to right, var(--sunken) 40%, transparent) left center / 28px 100% no-repeat local,
    linear-gradient(to left, var(--sunken) 40%, transparent) right center / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) left center / 10px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--text-muted) 30%, transparent), transparent) right center / 10px 100% no-repeat scroll;
}

/* ── EINGANG: JEDER VORGANG IST EINE KARTE ──
   Das Raster der Zeile bleibt (Farbmal des Menschen · was es ist · was zu tun ist). Der Avatar steht oben, die Knöpfe mittig — eine Karte mit drei Zeilen Text hat ihre Handlung in der
   Mitte der Kante, nicht an der Oberkante. Die Regel hat vier Klassen und schlägt damit die Linienfassung (`.posten:not(.hinweis)`, auch die letzte Zeile). */
.karte.karte-flach .posten:not(.hinweis) {
  margin: 0 0 var(--sp-3); padding: var(--sp-4); gap: var(--sp-1) var(--sp-4);
  background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-3); box-shadow: var(--sh-karte);
}
.karte-flach > .posten:last-child { margin-bottom: 0; }
.karte-flach .posten-tun { align-self: center; }
.karte-flach .posten-tun .knopf-primaer { box-shadow: none; }
/* Der Zeitraum ist die Auskunft, nach der gefragt wird: eine Stufe über dem Kleingedruckten (eingereicht, Anmerkung, Stand danach). Tage und halbe Tage stehen als neutrale Kapseln daneben. */
.posten-text > .posten-zeitraum {
  margin: 2px 0 0; max-width: none;
  font: 600 var(--fs-body)/1.4 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--text);
}
.posten-tage, .posten-zusatz {
  display: inline-flex; align-items: center; margin: 0 var(--sp-1) 0 2px; padding: 1px 9px; vertical-align: 1px;
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--sunken);
  font: 600 var(--fs-dense)/1.4 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--text-muted); white-space: nowrap;
}
.posten-zusatz { font-weight: 500; }
/* „Alles erledigt“ ist auch eine Karte: ohne sie stünde der Satz ohne Halt auf dem Grund. */
.karte-flach > .posten-leer {
  margin: 0; padding: var(--sp-4); max-width: none;
  background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-3); box-shadow: var(--sh-karte);
}
/* Was zugeklappt in einer Karte liegt (Hinweise zur Arbeitszeit), trägt die Kachel der zweiten Ebene: `--sunken` auf der Karte, dieselbe Rollenverteilung wie bei den Kacheln des Monatsstandes. */
details.karte.verlauf .posten:not(.hinweis) {
  margin: 0 0 var(--sp-2); padding: var(--sp-3) var(--sp-4); gap: var(--sp-1) var(--sp-4);
  background: var(--sunken); border: 1px solid var(--karte-rand); border-radius: var(--r-3);
}
details.karte.verlauf .posten:not(.hinweis):last-child { margin-bottom: 0; }
/* ⛔ AB 960 PX UNTER DEM TEXT, NICHT ERST AB 780 (Regel bei `.posten`): ein Tablet im Hochformat ist 820 breit, mit der Schiene bleiben der Karte gut 500 px — der Text stand dort in einer Spalte von 200 px
   neben zwei Knöpfen („23.11.2026 bis / 27.11.2026 · 5 Tage · / beantragt …“), und eine lange Kapsel („Maschinell beendet — bitte prüfen“) lief unter die Knöpfe. Die Knöpfe fallen unter den Text und
   beginnen links; in der Karte bekommen sie eine Trennlinie und die volle Breite, damit der Daumen sie trifft. Ein iPad im Querformat (1024) hat die Spalte noch. */
@media screen and (max-width: 960px) {
  .karte-flach .posten { grid-template-columns: auto minmax(0, 1fr); }
  .karte-flach .posten-tun { grid-column: 1 / -1; justify-content: flex-start; align-self: start; padding-top: var(--sp-2); border-top: 1px solid var(--row-line); }
  .karte-flach .hinweis-zelle .pill { white-space: normal; }
  .karte-flach .posten-tun > form { flex: 2 1 9rem; }
  .karte-flach .posten-tun > details.ablehnen:not([open]) { flex: 1 1 6rem; }
  .karte-flach .posten-tun > form > .knopf, .karte-flach .posten-tun > details.ablehnen > summary.knopf { width: 100%; }
}

/* ── MEINE EINTRÄGE UND DIE MITARBEITERLISTE: ZELLEN ALS KARTEN, SOLANGE DER PLATZ REICHT ──
   Dieselbe Regel für beide Tabellen, mit je eigener Grenze: darunter wird die Zeile selbst zur Karte (zwei Blöcke weiter unten). Die Grenzen schließen einander aus — sonst überstimmte die
   Zellenfassung (vier Klassen) die Kartenfassung, und eine Zeile trüge beides. */
@media screen and (min-width: 1181px) {
  .gitter.eintragsliste { border-collapse: separate; border-spacing: 0 6px; margin-top: -6px; }
  .gitter.eintragsliste th { background: none; border: 0; padding-block: var(--sp-1); }
  .gitter.eintragsliste td {
    padding-block: var(--sp-3); vertical-align: middle;
    background: var(--canvas); border-block: 1px solid var(--karte-rand);
    transition: background-color .15s ease-in-out, border-color .15s ease-in-out;
  }
  .gitter.eintragsliste td:first-child { border-left: 1px solid var(--karte-rand); border-radius: var(--r-3) 0 0 var(--r-3); }
  .gitter.eintragsliste td:last-child { border-right: 1px solid var(--karte-rand); border-radius: 0 var(--r-3) var(--r-3) 0; }
  .gitter.eintragsliste td:only-child { border-radius: var(--r-3); }
  .gitter.eintragsliste tr:hover td { background: var(--canvas); border-color: color-mix(in srgb, var(--border-strong) 55%, var(--karte-rand)); }
}
@media screen and (min-width: 1181px) {
  .gitter.mitarbeiterliste { border-collapse: separate; border-spacing: 0 6px; margin-top: -6px; }
  .gitter.mitarbeiterliste th { background: none; border: 0; padding-block: var(--sp-1); }
  .gitter.mitarbeiterliste td {
    padding-block: var(--sp-3); vertical-align: middle;
    background: var(--canvas); border-block: 1px solid var(--karte-rand);
    transition: background-color .15s ease-in-out, border-color .15s ease-in-out;
  }
  .gitter.mitarbeiterliste td:first-child { border-left: 1px solid var(--karte-rand); border-radius: var(--r-3) 0 0 var(--r-3); }
  .gitter.mitarbeiterliste td:last-child { border-right: 1px solid var(--karte-rand); border-radius: 0 var(--r-3) var(--r-3) 0; }
  .gitter.mitarbeiterliste td:only-child { border-radius: var(--r-3); }
  .gitter.mitarbeiterliste tr:hover td { background: var(--canvas); border-color: color-mix(in srgb, var(--border-strong) 55%, var(--karte-rand)); }
}
@media (prefers-reduced-motion: reduce) {
  .gitter.eintragsliste td, .gitter.mitarbeiterliste td { transition: none; }
}
.eintragsliste td { vertical-align: middle; }
.eintragsliste .eintrag-stand { min-width: 11rem; }

/* Wo der Platz nicht reicht, wird die Zeile selbst zur Karte. Beide Tabellen brechen bei 1180 px um: „Meine Einträge“ (fünf Spalten) braucht gut 820 px und die Mitarbeiterliste (sechs, mit Kapseln) noch mehr, ein iPad im Querformat ist 1024
   breit und behält mit der Schiene gut 700 px — gemessen: bei 1024 lagen „Zurücknehmen“ und „Nachweis“ hinter dem Rand. Ein iPad Pro (1194) behält die Tabelle. Am Telefon steht „Tage“ vor der Zahl und „Wochenmodell“ / „Beschäftigt“ vor ihren Werten. */
@media screen and (max-width: 1180px) {
  .eintragsliste thead { display: none; }
  .eintragsliste, .eintragsliste tbody { display: block; margin-top: 0; }
  .eintragsliste tr {
    display: grid; column-gap: var(--sp-3); row-gap: 0; align-items: start;
    margin: 0 0 var(--sp-2); padding: var(--sp-3) var(--sp-4);
    background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-3);
  }
  .eintragsliste td { display: block; padding: 0; border: 0; border-radius: 0; background: none; min-width: 0; }
  .gitter.eintragsliste tr:hover td { background: none; }
  .eintragsliste td[data-label]::before { content: attr(data-label) "\00a0"; font-size: var(--fs-dense); font-weight: 400; color: var(--text-muted); }
}
@media screen and (max-width: 1180px) {
  .mitarbeiterliste thead { display: none; }
  .mitarbeiterliste, .mitarbeiterliste tbody { display: block; margin-top: 0; }
  .mitarbeiterliste tr {
    display: grid; column-gap: var(--sp-3); row-gap: 0; align-items: start;
    margin: 0 0 var(--sp-2); padding: var(--sp-3) var(--sp-4);
    background: var(--canvas); border: 1px solid var(--karte-rand); border-radius: var(--r-3);
  }
  .mitarbeiterliste td { display: block; padding: 0; border: 0; border-radius: 0; background: none; min-width: 0; }
  .gitter.mitarbeiterliste tr:hover td { background: none; }
  .mitarbeiterliste td[data-label]::before { content: attr(data-label) "\00a0"; font-size: var(--fs-dense); font-weight: 400; color: var(--text-muted); }
}

/* Meine Einträge: oben die Art und die Tage, darunter der Zeitraum, dann die Kapseln, unten die Wege. */
@media screen and (max-width: 1180px) {
  .eintragsliste tr {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "was tage" "zeitraum zeitraum" "stand stand" "weg weg";
  }
  .eintragsliste td.eintrag-was { grid-area: was; align-self: center; }
  .eintragsliste td.eintrag-tage { grid-area: tage; align-self: center; text-align: right; white-space: nowrap; font-weight: 600; }
  .eintragsliste td.eintrag-tage .zeile-zusatz { display: inline; margin-left: var(--sp-1); font-weight: 400; }
  .eintragsliste td.eintrag-zeitraum { grid-area: zeitraum; margin-top: var(--sp-1); font-size: var(--fs-body); font-weight: 600; white-space: normal; }
  .eintragsliste td.eintrag-zeitraum .zeile-zusatz { font-weight: 400; }
  .eintragsliste td.eintrag-stand { grid-area: stand; margin-top: var(--sp-2); min-width: 0; }
  .eintragsliste td.eintrag-weg { grid-area: weg; }
  /* Die Wege tragen ihren Abstand selbst: eine Zeile ohne Weg bekommt keinen leeren Streifen am Fuß. */
  .eintragsliste td.eintrag-weg > * { margin-top: var(--sp-2); }
  .eintragsliste td.eintrag-weg .knopf { width: 100%; }
}

/* Die Mitarbeiterliste: Person und „Zeiten“ oben, Modell und Beschäftigung, die Kapseln darunter. Bis 1000 px drei Spalten in drei Zeilen, von 1000 bis 1180 px eine Zeile mit Modell, Beschäftigung und Status (iPad im Querformat), am Telefon zwei Spalten. */
@media screen and (max-width: 1180px) {
  .mitarbeiterliste tr {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-template-areas: "person person aktionen" "modell seit status" "zugang zugang zugang";
    row-gap: var(--sp-2);
  }
  .mitarbeiterliste td.mit-avatar { grid-area: person; }
  .mitarbeiterliste td.spalte-aktionen { grid-area: aktionen; justify-self: end; align-self: center; }
  .mitarbeiterliste td.spalte-modell { grid-area: modell; }
  .mitarbeiterliste td.spalte-seit { grid-area: seit; }
  .mitarbeiterliste td.spalte-status { grid-area: status; }
  .mitarbeiterliste td.spalte-zugang { grid-area: zugang; }
  /* Keine Trennlinien in der Karte: zwei Zellen nebeneinander ergäben zwei abgesetzte Strecken mit einer Lücke dazwischen — der Abstand trennt. */
  .mitarbeiterliste td.spalte-modell, .mitarbeiterliste td.spalte-seit, .mitarbeiterliste td.spalte-status, .mitarbeiterliste td.spalte-zugang { padding-top: var(--sp-1); }
  /* Die beiden Zellen mit Beschriftung stellen sie über den Wert, nicht daneben. */
  .mitarbeiterliste td[data-label]::before { display: block; margin-bottom: 1px; }
  /* Ein Wort bricht nur, wo es nicht mehr passt („Vertrauensarbeitszeit“ bleibt ganz, solange die Spalte es trägt); eine lange Kapsel („Anmeldung gesperrt“) bricht um, statt unter den Knopf zu laufen. */
  .mitarbeiterliste .zeile-zusatz { overflow-wrap: break-word; }
  .mitarbeiterliste .status-kapseln .pill { white-space: normal; }
}
@media screen and (min-width: 1000px) and (max-width: 1180px) {
  .mitarbeiterliste tr {
    grid-template-columns: minmax(0, 1.9fr) minmax(0, 1.6fr) minmax(0, 1.1fr) minmax(0, 1.3fr) auto;
    grid-template-areas: "person modell seit status aktionen" "zugang zugang zugang zugang zugang";
    align-items: start;
  }
  .mitarbeiterliste td.spalte-aktionen { align-self: start; }
  .mitarbeiterliste td.spalte-modell, .mitarbeiterliste td.spalte-seit, .mitarbeiterliste td.spalte-status { padding-top: 0; }
}
@media screen and (max-width: 640px) {
  .mitarbeiterliste tr {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "person aktionen" "modell seit" "status status" "zugang zugang";
  }
}

/* ── DAS URLAUBSKONTO UND DER ÜBERTRAG: RUHIGER ──
   Die Zahlen bleiben, wo sie waren; die Karten sagen dasselbe mit weniger Gewicht. Die Legende des Balkens besteht aus Kapseln (jede Menge mit ihrem Muster und ihrer Zahl), die Sätze zu
   Übertrag und Mehrurlaub aus ruhigen Notizen mit einer Kante an der Seite, die Aufteilung nach Töpfen liegt hinter einer leisen Zeile. ⛔ Nur Gestaltung: was dort steht und wann es dort
   steht (kein Verfall ohne dokumentierten Hinweis, kein Rot am Übertrag), bleibt in den Vorlagen und in `urlaub.js`. */
.urlaubskonto .legende { gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-4); font-size: var(--fs-dense); }
.urlaubskonto .legende li {
  gap: 7px; padding: 3px 11px 3px 9px;
  border: 1px solid var(--border); border-radius: var(--r-full); background: var(--sunken);
  color: var(--text); font-variant-numeric: tabular-nums;
}
.urlaubskonto .legende-mal { width: 12px; height: 12px; border-radius: 3px; }
.konto-notiz {
  margin: 0 0 var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border-left: 3px solid var(--heute-rand); border-radius: 0 var(--r-2) var(--r-2) 0; background: var(--sunken);
}
.urlaubskonto .feinheit { margin-top: var(--sp-2); }

/* Der Übertrag aus dem Vorjahr: drei Kacheln nebeneinander (Menge, Menge, Stichtag) statt eines Datenrasters. Es bleibt eine <dl> mit einem <div> je Paar; die Fläche ist `--sunken` auf der Karte. */
.konto-kacheln { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: var(--sp-3); margin: 0 0 var(--sp-4); }
.konto-kachel { padding: var(--sp-3) var(--sp-4); background: var(--sunken); border: 1px solid var(--karte-rand); border-radius: var(--r-3); }
.konto-kachel > dt { margin: 0; font: 600 var(--fs-micro)/1.4 var(--f-ui); letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted); }
.konto-kachel > dd { margin: 2px 0 0; font: 650 var(--fs-sect)/1.3 var(--f-ui); font-variant-numeric: tabular-nums; color: var(--text); }
.konto-kachel .einheit { color: var(--text-faint); font-size: var(--fs-dense); font-weight: 400; }

/* ── „MEINE WOCHE“: DIE RÜCKMELDUNG BEIM SPEICHERN ──
   Das Wort „Gespeichert“ (`[data-status]`, `role="status"`) bekommt einen Haken in der Marke, und die Zeile leuchtet kurz in der Kante der Marke auf (`public/js/woche-eingabe.js` setzt
   `data-gespeichert` für einen Augenblick). ⛔ DER HAKEN IST GEZEICHNET UND KEIN SCHRIFTZEICHEN: die Hausschrift trägt U+2713 nicht, und ein Zeichen aus der Systemschrift stünde neben ihr wie
   ein Fremdkörper. Er steht in einem Pseudoelement — der Text bleibt „Gespeichert“, wie ihn die Sprachausgabe und die Prüfungen lesen. ⛔ KEINE AMPEL: Marke, nicht Grün. */
.woche-status[data-art="ok"]::before {
  content: ""; display: inline-block; width: .62em; height: .32em; margin-right: .5em; vertical-align: .2em;
  border-left: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg);
}
.woche-tabelle td, .woche-tabelle tbody th, .woche-tabelle tr { transition: border-color .4s ease-in-out; }
.woche-tabelle tr[data-gespeichert] td, .woche-tabelle tr[data-gespeichert] th { border-color: var(--primary); }
@media screen and (max-width: 640px) {
  /* Am Telefon ist die Zeile selbst die Karte (die Zellen tragen keine Kante). */
  .woche-tabelle tr[data-gespeichert] { border-color: var(--primary); }
}
@media (prefers-reduced-motion: reduce) {
  .woche-tabelle td, .woche-tabelle tbody th, .woche-tabelle tr { transition: none; }
}

/* ── MITARBEITERLISTE: DER STIFT NEBEN DEM NAMEN UND DIE RUHIGE ZEILE (23.10.2026, aus Zeitkumpel) ──
   ⛔ KEINE DECKKRAFT AUF EINER ZEILE UND KEINE `--text-faint` AUF EINEM BEDIENELEMENT. Eine `opacity` auf `tr` blendet den Text mit dem Grund: der Sekundärtext (`--text-muted`, 7,2:1) fiel bei .65
   auf rund 3,2:1, die Begründung einer Ablehnung bei .75 auf rund 4:1 — unter die 4,5:1, die diese Seite dem Gelesenen zusagt (`test/farbkontrast.test.js` misst Töne, und eine Mischung ist keiner).
   `--text-faint` trägt 3,05:1 und ist „nur Platzhalter, Einheiten, disabled"; als Stift unter Deckkraft .6 lag er bei rund 1,9:1 — unter den 3:1 für ein Bedienelement (WCAG 1.4.11).
   Ruhig wird eine Zeile deshalb über TÖNE, die gemessen sind: ihre Fläche ist der Grund (wie das Wochenende im Kalender), der Name steht in `--text-muted`. */
/* Name und Stift in einer Zeile: passt der Name, steht der Stift gleich daneben; bricht er um, bleibt der Stift als einzelner Griff am Rand der Spalte (als Textfluss stünde er allein in einer eigenen Zeile). */
.personenzeile-kopf { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }

/* ⛔ DER STIFT IST EIN BEDIENELEMENT: 24 px sichtbar, unter einem Zeigegerät mit Finger eine unsichtbar auf 40 px erweiterte Fläche — dasselbe Maß wie das Fragezeichen `tipp()`, aus demselben Grund (er steht in einer
   Zeile neben einem Wert und darf nicht auf `--control-h` wachsen). Er führt dorthin, wohin der Name führt; sein Name für Sprachausgaben nennt den Menschen (`aria-label`), und er ersetzt den Namen als Weg nicht. */
.zeilen-stift {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--r-2);
  color: var(--text-muted);
  transition: color .15s ease, background-color .15s ease;
}
.zeilen-stift:hover { color: var(--primary); background: var(--sunken); text-decoration: none; }
@media (pointer: coarse) {
  .zeilen-stift::after { content: ""; position: absolute; inset: -8px; }
}
@media (prefers-reduced-motion: reduce) {
  .zeilen-stift { transition: none; }
}

/* Ausgeschiedene: die Karte wird zum Grund. Am Rechner tragen die Zellen die Fläche, darunter die Zeile selbst — dieselbe Grenze (1180 px) wie bei den Kartenfassungen oben; beim Darüberfahren kommt die Karte zurück. */
@media screen and (min-width: 1181px) {
  .gitter.mitarbeiterliste tr:has([data-ruhig]) td { background: var(--sunken); }
  .gitter.mitarbeiterliste tr:has([data-ruhig]):hover td { background: var(--canvas); }
}
@media screen and (max-width: 1180px) {
  .mitarbeiterliste tr:has([data-ruhig]) { background: var(--sunken); }
}
.mitarbeiterliste tr:has([data-ruhig]) .personenzeile-name { color: var(--text-muted); }
.mitarbeiterliste tr:has([data-ruhig]) .personenzeile-name:hover { color: var(--text); }
/* Der Initial-Badge ist Schmuck (`aria-hidden`); entsättigt sagt er „nicht mehr dabei", ohne einen Ton zu tragen. */
.mit-avatar-innen[data-ruhig] .avatar { filter: grayscale(1); }

/* ── IM AUSDRUCK BLEIBEN DIE TABELLEN TABELLEN ──
   Die Kartenfassungen von „Meine Einträge“ und der Mitarbeiterliste hängen an `@media screen` mit einer Breite: Papier ist rund 700 px breit, und eine reine Breitenabfrage hätte die Zeile dort zur Karte
   gemacht — im Druck stehen sie wie bisher als Tabelle. Übrig bleibt, was die Karten des Eingangs und die Notizen im Druck brauchen: keine Rundung, keine Fläche (Schatten und Töne setzt der Druckblock oben). */
@media print {
  .karte.karte-flach .posten:not(.hinweis), .karte-flach > .posten-leer { border-radius: 0; box-shadow: none; }
  .konto-notiz, .konto-kachel { background: none; }
}
