/* SPDX-License-Identifier: Apache-2.0 — Webkultur GmbH
 *
 * Eigenes, schlankes CSS. Kein Framework, kein CDN: die App darf nichts aus
 * dem Netz holen (VPN-intern), und ein Tailwind-Werkzeugkasten waere fuer
 * eine Handvoll Ansichten mehr Bau als Nutzen.
 *
 * ANMUTUNG bewusst wie die zugekauften Schwester-Apps (Urlaubsverwaltung und
 * Zeiterfassung von focus shift), weil die Praxis alle drei im selben Atemzug
 * benutzt: ruhige Zinc-Graustufen, gruene Hauptaktion, 0.875rem in
 * Bedienelementen, 6px Eckenradius, blauer Fokusring, drei Themen
 * (System/Hell/Dunkel) ueber eine Klasse am <html>.
 *
 * Herkunft der Werte: die Farbrollen und Abstaende sind an der
 * **Urlaubsverwaltung** (Apache-2.0, github.com/urlaubsverwaltung/urlaubsverwaltung,
 * src/main/css/theme.css und components/*.css) abgelesen; die dortigen Werte
 * sind die Tailwind-Standardpalette (MIT). Uebernommen sind nur Farbwerte und
 * Maße — kein Code, kein CSS, keine Templates. Aus der Zeiterfassung ist
 * NICHTS uebernommen (AGPL-3.0, Netzwerk-Copyleft; siehe
 * docs/konzept-dienstplanung.md).
 */

/* --- Farbrollen: hell ---------------------------------------------------- */
:root {
  color-scheme: light;

  --grund: #fafafa;          /* zinc-50   */
  --flaeche: #ffffff;
  --flaeche-leise: #f4f4f5;  /* zinc-100  */
  --flaeche-tot: #e4e4e7;    /* zinc-200  */
  --linie: #e4e4e7;          /* zinc-200  */
  --linie-stark: #d4d4d8;    /* zinc-300  */
  --text: #27272a;           /* zinc-800  */
  --text-leise: #52525b;     /* zinc-600  */
  --text-schwach: #71717a;   /* zinc-500  */

  --haupt: #15803d;          /* green-700 */
  --haupt-rand: #166534;     /* green-800 */
  --haupt-leise: #f0fdf4;    /* green-50  */
  /* Die Farbe des Zeichens. Im hellen Thema ist das `haupt`; im dunklen
     waere `haupt` (green-700) auf zinc-900 matt -- nebeneinander gelegt und
     angesehen, nicht geschaetzt. Dort traegt `haupt-rand` (green-600). Eine
     eigene Rolle, damit die Regel unten nichts vom Thema wissen muss. */
  --marke: var(--haupt);
  --haupt-text: #ffffff;

  --info: #1d4ed8;           /* blue-700  */
  --info-leise: #eff6ff;     /* blue-50   */
  --fokus: #93c5fd;          /* blue-300  */

  --warn: #b45309;           /* amber-700 */
  --warn-leise: #fffbeb;     /* amber-50  */
  --warn-rand: #fcd34d;      /* amber-300 */

  --gefahr: #b91c1c;         /* red-700   */
  --gefahr-leise: #fef2f2;   /* red-50    */
  --gefahr-rand: #fca5a5;    /* red-300   */

  --besetzt: #dbeafe;        /* blue-100  */
  --besetzt-rand: #1d4ed8;
  --besetzt-text: #1e3a8a;   /* blue-900  */

  --radius: 6px;
  --radius-klein: 4px;
  --schrift: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;
  --bedien-groesse: 0.875rem;
  --kopf-hoehe: 3.5rem;
  /* Breite des linken Modulmenues (docs/design-guidelines.md, Abschnitt 1). */
  --menue-breite: 15rem;
  /* 32px je Kachel-Spur = Balkenhoehe der Vorlage (ohne Kopfzeile). */
  --kachelhoehe: 2rem;
  --schatten: 0 1px 2px rgb(0 0 0 / 0.05);
  /* Rahmen nach docs/design-guidelines.md: linkes Menue, Springer im Plan, Kacheln. */
  --menue: #f4f4f5;            /* zinc-100  */
  --menue-aktiv: #e4e4e7;      /* zinc-200  */
  --springer: #ede9fe;         /* violet-100 */
  --springer-rand: #6d28d9;    /* violet-700 */
  --kachel-schatten: 0 1px 3px rgb(0 0 0 / 0.08);
}

/* --- Farbrollen: dunkel -------------------------------------------------- */
/* Zwei Wege, dasselbe Ergebnis: System-Einstellung (Klasse theme-system, der
 * Startwert) und ausdrueckliche Wahl (theme-dark). Jede Rolle wird hier neu
 * gesetzt -- genau das fehlte vorher, weshalb dunkel schwarze Baender ueber
 * den Zellen zeigte. */
@media (prefers-color-scheme: dark) {
  html.theme-system {
    color-scheme: dark;
    --grund: #18181b;          /* zinc-900 */
    --flaeche: #27272a;        /* zinc-800 */
    --flaeche-leise: #1f1f23;
    --flaeche-tot: #202024;
    --linie: #3f3f46;          /* zinc-700 */
    --linie-stark: #52525b;    /* zinc-600 */
    --text: #f4f4f5;           /* zinc-100 */
    --text-leise: #d4d4d8;     /* zinc-300 */
    --text-schwach: #a1a1aa;   /* zinc-400 */

    --haupt: #15803d;
    --haupt-rand: #16a34a;
    --haupt-leise: #14251a;
    --marke: var(--haupt-rand);
    --haupt-text: #f0fdf4;

    --info: #93c5fd;
    --info-leise: #1e293b;
    --fokus: #93c5fd;

    --warn: #fcd34d;
    --warn-leise: #2a2010;
    --warn-rand: #b45309;

    --gefahr: #fca5a5;
    --gefahr-leise: #2a1516;
    --gefahr-rand: #b91c1c;

    --besetzt: #1e3a5f;
    --besetzt-rand: #60a5fa;
    --besetzt-text: #dbeafe;

    --schatten: 0 1px 2px rgb(0 0 0 / 0.4);
    --menue: #1f1f23;
    --menue-aktiv: #2d2d33;
    --springer: #2e1065;         /* violet-950 */
    --springer-rand: #a78bfa;    /* violet-400 */
    --kachel-schatten: 0 1px 3px rgb(0 0 0 / 0.5);
  }
}

html.theme-dark {
  color-scheme: dark;
  --grund: #18181b;
  --flaeche: #27272a;
  --flaeche-leise: #1f1f23;
  --flaeche-tot: #202024;
  --linie: #3f3f46;
  --linie-stark: #52525b;
  --text: #f4f4f5;
  --text-leise: #d4d4d8;
  --text-schwach: #a1a1aa;

  --haupt: #15803d;
  --haupt-rand: #16a34a;
  --haupt-leise: #14251a;
  --marke: var(--haupt-rand);
  --haupt-text: #f0fdf4;

  --info: #93c5fd;
  --info-leise: #1e293b;
  --fokus: #93c5fd;

  --warn: #fcd34d;
  --warn-leise: #2a2010;
  --warn-rand: #b45309;

  --gefahr: #fca5a5;
  --gefahr-leise: #2a1516;
  --gefahr-rand: #b91c1c;

  --besetzt: #1e3a5f;
  --besetzt-rand: #60a5fa;
  --besetzt-text: #dbeafe;

  --schatten: 0 1px 2px rgb(0 0 0 / 0.4);
  /* Diese fuenf fehlten hier, waehrend `theme-system` sie im Dunkeln schon
     hatte. Der Fehler war im Browser sofort zu sehen und im Blatt nicht: wer
     ausdruecklich „Dunkel" gewaehlt hatte, bekam ein WEISSES Modulmenue neben
     einer schwarzen Seite, weil `--menue` still auf den hellen Wert der
     `:root`-Ebene zurueckfiel. CSS meldet so etwas nie — der Wert existiert ja.
     Der Waechter `tests/test_css_tokens.py` haelt die beiden dunklen Wege
     seitdem zusammen. */
  --menue: #1f1f23;
  --menue-aktiv: #2d2d33;
  --springer: #2e1065;
  --springer-rand: #a78bfa;
  --kachel-schatten: 0 1px 3px rgb(0 0 0 / 0.5);
}

/* --- Grundlagen --------------------------------------------------------- */
* { box-sizing: border-box; }

/* Das `hidden`-Attribut muss auch Elemente mit eigenem `display` verbergen
 * (z.B. `.knopf { display: inline-flex }`) — sonst zeigt der Bedarfs-Dialog
 * „zurueck zum Template" auch bei einem Template-Balken. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font: 15px/1.5 var(--schrift);
  color: var(--text);
  background: var(--grund);
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 { font-weight: 600; letter-spacing: -0.01em; }
a { color: var(--info); }

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

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

/* --- Kopfzeile ---------------------------------------------------------- */
/* Sie sitzt rechts neben dem Modulmenue und traegt nur noch die sechs Menues
   (Verlauf, Lesezeichen, Zahnrad, Neues, Hilfe, Benutzer). Die Navigation ist
   nach links gewandert; der Platz links in der Kopfzeile bleibt bewusst leer,
   dorthin kommt in Welle 2 die Suche. */
.kopf {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  height: var(--kopf-hoehe);
  padding: 0 1.25rem;
  background: var(--flaeche);
  border-bottom: 1px solid var(--linie);
  box-shadow: var(--schatten);
}

/* Das Zeichen der Marke. Hiess `marke-punkt`, weil es bis zum 08.09.2026 ein
   Punkt war -- ein ausdruecklich vorlaeufiges Zeichen. Der Name bleibt, damit
   nicht dreissig Vorlagen angefasst werden muessen; was er zeigt, ist jetzt
   der Turnus aus drei Boegen (static/img/turnuswerk-zeichen.svg).

   WARUM MASKE UND NICHT <img>: ein eingebettetes Bild erbt keine Farbe. Als
   Maske bestimmt `background` die Farbe, und damit faerbt der Themenwechsel
   das Zeichen mit -- im dunklen Thema traegt `haupt` denselben Wert, aber wer
   spaeter dort einen helleren Gruenton setzt, bekommt ihn hier geschenkt.

   `-webkit-mask` bleibt daneben stehen: Safari braucht es bis heute. */
.marke-punkt {
  width: 1.15rem; height: 1.15rem;
  flex: none;
  background: var(--marke);
  mask: url("../img/turnuswerk-zeichen.24798b09d534.svg") center / contain no-repeat;
  -webkit-mask: url("../img/turnuswerk-zeichen.24798b09d534.svg") center / contain no-repeat;
}

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

/* Segmentierter Umschalter System / Hell / Dunkel (jetzt im Benutzermenue) */
.thema-wahl {
  display: flex;
  gap: 0;
  margin: 0;
  padding: 2px;
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  background: var(--flaeche-leise);
}
.thema-wahl label {
  position: relative;
  font-size: 0.78rem;
  color: var(--text-leise);
  padding: 0.25rem 0.55rem;
  border-radius: var(--radius-klein);
  cursor: pointer;
}
.thema-wahl input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.thema-wahl input:checked + span { font-weight: 600; color: var(--text); }
.thema-wahl label:has(input:checked) { background: var(--flaeche); box-shadow: var(--schatten); }
.thema-wahl label:has(input:focus-visible) { outline: 2px solid var(--fokus); outline-offset: 1px; }
/* Der `<noscript>`-Knopf (Formular statt loser Radios, Welle 2): sichtbar nur,
   wenn der Browser kein JavaScript ausfuehrt — dann braucht er denselben
   Abstand wie die anderen Formulare im Benutzermenue (`.aufklapper-form`). */
.thema-form noscript { display: block; margin: 0.35rem 0.4rem 0.2rem; }
.thema-form noscript .knopf { width: 100%; }

main { padding: 1.25rem; }

/* Band ueber dem Inhalt: eine ablaufende Frist (Testzeitraum). Bewusst kein
   Dialog und nichts zum Wegklicken -- eine Warnung, die man schliessen kann,
   ist am dritten Tag geschlossen und am siebten vergessen. */
.frist-band {
  margin: 0;
  padding: 0.6rem 1.25rem;
  border-bottom: 1px solid var(--warn-rand);
  background: var(--warn-leise);
  color: var(--text);
  font-size: var(--bedien-groesse);
  line-height: 1.45;
}

/* Das Support-Band traegt zusaetzlich einen Knopf — darum Flex und nicht nur
   Text. Es steht neben `.frist-band` und nicht darin: ein Band ohne Knopf soll
   kein Flex-Kontext werden, sonst zerfaellt sein Fliesstext in Kaesten. */
.support-band {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  justify-content: space-between;
}

.fuss {
  padding: 1rem 1.25rem 2rem;
  border-top: 1px solid var(--linie);
  color: var(--text-schwach);
  font-size: 0.8rem;
}

/* --- Knoepfe ------------------------------------------------------------ */
.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  padding: 0.45rem 0.75rem;
  font: 500 var(--bedien-groesse)/1.2 var(--schrift);
  color: var(--text-leise);
  background: var(--flaeche-leise);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  text-decoration: none;
  cursor: pointer;
  transition: background 100ms ease-in-out, border-color 100ms ease-in-out;
}
.knopf:hover:not(:disabled) { background: var(--flaeche-tot); color: var(--text); }
.knopf:disabled { opacity: 0.6; cursor: not-allowed; }
.knopf-schmal { padding: 0.3rem 0.55rem; }
.knopf-haupt {
  color: var(--haupt-text);
  background: var(--haupt);
  border-color: var(--haupt-rand);
}
.knopf-haupt:hover:not(:disabled) { background: var(--haupt-rand); color: var(--haupt-text); }
.knopf-gefahr { color: var(--gefahr); border-color: var(--gefahr-rand); background: var(--gefahr-leise); }

/* --- Kopf des Rasters --------------------------------------------------- */
.raster-kopf {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  margin-bottom: 0.9rem;
}
.wochenwahl { display: flex; align-items: center; gap: 0.6rem; }
.wochenwahl h1 { font-size: 1.15rem; margin: 0; }
.wochenwahl h1 small { display: block; font-weight: 400; font-size: 0.78rem; color: var(--text-schwach); }

/* Freie Wochenwahl: Liste + Jahr + Anzeigen, dahinter die beiden Schnellspruenge.
   Bewusst dieselbe Hoehe und Randfarbe wie die Pfeilknoepfe daneben — es ist eine
   Leiste, nicht zwei. `flex-wrap` laesst sie auf schmalen Fenstern umbrechen,
   statt das Raster nach rechts zu schieben. */
.wochensprung { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem; margin-left: 0.4rem; }
.wochensprung select, .wochensprung input {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.3rem 0.4rem; color: var(--text); background: var(--flaeche);
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
}
.wochensprung-jahr { width: 5.2rem; }
/* Man steht schon in dieser Woche: der Knopf bleibt bedienbar (Neuladen), sagt
   den Zustand aber an — aria-current traegt die Aussage, die Farbe folgt ihr. */
.wochensprung-jetzt[aria-current] {
  color: var(--haupt-text); background: var(--haupt); border-color: var(--haupt-rand);
}

/* Kennzahlen = Filter. Drei Kacheln sind Knoepfe (aria-pressed), „Fehlende
   Stunden" ist eine Summe ohne Knopf. Masse aus der Vorlage: Name 10.5px
   Versalien, Wert 17px. Gedrueckt = gefuellt in der Signalfarbe des Fensters,
   das der Filter zeigt (gelb = unter Soll, rot = unter Minimum). */
.kennzahlen { display: flex; gap: 0.5rem; margin: 0; }
.kennzahl {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0.3rem 0.65rem;
  font: inherit;
  color: var(--text);
  text-align: left;
  background: var(--flaeche);
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background 100ms ease-in-out, border-color 100ms ease-in-out;
}
.kennzahl:hover:not(.kennzahl-summe) { background: var(--flaeche-leise); border-color: var(--linie-stark); }
.kennzahl-summe { cursor: default; border-color: transparent; background: transparent; }
.kennzahl-name {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-schwach);
  white-space: nowrap;
}
.kennzahl-name small { font-size: 9px; letter-spacing: 0; text-transform: none; opacity: 0.8; }
.kennzahl-wert { font-size: 17px; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.kennzahl.warnung .kennzahl-wert { color: var(--gefahr); }
.kennzahl[aria-pressed="true"] { background: var(--info-leise); border-color: var(--info); }
.kennzahl[aria-pressed="true"] .kennzahl-name { color: var(--text); }
.kennzahl-soll[aria-pressed="true"] { background: var(--warn-leise); border-color: var(--warn); }
.kennzahl-minimum[aria-pressed="true"] { background: var(--gefahr-leise); border-color: var(--gefahr); }

.status {
  margin-left: auto;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  font-size: 0.78rem;
  border: 1px solid var(--linie-stark);
  background: var(--flaeche-leise);
  color: var(--text-leise);
}
.status-veroeffentlicht { background: var(--haupt-leise); border-color: var(--haupt); color: var(--haupt); }

.meldung {
  margin: 0 0 0.8rem;
  min-height: 1.2rem;
  font-size: var(--bedien-groesse);
  color: var(--text-leise);
}
.meldung:empty { margin: 0; min-height: 0; }
.meldung[data-art="fehler"] {
  padding: 0.55rem 0.8rem;
  border: 1px solid var(--gefahr-rand);
  border-left: 4px solid var(--gefahr);
  border-radius: var(--radius);
  background: var(--gefahr-leise);
  color: var(--gefahr);
}
.meldung[data-art="erfolg"] {
  padding: 0.55rem 0.8rem;
  border: 1px solid var(--linie-stark);
  border-left: 4px solid var(--haupt);
  border-radius: var(--radius);
  background: var(--haupt-leise);
}

.hinweis {
  padding: 0.9rem 1.1rem;
  background: var(--warn-leise);
  border: 1px solid var(--warn-rand);
  border-radius: var(--radius);
  color: var(--text);
}

/* --- Arbeitsflaeche: Leute + Raster ------------------------------------- */
.arbeitsflaeche {
  display: grid;
  grid-template-columns: 292px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}
@media (max-width: 900px) {
  .arbeitsflaeche { grid-template-columns: minmax(0, 1fr); }
}

.leute {
  position: sticky;
  top: calc(var(--kopf-hoehe) + 1rem);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  background: var(--flaeche);
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  box-shadow: var(--schatten);
}
.leute h2 { margin: 0 0 2px; font-size: 14px; }
.leute-hilfe { margin: 0 0 6px; font-size: 12px; line-height: 1.4; color: var(--text-schwach); }
.leute-lage { margin: 0; font-size: 12px; color: var(--text-leise); }
.leute-lage:empty { display: none; }
/* Im Abschnitt-Modus wird die Lagezeile der Filter-Chip der Vorlage. */
.leute[data-modus="slot"] .leute-lage {
  padding: 8px 10px;
  background: var(--haupt-leise);
  border: 1px solid var(--haupt);
  border-radius: var(--radius);
}
/* „andere Zeiten" nur, wenn ein Abschnitt aktiv ist (freie Zeitwahl im Dialog). */
.leute-zeiten { display: none; }
.leute[data-modus="slot"] .leute-zeiten { display: inline-flex; align-self: flex-start; }
.leute-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }

/* Person = Avatar + Info (Name, Quali-Chips, Stunden, Hinweis). Masse aus der
   Vorlage: Avatar 34px, Rand 2px, Innenabstand 10/12px. Der Rand ist immer
   2px (Vorlage: 1.5 -> 2 im gewaehlten Zustand), damit die Auswahl nichts um
   einen halben Pixel verschiebt. */
.person {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  width: 100%;
  padding: 10px 10px 10px 12px;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: var(--flaeche);
  border: 2px solid var(--linie);
  border-radius: var(--radius);
  cursor: grab;
  transition: opacity 150ms ease-in-out, border-color 100ms ease-in-out, background 100ms ease-in-out;
}
.person:hover:not(:disabled) { border-color: var(--linie-stark); background: var(--flaeche-leise); }
.person:disabled { cursor: default; opacity: 0.65; }
.person-kuerzel {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border-radius: 999px;
  background: var(--besetzt);
  color: var(--besetzt-text);
  font-size: 11px;
  font-weight: 700;
  text-transform: lowercase;
}
.person-info { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1; }
.person-name {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
}
.person-check { flex: none; display: none; }
.person-tags { display: flex; flex-wrap: wrap; gap: 4px; }
.quali {
  font-size: 10.5px;
  line-height: 1.3;
  padding: 2px 7px;
  border: 1px solid var(--linie-stark);
  border-radius: 999px;
  color: var(--text-leise);
  background: var(--flaeche);
  white-space: nowrap;
}
.quali-arzt { border-color: var(--haupt); color: var(--haupt); background: var(--haupt-leise); }
.person-stunden { font-size: 12px; color: var(--text-schwach); font-variant-numeric: tabular-nums; }
.person-hinweis { font-size: 12px; line-height: 1.25; }
.person-hinweis:empty { display: none; }

/* Gewaehlt: Flaeche, kraeftiger Rand, Ring, Haekchen. */
.person[aria-pressed="true"] {
  background: var(--haupt-leise);
  border-color: var(--haupt);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--haupt) 22%, transparent);
}
.person[aria-pressed="true"] .person-check { display: block; }
/* Sobald EINE Person gewaehlt ist, werden ALLE anderen gedimmt -- daran erkennt
   man den aktiven Zustand ohne Nachdenken (Vorlage: opacity .42). */
.leute[data-modus="person"] .person:not([aria-pressed="true"]) { opacity: 0.42; }
.leute[data-modus="person"] .person:not([aria-pressed="true"]):hover:not(:disabled) { opacity: 0.8; }

/* --- Panel reagiert auf den gewaehlten Abschnitt (Richtung A) ---------- */
/* Geeignet: angeboten, hervorgehoben. Der Hinweis nennt den moeglichen
   Abschnitt. */
.person-geeignet { border-color: var(--haupt); }
.person-geeignet .person-hinweis { color: var(--haupt); }
/* Moeglich mit Hinweis: bleibt angeboten (ziehbar), aber sichtbar markiert —
   NICHT dasselbe wie gesperrt. */
.person-moeglich { border-color: var(--warn-rand); }
.person-moeglich .person-hinweis { color: var(--warn); }
/* Gesperrt: gezeigt MIT Grund, aber nicht angeboten. Form (durchgestrichenes
   Kuerzel, gedaempft) trage die Aussage mit, nicht nur die Farbe. */
.person-gesperrt {
  opacity: 0.55;
  cursor: not-allowed;
}
.person-gesperrt .person-kuerzel {
  background: var(--flaeche-tot);
  color: var(--text-schwach);
  text-decoration: line-through;
}
.person-gesperrt .person-hinweis { color: var(--gefahr); }
.person[aria-disabled="true"] { cursor: not-allowed; }

/* Kopf des Panels im Filterzustand: kleiner „zuruecksetzen"-Hinweis. */
.leute[data-modus="slot"] .leute-hilfe,
.leute[data-modus="person"] .leute-hilfe { display: none; }
.leute-zuruecksetzen { display: none; }
.leute[data-modus="person"] .leute-zuruecksetzen { display: inline-flex; align-self: flex-start; }

/* --- Bedienfluss „Zuweisen ist eine Handlung" (Konzept 2026-09-05) ------ */
/* EINE Akzentfarbe verbindet den aktiven Abschnitt im Raster mit der Kopfzeile
   der Liste -- daran erkennt man den Bezug Raster <-> Liste ohne Nachdenken. */
:root { --akzent-aktiv: var(--info); --akzent-aktiv-leise: var(--info-leise); }
.leute-ziel {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 8px;
  align-items: center;
  padding: 8px 10px;
  border: 2px solid var(--akzent-aktiv);
  border-radius: var(--radius);
  background: var(--akzent-aktiv-leise);
}
.leute-ziel-titel { grid-column: 1; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-leise); }
.leute-ziel-text { grid-column: 1; font-size: 13px; line-height: 1.3; }
.leute-abbrechen { grid-column: 2; grid-row: 1 / span 2; }
/* Im Abschnitt-Modus traegt die Kopfzeile den Bezug; die Lagezeile darunter
   ist dann nur noch die Zaehlung (anbietbar / gesperrt). */
.leute[data-modus="slot"] .leute-lage { padding: 0; background: transparent; border: 0; }
.leute-fehler {
  margin: 0;
  padding: 0.5rem 0.7rem;
  font-size: 12px;
  line-height: 1.35;
  border: 1px solid var(--gefahr-rand);
  border-left: 4px solid var(--gefahr);
  border-radius: var(--radius);
  background: var(--gefahr-leise);
  color: var(--gefahr);
}

/* Aktionstext am Kandidaten: „einteilen" bzw. „trotzdem einteilen…". Nur im
   Abschnitt-Modus sichtbar (JS fuellt ihn), als kleiner Knopf-im-Knopf. */
.person-aktion { flex: none; font-size: 11px; font-weight: 600; color: var(--haupt); white-space: nowrap; }
.person-aktion:empty { display: none; }
.person-name-text { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.person-weich .person-aktion { color: var(--warn); }
.leute[data-modus="slot"] .person:not(:disabled):hover .person-aktion,
.leute[data-modus="slot"] .person:not(:disabled):focus-visible .person-aktion { text-decoration: underline; }

/* Stammkraft der gefragten Position: kleines Kennzeichen (Empfehlung, keine Sperre). */
.stamm {
  font-size: 10px;
  line-height: 1.3;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--besetzt-rand);
  background: var(--besetzt);
  color: var(--besetzt-text);
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

/* Weich gesperrt: gedimmt wie gesperrt, aber anklickbar -- der Klick oeffnet
   „trotzdem einteilen?". Der gelbe Rand sagt: hier geht noch etwas. */
.person-weich { opacity: 0.7; border-color: var(--warn-rand); cursor: pointer; }
.person-weich .person-kuerzel { background: var(--warn-leise); color: var(--warn); }
.person-weich .person-hinweis { color: var(--warn); }
.person-weich:hover:not(:disabled) { opacity: 1; }

/* Waehrend der Anfrage: Knopf beschaeftigt, Zelle laedt (kein Layout-Sprung --
   die Zelle behaelt ihre Hoehe, nur die Deckkraft pulsiert). */
.person[aria-busy="true"] { cursor: progress; }
.person[aria-busy="true"] .person-aktion::after { content: " …"; }
td.zelle[data-laedt] .spuren { animation: zelle-laedt 900ms ease-in-out infinite alternate; }
@keyframes zelle-laedt { from { opacity: 1; } to { opacity: 0.6; } }
/* Zellen brauchen eine stabile Mindesthoehe, damit die optimistische Kachel
   nichts verschiebt (die Spurenhoehe ist ohnehin ausgerechnet). */
.spuren { min-height: var(--kachelhoehe); }

/* Optimistische Kachel („wird eingeteilt"): sofort sichtbar, gedaempft und
   pulsierend, bis der Server bestaetigt -- dann kommt die echte Zelle. */
.kachel-vorlaeufig {
  background: color-mix(in srgb, var(--besetzt) 70%, var(--flaeche));
  color: var(--besetzt-text);
  border: 1px dashed var(--besetzt-rand);
  cursor: progress;
  animation: kachel-pulst 900ms ease-in-out infinite alternate;
  z-index: 2;
}
@keyframes kachel-pulst { from { opacity: 0.55; } to { opacity: 0.95; } }
/* Vorschau beim Hover ueber einen Kandidaten: „so saehe es aus". */
.kachel-vorschau {
  background: transparent;
  color: var(--besetzt-text);
  border: 2px dashed var(--besetzt-rand);
  opacity: 0.75;
  pointer-events: none;
  z-index: 2;
}
.kachel-vorschau.kachel-vorschau-weich { border-color: var(--warn); color: var(--warn); }

/* Abweichend (Sperre mit Grund uebersteuert): Fahne + gestrichelter Innenrand,
   Grund im Tooltip -- die Aussage haengt nicht an der Farbe. */
.kachel-abweichend { box-shadow: inset 0 0 0 1px var(--warn), inset 0 0 0 2px var(--flaeche); }
.kachel-marke { flex: none; font-size: 10px; color: var(--warn); }
.legende-abweichend { display: inline-grid; place-items: center; font-size: 9px; color: var(--warn); border-color: var(--warn); }

/* Richtung B: Luecke, in die die gewaehlte Person nur mit Begruendung darf. */
.luecke.slot-weich {
  box-shadow: inset 0 0 0 1px var(--warn);
  background-image: repeating-linear-gradient(
    135deg, transparent 0 6px, color-mix(in srgb, var(--warn) 40%, transparent) 6px 7px);
}
.raster-rolle[data-person-aktiv] .luecke.slot-weich { opacity: 0.85; }

/* Der Uebersteuern-Dialog: Gruende als Liste, Vorschlaege als Chips. */
.ueber-gruende { margin: 0 0 0.6rem; padding-left: 1.1rem; font-size: var(--bedien-groesse); color: var(--gefahr); }
.ueber-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0 0 0.5rem; }
.chip {
  /* Ein Chip ist EIN Wort oder eine Frist -- er bricht nicht um. In der
     Dashboard-Tabelle wurde „erlaubt bis 29.09.2026 18:31" dreizeilig und die
     Spalte unlesbar (sf, 15.09.2026). */
  white-space: nowrap;
  padding: 0.2rem 0.6rem;
  font: 500 0.78rem/1.2 var(--schrift);
  color: var(--text-leise);
  background: var(--flaeche-leise);
  border: 1px solid var(--linie-stark);
  border-radius: 999px;
  cursor: pointer;
}
.chip:hover, .chip[aria-pressed="true"] { border-color: var(--haupt); color: var(--haupt); background: var(--haupt-leise); }
.ueber-grund-label { display: grid; gap: 0.25rem; font-size: 0.8rem; color: var(--text-leise); }
.ueber-grund-label small { color: var(--text-schwach); }
.ueber-grund-label textarea {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.4rem 0.5rem;
  color: var(--text);
  background: var(--flaeche);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  resize: vertical;
}
.ueber-grund-label textarea:invalid { border-color: var(--warn-rand); }

/* --- Slots reagieren auf die gewaehlte Person (Richtung B) ------------- */
/* Aktiver Slot (Richtung A ausgeloest): deutlich umrandet. */
.luecke.slot-aktiv, .balken.slot-aktiv {
  outline: 2px solid var(--info);
  outline-offset: 1px;
}
/* Andockbar fuer die gewaehlte Person: hervorgehoben. */
.luecke.slot-passend {
  box-shadow: inset 0 0 0 1px var(--haupt);
  background-image: repeating-linear-gradient(
    135deg, transparent 0 6px, color-mix(in srgb, var(--haupt) 45%, transparent) 6px 7px);
  color: var(--haupt);
  font-weight: 700;
}
/* Nicht passend, solange eine Person gewaehlt ist: gedaempft. */
.raster-rolle[data-person-aktiv] .luecke:not(.slot-passend) { opacity: 0.4; }

/* --- Kennzahlen-Filter: „wo muss ich noch ran?" -------------------------- */
/* data-zeige am Raster (offen | unter_soll | unter_minimum), data-lage am
   Balken (voll | unter_soll | unter_minimum). Ein Attribut, keine Klassen je
   Element: alles, was NICHT passt, wird gedimmt und entsaettigt, die Treffer
   bekommen einen Ring. Zusammen mit einer gewaehlten Person gilt: der Filter
   waehlt die FENSTER, die Person die LUECKEN darin -- die Treffer-Fenster
   bleiben voll sichtbar, nur ihre nicht passenden Luecken werden gedaempft. */
.raster-rolle[data-zeige="unter_minimum"] .balken:not([data-lage="unter_minimum"]),
.raster-rolle[data-zeige="unter_soll"] .balken:not([data-lage="unter_soll"]),
.raster-rolle[data-zeige="offen"] .balken[data-lage="voll"],
/* Eine Fortsetzung ist derselbe Bedarf wie am Vortag; der Filter zaehlt
   Fenster und nicht Haelften, also wird sie hier immer gedimmt. */
.raster-rolle[data-zeige] .balken[data-lage="fortsetzung"] {
  opacity: 0.3;
  filter: saturate(0.15);
}
.raster-rolle[data-zeige="unter_minimum"] .balken[data-lage="unter_minimum"],
.raster-rolle[data-zeige="unter_soll"] .balken[data-lage="unter_soll"],
.raster-rolle[data-zeige="offen"] .balken:not([data-lage="voll"]):not([data-lage="fortsetzung"]) {
  box-shadow: 0 0 0 3px var(--fokus);
}
/* Im gedimmten Fenster nicht doppelt daempfen -- sonst verschwinden die
   Luecken ganz und das Fenster sieht leer aus. */
.raster-rolle[data-zeige="unter_minimum"] .balken:not([data-lage="unter_minimum"]) .luecke,
.raster-rolle[data-zeige="unter_soll"] .balken:not([data-lage="unter_soll"]) .luecke,
.raster-rolle[data-zeige="offen"] .balken[data-lage="voll"] .luecke { opacity: 1; }

/* --- Das Raster --------------------------------------------------------- */
.raster-rolle { overflow-x: auto; }

table.wochenraster {
  width: 100%;
  min-width: 1080px;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--flaeche);
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  overflow: hidden;
  font-size: var(--bedien-groesse);
}

table.wochenraster th,
table.wochenraster td { border-bottom: 1px solid var(--linie); }

table.wochenraster thead th {
  /* Klebt am oberen Rand des waagerechten Scrollbereichs (.raster-rolle).
     Ein Versatz um die Kopfhoehe wuerde ihn INNERHALB des Bereichs nach
     unten schieben und die erste Zeile verdecken. */
  position: sticky;
  top: 0;
  z-index: 5;
  padding: 10px 12px 8px;
  background: var(--flaeche);
  border-bottom: 2px solid var(--linie-stark);
  font-weight: 600;
  text-align: left;
  vertical-align: top;
}
th.ecke { width: 150px; padding: 12px 14px; font-size: 12px; color: var(--text-leise); }
th.ecke small { display: block; font-weight: 400; color: var(--text-schwach); font-size: 12px; }

/* Tage als klar begrenzte Spalten: 2px Trennlinie links, jede zweite Spalte
   getoent (Vorlage: nth-child(odd) -- Di/Do/Sa, weil die Positionsspalte das
   erste Kind ist). Die Toenung gilt fuer Kopf UND Zellen derselben Spalte. */
th.tag { min-width: 9.5rem; border-left: 2px solid var(--linie-stark); }
th.tag:nth-child(odd), td.zelle:nth-child(odd) { background-color: var(--flaeche-leise); }
th.tag .tag-name { font-size: 14px; font-weight: 700; }
th.tag .tag-datum { margin-left: 4px; color: var(--text-schwach); font-weight: 400; font-size: 14px; }
th.tag-heute { box-shadow: inset 0 3px 0 var(--info); }
th.tag-zu { color: var(--text-schwach); }
.tag-grund {
  display: block;
  margin-top: 6px;
  font-weight: 400;
  font-size: 12px;
  color: var(--warn);
}

/* Zeitmarken unter dem Tag. Anders als in der Vorlage (space-between) stehen
   sie lagegenau auf der Achse -- auf denselben Uhrzeiten wie die Gitterlinien
   der Zellen; verteilt saehe „09 12 15 18" bei einer 07-18-Achse nur gleichmaessig
   aus, waere aber an der falschen Stelle. */
.achse { position: relative; display: block; height: 12px; margin-top: 6px; }
.achse-marke {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  font-size: 10px;
  line-height: 1;
  font-weight: 400;
  color: var(--text-schwach);
  font-variant-numeric: tabular-nums;
}

/* Gruppen-Baender: Versalien auf --flaeche-tot (Vorlage: 10.5px, .08em). */
.gruppenkopf th {
  padding: 7px 14px;
  background: var(--flaeche-tot);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-schwach);
  text-align: left;
  border-top: 1px solid var(--linie);
  border-bottom: 1px solid var(--linie);
}

th.position {
  padding: 12px 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: var(--flaeche);
  font-weight: 600;
  text-align: left;
  vertical-align: middle;
}
th.position small { display: block; font-size: 11px; color: var(--text-schwach); font-weight: 400; }

td.zelle {
  padding: 10px 6px;
  vertical-align: top;
  border-left: 2px solid var(--linie-stark);
  /* Hilfslinien auf denselben Uhrzeiten wie die Marken im Spaltenkopf. */
  background-image: repeating-linear-gradient(
    to right, var(--linie) 0 1px, transparent 1px var(--gitter, 25%));
  background-position: 6px 0;
  background-repeat: repeat;
}
/* Kein Bedarf fuer diese Position an dem Tag: nur die Spaltentoenung, kein
   Gitter -- eine leere Zelle sagt „hier ist nichts", wie in der Vorlage. */
td.zelle-leer { background-image: none; }
td.zelle-zu {
  background-color: var(--flaeche-tot);
  background-image: repeating-linear-gradient(
    135deg, transparent 0 6px, rgb(120 120 130 / 0.12) 6px 12px);
}

.spuren {
  /* Zeilenhoehe waechst mit den Kachel-Spuren: bei Sollbesetzung 2 stehen
     zwei Zuweisungen gleichzeitig im Fenster und brauchen zwei Ebenen.
     Ohne Kopfzeile ist der Balken genau so hoch wie seine Kacheln (32px je
     Spur, Vorlage) plus ein Abstand zwischen zwei Spuren. */
  --zeilenhoehe: calc(var(--kacheln, 1) * var(--kachelhoehe) + 0.6rem);
  position: relative;
  height: calc(var(--spuren, 1) * var(--zeilenhoehe) - 0.6rem);
}

/* --- Balken = Bedarfsfenster -------------------------------------------- */
/* Ruhig: kein Text auf dem Fenster, nur Kacheln und Luecken. Signal nur, wo
   etwas fehlt -- unter Soll: gelber Rand + gelber Punkt oben rechts; unter
   Minimum: roter 4px-Rand links + rote Flaeche. Voll besetzt: neutral, still. */
.balken {
  position: absolute;
  top: calc(var(--spur, 0) * var(--zeilenhoehe));
  height: calc(var(--kacheln, 1) * var(--kachelhoehe) + 2px);
  min-width: 2.2rem;
  padding: 0;
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  background: var(--flaeche);
  overflow: hidden;
  transition: opacity 150ms ease-in-out, box-shadow 150ms ease-in-out;
}
.balken-luecke { border-color: var(--warn); }
.balken-luecke::after {
  content: "";
  position: absolute;
  top: 4px; right: 4px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--warn);
  pointer-events: none;
  z-index: 1;
}
.balken-kritisch {
  border-color: var(--gefahr-rand);
  border-left-width: 4px;
  background: var(--gefahr-leise);
}
.balken-ausnahme { border-style: dashed; }

/* --- Dienst ueber Mitternacht ------------------------------------------- */
/* Ein Fenster 22:00-06:00 passt in keine Tagesspalte: es wird sichtbar
   geteilt und steht in ZWEI Spalten (siehe `dienstplan/ansicht.py`). Die
   Schnittkante wird dort geoeffnet, wo der Balken weiterlaeuft -- gerade
   Kante ohne Radius, gestrichelt, damit sie nicht wie ein Ende aussieht.
   Die AUSSAGE traegt aber der Pfeil und der Titel, nicht die Kante: eine
   fehlende Rundung ist ein Hinweis, kein Satz. */
.balken-weiter {
  border-right: 2px dashed var(--linie-stark);
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.balken-vortag {
  border-left: 2px dashed var(--linie-stark);
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}
/* Die Fortsetzung ist ein Spiegel, kein zweiter Fall: neutraler Rahmen,
   leicht zurueckgenommene Flaeche. Das SIGNAL (gelb/rot) steht am Starttag,
   wo das Fenster gezaehlt wird -- ein Alarm pro Tatsache. Die Luecke darin
   bleibt sichtbar und anklickbar. */
.balken-fortsetzung { border-color: var(--linie-stark); background: var(--flaeche-leise); }
/* Der Filter zaehlt Fenster, nicht Haelften -- die Fortsetzung wird darum
   gedimmt wie alles, was nicht gemeint ist (die Regeln dafuer stehen oben bei
   `[data-zeige]`), und nie hervorgehoben. */
/* Der Pfeil zur Tagesgrenze. Form, nicht Farbe -- und er sitzt UEBER den
   Kacheln, damit er auch in einem voll besetzten Fenster lesbar bleibt. */
.balken-grenze {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  font-size: 11px;
  line-height: 1;
  padding: 1px 2px;
  border-radius: var(--radius-klein);
  background: var(--flaeche);
  color: var(--text-leise);
  pointer-events: none;
}
.balken-weiter > .balken-grenze { right: 1px; }
.balken-vortag > .balken-grenze { left: 1px; }

.balken-flaeche {
  position: relative;
  display: block;
  height: calc(var(--kacheln, 1) * var(--kachelhoehe));
}

/* Luecke: schraffiert + „frei" -- Form UND Text, nicht nur Farbe. Die
   Uhrzeit steht im Titel und im Screenreader-Text. */
.luecke {
  position: absolute;
  top: 0; bottom: 0;
  display: grid;
  place-items: center;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
  background-image: repeating-linear-gradient(
    135deg, transparent 0 6px, var(--linie-stark) 6px 7px);
  color: var(--text-schwach);
  font: 400 10.5px/1 var(--schrift);
  cursor: copy;
  overflow: hidden;
}
.luecke:hover:not(:disabled) { box-shadow: inset 0 0 0 1px var(--info); color: var(--text); }
.luecke:disabled { cursor: default; }
/* Unter Mindestbesetzung: dichtere rote Schraffur -- in einem roten Fenster
   zeigt sie, WO niemand da ist (Soll 2/Min 1: nur der 0-von-2-Teil). */
.luecke-kritisch {
  color: var(--gefahr);
  font-weight: 700;
  background-image: repeating-linear-gradient(
    135deg, transparent 0 5px, color-mix(in srgb, var(--gefahr-rand) 55%, transparent) 5px 7px);
}
.luecke-kurz { padding: 0 3px; white-space: nowrap; }

/* Kachel = eine Zuweisung, ein Teilstueck des Fensters. Fuellt ihre Spur
   ganz aus (Vorlage: 11px fett, kein eigener Rand, 1px Fuge zum Nachbarn). */
.kachel {
  position: absolute;
  top: calc(var(--kachel-spur, 0) * var(--kachelhoehe));
  height: calc(var(--kachelhoehe) - 1px);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  min-width: 0;
  padding: 0 3px;
  border: 0;
  border-right: 1px solid var(--flaeche);
  border-radius: 0;
  background: var(--besetzt);
  color: var(--besetzt-text);
  font: 700 11px/1 var(--schrift);
  cursor: grab;
  overflow: hidden;
  white-space: nowrap;
}
.kachel:hover:not(:disabled) { filter: brightness(0.95); }
.kachel:disabled { cursor: default; }
.kachel-kuerzel { flex: 0 0 auto; text-transform: uppercase; letter-spacing: 0.02em; }
/* Die Uhrzeit erscheint nur waehrend des Ziehens am Rand (Live-Rueckmeldung);
   sonst steht sie im Titel und im Dialog. */
.kachel-zeit {
  display: none;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  opacity: 0.8;
}
.kachel.kachel-zieht .kachel-zeit { display: inline; }

/* Ziel beim Ziehen */
.ziel-aktiv {
  outline: 2px solid var(--haupt);
  outline-offset: 1px;
  background-color: var(--haupt-leise);
}
.balken.ziel-aktiv { outline-color: var(--haupt); }

/* --- Verwaiste Zuweisungen + Legende ------------------------------------ */
.verwaist {
  margin-top: 1.2rem;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--warn-rand);
  border-left: 4px solid var(--warn);
  border-radius: var(--radius);
  background: var(--warn-leise);
}
.verwaist h2 { margin: 0 0 0.3rem; font-size: 0.95rem; }
.verwaist p { margin: 0 0 0.5rem; font-size: 0.8rem; }
.verwaist ul { margin: 0; padding-left: 1.1rem; font-size: var(--bedien-groesse); }

/* Text-Legende (Bedarfs-Kalender) ... */
.legende {
  margin-top: 1rem;
  color: var(--text-schwach);
  font-size: 0.78rem;
  max-width: 78ch;
}
/* ... und die Musterreihe des Wochenrasters (Vorlage: Swatch + Wort, 11.5px). */
.legende-reihe {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  align-items: center;
  margin: 12px 0 0;
  max-width: none;
  font-size: 11.5px;
}
.legende-reihe > span { display: inline-flex; align-items: center; gap: 6px; }
.legende-text { flex-basis: 100%; }
.legende-muster {
  display: inline-block;
  width: 12px; height: 12px;
  border: 1px solid var(--linie-stark);
  border-radius: 3px;
  background: var(--flaeche);
}
.legende-besetzt { background: var(--besetzt); border-color: var(--besetzt-rand); }
.legende-frei { background-image: repeating-linear-gradient(135deg, transparent 0 3px, var(--linie-stark) 3px 4px); }
.legende-soll { position: relative; border-color: var(--warn); }
.legende-soll::after {
  content: ""; position: absolute; top: 1px; right: 1px;
  width: 4px; height: 4px; border-radius: 50%; background: var(--warn);
}
.legende-minimum { border-color: var(--gefahr-rand); border-left-width: 4px; background: var(--gefahr-leise); }
.legende-zu {
  background-color: var(--flaeche-tot);
  background-image: repeating-linear-gradient(135deg, transparent 0 3px, rgb(120 120 130 / 0.25) 3px 5px);
}
/* Dienst ueber Mitternacht: offene Kante rechts + Pfeil, wie am Balken. */
.legende-mitternacht {
  display: inline-grid;
  place-items: center;
  font-size: 9px;
  line-height: 1;
  color: var(--text-leise);
  border-right: 2px dashed var(--linie-stark);
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

/* --- Dialoge ------------------------------------------------------------ */
.dialog {
  width: min(30rem, calc(100vw - 2rem));
  padding: 0;
  color: var(--text);
  background: var(--flaeche);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  box-shadow: 0 10px 30px rgb(0 0 0 / 0.18);
}
.dialog::backdrop { background: rgb(24 24 27 / 0.45); }
.dialog-form { padding: 1rem 1.1rem; }
.dialog h2 { margin: 0 0 0.2rem; font-size: 1.05rem; }
.dialog-lage { margin: 0 0 0.8rem; font-size: var(--bedien-groesse); color: var(--text-leise); }
.dialog-hinweis { margin: 0.5rem 0 0.8rem; font-size: 0.75rem; color: var(--text-schwach); }

.zeitwahl { display: flex; align-items: end; gap: 0.6rem; flex-wrap: wrap; }
.zeitwahl label { display: grid; gap: 0.2rem; font-size: 0.75rem; color: var(--text-leise); }
.zeitwahl input {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.35rem 0.45rem;
  color: var(--text);
  background: var(--flaeche);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
}

.kandidaten { display: grid; gap: 0.3rem; max-height: 40vh; overflow-y: auto; }
.kandidat {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.2rem 0.5rem;
  align-items: center;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--linie);
  border-left: 4px solid var(--linie-stark);
  border-radius: var(--radius);
  background: var(--flaeche-leise);
}
.kandidat-geeignet { border-left-color: var(--haupt); }
.kandidat-moeglich { border-left-color: var(--warn); }
.kandidat-gesperrt { border-left-color: var(--gefahr); }
.kandidat-name { font-size: var(--bedien-groesse); font-weight: 600; }
.kandidat-klasse { font-size: 0.7rem; color: var(--text-schwach); }
.kandidat-grund { grid-column: 1 / -1; font-size: 0.72rem; color: var(--text-leise); }
.kandidat-knoepfe { display: flex; gap: 0.3rem; }

.dialog-fuss {
  display: flex;
  gap: 0.4rem;
  justify-content: flex-end;
  margin: 0.9rem 0 0;
  padding: 0;
}

/* --- Bewegung nur, wenn erwuenscht -------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* --- Tage ohne Bedarf: standardmaessig ausgeblendet ---------------------- */
/* Datengetrieben (`.tag-leer` am th UND an jeder Zelle der Spalte), nicht
 * Sa/So fest verdrahtet. Ausgeblendet ist der Standard; nur im
 * „alle Tage"-Modus (:root[data-alle-tage="ja"]) werden die Spalten gezeigt.
 * Der Standard greift auch ohne das Kopf-Skript (Attribut fehlt) — dann ist
 * die sichere Wahl „ausblenden". */
:root:not([data-alle-tage="ja"]) .tag-leer { display: none; }

.tage-leiste {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0 0 0.8rem;
}
.tage-ausgeblendet {
  margin: 0;
  font-size: 0.8rem;
  color: var(--text-schwach);
}
/* Die Ausblend-Zeile gilt nur, wenn wirklich ausgeblendet wird. */
:root[data-alle-tage="ja"] .tage-ausgeblendet { display: none; }

/* Der Umschalter zeigt die passende Beschriftung zum Zustand. */
.tage-umschalter .wenn-alle { display: none; }
:root[data-alle-tage="ja"] .tage-umschalter .wenn-ausgeblendet { display: none; }
:root[data-alle-tage="ja"] .tage-umschalter .wenn-alle { display: inline; }

/* =======================================================================
 * Bedarfs-Kalender (Ebene 2 grafisch: „was muss besetzt sein")
 * ===================================================================== */
.bedarf-intro { margin: 0 0 0.9rem; font-size: var(--bedien-groesse); color: var(--text-leise); max-width: 80ch; }
.bedarf-intro code { font-size: 0.8em; }

td.bedarf-zelle { position: relative; }
td.zelle-abweichung { background-color: color-mix(in srgb, var(--info-leise) 60%, transparent); }

.bedarf-spuren {
  --zeilenhoehe: 2.1rem;
  position: relative;
  height: calc(var(--spuren, 1) * var(--zeilenhoehe));
  margin-bottom: 0.15rem;
}

.bedarf-balken {
  position: absolute;
  top: calc(var(--spur, 0) * var(--zeilenhoehe));
  height: calc(var(--zeilenhoehe) - 0.3rem);
  min-width: 2.4rem;
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.1rem;
  padding: 0.1rem 0.3rem;
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius-klein);
  background: var(--flaeche-leise);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
}
.bedarf-balken:hover:not(:disabled) { border-color: var(--info); }
.bedarf-balken:disabled { cursor: default; }
/* Aus dem Muster: ruhiger, blauer Akzent. */
.bedarf-muster { border-color: var(--besetzt-rand); background: var(--besetzt); color: var(--besetzt-text); }
/* Tagesausnahme: gestrichelt + Sternchen -- Form traegt die Aussage mit. */
.bedarf-tagesausnahme {
  border-style: dashed;
  border-color: var(--warn); border-width: 1px 1px 1px 3px;
  background: var(--warn-leise); color: var(--text);
}
/* Ghost: was das Template an der Stelle saehe (ersetzt durch die Ausnahme). */
.bedarf-ghost {
  border-style: dotted;
  background: transparent;
  color: var(--text-schwach);
  opacity: 0.55;
  pointer-events: none;
}
.bedarf-kopf { display: flex; align-items: baseline; gap: 0.3rem; font-size: 0.66rem; line-height: 1; }
.bedarf-zeit { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bedarf-soll {
  margin-left: auto;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 0 0.15rem;
  border-radius: 3px;
  background: color-mix(in srgb, var(--flaeche) 70%, transparent);
}
.bedarf-marke { font-size: 0.6rem; color: var(--warn); font-weight: 800; }
@container (max-width: 4.2rem) { .bedarf-zeit { display: none; } }

.ausnahme-chip {
  display: flex; align-items: center; gap: 0.35rem;
  margin: 0.15rem 0 0;
  padding: 0.15rem 0.35rem;
  font-size: 0.68rem;
  border-radius: var(--radius-klein);
  background: var(--gefahr-leise);
  border: 1px solid var(--gefahr-rand);
  color: var(--text);
}
.ausnahme-chip .knopf { padding: 0.1rem 0.35rem; font-size: 0.66rem; }

.bedarf-plus {
  display: inline-block;
  margin-top: 0.2rem;
  padding: 0.15rem 0.4rem;
  font-size: 0.66rem;
  color: var(--text-schwach);
  background: transparent;
  border: 1px dashed var(--linie-stark);
  border-radius: var(--radius-klein);
  cursor: pointer;
  opacity: 0.5;
  transition: opacity 100ms;
}
td.bedarf-zelle:hover .bedarf-plus,
td.bedarf-zelle:focus-within .bedarf-plus { opacity: 1; }
.bedarf-plus:hover { border-color: var(--haupt); color: var(--haupt); }

.bedarf-art { border: 1px solid var(--linie); border-radius: var(--radius); padding: 0.5rem 0.7rem; margin: 0 0 0.7rem; }
.bedarf-art legend { padding: 0 0.3rem; font-size: 0.75rem; color: var(--text-schwach); }
.bedarf-art label { display: flex; align-items: center; gap: 0.4rem; font-size: var(--bedien-groesse); padding: 0.15rem 0; cursor: pointer; }

/* --- Wochenraster-Zeile: welches Muster gilt und warum -------------------- */
/* Eine ruhige Karte ueber dem Kalender. Der Name traegt die Aussage, die
 * Quelle steht als Satzteil daneben („aus Rotation ‚Standard', Woche 2 von 2"
 * bzw. „fuer diese Woche gewaehlt") — nie nur eine Farbe. */
.wochenmuster {
  display: flex; flex-direction: column; gap: 0.5rem;
  margin: 0 0 0.9rem;
  padding: 0.7rem 0.9rem;
  background: var(--flaeche);
  border: 1px solid var(--linie);
  border-left: 4px solid var(--besetzt-rand);
  border-radius: var(--radius);
}
.wochenmuster-lage { margin: 0; font-size: var(--bedien-groesse); color: var(--text-leise); display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.35rem 0.5rem; }
.wochenmuster-titel { text-transform: uppercase; letter-spacing: 0.04em; font-size: 0.7rem; color: var(--text-schwach); }
.wochenmuster-name { color: var(--text); font-size: 1rem; }
.wochenmuster-quelle { color: var(--text-leise); }
.wochenmuster-notiz { font-style: italic; color: var(--text-leise); }
.wochenmuster-spur { font-size: 0.72rem; color: var(--text-schwach); }
.wochenmuster-bedienung { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.wochenmuster-wahl { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.78rem; color: var(--text-schwach); }
.wochenmuster-wahl select, .wochenmuster-notizfeld, .musterwahl input, .musterwahl select {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.35rem 0.45rem; color: var(--text); background: var(--flaeche);
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
}
.wochenmuster-notizfeld { min-width: 14rem; }
.wochenmuster-hinweis {
  margin: 0; padding: 0.45rem 0.7rem;
  font-size: 0.78rem; color: var(--text);
  background: var(--warn-leise); border: 1px solid var(--warn-rand); border-radius: var(--radius);
}
/* Vorlage-Modus: das Banner ist gelb — hier wird die Vorlage geaendert, nicht die Woche. */
.wochenmuster-vorlage { border-left-color: var(--warn); background: var(--warn-leise); }
.wochenmuster-vorlage .wochenmuster-lage { color: var(--text); display: block; }
.musterwahl { display: grid; gap: 0.6rem; }
.musterwahl label { display: grid; gap: 0.2rem; font-size: 0.75rem; color: var(--text-leise); }
.dialog-hinweis-warnung { color: var(--warn); }
/* „gewaehlt" an der Muster-Kennzahl: kleiner Zusatz statt zweiter Kachel. */
.kennzahl-zusatz { font-size: 0.6rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--warn); vertical-align: middle; }

/* =======================================================================
 * Mitarbeiter-Ansicht („so arbeitest du"): ruhige Agenda
 * ===================================================================== */
.mitarbeiter-kopf {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.8rem 1.4rem; margin-bottom: 0.7rem;
}
.mitarbeiter-werkzeuge { display: flex; align-items: center; gap: 0.8rem; margin-left: auto; flex-wrap: wrap; }

.segmentwahl { display: inline-flex; border: 1px solid var(--linie-stark); border-radius: var(--radius); overflow: hidden; }
.segmentwahl a {
  padding: 0.3rem 0.7rem; font-size: 0.8rem; color: var(--text-leise); text-decoration: none;
  background: var(--flaeche-leise);
}
.segmentwahl a + a { border-left: 1px solid var(--linie-stark); }
.segmentwahl a.aktiv { background: var(--haupt); color: var(--haupt-text); font-weight: 600; }

.person-wahl { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.78rem; color: var(--text-schwach); }
.person-wahl select {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.3rem 0.4rem; color: var(--text); background: var(--flaeche);
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
}

.mitarbeiter-kennzahlen { display: flex; gap: 1.4rem; margin: 0 0 0.8rem; }
.mitarbeiter-kennzahlen dt { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-schwach); }
.mitarbeiter-kennzahlen dd { margin: 0; font-size: 1.15rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.mitarbeiter-kennzahlen .entwurf-hinweis dd { color: var(--warn); font-size: 0.9rem; }

.agenda {
  border: 1px solid var(--linie); border-radius: var(--radius); overflow: hidden;
  background: var(--flaeche); box-shadow: var(--schatten);
}
.agenda-tag { display: grid; grid-template-columns: 8.5rem 1fr; gap: 0.5rem; padding: 0.6rem 0.9rem; border-bottom: 1px solid var(--linie); }
.agenda-tag:last-child { border-bottom: 0; }
.agenda-tag.agenda-frei { background: var(--flaeche-leise); }
.agenda-datum { display: flex; flex-direction: column; gap: 0.1rem; }
.agenda-wtag { font-weight: 700; }
.agenda-dtext { font-size: 0.8rem; color: var(--text-schwach); font-variant-numeric: tabular-nums; }
.agenda-summe { font-size: 0.72rem; color: var(--text-schwach); font-variant-numeric: tabular-nums; }
.agenda-schichten { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.agenda-leer { font-size: 0.8rem; color: var(--text-schwach); font-style: italic; }

.schicht {
  display: inline-flex; align-items: baseline; gap: 0.5rem;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--besetzt-rand);
  border-left-width: 4px;
  border-radius: var(--radius);
  background: var(--besetzt); color: var(--besetzt-text);
}
.schicht-entwurf { background: var(--warn-leise); color: var(--text); border-color: var(--warn); }
.schicht-zeit { font-weight: 700; font-variant-numeric: tabular-nums; }
.schicht-position { font-weight: 600; }
.schicht-gruppe { font-size: 0.72rem; opacity: 0.75; }
.schicht-status { font-size: 0.68rem; padding: 0.05rem 0.35rem; border-radius: 999px; border: 1px solid var(--warn); color: var(--warn); }
.schicht-notiz { font-size: 0.72rem; opacity: 0.8; }
/* „Weicht von deiner ueblichen Zeit ab: <Grund>" -- eigene Zeile unter der Schicht. */
.schicht-abweichend { flex-basis: 100%; font-size: 0.72rem; color: var(--warn); font-weight: 600; }
.schicht:has(.schicht-abweichend) { flex-wrap: wrap; }

/* Nachtdienst: der Satz „endet am Folgetag um 06:00" bekommt eine eigene
   Zeile, damit er nicht neben der Uhrzeit untergeht -- die Aussage traegt der
   Text, nicht die Farbe. Was aus der Nacht HEREINlaeuft, ist keine eigene
   Schicht: gestrichelter Rand statt voller Kachel, damit die Stunden nicht
   zweimal gelesen werden. */
.schicht-nacht { flex-basis: 100%; font-size: 0.72rem; color: var(--text-leise); }
.schicht:has(.schicht-nacht) { flex-wrap: wrap; }
.schicht-aus-nacht { border-style: dashed; background: var(--flaeche-leise); }

.ical-box {
  margin-top: 1.2rem; padding: 0.9rem 1.1rem;
  border: 1px solid var(--linie); border-radius: var(--radius); background: var(--flaeche);
}
.ical-box h2 { margin: 0 0 0.3rem; font-size: 0.95rem; }
.ical-box p { margin: 0 0 0.6rem; font-size: 0.8rem; color: var(--text-leise); max-width: 70ch; }
.ical-zeile { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; margin-bottom: 0.5rem; }
.ical-zeile input {
  flex: 1 1 20rem; min-width: 0;
  font: 0.78rem var(--schrift); padding: 0.35rem 0.45rem;
  color: var(--text); background: var(--flaeche-leise);
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
}

/* =======================================================================
 * Drucken
 * ===================================================================== */
/* Gedruckt wird NICHT die Web-Ansicht, sondern eine eigene Druckseite
   (/dienstplan/druck/..., static/css/druck.css) -- die „Drucken"-Knoepfe oeffnen sie
   im neuen Tab. Landet doch jemand mit Strg+P auf einer Web-Seite, bleibt nur
   das Bedien-Chrome weg; ein zweiter Druckweg wird hier bewusst nicht gepflegt. */
@media print {
  :root { color-scheme: light; }
  .kopf, .fuss, .nur-bildschirm, .thema-wahl, dialog, [data-meldung] { display: none !important; }
}
/* Druck-Link unter dem Bedarfskalender (der Kopf dort gehoert dem Bedarf-Strang). */
.druck-leiste { display: flex; justify-content: flex-end; margin: 0.6rem 0 0; }

/* =======================================================================
 * Stammdaten (/dienstplan/stammdaten/): Reiter, Karten, Tabellen, Formulare
 * ===================================================================== */
.stammdaten { max-width: 76rem; }
.stamm-kopf { display: flex; align-items: center; flex-wrap: wrap; gap: 0.8rem 1.2rem; margin-bottom: 1rem; }
.stamm-kopf h1 { margin: 0; font-size: 1.15rem; }
.stamm-admin { margin-left: auto; font-size: 0.78rem; color: var(--text-schwach); }

/* Reiter wie der Woche/Monat-Umschalter der Mitarbeiter-Ansicht. */
.reiter { display: inline-flex; border: 1px solid var(--linie-stark); border-radius: var(--radius); overflow: hidden; }
.reiter a {
  padding: 0.35rem 0.8rem; font-size: var(--bedien-groesse); color: var(--text-leise); text-decoration: none;
  background: var(--flaeche-leise);
}
.reiter a + a { border-left: 1px solid var(--linie-stark); }
.reiter a:hover { background: var(--flaeche-tot); color: var(--text); }
.reiter a.aktiv { background: var(--haupt); color: var(--haupt-text); font-weight: 600; }

.karte {
  padding: 0.9rem 1.1rem; margin-bottom: 1rem;
  border: 1px solid var(--linie); border-radius: var(--radius);
  background: var(--flaeche); box-shadow: var(--schatten);
}
.karte-kopf { display: flex; align-items: center; gap: 0.8rem; margin-bottom: 0.5rem; }
.karte-kopf h2 { margin: 0; font-size: 0.95rem; }
.karte-kopf h2 small { font-weight: 400; color: var(--text-schwach); margin-left: 0.3rem; }
.karte-kopf > .knopf { margin-left: auto; }
.karten-raster { display: grid; grid-template-columns: repeat(auto-fit, minmax(21rem, 1fr)); gap: 1rem; align-items: start; }
.leise { color: var(--text-schwach); font-size: 0.78rem; }
p.leise { margin: 0 0 0.7rem; max-width: 80ch; line-height: 1.45; }

.meldungen { display: grid; gap: 0.4rem; margin: 0 0 0.8rem; }
.meldungen .meldung { margin: 0; }
.meldung[data-art="warn"], .meldung[data-art="info"] {
  padding: 0.55rem 0.8rem;
  border: 1px solid var(--linie-stark);
  border-left: 4px solid var(--warn);
  border-radius: var(--radius);
  background: var(--warn-leise);
  color: var(--text);
}
.meldung[data-art="info"] { border-left-color: var(--info); background: var(--info-leise); }

/* Tabellen der Stammdaten: ruhig, eine Zeile = ein Objekt, Aktionen rechts. */
.stamm-tabelle { width: 100%; border-collapse: collapse; font-size: var(--bedien-groesse); }
.stamm-tabelle th, .stamm-tabelle td {
  padding: 0.45rem 0.5rem; text-align: left; vertical-align: middle;
  border-bottom: 1px solid var(--linie);
}
.stamm-tabelle thead th { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-schwach); font-weight: 600; }
.stamm-tabelle .gruppenkopf th { background: var(--flaeche-leise); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-leise); }
.stamm-tabelle tr.inaktiv td { color: var(--text-schwach); }
.stamm-tabelle tr.inaktiv .zeilen-name { text-decoration: line-through; text-decoration-color: var(--linie-stark); }
.stamm-tabelle .zeilen-name { font-weight: 600; }
.stamm-tabelle a.zeilen-link { color: inherit; text-decoration: none; }
.stamm-tabelle a.zeilen-link:hover { text-decoration: underline; color: var(--info); }
.stamm-tabelle code { font-size: 0.8em; padding: 0.05rem 0.3rem; background: var(--flaeche-leise); border-radius: 4px; }
.stamm-tabelle td.aktionen, .stamm-tabelle th.aktionen { text-align: right; white-space: nowrap; }
.aktionen form { display: inline; }
/* P21: Abstand zwischen den Knoepfen einer Aktionszelle. `display: inline`
   gibt Formularen keinen eigenen Rand -- ohne diese Regel hing der Abstand
   davon ab, ob zwischen den Tags im Template zufaellig ein Leerzeichen im
   Quelltext stand (0px, wenn `{% if %}` es wegfrisst; gemessen in
   `_zeile_aktionen.html`). `> * + *` statt `:last-child`-Gegenstueck, weil die
   Zelle Formulare UND einen Link (Bearbeiten) UND einen reinen Text
   (`.leise` bei "in Verwendung") mischt. */
.aktionen > * + * { margin-left: 0.5rem; }
.aktionen .knopf { padding: 0.2rem 0.45rem; font-size: 0.75rem; vertical-align: middle; }
.zeile-form td { background: var(--flaeche-leise); }

.stamm-status {
  display: inline-block; padding: 0.05rem 0.5rem; border-radius: 999px; font-size: 0.72rem;
  border: 1px solid var(--haupt); color: var(--haupt); background: var(--haupt-leise);
}
.stamm-status-inaktiv { border-color: var(--linie-stark); color: var(--text-schwach); background: var(--flaeche-leise); }

/* Zusaetzliche Treffer aus einem Fremdsystem (Paket P16, weclapp) -- eigener
   Block unter der eigenen Tabelle, damit die beiden Herkuenfte nicht wie eine
   einzige Liste aussehen. */
.stamm-weclapp { margin-top: 1rem; padding-top: 0.8rem; border-top: 1px dashed var(--linie-stark); }
.stamm-weclapp h3 { margin: 0 0 0.4rem; font-size: 0.85rem; }
.stamm-weclapp-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.stamm-weclapp-liste li {
  display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; justify-content: space-between;
  padding: 0.4rem 0.5rem; border: 1px solid var(--linie); border-radius: var(--radius); background: var(--flaeche-leise);
}

/* Formulare: Raster aus Feldern; Textbereiche und Mehrfach-Haken ueber die volle Breite. */
.stamm-form {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.6rem 0.9rem; align-items: start;
}
.stamm-form-neu { padding: 0.8rem 0.9rem; margin-bottom: 0.9rem; border: 1px dashed var(--linie-stark); border-radius: var(--radius); background: var(--flaeche-leise); }
.stamm-form h3 { margin: 0; font-size: 0.85rem; }
.feld-breit { grid-column: 1 / -1; }
.stamm-form menu { grid-column: 1 / -1; display: flex; gap: 0.4rem; margin: 0.2rem 0 0; padding: 0; }
.feld { display: grid; gap: 0.2rem; font-size: 0.75rem; color: var(--text-leise); align-content: start; }
.feld label { font-weight: 500; }
.feld .pflicht { color: var(--text-schwach); }
.feld small { color: var(--text-schwach); line-height: 1.35; }
.feld input:not([type="checkbox"]):not([type="radio"]), .feld select, .feld textarea {
  width: 100%; font: var(--bedien-groesse) var(--schrift); padding: 0.35rem 0.45rem;
  color: var(--text); background: var(--flaeche);
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
}
.feld textarea { resize: vertical; }
/* Dateifelder. `min-width: 0` ist hier keine Kosmetik: ein `input[type=file]`
   bringt einen eigenen, breiten Mindestinhalt mit (Knopf plus „keine
   ausgewaehlt"), und in einem Raster zieht dieser Mindestinhalt die GANZE
   Spalte auf. `max-width: 100%` hilft dagegen nicht -- geklammert wird die
   Breite, nicht der Mindestbeitrag zur Spaltenbreite. Ohne diese Zeile lief
   die Rueckmeldungsseite auf einem schmalen Telefon 273 Pixel ueber den Rand,
   und zwar unabhaengig davon, was das Medienabfrage-Layout darueber sagt. */
.feld input[type="file"] { min-width: 0; }
.feld-fehler input, .feld-fehler select, .feld-fehler textarea { border-color: var(--gefahr); }
.feld-meldung { color: var(--gefahr); font-size: 0.72rem; }
/* `.feld-haken` selbst (Flex statt Raster, Kippschalter statt Kaestchen) steht
   jetzt weiter unten bei den anderen P21-Regeln zum Schalter — Aenderung, kein
   zweiter Satz. */
/* CheckboxSelectMultiple rendert eine <ul> */
.feld > div, .feld ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.3rem 0.9rem; }
.feld ul label { display: inline-flex; align-items: center; gap: 0.3rem; font-size: var(--bedien-groesse); color: var(--text); font-weight: 400; }

.chip-leiste { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; }
.chip-still { cursor: default; }
.chip-still:hover { border-color: var(--linie-stark); color: var(--text-leise); background: var(--flaeche-leise); }

/* Mitarbeiter-Detail: Karten-Formulare in einer Zeile, Stamm-Chips, Zeit-Bloecke. */
.form-inline { display: flex; flex-wrap: wrap; gap: 0.5rem 0.7rem; align-items: end; margin-top: 0.7rem; padding-top: 0.7rem; border-top: 1px dashed var(--linie); }
.form-inline .feld { flex: 1 1 8rem; }
.form-inline .feld-breit { flex-basis: 100%; }
.form-inline > .knopf { flex: none; }
.stamm-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem; }
.stamm-chip {
  /* P21: Abstand auf 0.5rem angehoben (Auftrag „Knoepfe ohne Abstand") -- die
     Pfeile und das Entfernen-Kreuz sassen mit 0.15rem/0.4rem unter dem
     Guideline-Mindestmass von 0.5rem und klebten optisch aneinander. */
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.2rem 0.3rem 0.2rem 0.7rem;
  border: 1px solid var(--linie-stark); border-radius: 999px; background: var(--flaeche-leise);
  font-size: var(--bedien-groesse);
}
.stamm-chip .rang { font-weight: 700; color: var(--haupt); }
.stamm-chip form { display: inline-flex; gap: 0.5rem; }
.stamm-chip .knopf { padding: 0.05rem 0.4rem; font-size: 0.72rem; border-radius: 999px; }
.zeiten { display: grid; gap: 0; }
.zeiten-tag { display: grid; grid-template-columns: 6.5rem 1fr; gap: 0.4rem; align-items: center; padding: 0.3rem 0; border-bottom: 1px solid var(--linie); font-size: var(--bedien-groesse); }
.zeiten-tag:last-child { border-bottom: 0; }
.zeiten-tag-name { font-weight: 600; }
.zeiten-bloecke { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.zeiten-frei { color: var(--text-schwach); font-style: italic; }
.zeit-block {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.1rem 0.2rem 0.1rem 0.55rem;
  border: 1px solid var(--besetzt-rand); border-radius: var(--radius);
  background: var(--besetzt); color: var(--besetzt-text); font-variant-numeric: tabular-nums; font-weight: 600;
}
.zeit-block form { display: inline; }
.zeit-block .knopf { padding: 0 0.35rem; font-size: 0.72rem; }

/* „Uebernehmen aus ...": zwei Quellen nebeneinander, je Person eine Zeile. */
.sync-block h3 { margin: 0 0 0.3rem; font-size: 0.9rem; }
.sync-block h3 small { font-weight: 400; color: var(--text-schwach); }
.sync-leer { margin: 0; padding: 0.6rem 0.8rem; font-size: var(--bedien-groesse); color: var(--text-leise); background: var(--flaeche-leise); border-radius: var(--radius); }
.sync-zeile {
  display: flex; flex-wrap: wrap; gap: 0.5rem 0.7rem; align-items: end;
  padding: 0.6rem 0.7rem; margin-bottom: 0.5rem;
  border: 1px solid var(--linie); border-radius: var(--radius); background: var(--flaeche-leise);
}
.sync-zeile .feld { flex: 1 1 7rem; }
.sync-quelle { flex-basis: 100%; display: flex; flex-wrap: wrap; gap: 0.2rem 0.6rem; align-items: baseline; font-size: var(--bedien-groesse); }
.sync-grund { flex-basis: 100%; font-size: 0.75rem; color: var(--haupt); }
.sync-wahl { display: flex; gap: 0.5rem; align-items: end; flex: 1 1 100%; }
.sync-wahl .feld { flex: 1 1 auto; }
.sync-wahl .knopf { flex: none; }

/* --- Einstellungen: Rotation/Muster/Schliesstage (gleiche Bausteine wie Stammdaten) --- */
.einstellungen .karte-innen { margin-bottom: 0; }
.einstellungen .vorschau-titel { margin: 1rem 0 0.4rem; font-size: 0.85rem; }
.einstellungen .vorschau-titel small { font-weight: 400; }
.einstellungen .wirksam { margin: 0.8rem 0 0; padding: 0.5rem 0.7rem; font-size: 0.78rem; color: var(--text-leise); background: var(--flaeche-leise); border-radius: var(--radius); }
.einstellungen .wirksam dt { display: inline; font-weight: 600; margin-right: 0.4rem; }
.einstellungen .wirksam dd { display: inline; margin: 0; }
.einstellungen tr.gewaehlt td { background: var(--haupt-leise); }
.einstellungen tr.vorschau-gewaehlt td { background: var(--haupt-leise); }
.einstellungen tr.vorbei td { color: var(--text-schwach); }
.einstellungen tr.wochenende td { color: var(--text-schwach); }
.einstellungen .form-inline { margin-top: 0.2rem; border-top: 0; padding-top: 0; }

/* =======================================================================
 * Hilfe (/dienstplan/hilfe/): docs/anleitung.md als Lesetext mit Inhaltsverzeichnis
 * ===================================================================== */
/* Link in der Kopfzeile, gleiche Anmutung wie die Hauptnavigation. */
.hilfe-link {
  color: var(--text-leise); text-decoration: none; font-size: var(--bedien-groesse);
  padding: 0.35rem 0.5rem; border-radius: var(--radius-klein);
}
.hilfe-link:hover { background: var(--flaeche-leise); color: var(--text); }

/* Kontext-Hilfe „?" neben einer Ueberschrift: klein, rund, unaufdringlich. */
.hilfe-punkt {
  display: inline-grid; place-items: center; width: 1.35rem; height: 1.35rem;
  border: 1px solid var(--linie-stark); border-radius: 999px;
  font-size: 0.78rem; font-weight: 600; line-height: 1; text-decoration: none;
  color: var(--text-schwach); background: var(--flaeche);
}
.hilfe-punkt:hover { color: var(--info); border-color: var(--info); background: var(--info-leise); }

/* Zwei Spalten: klebendes Verzeichnis links, Text in Lesebreite rechts. */
.hilfe { display: grid; grid-template-columns: 17rem minmax(0, 72ch); gap: 2rem; align-items: start; }
.hilfe-toc {
  position: sticky; top: calc(var(--kopf-hoehe) + 1rem);
  max-height: calc(100vh - var(--kopf-hoehe) - 2rem); overflow: auto;
  padding: 0.9rem 1rem; font-size: 0.82rem;
  border: 1px solid var(--linie); border-radius: var(--radius); background: var(--flaeche); box-shadow: var(--schatten);
}
.hilfe-toc-titel { margin: 0 0 0.4rem; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-schwach); }
.hilfe-toc ul { list-style: none; margin: 0; padding: 0; }
.hilfe-toc ul ul { padding-left: 0.85rem; margin: 0.15rem 0 0.35rem; }
.hilfe-toc li { margin: 0.15rem 0; }
.hilfe-toc a { color: var(--text-leise); text-decoration: none; display: block; padding: 0.12rem 0.3rem; border-radius: var(--radius-klein); }
.hilfe-toc > .toc > ul > li > a { font-weight: 600; color: var(--text); }
.hilfe-toc a:hover { background: var(--flaeche-leise); color: var(--text); }
.hilfe-toc-fuss { margin: 0.6rem 0 0; }

.hilfe-text { font-size: 0.95rem; line-height: 1.6; }
.hilfe-text h1 { font-size: 1.5rem; margin: 0 0 1rem; }
.hilfe-text h2 { font-size: 1.2rem; margin: 2.2rem 0 0.6rem; padding-top: 1rem; border-top: 1px solid var(--linie); }
.hilfe-text h3 { font-size: 1rem; margin: 1.5rem 0 0.4rem; }
/* Sprungziele nicht unter der klebenden Kopfzeile verschwinden lassen. */
.hilfe-text h2, .hilfe-text h3 { scroll-margin-top: calc(var(--kopf-hoehe) + 0.75rem); }
.hilfe-text p, .hilfe-text ul, .hilfe-text ol { margin: 0 0 0.8rem; }
.hilfe-text li { margin: 0.2rem 0; }
.hilfe-text blockquote {
  margin: 0 0 1rem; padding: 0.6rem 0.9rem; color: var(--text-leise);
  border-left: 4px solid var(--haupt); background: var(--haupt-leise); border-radius: var(--radius);
}
.hilfe-text blockquote p:last-child { margin: 0; }
.hilfe-text code { font-size: 0.85em; padding: 0.05rem 0.3rem; background: var(--flaeche-leise); border: 1px solid var(--linie); border-radius: var(--radius-klein); }
.hilfe-text table { border-collapse: collapse; width: 100%; margin: 0 0 1rem; font-size: 0.88rem; }
.hilfe-text th, .hilfe-text td { padding: 0.4rem 0.6rem; border: 1px solid var(--linie); vertical-align: top; text-align: left; }
.hilfe-text th { background: var(--flaeche-leise); font-weight: 600; }
/* Begriffe und Fragen als Definitionsliste: Begriff fett, Erklaerung eingerueckt. */
.hilfe-text dl { margin: 0 0 1rem; }
.hilfe-text dt { font-weight: 600; margin-top: 0.7rem; }
.hilfe-text dd { margin: 0.15rem 0 0 1.2rem; color: var(--text-leise); }
.hilfe-text hr { border: 0; border-top: 1px solid var(--linie); margin: 1.5rem 0; }

@media (max-width: 900px) {
  .hilfe { grid-template-columns: minmax(0, 1fr); }
  .hilfe-toc { position: static; max-height: none; }
}
@media print {
  .hilfe { display: block; }
  .hilfe-punkt, .hilfe-link { display: none !important; }
}

/* --- Vorlage: kopieren (Tag / Zeile / Fenster) ---------------------------- */
/* Die Kopier-Knoepfe sitzen in Spalten- und Zeilenkopf; leise, damit sie das
   Raster nicht dominieren, aber immer sichtbar (kein Hover-Raetsel). */
.kopier-knopf { display: block; margin-top: 0.25rem; font-size: 0.66rem; padding: 0.1rem 0.4rem; color: var(--text-schwach); }
th.tag .kopier-knopf { display: inline-block; margin: 0 0 0 0.4rem; vertical-align: middle; }
.kopier-knopf:hover { color: var(--haupt); border-color: var(--haupt); }
.kopier-felder { display: grid; gap: 0.7rem; }
.kopier-quelle { display: grid; gap: 0.2rem; font-size: 0.75rem; color: var(--text-leise); }
.kopier-quelle select {
  font: var(--bedien-groesse) var(--schrift);
  padding: 0.35rem 0.45rem;
  color: var(--text);
  background: var(--flaeche);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
}
.kopier-ziele { display: flex; flex-wrap: wrap; gap: 0.3rem 0.7rem; margin: 0; padding: 0.4rem 0.6rem; border: 1px solid var(--linie); border-radius: var(--radius); }
.kopier-ziele legend { font-size: 0.75rem; color: var(--text-leise); padding: 0 0.2rem; }
.kopier-ziele label { display: inline-flex; align-items: center; gap: 0.25rem; font-size: var(--bedien-groesse); }
.kopier-ziele input:disabled + span { color: var(--text-schwach); text-decoration: line-through; }
.fenster-kopie { margin: 0.7rem 0 0; padding: 0.5rem 0.6rem; border: 1px solid var(--linie); border-radius: var(--radius); }
.fenster-kopie legend { font-size: 0.75rem; color: var(--text-leise); padding: 0 0.2rem; }
.tag-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; }
.tag-chips .chip:disabled { opacity: 0.45; cursor: not-allowed; }
.tag-chips .knopf { margin-left: auto; }

/* =====================================================================
 * Klammer: die Startseite /ich/
 * =====================================================================
 *
 * Hier stand bis Welle 1 der Werkzeug-Umschalter (`.wechsler`) -- ein
 * Aufklappmenue in der Kopfzeile, das immer nur EIN Modul zeigte. Er ist
 * durch das linke Modulmenue ersetzt (Abschnitt „Rahmen" am Ende dieser
 * Datei); seine Regeln sind mitgegangen, damit niemand sie aus Versehen
 * weiterbenutzt.
 */

/* --- Startseite „Fuer mich" ------------------------------------------- */
/* Volle Breite wie in jedem anderen Modul. Vorher klebte die Seite auf 44rem
   in der Mitte und liess auf einem gewoehnlichen Monitor links und rechts
   handbreit Nichts stehen — als waere die Seite kaputt geladen.
   Die Zeilenlaenge bleibt trotzdem lesbar, weil die Kaesten NEBENEINANDER
   wachsen statt in die Breite gezogen zu werden. */
.ich-seite { padding: 1rem 1.25rem 2rem; display: grid; gap: 0.9rem; align-content: start; }
.ich-seite > .meine-reiter { grid-column: 1 / -1; }
@media (min-width: 60rem) {
  .ich-seite { grid-template-columns: minmax(22rem, 30rem) minmax(20rem, 1fr); align-items: start; }
  /* „Heute" ist der einzige Kasten, der ueber beide Spalten geht: er muss
     ueber den Flur lesbar sein, und dafuer braucht er Luft. */
  .ich-seite > .ich-heute { grid-column: 1 / -1; }
  .ich-seite > .ich-fuss { grid-column: 1 / -1; }
}
.ich-heute {
  border: 1px solid var(--linie-stark); border-radius: var(--radius);
  background: var(--flaeche); padding: 1rem 1.1rem; box-shadow: var(--schatten);
}
.ich-heute h1 { margin: 0 0 0.6rem; font-size: 1.05rem; color: var(--text-leise); font-weight: 600; }
.ich-schicht {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.3rem 0.8rem;
  padding: 0.4rem 0; border-top: 1px solid var(--linie);
}
.ich-schicht:first-of-type { border-top: 0; }
/* „Heute ist gross": die Uhrzeit muss ueber den Flur lesbar sein. */
.ich-zeit { font-size: 1.6rem; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.ich-position { font-size: 1.1rem; font-weight: 600; }
.ich-position small { font-weight: 400; color: var(--text-schwach); font-size: 0.8rem; }
.ich-abweichung { flex-basis: 100%; font-size: 0.8rem; color: var(--warn); font-weight: 600; }
/* Nachtdienst auf „Fuer mich": eigene Zeile fuer den Satz, und was aus der
   Nacht hereinlaeuft bekommt einen gestrichelten Rand -- es ist keine zweite
   Schicht, sondern die von gestern. */
.ich-nacht { flex-basis: 100%; font-size: 0.8rem; color: var(--text-leise); }
.ich-schicht-nacht { border-left: 3px dashed var(--linie-stark); padding-left: 0.5rem; }
.ich-frei { margin: 0; font-size: 1.2rem; color: var(--text-leise); }
.ich-morgen { margin: 0.7rem 0 0; padding-top: 0.5rem; border-top: 1px solid var(--linie); font-size: var(--bedien-groesse); color: var(--text-leise); }
.ich-karte { margin: 0; }
.ich-karte .karte-kopf h2 { font-size: 0.9rem; }
.ich-karte .karte-kopf h2 small { color: var(--text-schwach); font-weight: 400; margin-left: 0.3rem; }
.ich-aufgaben { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.3rem; }
.ich-aufgaben li { display: flex; align-items: center; gap: 0.5rem; font-size: var(--bedien-groesse); }
.ich-nr {
  flex: none; display: grid; place-items: center; width: 1.4rem; height: 1.4rem; border-radius: 50%;
  background: var(--flaeche-leise); border: 1px solid var(--linie-stark); font-size: 0.7rem; font-weight: 700;
}
.ich-aufgabe-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ich-aufgabe-text.erledigt { text-decoration: line-through; color: var(--text-schwach); }
.ich-aufgabe-zeit { flex: none; font-variant-numeric: tabular-nums; color: var(--text-leise); }
.ich-woche { list-style: none; margin: 0 0 0.4rem; padding: 0; display: grid; gap: 0.15rem; font-size: var(--bedien-groesse); }
.ich-woche li { display: flex; gap: 0.6rem; padding: 0.15rem 0.3rem; border-radius: var(--radius-klein); }
.ich-woche li.heute { background: var(--haupt-leise); font-weight: 600; }
.ich-woche li.frei .ich-wschichten { color: var(--text-schwach); }
.ich-wtag { flex: none; width: 2rem; font-weight: 600; color: var(--text-leise); }
.ich-abwesenheiten { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.2rem; font-size: var(--bedien-groesse); }
.ich-fuss { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.2rem 0 0; }
.ich-werkzeuge { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.3rem; }
.ich-werkzeuge a { display: flex; gap: 0.5rem; align-items: baseline; text-decoration: none; color: var(--text); padding: 0.35rem 0.4rem; border-radius: var(--radius-klein); }
.ich-werkzeuge a:hover { background: var(--flaeche-leise); }
.ich-werkzeuge small { color: var(--text-schwach); }

/* Schmale Bildschirme: die Startseite bekommt weniger Rand. */
@media (max-width: 620px) {
  .ich-seite { padding: 0.8rem 0.9rem 2rem; }
}

/* --- Hilfe: Einstieg je Modul -------------------------------------------
 * EIN Dokument, vier Einstiege. Der Hilfe-Knopf der Kopfzeile springt in das
 * Kapitel des Moduls, in dem man gerade steht; hier oben stehen alle. Vier
 * getrennte Hilfetexte waeren vier Dokumente, die auseinanderdriften. */
.hilfe-module { list-style: none; margin: 0 0 1rem; padding: 0; font-size: 0.9rem; }
.hilfe-module li { margin: 0.15rem 0; }
.hilfe-module a { display: block; padding: 0.2rem 0.3rem; border-radius: 4px; text-decoration: none; }
.hilfe-module a:hover { background: var(--flaeche-leise); }
.hilfe-module a.aktiv { background: var(--flaeche-leise); font-weight: 600; }

/* --- Der Modulkopf: gleiche Dinge an derselben Stelle ---------------------
 *
 * Jedes Modul beantwortet oben dieselben drei Fragen, und zwar in dieser
 * Reihenfolge — waagerecht gelesen, nicht ueber die ganze Breite verteilt:
 *
 *   1. WO bin ich?      Titel, darunter ggf. eine Zeile Erklaerung
 *   2. WAS kann ich?    Aktionen, Hauptaktion zuerst, immer links
 *   3. WELCHER AUSSCHNITT?  Zeitraumwahl — und der Filter DANEBEN
 *
 * Der dritte Punkt ist der Grund fuer diesen Block. Vorher hing der
 * Bereichsfilter der Abwesenheiten per `margin-left: auto` am rechten
 * Bildschirmrand, meterweit von der Tabelle entfernt, die er bestimmt.
 * Wer zwischen den Modulen wechselt, soll nichts suchen muessen.
 */
.modulkopf { margin-bottom: 0.9rem; }
.modulkopf h1 { margin: 0 0 0.15rem; }
.modulkopf > p.leise { margin: 0 0 0.6rem; max-width: 62ch; }
.modulkopf-aktionen {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
  margin: 0 0 0.6rem;
}
.modulkopf-aktionen .knopf.aktiv { background: var(--haupt-leise); border-color: var(--haupt); }

/* Zeitraumwahl — `templates/_monatswahl.html` und alles, was so aussehen soll. */
.wahl {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 0.6rem;
}
.wahl select, .wahl input[type="number"], .wahl input[type="date"] {
  font-size: var(--bedien-groesse);
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  background: var(--flaeche);
  color: var(--text);
}
.wahl label:not(.nur-sr) { font-size: 0.78rem; color: var(--text-leise); margin-left: 0.4rem; }
.wahl-jahr { width: 5.5rem; }
.wahl-spruenge { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-left: 0.5rem; }
.wahl [aria-current="page"] {
  background: var(--flaeche-tot);
  border-color: var(--linie-stark);
  font-weight: 600;
}
/* Der Filter sitzt am selben Faden wie die Wahl — nur durch einen Strich
   abgesetzt, damit man sieht: andere Frage, gleiche Leiste. */
.wahl-filter {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: 0.6rem;
  padding-left: 0.7rem;
  border-left: 1px solid var(--linie);
}
.wahl-person { margin-top: -0.2rem; }

@media (max-width: 700px) {
  .wahl-spruenge { margin-left: 0; }
  .wahl-filter { margin-left: 0; padding-left: 0; border-left: 0; }
}

/* --- „Fuer mich": eine Leiste, die mitwandert -----------------------------
 *
 * Wer ausser Stempeln nicht viel darf, sieht von der Software fast nichts:
 * seine Dienste stehen im Dienstplan, seine Zeiten in der Zeiterfassung, sein
 * Urlaub in den Abwesenheiten — drei Werkzeuge fuer drei Fragen, die dieselbe
 * Person zu sich selbst stellt.
 *
 * Die Reiter fuehren auf die vorhandenen Modulseiten, nicht auf Kopien: eine
 * zweite „Meine Zeiten"-Ansicht waere eine zweite Wahrheit. Die Leiste wandert
 * stattdessen mit — sie steht ueberall dort, wo es um die eigene Person geht.
 */
.meine-reiter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem;
  margin: 0 0 1rem;
  border-bottom: 1px solid var(--linie);
}
.meine-reiter a {
  padding: 0.4rem 0.75rem;
  font-size: var(--bedien-groesse);
  color: var(--text-leise);
  text-decoration: none;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  margin-bottom: -1px;
  white-space: nowrap;
}
.meine-reiter a:hover { background: var(--flaeche-leise); color: var(--text); }
/* Die aktive Lasche haengt an der Linie, statt darauf zu liegen: so sieht man,
   dass der Inhalt darunter zu ihr gehoert. */
.meine-reiter a[aria-current="page"] {
  background: var(--flaeche);
  border-color: var(--linie);
  border-bottom: 1px solid var(--flaeche);
  color: var(--text);
  font-weight: 600;
}


/* --- Rahmen-Vertrag (Welle 0): Meldungsbereich und Seitenraster ------------
   Reservierte Mindesthoehe, damit eine Meldung die Seite nicht verschiebt.
   Leer ist der Bereich unsichtbar, nimmt aber Platz -- das ist der Zweck.
   FEHLER (P5, Anlass „Lukas eingeteilt" liess das Raster springen): hier
   stand zusaetzlich `.meldungsbereich:empty { min-height: 0; }` -- das hat
   die reservierte Hoehe genau dann auf 0 kollabiert, wenn noch keine Meldung
   da war, und sie sprang beim ERSTEN Erscheinen einer Meldung wieder auf.
   Genau das widerspricht dem Kommentar direkt darueber und ist ersatzlos
   raus: die Hoehe bleibt reserviert, ob leer oder nicht. */
/* 2.75rem und nicht 2.5rem — GEMESSEN, nicht geschaetzt (Paket P11): eine
   einzeilige `.meldung` ist mit ihrem Innenabstand 40,6 px hoch, die
   reservierten 2.5rem waren 40 px. Die Seite sprang also bei JEDER Meldung um
   ein halbes Pixel nach unten; auf einem Bildschirm mit doppelter Punktdichte
   ist das ein sichtbarer Ruck. Aufgefallen ist es erst, als der Schnellmodus
   die Hoehe wirklich vermessen hat statt sie anzunehmen. */
.meldungsbereich { min-height: 2.75rem; }
/* `.meldung` traegt sonst `margin-bottom: 0.8rem` (fuer den freistehenden
   Gebrauch, siehe weiter oben) -- NUR wenn sie Text hat (`.meldung:empty`
   setzt sie auf 0). Innerhalb des Meldungsbereichs blieb genau DIESE Kante
   der Rest des Sprungs, nachdem `.meldungsbereich:empty` oben schon repariert
   war: leer 2.5rem, mit Text 2.5rem + 0.8rem Aussenabstand -- der Rand
   gehoert hier der reservierten Hoehe, nicht der Meldung selbst. */
.meldungsbereich .meldung { margin-bottom: 0; }
.seite { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; }
.seite.mit-seitenleiste { grid-template-columns: minmax(0, 1fr) 20rem; }
@media (max-width: 60rem) { .seite.mit-seitenleiste { grid-template-columns: minmax(0, 1fr); } }
@keyframes puls { from { background: var(--haupt-leise); } to { background: transparent; } }
.puls { animation: puls 1.2s ease-out 1; }


/* =====================================================================
 * Rahmen (Welle 1): linkes Modulmenue, Kopfmenues, Aktionsleiste
 * =====================================================================
 *
 * Ein Raster ueber das GANZE Dokument, nicht verschachtelte Kaesten: links das
 * Menue ueber die volle Hoehe, rechts Kopfzeile, Inhalt, Fuss. Damit steht das
 * Menue beim Scrollen still, ohne dass irgendwo `position: fixed` noetig ist —
 * und `fixed` ist genau die Eigenschaft, die auf Telefonen mit der ein- und
 * ausfahrenden Adresszeile kaempft.
 */
body.rahmen {
  display: grid;
  grid-template-columns: var(--menue-breite) minmax(0, 1fr);
  grid-template-rows: var(--kopf-hoehe) 1fr;
  min-height: 100vh;
}

.modulmenue {
  grid-column: 1;
  grid-row: 1 / span 2;
  display: flex;
  flex-direction: column;
  background: var(--menue);
  border-right: 1px solid var(--linie);
  /* `sticky` + `align-self: start` statt `fixed`: das Menue bleibt im Raster
     und braucht darum keine ausgerechnete Breite irgendwo sonst. */
  position: sticky;
  top: 0;
  align-self: start;
  /* Genau eine Bildschirmhoehe, nicht die Hoehe des Inhalts: `align-self:
     start` laesst das Menue sonst nach der letzten Zeile aufhoeren, und dann
     bricht die graue Flaeche mitten auf der Seite ab. `stretch` waere die
     andere Loesung und hebt `sticky` auf — ein Element, das schon so hoch wie
     die Zeile ist, kann nirgendwohin kleben. */
  height: 100vh;
  overflow-y: auto;
}

.kopf { grid-column: 2; grid-row: 1; }
.rahmen-inhalt { grid-column: 2; grid-row: 2; min-width: 0; display: flex; flex-direction: column; }
.rahmen-inhalt > .seite { flex: 1; }
/* Der Menueknopf gilt nur schmalen Bildschirmen; auf breiten ist das Menue
   immer offen und der Knopf waere ein Schalter ohne Wirkung. */
.menue-schalter { display: none; }

/* --- Logo-Kachel --------------------------------------------------------
 * Hoehe = Kopfzeile, Breite = Menue (Guidelines). Das Kundenlogo wird
 * EINGEPASST und nicht gestreckt: ein verzerrtes Praxislogo ist schlimmer als
 * gar keins. */
.logokachel {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 0.5rem;
  height: var(--kopf-hoehe);
  flex: none;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--linie);
  color: var(--text);
  text-decoration: none;
  font-weight: 700;
  overflow: hidden;
}
/* FESTE HOEHE, BREITE AUS DEM VERHAELTNIS — bei allen drei Stellen, an denen
   das Kundenlogo steht (Kachel, Menueknopf, Vorschau im Zahnrad).
   Grund: ein SVG ohne `width`/`height`-Attribute hat keine Eigengroesse,
   sondern nur ein Seitenverhaeltnis. Mit `max-height` allein hat der Browser
   dann nichts, woraus er eine Groesse ableiten koennte — er rechnet 0 x 0 aus,
   und das Logo ist unsichtbar, obwohl die Datei geladen wurde. Genau so kommen
   Logos aus Illustrator; im Browser gemessen, nicht vermutet. */
.logokachel img { height: calc(var(--kopf-hoehe) - 1rem); width: auto; max-width: 100%; object-fit: contain; }
.logokachel-name {
  font-size: 0.95rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --- Die Module ---------------------------------------------------------- */
.modulliste { list-style: none; margin: 0.5rem 0 0; padding: 0 0.4rem; display: grid; gap: 0.1rem; }
.modulliste-fremd {
  margin-top: auto;
  padding-top: 0.5rem;
  padding-bottom: 0.75rem;
  border-top: 1px solid var(--linie);
}
.modulzeile-kopf {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.55rem;
  border-radius: var(--radius-klein);
  color: var(--text-leise);
  text-decoration: none;
  font-size: var(--bedien-groesse);
  /* Beruehrungsziel nach Guidelines (Abschnitt 1, Mobil). */
  min-height: 2.25rem;
}
.modulzeile-kopf:hover { background: var(--menue-aktiv); color: var(--text); }
.modulzeile.aktiv > .modulzeile-kopf { color: var(--text); font-weight: 600; }
.modulzeichen {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.modulzeile.aktiv > .modulzeile-kopf .modulzeichen { color: var(--haupt); }
.modulzeichen-extern { margin-left: auto; width: 0.85rem; height: 0.85rem; color: var(--text-schwach); }

/* --- Die Punkte des aktiven Moduls --------------------------------------- */
.modulpunkte { list-style: none; margin: 0.1rem 0 0.4rem; padding: 0 0 0 1.75rem; display: grid; gap: 0.05rem; }
.modulpunkte li { display: flex; align-items: center; }
.modulpunkte li > a:first-child {
  flex: 1;
  min-width: 0;
  padding: 0.4rem 0.5rem;
  border-radius: var(--radius-klein);
  /* Die linke Kante gehoert dem aktiven Punkt; hier haelt sie nur den Platz
     frei, damit beim Wechsel nichts um drei Pixel springt. */
  border-left: 3px solid transparent;
  color: var(--text-leise);
  text-decoration: none;
  font-size: var(--bedien-groesse);
  min-height: 2rem;
  display: flex;
  align-items: center;
}
.modulpunkte li > a:first-child:hover { background: var(--menue-aktiv); color: var(--text); }
.modulpunkte li.aktiv > a:first-child {
  background: var(--flaeche-leise);
  border-left-color: var(--haupt);
  color: var(--text);
  font-weight: 600;
}
/* „In neuem Tab oeffnen": immer im Dokument (sonst faende die Tastatur ihn
   nie), sichtbar beim Hover und beim Fokus. */
.neuer-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 0.35rem;
  border-radius: var(--radius-klein);
  color: var(--text-schwach);
  opacity: 0;
}
.neuer-tab svg { width: 0.85rem; height: 0.85rem; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.modulpunkte li:hover .neuer-tab, .neuer-tab:focus-visible { opacity: 1; }
/* Zeigegeraet ohne Hover (Telefon, Tablet): dort gibt es kein „neuer Tab" im
   Sinne des Nutzers, und ein Dauer-Symbol neben jedem Punkt waere Krach. */
@media (hover: none) {
  .neuer-tab { display: none; }
}

/* --- Aufklappmenues der Kopfzeile ---------------------------------------- */
.aufklapper { position: relative; }
.aufklapper > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 2.25rem;
  padding: 0.35rem 0.5rem;
  border-radius: var(--radius-klein);
  color: var(--text-leise);
  font-size: var(--bedien-groesse);
}
.aufklapper > summary::-webkit-details-marker { display: none; }
.aufklapper > summary::marker { content: ""; }
.aufklapper > summary:hover { background: var(--flaeche-leise); color: var(--text); }
.aufklapper[open] > summary { background: var(--flaeche-leise); color: var(--text); }
.kopfzeichen {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.zeichen-aktiv { color: var(--haupt); fill: currentColor; }
.benutzer-name { max-width: 10rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.aufklapper-panel {
  position: absolute;
  top: calc(100% + 0.3rem);
  right: 0;
  z-index: 30;
  width: max-content;
  min-width: 14rem;
  /* Nie ueber den Bildschirmrand: auf 390px ist ein 20rem breites Panel
     breiter als das Fenster, und dann scrollt die ganze Seite waagerecht. */
  max-width: min(24rem, calc(100vw - 1.5rem));
  padding: 0.35rem;
  background: var(--flaeche);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.18);
  max-height: min(32rem, calc(100vh - var(--kopf-hoehe) - 1rem));
  overflow-y: auto;
}
.aufklapper-breit { min-width: 17rem; }
.aufklapper-titel {
  margin: 0.35rem 0.5rem 0.25rem;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-schwach);
}
.aufklapper-eintrag {
  display: block;
  padding: 0.45rem 0.5rem;
  border-radius: var(--radius-klein);
  color: var(--text);
  text-decoration: none;
  font-size: var(--bedien-groesse);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.aufklapper-eintrag:hover { background: var(--flaeche-leise); }
.aufklapper-eintrag.aktiv { background: var(--haupt-leise); font-weight: 600; }
.aufklapper-leer { margin: 0.3rem 0.55rem 0.5rem; color: var(--text-schwach); font-size: 0.8rem; white-space: normal; }
.aufklapper-panel hr { border: 0; border-top: 1px solid var(--linie); margin: 0.35rem 0.4rem; }
.aufklapper-form { margin: 0.35rem 0.4rem 0.2rem; }
.aufklapper-form .knopf { width: 100%; }
.aufklapper-panel .thema-wahl { margin: 0.35rem 0.4rem; }
.aufklapper-panel .thema-wahl legend { font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-schwach); padding: 0 0.2rem; }
/* P21: `.aufklapper-flach` trug bislang KEIN eigenes CSS. Ein <details> ohne
   Regel gibt seinem Inhalt keinen Innenabstand, und mehrere `<form>`
   hintereinander (Bearbeiten, Aktivieren/Stilllegen, Loeschen, die
   Reihenfolge-Pfeile) haben von Haus aus 0px Rand -- sie klebten aneinander
   (gemessen in `abwesenheiten/_zellen_arten.html`). `> p` daneben deckt die
   anderen Aufklapper ab, die einzelne Absaetze als direkte Kinder haben.
   Rechts UND unten Rand, nicht nur unten: `.tabelle td form` (tabelle.css)
   macht aus jedem Formular in einer Tabellenzelle ein `inline-flex`-Element,
   und zwei Inline-Boxen ruecken nur durch einen RECHTEN Rand auseinander --
   ein unterer Rand wirkt erst, wenn sie ohnehin schon umbrechen. */
.aufklapper-flach > summary { margin-bottom: 0.5rem; }
.aufklapper-flach > form,
.aufklapper-flach > p { margin: 0 0.5rem 0.5rem 0; }
.aufklapper-flach > form:last-child,
.aufklapper-flach > p:last-child { margin: 0; }
/* Dieselben Regeln, eine Klasse spezifischer: `.tabelle td form` liegt bei
   (0,1,2) und schlaegt `.aufklapper-flach > form` bei (0,1,1) -- unabhaengig
   davon, welches Blatt zuletzt eingebunden ist. `.tabelle` davor hebt uns auf
   (0,2,1) und gewinnt in jeder Ladereihenfolge. */
.tabelle .aufklapper-flach > form,
.tabelle .aufklapper-flach > p { margin: 0 0.5rem 0.5rem 0; }
.tabelle .aufklapper-flach > form:last-child,
.tabelle .aufklapper-flach > p:last-child { margin: 0; }

/* Zahl-Chip an „Neues" — die einzige Zahl in der Kopfzeile, darum darf sie
   auffallen. */
.zahl-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.1rem;
  height: 1.1rem;
  padding: 0 0.25rem;
  border-radius: 999px;
  background: var(--gefahr);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
}
.neues-eintrag { padding: 0.4rem 0.5rem; border-radius: var(--radius-klein); font-size: var(--bedien-groesse); }
.neues-eintrag p { margin: 0.2rem 0 0; color: var(--text-leise); }
.neues-eintrag small { margin-left: 0.35rem; }
.neues-ungelesen { background: var(--info-leise); }

/* --- Aktionsleiste -------------------------------------------------------
 * Alles, was auf das gezeigte Objekt wirkt, steht HIER — nicht unten rechts
 * und nicht im Inhalt verstreut (Guidelines, Abschnitt 1). Links genau eine
 * Hauptaktion, dann Gruppen als Aufklapper, rechts der Ansichtsumschalter. */
.aktionsleiste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 1.25rem;
  background: var(--flaeche);
  border-bottom: 1px solid var(--linie);
}
.aktionsleiste-ansicht { margin-left: auto; display: flex; align-items: center; gap: 0.5rem; }
.aktionsgruppe { position: relative; }
.aktionsgruppe > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.75rem;
  font: 500 var(--bedien-groesse)/1.2 var(--schrift);
  color: var(--text-leise);
  background: var(--flaeche-leise);
  border: 1px solid var(--linie-stark);
  border-radius: var(--radius);
}
.aktionsgruppe > summary::-webkit-details-marker { display: none; }
.aktionsgruppe > summary::marker { content: ""; }
.aktionsgruppe > summary:hover { background: var(--flaeche-tot); color: var(--text); }
.aktionsgruppe > .aufklapper-panel { left: 0; right: auto; }

/* --- Schmale Bildschirme (< 60rem) ---------------------------------------
 * Das Menue klappt hinter einen Knopf. Der Knopf steht als GESCHWISTER vor
 * dem Menue (`~`), weil sich ein zugeklapptes `<details>` per CSS nicht
 * verlaesslich wieder aufklappen laesst — die Begruendung steht ausfuehrlich
 * in `templates/basis.html`. */
@media (max-width: 60rem) {
  body.rahmen {
    /* Die ZWEITE Spalte bekommt `min-content` als Untergrenze, nicht 0: sonst
       laesst das Raster den Knopf links seine volle Breite nehmen, die sechs
       Symbole rechts werden gequetscht, und das letzte steht 15 Pixel neben
       dem Bildschirm — gemessen, nicht vermutet. Der Knopf gibt nach, weil der
       Betriebsname darin ohnehin mit Auslassungspunkten endet. */
    grid-template-columns: minmax(0, auto) minmax(min-content, 1fr);
    grid-template-rows: var(--kopf-hoehe) auto 1fr;
  }
  .menue-schalter {
    display: block;
    min-width: 0;
    grid-column: 1;
    grid-row: 1;
    background: var(--flaeche);
    border-bottom: 1px solid var(--linie);
  }
  .menue-schalter > summary {
    list-style: none;
    cursor: pointer;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    height: var(--kopf-hoehe);
    padding: 0 0.9rem;
    color: var(--text-leise);
    font-size: var(--bedien-groesse);
  }
  .menue-schalter > summary::-webkit-details-marker { display: none; }
  .menue-schalter > summary::marker { content: ""; }
  .schalter-marke { display: inline-flex; align-items: center; gap: 0.4rem; min-width: 0; }
  .schalter-marke img { height: 2rem; width: auto; max-width: 8rem; object-fit: contain; }
  .schalter-marke .logokachel-name {
    font-weight: 700; color: var(--text); font-size: 0.95rem;
    max-width: 7rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .kopf { grid-column: 2; grid-row: 1; padding: 0 0.75rem; gap: 0.5rem; }
  .modulmenue {
    display: none;
    grid-column: 1 / -1;
    grid-row: 2;
    position: static;
    height: auto;
    border-right: 0;
    border-bottom: 1px solid var(--linie);
  }
  .menue-schalter[open] ~ .modulmenue { display: block; }
  /* Die Logo-Kachel steckt schon im Knopf daneben — zweimal waere Doppelung. */
  .menue-schalter[open] ~ .modulmenue .logokachel { display: none; }
  .rahmen-inhalt { grid-column: 1 / -1; grid-row: 3; }
  .benutzer-name { display: none; }
  .aktionsleiste { padding: 0.5rem 0.9rem; }
  /* Das Panel einer Aktionsgruppe oeffnet auf breiten Schirmen linksbuendig
     unter seinem Knopf (`left: 0`). Auf 390px steht der zweite Knopf schon
     bei x=213 — das Panel ragte damit 47px ueber den rechten Rand, und die
     ganze Seite scrollte waagerecht (gemessen im Paket P10). Auf schmalen
     Schirmen also rechtsbuendig; die `max-width` weiter oben haelt es
     zusaetzlich im Fenster. */
  .aktionsgruppe > .aufklapper-panel { left: auto; right: 0; }
  /* Beruehrungsziel >= 2.75rem (Guidelines, Abschnitt 1, Mobil). */
  .aufklapper > summary, .modulzeile-kopf, .modulpunkte li > a:first-child { min-height: 2.75rem; }
}

/* --- Kopfzeile des Objekts (Block `kopfzeile`) ---------------------------
 * Eine Zeile, Muster: „Wochenplan KW 37 · 3 Luecken · Vorlage Standardwoche".
 * Titel fett, Kennzahlen als Text, Verknuepfungen als Links. Sie beantwortet
 * die Frage „was ist hier gerade offen", und zwar bevor man den Inhalt liest.
 *
 * `data-verlauf-titel` steht an diesem Element: der Verlauf soll „Auftrag
 * AB-11240" merken und nicht den Fenstertitel — Begruendung in
 * `basis/verlauf.py`. */
.objektkopf {
  margin: 0;
  padding: 0.6rem 1.25rem;
  background: var(--flaeche);
  border-bottom: 1px solid var(--linie);
  font-size: var(--bedien-groesse);
  color: var(--text-leise);
}
.objektkopf strong { color: var(--text); font-size: 1rem; }
/* Pfadzeile (basis/pfad.py): eine leise Zeile ueber der Aktionsleiste.
   Trennzeichen per CSS, damit die Liste fuer Vorleser eine Liste bleibt. */
.pfad { padding: 0.4rem 1.25rem 0; font-size: var(--bedien-groesse); color: var(--text-leise); }
.pfad ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.25rem 0; }
.pfad li + li::before { content: "\203A"; margin: 0 0.5rem; color: var(--text-schwach); }
.pfad a { color: var(--text-leise); text-decoration: none; }
.pfad a:hover, .pfad a:focus-visible { color: var(--text); text-decoration: underline; }
.pfad [aria-current="page"] { color: var(--text); }
@media (max-width: 60rem) {
  .pfad { padding: 0.4rem 0.9rem 0; }
}
/* Kopfzeile mit Schalter oder Blaetterung rechts: ein div (der Schalter ist ein
   <form>) mit dem Flex-Verhalten, das ein Absatz von allein haette. Stand bis 0.9.2
   wortgleich in urlaub.css und auftragsplanung.css -- und fehlte damit ueberall
   sonst (die Kategorien-Seite zeigte beide Fragezeichen nebeneinander). */
.objektkopf-flex { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
@media (max-width: 60rem) {
  .objektkopf { padding: 0.55rem 0.9rem; }
}

/* --- Chip-Zustaende (Guidelines Abschnitt 4) -----------------------------
 * Umgezogen aus dashboard.css (Welle 2, P3b): dort standen sie nur
 * uebergangsweise, weil diese Datei die Chip-Familie noch nicht vollstaendig
 * hatte. `.chip` und `.chip-still` bleiben an ihrer Stelle weiter oben --
 * hier nur die drei Zustandsfarben, damit an dieser Datei nichts umsortiert
 * werden muss, waehrend andere Pakete parallel ebenfalls ans Ende anhaengen.
 * Der Zustand steht zusaetzlich immer als WORT im Chip -- Farbe allein
 * traegt hier nichts. */
.chip-warn { color: var(--warn); background: var(--warn-leise); border-color: var(--warn-rand); }
.chip-gefahr { color: var(--gefahr); background: var(--gefahr-leise); border-color: var(--gefahr-rand); }
.chip-info { color: var(--info); background: var(--info-leise); border-color: var(--info); }
.chip-warn:hover, .chip-gefahr:hover, .chip-info:hover { color: inherit; background: inherit; border-color: inherit; }

/* --- Springer / Bereitschaft (Paket P9, Welle 2) -------------------------- */
/* Eigener Block je Zelle (siehe dienstplan/templates/dienstplan/_zelle.html)
   -- bewusst AUSSERHALB von `.spuren`: dessen Hoehe ist exakt aus
   `--spuren`/`--kacheln` berechnet (fuer die absolut positionierten Balken
   und Kacheln), ein zweiter Bewohner dort haette entweder die Zelle
   verschoben oder waere unter ihnen verschwunden. Normaler Blockfluss danach
   ruehrt diese Geometrie nicht an -- gemessen mit Playwright (Bericht P9). */
.springer-block {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.3rem;
  padding-top: 0.25rem;
  border-top: 1px dashed var(--linie);
}
/* Kuerzel + „S", gestrichelter Rand, Farbrolle springer (Vorlage: violett,
   siehe design-guidelines.md Abschnitt 3) -- eine Bereitschaft sieht anders
   aus als eine Kachel (durchgezogen, `--besetzt`), weil sie etwas anderes
   ist: sie besetzt nichts. */
.springer-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 1px 5px;
  border: 1px dashed var(--springer-rand);
  border-radius: var(--radius-klein);
  background: var(--springer);
  color: var(--springer-rand);
  font: 700 10.5px/1.4 var(--schrift);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.springer-chip-marke { font-weight: 700; }
/* Eingesprungen = tatsaechlicher Einsatz, kein „nur geplant" mehr -- der
   Rand wird durchgezogen statt gestrichelt, dieselbe Regel wie bei `--`
   Fortsetzung/Original ueberall im Raster: Form traegt die Aussage mit. */
.springer-chip-eingesprungen { border-style: solid; }
.springer-details { font-size: 10.5px; }
.springer-details > summary {
  cursor: pointer;
  color: var(--springer-rand);
  list-style: none;
}
.springer-details > summary::-webkit-details-marker { display: none; }
.springer-formular, .springer-inline-formular {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.3rem;
}
.springer-formular select { font: inherit; }
.legende-springer {
  display: inline-grid;
  place-items: center;
  border: 1px dashed var(--springer-rand);
  background: var(--springer);
  color: var(--springer-rand);
  font-weight: 700;
}

/* --- Springer-Auswertung (dienstplan:springer_auswertung) ----------------- */
.springer-auswertung { max-width: 60rem; }
.springer-zeitraum { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: end; margin: 0.6rem 0; }
.springer-zeitraum label { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.8rem; }
.springer-zeitraum-text { color: var(--text-schwach); margin-bottom: 0.6rem; }
.springer-tabelle-rahmen { overflow-x: auto; }
.springer-tabelle { border-collapse: collapse; width: 100%; }
.springer-tabelle th, .springer-tabelle td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--linie); text-align: left; }
.springer-tabelle-eigene { background: var(--haupt-leise); }
.springer-fairness { min-width: 10rem; }
/* Feste Spur, damit die Balkenbreite VERGLEICHBAR ist -- ein Prozentwert
   relativ zur (unterschiedlich breiten) Tabellenzelle waere zwischen zwei
   Zeilen nicht dieselbe Aussage. */
.springer-fairness-track {
  display: inline-block;
  width: 6rem;
  height: 0.6rem;
  border-radius: var(--radius-klein);
  background: var(--flaeche-leise);
  vertical-align: middle;
}
.springer-fairness-balken {
  display: block;
  height: 100%;
  width: var(--balken-prozent, 0%);
  border-radius: var(--radius-klein);
}
.springer-fairness-ueber { background: var(--springer-rand); }
.springer-fairness-unter { background: var(--linie-stark); }
.springer-fairness-text { margin-left: 0.4rem; font-variant-numeric: tabular-nums; color: var(--text-schwach); }
.springer-auswertung-fussnote { margin-top: 1rem; color: var(--text-schwach); font-size: 0.8rem; }

/* --- P19: Planungskopf aufgeraeumt (eine Kopfzeile statt zwei) -----------
 * Angehaengt statt eingefuegt (Hausregel: `turnuswerk.css` nur anhaengen,
 * Parallelarbeit anderer Pakete). Die Selektoren docken an bestehende
 * Klassen an (`.objektkopf`, `.kennzahlen`) oder fuehren neue, eng gefasste
 * ein (`.objektkopf-zeile`, `.objektkopf-detail`). */

/* Die Kennzahlen sind aus `_raster.html` in den Objektkopf gezogen (Guidelines
 * Abschnitt 1: Kopfzeile UND Kennzahlen sind ein Bauteil, nicht zwei). Diese
 * Regel fehlte schon vorher und ist der eigentliche Grund fuer den 247px-
 * Mobil-Ueberlauf (gemessen: `.kennzahlen` allein stand bei 637px auf einem
 * 390px-Schirm) -- `flex-wrap` gehoert dazu, wo immer die Zeile steht. */
.kennzahlen { flex-wrap: wrap; }
.objektkopf-kennzahlen { margin-top: 0.5rem; }
.objektkopf-zeile { margin: 0; }
/* Zusatztext am Status-Chip (wann/von wem veroeffentlicht, „seit … geaendert“)
 * -- EIN Chip traegt jetzt beides, statt eines zweiten Status-Blocks
 * darunter (vorher `.veroeffentlichung`/`.veroeff-info` in `_raster.html`). */
.objektkopf-detail { margin-left: 0.35rem; font-size: 0.78rem; color: var(--text-schwach); }
.objektkopf-warnung { color: var(--warn); }

/* --- P19: Springer einteilen, eingeklappt (Aufklapper statt Klartext) ----
 * Vorher: je Bedarfsfenster ein eigenes `<details>` mit ausgeschriebenem
 * Summary („Als Springer einteilen (07:30–12:30)“) -- unter jeder besetzten
 * Zelle stand mindestens eine Zeile Text, ungefragt. Jetzt: ein kleiner
 * „…“-Knopf, der beim Oeffnen die Formulare zeigt (`_zelle.html`). */
.springer-aufklapper-knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.4rem;
  height: 1.4rem;
  min-height: 0;
  padding: 0;
  color: var(--springer-rand);
  border-radius: var(--radius-klein);
}
.springer-aufklapper-knopf:hover { background: var(--springer); }
.springer-aufklapper-knopf svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 1.6; }
/* KEIN schwebendes Panel wie beim Standard-Aufklapper der Kopfzeile: dort
 * (`.aufklapper-panel`, `position: absolute`) waere das Panel vom Scrollkasten
 * `.raster-rolle` beschnitten -- gemessen mit Playwright, ein Fenster nahe dem
 * linken Rand der Tabelle zeigte nur „…-12:30" statt „07:30–12:30". `position:
 * static` haengt das Panel stattdessen in den normalen Blockfluss NACH
 * `.spuren` (wie schon `.springer-block` selbst) -- die Zelle wird dabei
 * kurzzeitig hoeher, aber nur auf einen bewussten Klick hin, nicht automatisch. */
.springer-aufklapper-panel {
  position: static;
  width: auto;
  max-width: none;
  max-height: none;
  min-width: 0;
  margin-top: 0.3rem;
  padding: 0.3rem;
  box-shadow: none;
  border-color: var(--springer-rand);
}
.springer-aufklapper-panel .aufklapper-titel { margin: 0.2rem 0.15rem 0.15rem; }
.springer-aufklapper-panel .springer-formular { margin: 0 0 0.4rem; flex-wrap: nowrap; }
.springer-aufklapper-panel .springer-formular:last-child { margin-bottom: 0; }
.springer-aufklapper-panel .springer-formular select { flex: 1 1 auto; min-width: 0; }

/* --- P19: Scrollkaesten brauchen `position: relative` --------------------
 * CLAUDE.md, „Fehler die schon zweimal passiert sind“: ein Scrollkasten ohne
 * `position: relative` haelt seinen eigenen Ueberlauf nicht fest -- die
 * SEITE laeuft dann trotzdem ueber, auch wenn die Box selbst brav scrollt
 * (gemessen: `.springer-tabelle-rahmen` allein trug 105px bei, `.raster-rolle`
 * einen Teil der 247px auf 390px -- beide ohne ein einziges `position:
 * absolute` darin; das Fehlen von `position: relative` reicht dafuer schon).
 * `.aufklapper` selbst bleibt `position: relative` und verankert sein Panel
 * unabhaengig davon -- diese Regel schliesst nur die Seite selbst ab. */
.raster-rolle { position: relative; }
.springer-tabelle-rahmen { position: relative; }

/* --- P19: `.aktionsleiste-ansicht` braucht jetzt auch `flex-wrap` --------
 * Fuenf Verknuepfungen statt zwei (seit P19 zusaetzlich: zweimal Drucken,
 * Springer-Auswertung) -- ohne `flex-wrap` ist dieser Block EIN Flex-Kind
 * von `.aktionsleiste`, das nicht schrumpft (Flex-Kinder sind `min-width:
 * auto`, also ihr eigener, ungebrochener Mindestinhalt); die Summe der fuenf
 * Knopftexte zog die ganze Seite auf 556px, obwohl `.aktionsleiste` selbst
 * schon `flex-wrap: wrap` hat -- das wrappt nur SEINE EIGENEN Kinder, nicht
 * die Kinder eines Kindes. Gefunden mit Playwright (Ausblenden von
 * `.aktionsleiste-ansicht` allein brachte den Seiten-Ueberlauf auf 0 zurueck);
 * `min-width: 0` an derselben Stelle reichte NICHT (das haette nur verhindert,
 * dass der Block selbst nicht schrumpft -- er haette seine Kinder trotzdem
 * unveraendert nebeneinander gehalten). */
.aktionsleiste-ansicht { flex-wrap: wrap; }

/* --- P21: Kippschalter (iOS-Stil) statt Checkbox fuer Einzel-Entscheidungen
 * Auftrag „Schieberegler statt Checkboxen — kennst du von Apple". Eine ECHTE
 * Checkbox bleibt darunter (Tab, Leertaste, Screenreader unveraendert); nur
 * `.schalter-strecke` zeichnet Strecke und Griff per CSS auf den Sibling-
 * Selektor `input + .schalter-strecke`. Das traegt sowohl das Include
 * `templates/_schalter.html` (Name/Id/Checked von Hand) als auch
 * `dienstplan/stammdaten/_feld.html` (dieselbe Klasse direkt um `{{ feld }}`,
 * die Django-Checkbox liefert Name/Id/Checked selbst).
 *
 * Farbrolle: `--haupt` fuer an, `--flaeche-tot` fuer aus — beide Rollen sind
 * in hell und dunkel schon definiert (Abschnitt 3 der Guidelines), eine neue
 * Rolle fuer den Schalter waere unnoetig gewesen.
 *
 * Touchziel 2.75rem (44px): nicht die sichtbare Strecke ist so hoch, sondern
 * das ganze `<label>` — Klick auf Strecke ODER Beschriftung schaltet um
 * (Browser-Standard: ein Label traegt sein Kind-Input), das Label bekommt
 * darum die Mindesthoehe.
 *
 * `prefers-reduced-motion` ist schon global geloest (`* { transition: none
 * !important }` weiter oben in dieser Datei) und muss hier nicht wiederholt
 * werden — `!important` gewinnt unabhaengig von der Regelreihenfolge.
 */
.schalter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  cursor: pointer;
  font: var(--bedien-groesse) var(--schrift);
  color: var(--text);
}
.schalter input[type="checkbox"] {
  /* Wie `.nur-sr`: nicht `display:none` (dann verschwindet der Fokus), nur
     visuell auf einen Punkt geklemmt. Die Strecke daneben zeichnet den
     sichtbaren Zustand. */
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
.schalter-strecke {
  position: relative;
  flex: none;
  width: 2.75rem;
  height: 1.5rem;
  border-radius: 999px;
  background: var(--flaeche-tot);
  transition: background-color 0.15s ease;
}
.schalter-strecke::before {
  content: "";
  position: absolute;
  top: 0.1875rem;
  left: 0.1875rem;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: var(--flaeche);
  box-shadow: var(--schatten);
  transition: transform 0.15s ease;
}
.schalter input:checked + .schalter-strecke { background: var(--haupt); }
.schalter input:checked + .schalter-strecke::before { transform: translateX(1.25rem); }
.schalter input:focus-visible + .schalter-strecke { outline: 2px solid var(--fokus); outline-offset: 2px; }
.schalter input:disabled + .schalter-strecke { opacity: 0.5; }
.schalter:has(input:disabled) { cursor: not-allowed; }
.schalter-text { font-weight: 400; }
/* Im generischen Formularfeld (`_feld.html`) ersetzt `.schalter` das bisherige
   `input + label` Paar; die Karte braucht keine eigene Beschriftungszeile
   mehr darueber (anders als Text-/Auswahlfelder), darum bleibt der Ausgleichs-
   abstand `padding-top` erhalten, aber als Flex- statt Rasterzeile: nach dem
   Umbau steht darin ein einzelnes `<label class="schalter">`, kein Zeilenpaar
   aus Eingabe und Text mehr. */
.feld-haken { display: flex; align-items: center; gap: 0.4rem; padding-top: 1.3rem; }
.form-inline .feld-haken { padding-top: 0; }

/* =======================================================================
 * Formularraster (P26) -- Einstellungsformulare senkrecht
 *
 * Anlass (sf, 15.09.2026, Bildschirmfoto Dienstplan -> Einstellungen): die
 * Felder standen NEBENEINANDER, jedes mit einem Absatz Hilfetext darunter,
 * der Kippschalter eingequetscht zwischen Schrittweite und Wochen im Voraus.
 * Vorbild weclapp: Seitentitel, Abschnitte mit Zwischenueberschrift und
 * Linie, darunter je Zeile links die Beschriftung, rechts das Bedienelement,
 * eine Einstellung je Zeile, kein Hilfetext in der Flaeche.
 *
 * Das dreispaltige `.stamm-form`/`.feld`-Raster bleibt fuer OBJEKTMASKEN
 * (Mitarbeiter, Position), wo man viele kurze Angaben auf einen Blick
 * vergleicht. Einstellungen liest man von oben nach unten, eine nach der
 * anderen -- darum ein zweites Raster und kein Umbau des ersten.
 *
 * Masse: Beschriftung 18rem, Bedienelement bis 36rem (laengere Zeilen liest
 * niemand am Stueck), unter 60rem untereinander. Zahlen und Zeiten 8rem
 * (`.formularraster-kurz`): ein Zeitfeld ueber 36rem sieht nach Freitext aus.
 * ===================================================================== */
.formularraster { max-width: 55rem; min-width: 0; }
.formularraster-abschnitt { margin: 0 0 1.5rem; min-width: 0; }
.formularraster-abschnitt:last-of-type { margin-bottom: 1rem; }
.formularraster-abschnitt > h3 {
  margin: 0 0 0.5rem; padding-bottom: 0.5rem;
  font-size: 0.85rem; font-weight: 600; color: var(--text);
  border-bottom: 1px solid var(--linie);
}
.formularraster-zeile {
  display: grid; grid-template-columns: 18rem minmax(0, 36rem);
  gap: 0.5rem 1rem; align-items: start;
  padding: 0.5rem 0;
}
/* Beschriftung und Fragezeichen in einer Zeile; `padding-top` bringt den Text
   auf die Grundlinie des Feldes daneben (Feldhoehe 2.25rem, Schrift 0.875rem). */
.formularraster-beschriftung {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0;
  min-width: 0; padding-top: 0.5rem;
  font-size: var(--bedien-groesse); font-weight: 500; color: var(--text-leise);
}
.formularraster-beschriftung label { margin: 0; overflow-wrap: anywhere; }
.formularraster-beschriftung .pflicht { margin-left: 0.25rem; font-weight: 400; color: var(--text-schwach); }
.formularraster-feld { display: grid; gap: 0.25rem; min-width: 0; align-content: start; }
.formularraster-feld input:not([type="checkbox"]):not([type="radio"]),
.formularraster-feld select,
.formularraster-feld textarea {
  width: 100%; min-height: 2.25rem; padding: 0.35rem 0.5rem;
  font: var(--bedien-groesse) var(--schrift); color: var(--text);
  background: var(--flaeche); border: 1px solid var(--linie-stark); border-radius: var(--radius);
}
.formularraster-feld textarea { min-height: 4.5rem; resize: vertical; }
.formularraster-kurz input:not([type="checkbox"]):not([type="radio"]),
.formularraster-kurz select { width: 8rem; max-width: 100%; }
/* Der Kippschalter steht links buendig in der Bedienspalte, ohne eigenen Text:
   die Beschriftung links ist sein `<label for>`. `min-height` wie das Feld,
   damit die Zeile nicht springt (der Schalter selbst hat 2.75rem Zielgroesse,
   die Zeile daneben 2.25rem -- der Unterschied sitzt oben, nicht in der Mitte). */
.formularraster-feld > .schalter { justify-self: start; min-height: 2.25rem; }
.formularraster-hilfe { margin: 0; font-size: 0.75rem; line-height: 1.35; color: var(--text-schwach); }
.formularraster-fehler input, .formularraster-fehler select, .formularraster-fehler textarea { border-color: var(--gefahr); }
.formularraster-aktionen { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.5rem 0 0; padding: 0; }
/* Abschnitte einer Karte, die schon ein Formularraster ist: die Zeile
   „Wirksam" darunter braucht Abstand zum Knopf, nicht zur Karte. */
.formularraster + .wirksam { margin-top: 1rem; }
@media (max-width: 60rem) {
  .formularraster-zeile { grid-template-columns: minmax(0, 1fr); gap: 0.25rem; padding: 0.5rem 0; }
  .formularraster-beschriftung { padding-top: 0; }
  .formularraster-kurz input:not([type="checkbox"]):not([type="radio"]),
  .formularraster-kurz select { width: 100%; }
}

/* --- Breite Tabellen rollen in ihrem eigenen Behaelter -------------------
 * Guidelines Abschnitt 1 (Mobil). Bis P26 in `mitarbeiter.css`; gemessen dort
 * auf 390px: die Qualifikationsliste zog die Seite um 324 Pixel ueber den
 * Bildschirm hinaus. `max-width: 100%` an der Tabelle hilft nicht -- ihre
 * Zellen geben die Mindestbreite vor; erst ein rollender Kasten darum tut es.
 * P26 mass dasselbe an den Einstellungsreitern: Wochenvorlagen 685px,
 * Rotation 88px, Schliesstage 12px ueber den Rand. */
.tabelle-rollt {
  overflow-x: auto;
  /* Ohne `min-width: 0` gibt ein Rasterkind seine Mindestbreite nicht her und
     der Kasten rollt nie (CLAUDE.md, „Layout selbst ansehen, nicht annehmen"). */
  min-width: 0;
  max-width: 100%;
  /* `overflow-x: auto` allein haelt nichts fest: ohne `position: relative`
     entkommt jedes `position: absolute` darin (die `.nur-sr`-Beschriftungen)
     und der umschliessende Block ist das Fenster (CLAUDE.md, zweimal passiert). */
  position: relative;
}

/* --- Reiter im Rahmenblock `reiter` -------------------------------------
 * Bis P26 standen diese Regeln wortgleich in `mitarbeiter.css` und
 * `auftragsplanung.css` („wenn ein Paket turnuswerk.css aufraeumen darf,
 * gehoeren beide Kopien dorthin"). Die Dienstplan-Einstellungen sind die
 * dritte Seite, die Reiter in den Rahmenblock legt -- drei Kopien waeren eine
 * zu viel. `flex-wrap` ist der Kern: als `inline-flex` traegt die Leiste die
 * Summe ihrer Reiter als MINDESTbreite nach oben und zieht die ganze Seite
 * auf (gemessen an der Mitarbeitermaske: 589px Reiter -> 618px Seite). */
.reiter-objekt { margin: 0 1.25rem; display: flex; flex-wrap: wrap; min-width: 0; max-width: calc(100% - 2.5rem); }
.reiter-objekt a { white-space: nowrap; min-height: 2.75rem; display: inline-flex; align-items: center; }
@media (max-width: 60rem) {
  .reiter-objekt { margin: 0 0.9rem; max-width: calc(100% - 1.8rem); }
  /* Umgebrochene Reiter brauchen ihre Trennlinie oben statt links, sonst
     klebt die zweite Zeile randlos an der ersten. */
  .reiter-objekt a { border-top: 1px solid var(--linie-stark); }
  .reiter-objekt a:first-child { border-top: 0; }
}
/* Der Objektkopf der Einstellungen traegt rechts den Admin-Link und das
   Haupt-Fragezeichen; beide in einer Gruppe, damit `space-between` sie
   zusammen an den Rand schiebt. */
.objektkopf-rechts { display: inline-flex; align-items: center; gap: 0.75rem; }
.objektkopf-rechts .stamm-admin { margin-left: 0; }
/* Auswahllisten (RadioSelect, CheckboxSelectMultiple) im Formularraster: die
   Optionen nebeneinander in der Bedienspalte, jede als Zeile aus Kaestchen und
   Text -- wie `.feld > div` im Objektraster, nur ohne dessen Schriftfarbe. */
.formularraster-feld > div, .formularraster-feld ul {
  list-style: none; margin: 0; padding: 0.25rem 0;
  display: flex; flex-wrap: wrap; gap: 0.5rem 1rem;
}
.formularraster-feld > div label, .formularraster-feld ul label {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 2.25rem;
  font: var(--bedien-groesse) var(--schrift); font-weight: 400; color: var(--text);
}
