/*
  Werkstattplaner — Erscheinung der sutter carrosserie ag. Farbtokens, Radien
  nach Rolle, Haarlinien, Knopffarben-Regel, Symbolgrammatik und die
  Daumenleiste sind aus dem Reifenhotel uebernommen (C:\Workspace\reifenhotel,
  DESIGN.md dort, entnommen am 31.08.2026); bei Abweichungen gilt jenes Repo.

  Zwei Oberflaechen, eine Welt: die oeffentliche Buchung als Schrittweg am
  Handy und der interne Werkstatttag am Bueroschirm. Zwei Komponenten nehmen
  die ganze Bahn, weil sie Karten sind und keine Felder — die Terminwand
  (freie Zeiten eines Tages) und das Tagesraster (je Kapazitaetsgruppe eine
  Spalte, die Zeit laeuft senkrecht). Alles, was getippt oder gelesen wird,
  bleibt in der Spalte.

  Kein Fremdcode, Schriften lokal ausgeliefert (SIL OFL).
*/

@font-face {
  font-family: "Archivo Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("/assets/fonts/archivo-latin-wght-normal.woff2") format("woff2-variations");
}
@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("/assets/fonts/inter-latin-wght-normal.woff2") format("woff2-variations");
}

:root {
  /* Farben — Namen und Werte wie auf suttercarrosserie.ch und im Reifenhotel */
  --marke: #004394;
  --marke-tief: #00224C;
  --akzent: #FFB735;
  --akzent-dunkel: #8A5A00;
  --text: #1A1D21;
  --grund: #FFFFFF;
  --flaeche: #F5F2EC;
  --kante: #E6E0D7;
  --kante-stark: #8C8279;
  --kante-auf-marke: #265FA4;
  --kante-auf-tief: #204672;
  --auf-tief: #CFE0F5;
  --platzhalter: #6B655E;
  /* Ergaenzungen des Werkzeugs (nicht auf der Website): */
  --text-neben: #5C574F;    /* nachgeordneter Text auf hellem Grund, 7.0:1 */
  --fehler: #A8321F;        /* Fehler, ungueltiges Feld, Stornieren, Abbrechen, 6.6:1 */
  --fehler-tief: #7E2517;   /* Hover der roten Flaeche, 9.6:1 */
  /* Gruen ist nicht Teil des Markenfarbsatzes und traegt eine einzige
     Bedeutung: dieser Knopf aendert etwas — buchen, verschieben, planen,
     speichern. Blau bleibt der reinen Abfrage (filtern, Zeiten anzeigen). */
  --handlung: #1B6B3A;      /* 6.6:1 */
  --handlung-tief: #124726; /* 10.7:1 */

  /* Die sechs Gruppentoene des Kalenders (Spezifikation vom 17.09.2026). Das
     Altsystem faerbte die Termine nach Ressource, und die Werkstatt liest das
     Raster so; Belbos Triade laesst sich aber nicht kopieren, weil zwei ihrer
     Farben hier belegt sind: Rot ist `fehler` (ein rotes Kaestchen laese sich
     als abgesagt), und Gelb ist ein 2-px-Zeichen und nie eine Flaeche. Petrol
     tritt an die Stelle von Rot, dunkles Gold an die von Gelb.
     Jeder Ton traegt weisse Schrift ueber 6.9:1 — der schwaechste Wert des
     bestehenden Satzes ist `handlung` mit 6.54. Nebenzeile und Hover werden
     abgeleitet und nicht deklariert (siehe .kalender__block): zwoelf Token
     fuer sechs Toene waeren zwoelf Stellen, an denen einer nicht passt.
     Bei Rot-Gruen-Blindheit ruecken Petrol/Pflaume und Moos/Gold zusammen;
     tragend ist darum der Gruppenname im Kopf, die Farbe ist die Zugabe. */
  --gruppe-blau: #004394;    /* = marke, der Vorgabewert, 9.4:1 */
  --gruppe-petrol: #0E5A66;  /* 7.9:1 */
  --gruppe-gold: #7C5000;    /* 7.0:1 */
  --gruppe-graphit: #3A4046; /* 10.5:1 */
  --gruppe-pflaume: #5B2F63; /* 10.3:1 */
  --gruppe-moos: #3C5A2E;    /* 7.8:1 */

  --schrift-titel: "Archivo Variable", system-ui, sans-serif;
  --schrift-text: "Inter Variable", system-ui, sans-serif;

  --radius-klein: 0.5rem;
  --radius-gross: 1.25rem;
  --radius-voll: 9999px;

  --weich: cubic-bezier(0.22, 1, 0.36, 1);
  /* Kein Schattentoken: dieses Werkzeug hat keine Karte, die ein Verweis ist.
     Seine bedienbaren Flaechen antworten mit Farbe, nicht mit Tiefe. */

  --bahn: 64rem;
  /* Die interne Bahn: 120 rem sind bei 16-px-Wurzel genau 1920 px. Auf dem
     Zielbildschirm greift der Deckel darum nie — er schuetzt allein groessere
     Bildschirme davor, dass eine Tabellenzeile ins Unlesbare waechst. */
  --bahn-intern: 120rem;
  --spalte: 36rem;
  /* Lesebreite fuer Fliesstext auf der breiten Bahn. */
  --lesetext: 42rem;
  --rand: 1rem;
  /* Der senkrechte Feldrhythmus eines Formulars (DESIGN.md, `feld-abstand`).
     Er liegt am Zeilenabstand des Rasterformulars -- ein Token, weil die
     Buchungsstrecke und der interne Bereich denselben Rhythmus teilen. */
  --feld-abstand: 1rem;
  /* Tagesraster: links die stehende Zeitachse, rechts je Kapazitaetsgruppe
     eine Spalte. --spur-min ist die Mindestbreite einer Unterspur,
     --tagesraster die Mindesthoehe der zehn Stunden von 07:30 bis 17:30. */
  --zeitspalte: 3.75rem;
  --spur-min: 8.5rem;
  --tagesraster: 26rem;
  /* Hoehe des Tageskopfs im Wochenraster und zugleich der Haltepunkt, an dem
     der Gruppenkopf darunter stehen bleibt. Eine Zahl fuer beide: geraten
     waere sie irgendwann falsch, und dann klebte der zweite Kopf im ersten. */
  --wochenkopf-tag: 2.75rem;
  /* Der Boden, unter den das Tagesraster nicht faellt, wenn die Tageskarte
     darueber viel Platz nimmt. Nicht dasselbe wie --tagesraster: das ist die
     Wunschhoehe der zehn Stunden und passt auf 1366x768 ohnehin nie (dort
     bleiben dem Raster rund 334 px). Dieser Wert ist die Grenze, ab der die
     Seite lieber rollt, als das Raster zu opfern -- 16 rem zeigen den Tag
     gestaucht, aber jeder Block nennt noch seine Zeit. */
  --tagesraster-boden: 16rem;
}

/* ---- Grundlagen ------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
/* Das `hidden`-Attribut muss staerker sein als jede Klasse, die `display`
   setzt. Die Browserregel dafuer ist `[hidden] { display: none }` und damit
   ein Attributselektor -- `.knopf { display: inline-flex }` schlaegt sie bei
   gleicher Spezifitaet ueber die Reihenfolge, und am 15.09.2026 blieb genau
   so der versteckte Knopf «Anzeigen» sichtbar, waehrend `element.hidden`
   brav `true` meldete. Ein `!important` ist hier kein Notnagel, sondern die
   Bedeutung des Attributs: versteckt heisst versteckt. */
[hidden] { display: none !important; }

html {
  color-scheme: light;
  -webkit-text-size-adjust: 100%;
}

/* Spalte ueber die volle Fensterhoehe: die Fusszeile sitzt unten, und der
   Kalender kann die Resthoehe fuellen, statt eine Bahn nach der anderen
   unter den Falz zu schieben. */
body {
  display: flex;
  flex-direction: column;
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--grund);
  color: var(--text);
  font: 400 1rem/1.625 var(--schrift-text);
  text-wrap: pretty;
}

h1, h2, h3 {
  margin: 0;
  font-family: var(--schrift-titel);
  font-weight: 700;
  line-height: 1.15;
  text-wrap: balance;
}
h1 { font-size: 1.75rem; margin-bottom: 1rem; }
h2 { font-size: 1.25rem; margin: 2rem 0 0.75rem; }
h3 { font-size: 1.125rem; }
p { margin: 0 0 0.75rem; }

a { color: var(--marke); text-decoration: underline; text-underline-offset: 4px; }

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

.visuell-versteckt {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.icon { width: 1.5rem; height: 1.5rem; flex: none; }

/* Die Wortmarke laeuft ueber eine Maske und nimmt currentColor an:
   weiss im Kopfband, blau auf hellem Grund. Eine Datei, zwei Zustaende. */
.logo {
  display: inline-block;
  width: 4rem; height: 1.4125rem;
  background: currentColor;
  -webkit-mask: url("/assets/logo-sutter-carrosserie.svg") no-repeat center / contain;
          mask: url("/assets/logo-sutter-carrosserie.svg") no-repeat center / contain;
}

pre { overflow: auto; white-space: pre-wrap; }
code { font-family: ui-monospace, monospace; font-size: 0.9em; }

/* ---- Kopfband --------------------------------------------------------- */

.kopf {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-height: 3.5rem;
  padding: 0.5rem var(--rand);
  background: var(--marke);
  color: var(--grund);
}
.kopf__marke {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 2.75rem;
  padding: 0.25rem 0;
  color: inherit;
  text-decoration: none;
}
.kopf__trenner { width: 1px; height: 1.25rem; background: var(--kante-auf-marke); }
.kopf__titel {
  font-family: var(--schrift-titel);
  font-weight: 700;
  font-size: 1.125rem;
  letter-spacing: -0.01em;
}
.kopf__nav { display: none; }
/* Auf blauem Grund traegt Gelb den Fokusring: Blau auf Blau waere unsichtbar. */
.kopf :focus-visible { outline-color: var(--akzent); }

/* Der Anzeigename ist der einzige Teil des Kopfbands, der sich kuerzen laesst,
   ohne dass etwas verlorengeht -- Wortmarke, Navigation und der Knopf selbst
   muessen ganz dastehen. Er traegt darum die Schrumpfkette (min-width: 0 bis
   hinunter zum Namen) und endet notfalls mit Auslassungspunkten.
   Ohne sie lief das Kopfband zwischen 768 und rund 795 px Fensterbreite ueber
   und mit ihm die ganze Seite: bei 768 px schaltet die Navigation ein und der
   Name erscheint, zusammen brauchten die drei Kaesten dann 732 px bei 705 px
   Inhaltsbreite. Ein hoeherer Umschaltpunkt haette nur diesen einen Namen
   gerettet -- «Dev Administration» passt, ein laengerer nicht. */
.abmelden { margin-left: auto; min-width: 0; }
.abmelden__knopf {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  min-width: 2.75rem;
  max-width: 100%;
  padding: 0.5rem;
  border: 0;
  border-radius: var(--radius-klein);
  background: transparent;
  color: var(--auf-tief);
  font: inherit;
  cursor: pointer;
}
.abmelden__knopf:hover { color: var(--grund); }
.abmelden__name { display: none; }

@media (min-width: 48rem) {
  .kopf { padding: 0.5rem 1.5rem; }
  .kopf__nav { display: flex; gap: 0.25rem; margin-left: 1rem; }
  .kopf__nav a {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: var(--radius-klein);
    color: var(--auf-tief);
    text-decoration: none;
    font-family: var(--schrift-titel);
    font-weight: 600;
    font-size: 0.9375rem;
  }
  .kopf__nav a:hover { color: var(--grund); }
  .kopf__nav a.ist-aktiv { color: var(--grund); }
  /* Markierungsstrich statt Flaeche: Gelb zeigt, es fuellt nicht. */
  .kopf__nav a.ist-aktiv::after {
    content: "";
    position: absolute;
    left: 0.75rem; right: 0.75rem; bottom: 0.25rem;
    height: 2px;
    background: var(--akzent);
  }
  .abmelden__name { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ---- Daumenleiste (Handy, interner Bereich) --------------------------- */
/* Kalender und Verwaltung werden am Fahrzeug bedient. Die Leiste haelt die
   Arbeitspunkte in Daumenreichweite und erscheint nur auf den internen
   Routen; die oeffentliche Buchung traegt nur das Kopfband. */

.leiste {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 10;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--kante);
  background: var(--grund);
}
.leiste a {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  min-height: 3.75rem;
  padding: 0.5rem 0;
  color: var(--text-neben);
  text-decoration: none;
  font-family: var(--schrift-titel);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* Ganzzahlige Hoehe (8 + 24 + 4 + 16 + 8 = 60 px): sonst liegt die Leiste
     auf einer Bruchkoordinate und der 2-px-Marker verschwimmt mit der Kante. */
  line-height: 1rem;
}
.leiste a.ist-aktiv { color: var(--marke); }
.leiste a.ist-aktiv::before {
  content: "";
  position: absolute;
  top: -1px;
  left: calc(50% - 0.75rem);
  width: 1.5rem; height: 2px;
  background: var(--akzent);
}
@media (min-width: 48rem) { .leiste { display: none; } }

/* ---- Inhalt, Meldungen, Fusszeile ------------------------------------ */

.inhalt {
  flex: 1;
  max-width: var(--bahn);
  margin: 0 auto;
  padding: 1.25rem var(--rand) 2rem;
}
/* Der Kalender ist ein Arbeitsbild, kein Lesetext. Seine Hoehe regelt `--voll`
   hier, seine Breite die Regel am Ende dieser Datei bei der internen Bahn: die
   zwei Rasteransichten nehmen seit dem 17.09.2026 die ganze Fensterbreite,
   weil fuenf Tage mal drei Gruppen nicht auf 120 rem gehen. Die Formularspalte
   des Filters bleibt trotzdem in Lesebreite — ein Suchfeld darf nicht zwei
   Meter breit werden. */
.inhalt--voll { padding-bottom: 1rem; }
@media (min-width: 48rem) {
  /* Feste Fensterhoehe statt Mindesthoehe: erst dadurch ist die Hoehe der
     Kalenderseite bestimmt und ihre 1fr-Zeile kann rechnen. Sonst waechst
     eine volle Woche einfach weiter und die Seite rollt doch. */
  body:has(> .inhalt--voll) { height: 100dvh; }
  /* `overflow-y: auto` ist der Notausgang, nicht der Normalfall: solange die
     Tageskarte klein ist oder zugeklappt, fuellt die Kalenderseite das
     Fenster und rollt hier gar nichts. Erst wenn Karte und Rasterboden
     zusammen mehr verlangen als das Fenster hergibt, rollt diese Flaeche --
     besser als eine Karte, die unten abgeschnitten ist, oder ein Raster, das
     auf zwei Pixel zusammenfaellt. */
  .inhalt--voll { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }
  .inhalt--voll > .kalenderseite {
    flex: 1;
    min-height: 0;
    grid-template-rows: auto auto minmax(0, 1fr);
  }
  /* Die Tagesansicht traegt zusaetzlich den Tagesblock zwischen Filter und
     Raster -- eine Zeile mehr als Wochenansicht und Liste, darum eigens
     ausgezeichnet statt der geteilten Regel eine vierte Zeile aufzuzwingen.

     Die Rasterzeile hat hier einen Boden statt einer Null: der Tagesblock ist
     seit dem 15.09.2026 ungedeckelt und damit `auto` ueber seinem vollen
     Inhalt. Ohne Boden nahm er sich alles -- gemessen 433 px, und dem Raster
     blieben zwei. Der Boden ist `--tagesraster-boden` und bewusst nicht
     `--tagesraster`: Letzteres ist die Wunschhoehe der zehn Stunden und
     ueberschreitet auf 1366x768 schon ohne Tageskarte, was da ist. */
  .inhalt--voll > .kalenderseite:has(.tagesblock) {
    grid-template-rows: auto auto auto minmax(var(--tagesraster-boden), 1fr);
  }
  /* Der Filter laeuft ueber die ganze Bahn, bleibt aber eine Zeile hoch:
     Datumsfeld und Aufklappzeile nebeneinander. Seine Felder halten
     Lesebreite — ein Suchfeld darf nicht einen halben Bildschirm breit sein.

     Die Anordnung selbst steht nicht hier, sondern bei der Komponente: sie
     haengt nicht an der Hoehe, und sie muss der spaeteren Basisregel in der
     Kaskade folgen koennen. */
  /* Das Wochenraster darf weiter auf null schrumpfen -- ueber ihm steht kein
     Tagesblock. Das Tagesraster nicht mehr: seinen Boden setzt die Zeile
     oben, und ein `min-height: 0` hier haette ihn wieder aufgehoben. */
  .inhalt--voll .wochenraster { min-height: 0; }
  /* Jede Zeile ueber dem Raster ist eine Zeile weniger Tag: Titel und Datum
     stehen nebeneinander, Abstaende und Filterpolster fallen knapper aus. */
  .inhalt--voll > .kalenderseite { gap: 1rem; }
  .inhalt--voll .kalenderkopf > div { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 0.75rem; }
  .inhalt--voll .kalenderdatum { margin: 0; }
  .inhalt--voll .kalenderfilter { padding: 0.5rem 1rem 0.75rem; }
  .inhalt--voll .kalenderfilter label { margin-top: 0.375rem; }
  /* Der Tagesblock traegt hier KEINEN Deckel. Vom 14. bis zum 15.09.2026 war
     sein Inhalt auf 9 rem gedeckelt und rollte in sich, damit er dem
     Tagesraster die Hoehe nicht nimmt. Gemessen brachte das drei ineinander
     liegende Rollflaechen auf einer Seite: Blockinhalt (144 von 379 px),
     Aufgabenliste (224 von 227) und das Raster selbst (188 von 566) -- und
     der Block nahm mit 194 px immer noch so viel wie das Raster mit 190.
     Ein Deckel, der die Nebensache nicht kleiner macht, sondern nur
     verbirgt, kostet zweimal Rollen und spart nichts.
     Jetzt gilt die einfache Ordnung: die Karte ist immer ganz da, und das
     Raster ist die einzige Rollflaeche der Seite. Wer die Karte nicht
     braucht, klappt sie zu -- die Aufklappzeile mit «N offen» und «Notiz»
     bleibt sichtbar. */
}
.meldungen {
  max-width: var(--bahn);
  margin: 1rem auto 0;
  padding: 0 var(--rand);
}
.meldung {
  position: relative;
  margin: 0 0 0.5rem;
  padding: 0.875rem 1rem 0.875rem 3rem;
  border-radius: var(--radius-klein);
  background: var(--flaeche);
}
/* Einsatzstrich 24 x 2 px — das Zeichen der Marke, nie eine Flaeche. */
.meldung::before {
  content: "";
  position: absolute;
  left: 1rem; top: calc(50% - 1px);
  width: 1.5rem; height: 2px;
  background: var(--akzent);
}
.meldung--erfolg::before { background: var(--marke); }
.meldung--fehler { color: var(--fehler); font-weight: 500; }
.meldung--fehler::before { background: var(--fehler); }

.fuss {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.5rem;
  align-items: center;
  max-width: var(--bahn);
  margin: 0 auto;
  padding: 0.5rem var(--rand) 2.5rem;
  border-top: 1px solid var(--kante);
  color: var(--text-neben);
  font-size: 0.9375rem;
}
.fuss > span { display: inline-flex; align-items: center; min-height: 2.75rem; }
.fuss nav { display: flex; flex-wrap: wrap; gap: 0 1.25rem; }
.fuss a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--text-neben);
  text-decoration: none;
}
.fuss a:hover { color: var(--marke); text-decoration: underline; }
/* Wo die Daumenleiste steht, traegt die Fusszeile ihren Freiraum mit. */
/* Freiraum fuer die Daumenleiste — nur dort, wo sie auch steht. Am Desktop
   ist die Leiste ausgeblendet und ihr Platzhalter waere verschenkte Hoehe. */
.fuss--leiste { padding-bottom: 6rem; }
@media (min-width: 48rem) { .fuss--leiste { padding-bottom: 2.5rem; } }
@media (min-width: 48rem) { .fuss--voll, .fuss--voll.fuss--leiste { padding-bottom: 1rem; } }

.seitenkopf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  margin-bottom: 1rem;
}
.seitenkopf h1 { margin: 0; }
.seitenkopf--spalte { max-width: var(--spalte); }
/* Die Kontextzeile steht ausschliesslich im Terminkopf (views/termin.php), und
   der setzt seine Ueberschrift randlos. Die -0.5 rem, die sie unter eine
   gewoehnliche Ueberschrift zurueckholten, zogen sie dort acht Pixel IN die
   Ueberschrift: auf schmalen Bildschirmen ueberlappte die Statusmarke das
   Kennzeichen. Der untere Rand von 1.25 rem doppelte ausserdem den
   Zeilenabstand des Flexkopfs und riss vor dem umgebrochenen Kalenderlink ein
   Loch. Den Abstand nach unten traegt jetzt der Kopf allein. */
.kontext { margin: 0.25rem 0 0; color: var(--text-neben); }
.kontext strong { color: var(--text); font-family: var(--schrift-titel); }
.hinweis { margin: 0 0 0.75rem; color: var(--text-neben); font-size: 0.875rem; }
.optional { color: var(--text-neben); font-weight: 400; }

.leer {
  padding: 2rem 1rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
  color: var(--text-neben);
  text-align: center;
}

/* ---- Knoepfe ---------------------------------------------------------- */
/* Jede Farbe traegt genau eine Bedeutung: gruen veraendert, blau fragt ab,
   rot loescht (gefuellt) oder bricht ab (Rand). Innerhalb einer Farbe trennt
   das Gewicht die Rangfolge — gefuellt ist die erste, der Rand die zweite
   Aktion. `button:not([class])` ist das Netz fuer einen Knopf ohne Klasse. */

.knopf, button:not([class]) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0.75rem 1.5rem;
  border: 0;
  border-radius: var(--radius-klein);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 1rem;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s var(--weich), color 0.2s var(--weich);
}
.knopf--handlung, button:not([class]) { background: var(--handlung); color: var(--grund); }
.knopf--handlung:hover, button:not([class]):hover { background: var(--handlung-tief); }
.knopf--primaer { background: var(--marke); color: var(--grund); }
.knopf--primaer:hover { background: var(--marke-tief); }
.knopf--gefahr { background: var(--fehler); color: var(--grund); }
.knopf--gefahr:hover { background: var(--fehler-tief); }
/* Umriss-Gewicht: drei Farben, eine Geometrie. Der Rand steht je Farbe fest,
   damit er beim Fuellen im Hover bleibt. */
.knopf--umriss,
.knopf--handlung-umriss,
.knopf--abbruch {
  min-height: 2.75rem;
  padding: 0.5rem 1rem;
  border: 1px solid currentColor;
  background: var(--grund);
}
.knopf--umriss { color: var(--marke); border-color: var(--marke); }
.knopf--umriss:hover { background: var(--flaeche); }
.knopf--handlung-umriss { color: var(--handlung); border-color: var(--handlung); }
.knopf--handlung-umriss:hover { background: var(--handlung); color: var(--grund); }
.knopf--abbruch { color: var(--fehler); border-color: var(--fehler); }
.knopf--abbruch:hover { background: var(--fehler); color: var(--grund); }
.knopf--breit { width: 100%; }
.knopf--klein { min-height: 2.75rem; padding: 0.5rem 1rem; font-size: 0.9375rem; }
.knopf:disabled, button:not([class]):disabled {
  background: var(--kante);
  color: var(--text-neben);
  cursor: default;
}

.aktionen { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin: 1.75rem 0 0; }
.aktionen form { display: contents; }
.aktionen .knopf { flex: 1 1 12rem; }
@media (min-width: 48rem) { .aktionen .knopf { flex: 0 0 auto; min-width: 12rem; } }

/* Leiser Weg zurueck: kein Knopf, denn Zurueckgehen ist keine Handlung. */
.bedienflaeche {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 2.75rem;
  min-width: 2.75rem;
  padding: 0.5rem 0;
  color: var(--text-neben);
  text-decoration: none;
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.9375rem;
}
.bedienflaeche:hover { color: var(--marke); text-decoration: underline; }
.bedienflaeche .icon { width: 1.125rem; height: 1.125rem; }
.zurueck { order: -1; }

/* ---- Formulare -------------------------------------------------------- */

.formular { max-width: var(--spalte); }

label { display: block; margin: 1rem 0 0.375rem; font-weight: 600; font-size: 0.875rem; }
label:first-child { margin-top: 0; }

input, select, textarea {
  width: 100%;
  min-height: 3rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--kante-stark);
  border-radius: var(--radius-klein);
  background: var(--grund);
  color: var(--text);
  font: inherit;
}
input::placeholder { color: var(--platzhalter); opacity: 1; }
textarea { min-height: 5rem; resize: vertical; }
[aria-invalid="true"] { border-color: var(--fehler); }
select {
  appearance: none;
  padding-right: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231A1D21' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 1.25rem;
}
fieldset { min-width: 0; margin: 1.75rem 0 0; padding: 0; border: 0; }
legend {
  margin-bottom: 0.25rem;
  padding: 0;
  font-family: var(--schrift-titel);
  font-weight: 700;
  font-size: 1.125rem;
}

/* Der obere Rand der Beschriftung ist der Feldrhythmus — auch in der Zeile,
   die nur waagrechten Abstand hat. Die Regel gilt fuer jede Breite, sonst
   kleben einspaltig gestapelte Felder aneinander. */
.zeile { display: grid; gap: 0 1rem; }
.zeile label { margin-top: 1rem; }
.zeile p { margin: 0; }
@media (min-width: 30rem) { .zeile { grid-template-columns: 1fr 1fr; } }

.kaestchen, label:has(> input[type="checkbox"]) {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3rem;
  margin-top: 0.5rem;
  font-size: 1rem;
}
input[type="checkbox"], input[type="radio"] {
  width: 1.375rem;
  height: 1.375rem;
  min-height: 0;
  flex: none;
  margin: 0;
  padding: 0;
  accent-color: var(--marke);
}

.feldfehler { display: block; margin-top: 0.375rem; color: var(--fehler); font-weight: 600; font-size: 0.875rem; }

/* Fehlerzusammenfassung: dieselbe Meldung, nur mit Liste — sie steht vor dem
   Formular, ist fokussierbar und verweist auf die betroffenen Felder. */
.fehlerzusammenfassung {
  position: relative;
  max-width: var(--spalte);
  margin: 1rem 0 1.5rem;
  padding: 0.875rem 1rem 0.875rem 3rem;
  border-radius: var(--radius-klein);
  background: var(--flaeche);
}
.fehlerzusammenfassung::before {
  content: "";
  position: absolute;
  left: 1rem; top: 1.5rem;
  width: 1.5rem; height: 2px;
  background: var(--fehler);
}
.fehlerzusammenfassung h2 { margin: 0 0 0.5rem; color: var(--fehler); font-size: 1.125rem; }
.fehlerzusammenfassung ul { margin: 0; padding-left: 1.25rem; }
.fehlerzusammenfassung a { color: var(--fehler); }

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

.buchung { max-width: var(--spalte); }

/* ---- Schritte --------------------------------------------------------- */
/* Nummer als Vollkreis: offen, erledigt, aktuell. Unter 30 rem tragen nur
   der aktuelle Schritt seinen Namen, die anderen schrumpfen auf die Nummer. */

.fortschritt { max-width: var(--spalte); margin-bottom: 1.5rem; }
.fortschritt ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
.fortschritt li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.8125rem;
}
.fortschritt__nr {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem; height: 1.75rem;
  flex: none;
  border-radius: var(--radius-voll);
  background: var(--kante);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.fortschritt li.erledigt .fortschritt__nr { background: var(--marke); color: var(--grund); }
.fortschritt li.aktiv .fortschritt__nr { background: var(--akzent); color: var(--text); }
.fortschritt li.aktiv { color: var(--marke); }
/* Unter 30 rem verschwinden nur die Namen. Die Nummern bleiben — sonst faellt
   die halbe Schrittleiste weg, und ein `display: inline` auf dem aktiven
   Element wuerde die Ziffer aus ihrem Kreis schieben. */
@media (max-width: 29.99rem) {
  .fortschritt li:not(.aktiv) .fortschritt__name { display: none; }
}

/* ---- Terminwand (Signatur, oeffentlich) ------------------------------- */
/* Der Tag als Wand freier Faecher. Sie ist die Karte des Tages und nimmt
   darum die ganze Bahn; das Datumsfeld daneben bleibt in der Spalte. */

.terminwand { max-width: none; }
.terminwand h1,
.terminwand h2,
.terminwand p,
.terminwand dl,
.terminwand .datumwahl,
.terminwand .aktionen,
.terminwand .fehlerzusammenfassung,
.terminwand .auftragskarte,
.terminwand .fortschritt { max-width: var(--spalte); }

.datumwahl { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: end; max-width: var(--spalte); }
.datumwahl label { flex-basis: 100%; margin-bottom: 0; }
.datumwahl input { width: min(15rem, 100%); }
.datumwahl .knopf { flex: none; }

/* Der Vorschlag «naechster freier Tag» steht unter der Leermeldung der
   Terminwand: Knopf und Begruendung nebeneinander.

   `flex: 1 1 12rem` am Hinweis und nicht bloss eine Schriftfarbe: Ohne Basis
   bricht er am Handy MITTEN im Satz neben dem Knopf um («naechster» rechts,
   der Rest darunter). Mit Basis wandert er als Ganzes auf die naechste Zeile. */
.vorschlag { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin: 1rem 0 0; }
.vorschlag__hinweis { flex: 1 1 12rem; color: var(--text-neben); font-size: 0.875rem; }

.slotfelder { margin-top: 1.5rem; }

/* Die Wand ist eine ruhende Flaeche mit Kopf und beschrifteten Reihen — das
   Fach liegt als Papierweiss darauf, wie im Regal des Reifenhotels. */
.terminwand__wand {
  margin-top: 0.75rem;
  padding: 1rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
}
.terminwand__stand { margin: 0 0 0.75rem; color: var(--text-neben); font-size: 0.875rem; }
.terminwand__reihe { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: 0 0.75rem; align-items: start; }
.terminwand__reihe + .terminwand__reihe { margin-top: 0.75rem; }
.terminwand__reihe-name {
  padding-top: 0.75rem;
  text-align: right;
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
@media (max-width: 29.99rem) {
  .terminwand__reihe { grid-template-columns: minmax(0, 1fr); }
  .terminwand__reihe-name { padding-top: 0; text-align: left; }
}
.slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5rem, 1fr));
  gap: 0.375rem;
}
/* Das Fach der Terminwand: frei ist weiss mit starker Kante, gewaehlt ist
   markiert. Der Radiopunkt selbst bleibt fuer Tastatur und Screenreader da,
   sichtbar traegt die Flaeche den Zustand. */
.slot {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  /* Die Zelle ist ein <label> und darf den Feldrhythmus nicht erben. */
  margin: 0;
  padding: 0.25rem;
  border: 1px solid var(--kante-stark);
  border-radius: var(--radius-klein);
  background: var(--grund);
  /* Anders als das freie Fach im Reifenhotel ist die freie Zeit hier der
     Inhalt und nicht der Rest: sie steht in Textfarbe, nicht nachgeordnet. */
  color: var(--text);
  font-family: var(--schrift-titel);
  font-weight: 700;
  font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: border-color 0.2s var(--weich), background-color 0.2s var(--weich), color 0.2s var(--weich);
}
.slot input {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
.slot:hover { border-color: var(--marke); color: var(--marke); }
.slot:has(input:checked) { border-color: var(--akzent); background: var(--akzent); color: var(--text); }
.slot-fokus:focus-within { outline: 3px solid var(--marke); outline-offset: 2px; }

/* ---- Leistungswahl ---------------------------------------------------- */

.leistungswahl { display: grid; gap: 0.375rem; max-width: var(--spalte); margin-top: 0.75rem; }
/* Die Rubrik buendelt die Wahl, und ihre Beschriftung steht in der Rolle Label
   -- dieselbe wie die Reihenbeschriftung der Terminwand, nur ueber der Gruppe
   statt neben ihr, weil eine Leistungskarte die ganze Spalte nimmt. Den
   Abstand zur ersten Karte traegt .leistungswahl, darum keine eigene Marge
   unter der Legende. */
.leistungsgruppe { margin-top: 1.25rem; }
.leistungsgruppe:first-of-type { margin-top: 0; }
.leistungsgruppe > legend {
  margin-bottom: 0;
  color: var(--text-neben);
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
/* Die Karte ist ein Rahmen um Radiozeile UND Zusatzwahl: der Aufklappblock
   «Optional dazu buchen» gehoert zur Leistung und steht darum in ihrem
   Rahmen, nicht darunter. Der Rahmen liegt auf .leistungskarte, weil ein
   details nicht in einem label liegen darf; die Radiozeile .leistung traegt
   nur noch Raster und Polster. */
.leistungskarte {
  border: 1px solid var(--kante);
  border-radius: var(--radius-klein);
  background: var(--grund);
  transition: border-color 0.2s var(--weich), background-color 0.2s var(--weich);
}
.leistungskarte:hover { border-color: var(--kante-stark); }
.leistung {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.75rem;
  align-items: start;
  min-height: 3rem;
  margin: 0;
  padding: 0.875rem 1rem;
  font-size: 1rem;
  font-weight: 400;
  cursor: pointer;
}
.leistung input { margin-top: 0.25rem; }
.leistung strong { font-family: var(--schrift-titel); font-weight: 700; font-size: 1.125rem; }
.leistung small { display: block; margin-top: 0.25rem; color: var(--text-neben); font-size: 0.875rem; line-height: 1.4; }
/* Gilt unabhaengig vom Element (Label-Zeile oder Angabe auf der Bestaetigung):
   der Preis ist immer Nebentext, auch bei einer kostenlosen Leistung. */
.leistung__preis { color: var(--text-neben); }
/* Rahmen in `marke` und Flaeche in `flaeche` sagen «gewaehlt». Kein gelber
   Strich obendrauf: er laege auf der eigenen Kante der Karte und fraesse ein
   Stueck aus dem Rahmen -- ein Defekt, kein Zeichen. */
/* Nur der Radiopunkt waehlt die Karte -- ein von Hand gesetztes Kaestchen in
   einer NICHT gewaehlten Karte darf sie nicht als gewaehlt faerben. */
.leistungskarte:has(input[type="radio"]:checked) { border-color: var(--marke); background: var(--flaeche); }

/* Zusatzwahl: Belbos «Optional dazu buchen»-Dialog als Aufklappblock IN der
   Leistungskarte, unter der Radiozeile, ohne JavaScript bedienbar. Er sitzt
   2.25 rem eingerueckt, also unter dem Text der Radiozeile, nicht unter
   ihrem Radiopunkt; der negative obere Rand zieht die Aufklappzeile an das
   Polster der Radiozeile heran. Die Aufklappzeile haelt die Trefferflaeche
   der Daumen-Regel wie .feldgruppe > summary. Ist die Leistung darueber
   gewaehlt, tritt der Block hervor; ohne :has() bleibt er ein
   gewoehnliches details. */
.zusatzwahl { margin: -0.5rem 1rem 0.375rem 2.25rem; }
.zusatzwahl > summary {
  min-height: 2.75rem;
  padding: 0.75rem 0;
  cursor: pointer;
  list-style-position: inside;
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.875rem;
}
.zusatzwahl[open] > summary { color: var(--text); }
.leistung:has(input:checked) + .zusatzwahl > summary { color: var(--marke); }
.zusatzwahl .kaestchen { margin-top: 0.25rem; }
/* Kontextabweichung Erfassungsmaske (views/termin_erfassen.php): dort steht
   .zusatzwahl in form.rasterformular direkt unter dem Leistungsfeld, nicht
   unter einer Radiozeile der Buchungskarte -- der negative obere Rand und der
   Einzug von 2.25rem passen dort nicht. .zusatzwahl > summary (Trefferflaeche,
   BarrierefreiheitTest.php) bleibt unangetastet. */
.rasterformular > .zusatzwahl { margin: 0; }
.rasterformular > .zusatzwahl > div { margin-top: 0.75rem; }
.pruefung__zusatz dd { color: var(--text-neben); }

/* ---- Angaben (Pruefen, Kundenlink, Termin) ---------------------------- */

.pruefung, .auftragskarte dl { display: grid; gap: 0; margin: 1.5rem 0 0; }
.pruefung > div, .auftragskarte dl > div {
  padding: 0.75rem 0;
  border-top: 1px solid var(--kante);
}
.pruefung dt, .auftragskarte dt {
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-neben);
}
.pruefung dd, .auftragskarte dd { margin: 0.25rem 0 0; }
/* Ohne diese Regel galt fuer die Tagesliste eines mehrtaegigen Termins die
   Browservorgabe von 40 px Einzug — der einzige Abstand im Haus, den
   niemand gesetzt hatte. 1.25 rem traegt die Aufzaehlungspunkte. */
.auftragskarte dd ul { margin: 0.25rem 0 0; padding-left: 1.25rem; }
/* Verweise in der Angabenliste stehen je auf eigener Zeile und sind
   Handlungen — die Kartei oeffnen, eine Mail schreiben —, keine Woerter in
   einem Satz. Sie tragen darum die Trefferflaeche der Daumen-Regel. */
.auftragskarte dd > a { display: inline-flex; align-items: center; min-height: 2.75rem; }
.auftragskarte .pruefung > div:first-child, .auftragskarte dl > div:first-child { border-top: 0; padding-top: 0; }

/* Die groesste Angabe der oeffentlichen Seite ist die bestaetigte Zeit. */
.zeitgross {
  display: block;
  margin: 0 0 0.5rem;
  font-family: var(--schrift-titel);
  font-weight: 800;
  font-size: clamp(2.25rem, 9vw, 3rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--marke);
}

/* Die Zeit in einer Angabenzeile: gross genug, um die Zeile zu fuehren. */
.zeitmarke {
  font-family: var(--schrift-titel);
  font-weight: 800;
  font-size: 1.75rem;
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--marke);
}

/* ---- Karte (ruhende Flaeche) ----------------------------------------- */

.auftragskarte, .planungskarte {
  padding: 1rem 1.25rem;
  border: 1px solid var(--kante);
  border-radius: var(--radius-gross);
  background: var(--grund);
}
.auftragskarte h2, .planungskarte h2 { margin-top: 0; }
.kundenkarte { max-width: var(--spalte); }

/* ---- Anmeldung -------------------------------------------------------- */

/* Die einzige Karte einer sonst leeren Seite wird mittig gesetzt statt oben
   angeschlagen: Der Koerper ist ein Sticky-Footer-Flexraster, und darin stand
   unter der 350 px hohen Anmeldekarte bis zum 14.09.2026 ein Leerfeld von
   ueber 320 px — das liest sich wie eine halb geladene Seite, ausgerechnet
   auf der ersten Seite, die jede interne Nutzerin sieht. Der Zuschlag von
   4 rem haelt die Karte dabei ueber der Mitte statt genau darauf; exakt
   mittig wirkt ein kurzes Formular zu tief. */
@media (min-height: 40rem) {
  .inhalt:has(> .anmeldung) { display: flex; flex-direction: column; justify-content: center; padding-bottom: 4rem; }
}
.anmeldung {
  max-width: 24rem;
  margin: 1.5rem auto;
  padding: 1.5rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
}
.anmeldung p { margin: 0; }
.anmeldung .knopf { margin-top: 1.75rem; }

/* ---- Fehlerseite ------------------------------------------------------ */

.fehler { max-width: var(--spalte); }
.korrelationskennung { color: var(--text-neben); font-size: 0.875rem; }

/* ---- Tagesraster (Signatur, intern) ---------------------------------- */
/* Der Werkstatttag steht: die Zeit laeuft senkrecht, jede Kapazitaetsgruppe
   ist eine Spalte. Blau heisst «hier wird gearbeitet», weiss mit starker
   Kante «hier kommt die Kundin». Das Raster nimmt Breite und Resthoehe des
   Fensters — der Tag soll am Bildschirm liegen, nicht durchgerollt werden. */

/* Eine Spalte mit minmax(0, 1fr), nicht die implizite auto-Spalte: die richtet
   sich nach dem breitesten Inhalt (ein langes Auswahlfeld im Filter, die
   Terminliste) und liess die Seite unter 64 rem waagrecht rollen -- gegen die
   Formularspalten-Regel in DESIGN.md. In inhalt--voll ist die Seite ein
   Flex-Stapel, dort greift die Spaltenangabe nicht. */
.kalenderseite { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
.kalenderkopf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}
.kalenderkopf h1 { margin: 0; }
.kalenderdatum { margin: 0.25rem 0 0; color: var(--text-neben); font-variant-numeric: tabular-nums; }
.kalendernavigation { display: flex; flex-wrap: wrap; gap: 0 1rem; }
.kalendernavigation a { position: relative; }
/* «Heute» ist der markierte Punkt der Navigation, keine gelbe Flaeche. Der
   Strich unterstreicht das ganze Wort wie in Kopf- und Verwaltungsnavigation;
   ein fest breites Stueck darunter laese sich als abgeschnittener Unterstrich.
   Der Verweis hat kein waagrechtes Polster, `left`/`right` treffen darum
   genau die Textbreite. */
.kalendernavigation__heute { color: var(--marke); }
.kalendernavigation__heute::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0.5rem;
  height: 2px;
  background: var(--akzent);
}

/* Tagesblock (Teilprojekt 8): ruhende Flaeche wie die Terminwand,
   aufklappbar, damit er in inhalt--voll die Fensterhoehe nicht sprengt. */
.tagesblock { border: 1px solid var(--kante); border-radius: var(--radius-gross); background: var(--flaeche); }
.tagesblock > summary {
  min-height: 2.75rem;
  padding: 0.75rem 1rem;
  cursor: pointer;
  list-style-position: inside;
  color: var(--text);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.9375rem;
}
.tagesblock__inhalt { display: grid; gap: 1rem; padding: 0 1rem 1rem; }
@media (min-width: 48rem) { .tagesblock__inhalt { grid-template-columns: minmax(16rem, 1fr) minmax(0, 2fr); } }
.tagesblock__notiz textarea { width: 100%; resize: vertical; }
.tagesblock__aufgaben h2 { margin: 0 0 0.5rem; font-size: 1rem; }
.tagesblock__liste { list-style: none; margin: 0; padding: 0; }
/* Rollende Innenflaechen zeigen ihre Leiste in den Farben des Hauses, und die
   Spur bleibt reserviert. Eine ueberblendete Leiste verschwindet im
   Ruhezustand und mit ihr der einzige Hinweis, dass unter der Kante mehr
   steht; ein Schatten waere der uebliche Hinweis und ist hier verboten
   (Flach-Regel), die Leiste selbst tut es ohne Erhebung. Der Tagesblock
   stand hier bis zum 15.09.2026 mit -- er rollt nicht mehr. */
.kalender__kapazitaet[open] ul, .tabellenrahmen {
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--kante-stark) transparent;
}
.tagesblock__aufgabe { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; padding: 0.375rem 0; border-top: 1px solid var(--kante); }
.tagesblock__aufgabe:first-child { border-top: 0; }
.tagesblock__text { flex: 1 1 14rem; }
.tagesblock__text small { color: var(--text-neben); }
.tagesblock__aufgabe--ueberfaellig .tagesblock__text small { color: var(--fehler); }
.tagesblock__aufgabe--erledigt .tagesblock__text { color: var(--text-neben); }
.tagesblock__aktion { display: inline; }
.tagesblock__neu { display: flex; flex-wrap: wrap; align-items: end; gap: 0.5rem; margin-top: 0.75rem; }
.tagesblock__neu label { flex: 1 1 100%; }
.tagesblock__neu input { flex: 1 1 14rem; }

.kalenderfilter {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0 1rem;
  align-items: end;
  padding: 1rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
}
.kalenderfilter label { margin-top: 0.75rem; }
/* Ein Datumsfeld ist immer gleich breit — zehn Zeichen. Ueber die ganze
   Spaltenbreite gezogen sieht es nicht nach Datum aus, und iOS zentriert
   seinen Wert dann in der Leere. Dieselben 12 rem, die die Spalte ab 48 rem
   ohnehin bekommt. */
.kalenderfilter input[type="date"] { max-width: 12rem; }
.filter { grid-column: 1 / -1; }
/* Kein display: flex — sonst verschwindet in Chromium der Aufklappmarker. */
.filter summary {
  padding: 0.75rem 0;
  cursor: pointer;
  list-style-position: inside;
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.875rem;
}
.filter[open] summary { color: var(--text); }
.filter__aktiv {
  display: inline-block;
  margin-left: 0.375rem;
  padding: 0 0.5rem;
  border-radius: var(--radius-voll);
  background: var(--akzent);
  color: var(--text);
  font-size: 0.75rem;
}
.filter__felder { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0 1rem; }
@media (min-width: 30rem) { .filter__felder { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.kalenderfilter .knopf { margin-top: 1.25rem; justify-self: start; }
@media (min-width: 30rem) { .kalenderfilter { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Ab 48 rem ist der Filter eine Zeile statt eines Rasters: Datumsfeld,
   Aufklappzeile und Knopf nebeneinander, die Felder in Lesebreite — ein
   Suchfeld darf nicht einen halben Bildschirm breit sein.

   Diese Anordnung hing bis zum 14.09.2026 an `.inhalt--voll`, und weil die
   Terminliste als einzige Kalenderansicht davon ausgenommen ist (sie rollt,
   statt die Fensterhoehe zu nehmen), verlor sie damit eine Regel, die mit
   Hoehe nichts zu tun hat: derselbe geteilte Baustein mass dort 236 statt
   103 Pixeln. Hoehe und Anordnung sind zwei Fragen. Die Regel steht hier
   und nicht oben bei den Hoehenregeln, weil sie sonst VOR der Rasterregel
   dieser Komponente stuende und bei gleicher Spezifitaet verloere — der
   Filter wurde dadurch im ersten Anlauf hoeher statt flacher. */
@media (min-width: 48rem) {
  .kalenderfilter { display: flex; flex-wrap: wrap; align-items: end; gap: 0 1.5rem; }
  .kalenderfilter > div { flex: 0 0 12rem; }
  .filter { flex: 1 1 16rem; }
  .filter__felder { grid-template-columns: repeat(auto-fill, minmax(0, 18rem)); }
}

.kalender {
  overflow: auto;
  border: 1px solid var(--kante);
  border-radius: var(--radius-gross);
  background: var(--grund);
}
/* Zwei Zeilen, beliebig viele Spalten: oben die stehenden Spaltenkoepfe,
   unten die Zeitflaeche. Die Gruppenspalte ist ein eigenes Element — sie
   traegt Kopf und Flaeche zusammen — und uebernimmt die Zeilen per subgrid,
   damit alle Zeitflaechen auf derselben Hoehe beginnen. */
.kalender__flaeche {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: var(--zeitspalte);
  grid-auto-columns: 1fr;
  grid-template-rows: auto minmax(var(--tagesraster), 1fr);
  min-height: 100%;
}
.kalender__zeitspalte,
.kalender__bahn {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  min-width: 0;
}
/* Die Zeitachse bleibt beim waagrechten Rollen stehen, sonst liest man
   Zeiten zu Spalten, die sie nicht mehr benennen. */
.kalender__zeitspalte {
  position: sticky;
  left: 0;
  z-index: 3;
  border-right: 1px solid var(--kante);
  background: var(--flaeche);
}
.kalender__ecke {
  position: sticky;
  top: 0;
  z-index: 1;
  border-bottom: 1px solid var(--kante);
  background: var(--flaeche);
}
.kalender__zeiten { position: relative; }
/* Zeitmarken sind Zahlen, keine Woerter: tabellarisch, ohne Versalien, auf
   der Stundenlinie liegend. */
.kalender__zeiten span {
  position: absolute;
  top: var(--zeit);
  right: 0.5rem;
  transform: translateY(-50%);
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

/* Eine Unterspur faellt nie unter ihre Mindestbreite: lieber rollt das
   Raster waagrecht, als dass ein Arbeitsblock zum Farbfleck wird. */
.kalender__bahn {
  min-width: calc(var(--spuren, 1) * var(--spur-min));
  border-left: 1px solid var(--kante);
}
.kalender__bahn:first-of-type { border-left: 0; }
.kalender__bahn > header {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--kante);
  background: var(--flaeche);
}
/* Der Spaltenname traegt dieselbe Rolle wie der Regalname im Reifenhotel. */
.kalender__bahn h2 {
  margin: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--ton, var(--marke));
  font-size: 1.0625rem;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.kalender__bahn > header p { margin: 0.25rem 0 0; color: var(--text-neben); font-size: 0.8125rem; }
.kalender__badge {
  display: inline-block;
  padding: 0 0.375rem;
  border: 1px solid var(--kante-stark);
  border-radius: var(--radius-klein);
  background: var(--grund);
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  vertical-align: 0.15em;
}
.kalender__kapazitaet { color: var(--text-neben); font-size: 0.75rem; }
/* Die Aufklappzeile ist eine Trefferflaeche und haelt darum die Daumen-Regel
   ein: derselbe Abstand wie am Schwesterelement .filter summary, dazu die
   Mindesthoehe -- bei 0.75 rem Schrift reicht das Polster allein nicht bis an
   die 2.75 rem. Den Abstand nach oben traegt das Polster selbst, die Zeile
   braucht keine eigene Marge mehr. Kein display: flex, sonst verschwindet in
   Chromium der Aufklappmarker. */
.kalender__kapazitaet summary {
  min-height: 2.75rem;
  padding: 0.75rem 0;
  cursor: pointer;
  font-weight: 600;
  list-style-position: inside;
}
.kalender__kapazitaet ul { margin: 0 0 0.25rem; padding-left: 1rem; }
/* Aufgeklappt darf die Abschnittsliste den stehenden Kopf nicht ueber die
   halbe Spalte wachsen lassen. */
.kalender__kapazitaet[open] ul { max-height: 8rem; overflow-y: auto; }

.kalender__spur { position: relative; min-width: 0; }
/* Stundenlinien als Haarlinien aus Tokens, nicht als Verlauf. */
.kalender__stunde {
  position: absolute;
  left: 0; right: 0;
  top: var(--zeit);
  height: 1px;
  background: var(--kante);
}
/* Der Arbeitsblock liegt auf --oben/--hoehe in Prozent der Tageshoehe und
   teilt sich die Spaltenbreite mit den Unterspuren; 1 px Fuge ringsum
   trennt Nachbarn, ohne eine zweite Kantenfarbe einzufuehren. */
.kalender__block {
  position: absolute;
  top: var(--oben);
  left: calc(var(--spur) * 100% / var(--spuren, 1) + 1px);
  width: calc(100% / var(--spuren, 1) - 2px);
  height: calc(var(--hoehe) - 2px);
  /* Eine Zeile Text passt genau in die Mindesthoehe: eine Viertelstunde ist
     im gestauchten Tag nur rund 18 px hoch und soll ihre Zeit noch nennen. */
  min-height: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 0 0.5rem;
  overflow: hidden;
  padding: 0.1875rem 0.5rem;
  border-radius: var(--radius-klein);
  background: var(--ton, var(--marke));
  color: var(--grund);
  text-decoration: none;
  line-height: 1.35;
  transition: background-color 0.2s var(--weich);
}
/* Derselbe Schritt in die Tiefe wie von `marke` zu `marke-tief`, nur
   gerechnet statt sechsmal gesetzt: 51 % des Tons auf Schwarz bildet
   Werkstattblau (#004394) auf #00224B ab — `marke-tief` ist #00224C. Die
   Regel «im Hover wird die Flaeche tiefer, nicht heller» gilt damit fuer
   jeden der sechs Toene aus einer Zeile. */
.kalender__block:hover,
.kalender__block:focus-visible { background: color-mix(in srgb, var(--ton, var(--marke)) 51%, #000); }
/* Die Zeit steht immer zuerst; der Name rueckt neben sie und faellt erst in
   die naechste Zeile, wenn die Spur dafuer zu schmal ist. Leistung und
   Status bekommen je eine eigene Zeile und werden im kurzen Termin
   abgeschnitten — die Viertelstunde bleibt lesbar. */
.kalender__block > * {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.kalender__block strong {
  flex: 0 0 auto;
  font-family: var(--schrift-titel);
  font-weight: 700;
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
}
.kalender__block span { flex: 1 1 6rem; font-size: 0.8125rem; }
/* Die Nebenzeile wird aus dem Ton gemischt und nicht deklariert: `auf-tief`
   ist ein helles Blau und passt zu keinem der anderen fuenf Toene. 80 % Weiss
   halten auf jedem Ton mindestens 5.1:1 — schwaechster Fall ist Gold. */
.kalender__block .leise,
.kalender__block small { flex: 1 0 100%; color: color-mix(in srgb, #FFF 80%, var(--ton, var(--marke))); }
.kalender__block .leise { font-size: 0.8125rem; }
.kalender__block small { font-size: 0.75rem; }
.kalender__marke { display: none; }

/* Das Anlieferfenster ist noch keine Arbeit: weiss mit starker Kante, und
   Gelb markiert es als die Zeit, in der die Kundin vor der Tuer steht. Das
   Zeichen bleibt 24 x 2 px und steht neben der Zeit, nicht ueber ihr — im
   stehenden Tag ist Hoehe Zeit und darf nicht an Zier gehen. */
.kalender__block--anlieferung {
  border: 1px solid var(--kante-stark);
  /* Die Kante frisst bei border-box zwei Pixel Inhaltsbreite, die der blaue
     Arbeitsblock nicht verliert -- derselbe Name passte im Arbeitsblock und
     wurde im Anlieferfenster daneben mit der Ellipse gekappt (gemessen 179
     auf 177 px). Das seitliche Polster gibt sie zurueck, damit in beiden
     Blocktypen gleich viel Text steht. */
  padding-inline: calc(0.5rem - 1px);
  background: var(--grund);
  color: var(--text);
}
.kalender__block--anlieferung:hover,
.kalender__block--anlieferung:focus-visible { background: var(--flaeche); }
.kalender__block--anlieferung .leise,
.kalender__block--anlieferung small { color: var(--text-neben); }
.kalender__block--anlieferung .kalender__marke {
  display: block;
  flex: 0 0 auto;
  align-self: center;
  width: 1.5rem; height: 2px;
  background: var(--akzent);
}

.kalender__mobilliste { display: none; }

@media (max-width: 47.99rem) {
  .kalender { display: none; }
  .kalender__mobilliste { display: grid; gap: 1rem; }
  .kalender__listenbahn {
    overflow: hidden;
    border: 1px solid var(--kante);
    border-radius: var(--radius-gross);
    background: var(--grund);
  }
  .kalender__listenbahn h2 { margin: 0; padding: 1rem; background: var(--flaeche); color: var(--ton, var(--marke)); font-weight: 800; }
  .kalender__listenbahn > p { margin: 0; padding: 1rem; color: var(--text-neben); }
  .kalender__listenblock {
    display: grid;
    gap: 0.25rem;
    min-height: 3rem;
    padding: 0.875rem 1rem;
    border-top: 1px solid var(--kante);
    color: var(--text);
    text-decoration: none;
  }
  .kalender__listenblock:hover, .kalender__listenblock:focus-visible { background: var(--flaeche); }
  .kalender__listenblock strong {
    font-family: var(--schrift-titel);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }
  .kalender__listenblock span { color: var(--text-neben); font-size: 0.875rem; }
}

/* ---- Gruppentoene ----------------------------------------------------- */

/* Die Bahn traegt `data-ton`, das Raster liest `--ton`. Ein Attribut und keine
   Klasse: KalenderHandlerTest haelt die Inline-Stile der Bahn wortgetreu
   (`style="--spuren: 1"`), ein angehaengtes `--ton` braeche sie ohne
   fachlichen Grund. Fehlt der Ton, bleibt Werkstattblau — darum liest jede
   Regel unten `var(--ton, var(--marke))` und nie `var(--ton)` allein. */
[data-ton="blau"] { --ton: var(--gruppe-blau); }
[data-ton="petrol"] { --ton: var(--gruppe-petrol); }
[data-ton="gold"] { --ton: var(--gruppe-gold); }
[data-ton="graphit"] { --ton: var(--gruppe-graphit); }
[data-ton="pflaume"] { --ton: var(--gruppe-pflaume); }
[data-ton="moos"] { --ton: var(--gruppe-moos); }

/* ---- Wochenraster ----------------------------------------------------- */

/* Fuenf Tageskalender nebeneinander: Spalten sind Tag mal Kapazitaetsgruppe,
   die Zeit laeuft von oben nach unten. Bis zum 17.09.2026 stand hier das
   Gegenteil -- Zeilen waren Gruppen, eine Zelle trug Textzeilen ohne
   Zeitachse. Der Block traegt darum jetzt dieselben Klassen wie im Tagesraster
   (.kalender__block, .kalender__spur, .kalender__stunde): dieselbe Grammatik
   in beiden Rastern, eine Regel statt zweier. Am Handy tritt weiterhin die
   Wochenliste an seine Stelle. */
.wochenraster {
  display: block;
  overflow: auto;
  min-height: var(--tagesraster);
  border: 1px solid var(--kante);
  border-radius: var(--radius-gross);
  background: var(--grund);
}

/* Drei Zeilen: Tageskopf, Gruppenkopf, Zeitflaeche. Die Spalten entstehen von
   selbst -- je Tag so viele, wie es Gruppen gibt. Die Breite einer Bahn
   waechst mit ihren Unterspuren, genau wie im Tagesraster. */
.wochenraster__flaeche {
  display: grid;
  grid-auto-flow: column;
  grid-template-columns: var(--zeitspalte);
  grid-auto-columns: 1fr;
  grid-template-rows: auto auto minmax(var(--tagesraster), 1fr);
  min-width: min-content;
  min-height: 100%;
}

/* Die Zeitachse gilt fuer die ganze Woche und bleibt beim waagrechten Rollen
   stehen -- ohne sie sagt eine Blockhoehe zwei Tage weiter rechts nichts
   mehr. */
.wochenraster__zeitspalte {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  position: sticky;
  left: 0;
  z-index: 3;
  min-width: 0;
  border-right: 1px solid var(--kante);
  background: var(--flaeche);
}
/* Die Ecke deckt beide Kopfzeilen; darunter beginnt die Zeit. */
.wochenraster__ecke {
  grid-row: 1 / 3;
  position: sticky;
  top: 0;
  z-index: 1;
  border-bottom: 1px solid var(--kante);
  background: var(--flaeche);
}

/* Ein Tag ist ein Abschnitt ueber seinen Gruppenspalten. Er uebernimmt
   Spalten UND Zeilen der Flaeche (zweifaches subgrid), damit Tageskopf,
   Gruppenkopf und Zeitflaeche ueber alle Tage hinweg fluchten. Die staerkere
   Kante links trennt Tag von Tag, die feine innerhalb Gruppe von Gruppe. */
.wochenraster__tag {
  display: grid;
  grid-row: 1 / -1;
  grid-column: span var(--gruppen);
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
  border-left: 1px solid var(--kante-stark);
}

/* Der Tageskopf ist EINE Zeile hoch, Marken eingeschlossen: seine Hoehe ist
   zugleich der Haltepunkt des Gruppenkopfs darunter (--wochenkopf-tag), und
   ein umbrechender Kopf wuerde diesen Versatz verschieben. Die Marken
   schrumpfen darum mit Auslassungspunkten, statt eine zweite Zeile zu
   nehmen. */
.wochenraster__tagkopf {
  grid-column: 1 / -1;
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: var(--wochenkopf-tag);
  margin: 0;
  padding: 0 0.75rem;
  border-bottom: 1px solid var(--kante);
  background: var(--flaeche);
  color: var(--marke);
  font-family: var(--schrift-titel);
  font-size: 0.9375rem;
  font-weight: 800;
  white-space: nowrap;
}
/* Der Halt rechnet die Zeitachse mit: sie liegt ueber dem Kopf (z-index) und
   schluckte den Tagesnamen sonst Buchstabe um Buchstabe. */
.wochenraster__tagname {
  position: sticky;
  left: calc(var(--zeitspalte) + 0.75rem);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  max-width: 100%;
}
.wochenraster__tagname > span { color: var(--text-neben); font-weight: 600; }

.wochenraster__bahn {
  display: grid;
  grid-row: 2 / -1;
  grid-template-rows: subgrid;
  min-width: calc(var(--spuren, 1) * var(--spur-min));
  border-left: 1px solid var(--kante);
}
/* Der Gruppenkopf haelt unter dem Tageskopf an. Der Versatz ist die Hoehe des
   Tageskopfs und keine geratene Zahl -- beide lesen dasselbe Token. */
.wochenraster__bahn > header {
  position: sticky;
  top: var(--wochenkopf-tag);
  z-index: 1;
  padding: 0.375rem 0.5rem;
  border-bottom: 1px solid var(--kante);
  background: var(--flaeche);
}
/* Der Gruppenname umbricht, statt abzuschneiden: eine Spalte ist hier nur
   8.5 rem breit, und ein abgeschnittenes Badge las sich als «(INA» -- das
   sieht nach Fehler aus, wo Auslassungspunkte nach Kuerzung aussehen. Die
   Kopfzeile ist eine Rasterzeile und darum ueber alle Spalten gleich hoch. */
.wochenraster__bahn h3 {
  margin: 0;
  color: var(--ton, var(--marke));
  font-family: var(--schrift-titel);
  font-size: 0.9375rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.wochenraster__bahn header p {
  margin: 0.25rem 0 0;
  color: var(--text-neben);
  font-size: 0.75rem;
  line-height: 1.4;
}
.wochenraster__bahn header .bedienflaeche { margin-top: 0.25rem; }

/* Geschlossen ist keine leere Spalte: die Off-White-Flaeche sagt «hier ist
   gar nicht offen», das Wort im Kopf sagt es noch einmal. Traegt die Spalte
   trotzdem Bloecke -- von Hand in nachtraeglich geschlossene Zeit erfasst --,
   stehen beide da; der Widerspruch wird gezeigt, nicht versteckt. */
.wochenraster__bahn--geschlossen { background: var(--flaeche); }

/* Die Marken des Tageskopfs: ein Verweis auf den Tag, keine eigene Handlung.
   Die Notiz schrumpft zuerst, die Aufgabenzahl bleibt ganz -- eine
   abgeschnittene Zahl waere eine falsche Zahl. */
.wochenraster__marken { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.wochenraster__notiz, .wochenraster__aufgaben { display: flex; align-items: center; align-self: stretch; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; font-weight: 600; }
.wochenraster__notiz { flex: 0 1 auto; color: var(--text); }
.wochenraster__aufgaben { flex: 0 0 auto; color: var(--marke); }
.kalenderwoche__notiz { margin: 0.5rem 0 0; font-size: 0.875rem; }

/* ---- Wochenliste (Mobilfassung des Rasters) --------------------------- */

.kalenderwoche {
  display: grid;
  gap: 1px;
  border: 1px solid var(--kante);
  border-radius: var(--radius-gross);
  background: var(--kante);
  grid-template-columns: 1fr;
}
.kalenderwoche > section { padding: 1rem; background: var(--grund); }
.kalenderwoche h2 { margin: 0; font-size: 1rem; }
.kalenderwoche > section > p { margin: 0.5rem 0 0; color: var(--text-neben); font-size: 0.875rem; }
.kalenderwoche > section > p strong {
  color: var(--text);
  font-family: var(--schrift-titel);
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
}
.kalenderwoche a {
  display: block;
  min-height: 2.75rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--kante);
  color: var(--text);
  text-decoration: none;
  font-size: 0.8125rem;
}
.kalenderwoche a strong {
  display: block;
  font-family: var(--schrift-titel);
  font-variant-numeric: tabular-nums;
}
.kalenderwoche a span { display: block; color: var(--text-neben); }
.kalenderwoche a:hover strong, .kalenderwoche a:focus-visible strong { color: var(--marke); }

/* Genau eine der beiden Fassungen steht im Fluss. Der Umschalter liegt
   bewusst hinter den Grundregeln beider Komponenten: stuende er davor,
   holten diese ihre eigene display-Angabe zurueck. */
@media (max-width: 47.99rem) {
  .wochenraster { display: none; }
}
@media (min-width: 48rem) {
  .kalenderwoche { display: none; }
}

/* ---- Terminliste ------------------------------------------------------ */
/* Die dritte Kalenderansicht ist kein Raster, sondern eine Liste: je Tag ein
   Abschnitt mit Ueberschrift, darin die Datentabelle der Kundenliste. Sie
   braucht darum fast kein eigenes CSS -- nur den Abstand zwischen den Tagen.
   Die feste Fensterhoehe bekommt sie bewusst nicht: in den Rastern heisst
   Hoehe Zeit, hier heisst sie Menge. */
/* minmax(0, 1fr) statt der impliziten auto-Spalte: die Tabelle darf breiter
   sein als die Seite, rollt dann aber in ihrem .tabellenrahmen -- nie die Seite. */
.terminliste { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
.terminliste h2 { margin: 0 0 0.5rem; }

/* `.leise` ist sonst nur innerhalb der Kalenderbloecke definiert. In der
   Tabelle erbt die Spanne sonst die Zeitmarke und stuende gleich laut wie die
   Uhrzeit -- genau das Gegenteil ihres Namens. */
.terminliste .leise { font: inherit; color: var(--text-neben); }

/* ---- Terminseite ------------------------------------------------------ */

.terminseite { display: grid; gap: 1.5rem; }
.terminkopf { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.5rem 1rem; }
.terminkopf h1 { margin: 0; font-size: 2rem; font-weight: 800; letter-spacing: -0.02em; }
.terminraster { display: grid; gap: 1rem; }
@media (min-width: 48rem) { .terminraster { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Statusmarke: immer ausgeschriebener Text, davor der Einsatzstrich. Seine
   Farbe sagt, ob der Termin laeuft, auf die Kundin wartet oder beendet ist. */
.statusmarke {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2rem;
  padding: 0 0.75rem;
  border-radius: var(--radius-klein);
  background: var(--flaeche);
  color: var(--text);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.8125rem;
}
.statusmarke::before { content: ""; width: 1.5rem; height: 2px; flex: none; background: var(--marke); }
/* In einer Textzeile sitzt die Marke auf deren Mitte und nicht auf der
   Grundlinie: sie ist 2 rem hoch, die Zeile um sie herum misst 20 px, und
   auf der Grundlinie haengt sie 5 px zu tief -- auf der Terminseite las sich
   «Termin 64 · Bereit» dadurch als zwei Zeilen, die knapp danebenliegen.
   `vertical-align: middle` brachte den Versatz auf 1.6 px, weil es an
   (Grundlinie + halbe x-Hoehe) ausrichtet und nicht an der Textmitte; die
   Kontextzeile ist darum ein Flexkasten und trifft die Mitte genau. Der
   Textknoten «Termin 64 ·» wird dabei zum anonymen Flexitem, das
   Trennzeichen bleibt also im Satz und wandert nicht ins Markup. */
.kontext { display: flex; flex-wrap: wrap; align-items: center; gap: 0 0.375rem; }
.verlaufsliste .statusmarke { vertical-align: middle; }
.statusmarke--warten::before { background: var(--akzent); }
.statusmarke--beendet { color: var(--fehler); }
.statusmarke--beendet::before { background: var(--fehler); }

/* Anzeige der geplanten Spanne, eine blaue Flaeche wie der Arbeitsblock im
   Kalender -- Blau heisst «hier liegt Arbeit». Seit dem 15.09.2026 kein
   Bedienelement mehr: Greifzeiger, Ziehsperre, Fokusring und der gelbe Strich
   als «Kante der Dauer» sind weg, weil hier nichts mehr gezogen wird.
   Geplant wird im Formular darunter. */
.planungsbalken {
  display: grid;
  align-content: center;
  gap: 0.25rem;
  flex: none;
  width: 100%;
  max-width: 20rem;
  min-height: 4.25rem;
  margin: 0;
  padding: 0.75rem 0.875rem;
  border-radius: var(--radius-klein);
  background: var(--marke);
  color: var(--grund);
}
.planungsbalken strong {
  font-family: var(--schrift-titel);
  font-weight: 700;
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
}
.planungsbalken small { color: var(--auf-tief); font-size: 0.75rem; line-height: 1.3; }

.planungskarte__kopf { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; }
/* Gemeinsames Formularraster fuer Planung und Verwaltung. Es bleibt in der
   Formularspalte: ein Datumsfeld oder eine einstellige Kapazitaet darf nicht
   ein Drittel der Bahn breit werden. Zwei Spalten ab 30 rem, eine darunter.

   Der senkrechte Feldrhythmus liegt am Zeilenabstand des Rasters und nicht
   mehr am oberen Rand der Beschriftung. Jedes Feld steht in einem eigenen
   div, und darin ist die Beschriftung `:first-child` -- der Reset aus der
   Grundregel (`label:first-child { margin-top: 0 }`) traf damit JEDE
   Beschriftung des Rasters statt nur der ersten. Mit `gap: 0 1rem` blieb
   zwischen den Zeilen darum gar kein Abstand: die Beschriftung der zweiten
   Zeile klebte am Feld der ersten, und das galt in jedem Formular des
   internen Bereichs. Der Zeilenabstand kann das, was der Rand der
   Beschriftung nicht kann: er laesst die erste Zeile unberuehrt und haelt
   beide Spalten einer Zeile auf derselben Hoehe. */
.rasterformular, .planungsformular { display: grid; gap: var(--feld-abstand) 1rem; max-width: var(--spalte); }
.planungsformular { margin-top: 1.25rem; }
.rasterformular > div, .planungsformular > div { min-width: 0; }
.rasterformular__breit, .planungsformular__notiz { grid-column: 1 / -1; }
/* Der Schalter, der eine ganze Leistung oder Kapazitaetsgruppe fuer die
   Kundschaft abschaltet, ist keine weitere Zeile der Liste ueber ihm. Er
   stand bis zum 14.09.2026 im selben 0.5-rem-Rhythmus wie die Zusatzhaken
   beziehungsweise «Platzgebunden» darueber und las sich als deren letzter
   Punkt — dabei nimmt ein Fehlklick dort eine Leistung aus dem oeffentlichen
   Katalog. Derselbe Abstand wie vor einem Fieldset, dazu die Haarlinie, die
   sagt: hier endet die Liste und beginnt etwas anderes. */
.rasterformular__abschluss { margin-top: 0.75rem; padding-top: 1rem; border-top: 1px solid var(--kante); }
.rasterformular__abschluss .kaestchen { margin-top: 0; }
.rasterformular > fieldset { margin-top: 0; }
/* Eine Rasterzelle, die nur einen Knopf traegt («Vorschlag übernehmen»,
   «Ganzer Tag»), hat keine Beschriftung ueber sich und begann darum sofort
   oben in der Zeile -- gemessen 17 px hoeher als die Felder daneben. Sie
   schiebt ihren Knopf jetzt an die Unterkante der Zeile, wo die Felder
   enden. Der abschliessende Absendeknopf ist davon nicht betroffen: er
   spannt alle Spalten und steht ohnehin allein in seiner Zeile. */
.rasterformular > div:has(> .knopf:only-child),
.planungsformular > div:has(> .knopf:only-child) {
  display: flex;
  align-items: flex-end;
}

/* Der Absendeknopf steht weiter 1.75 rem unter dem letzten Feld -- seit das
   Raster einen Zeilenabstand hat, traegt dieser den ersten Rem davon. */
.rasterformular .knopf, .planungsformular .knopf,
.rasterformular > button, .planungsformular > button {
  grid-column: 1 / -1;
  justify-self: start;
  margin-top: 0.75rem;
}
@media (min-width: 30rem) {
  .rasterformular, .planungsformular { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Fahrzeuge der Kundenkartei: ein Block je Fahrzeug. Mehrere
   `.rasterformular` untereinander haben sonst keinen Abstand — der
   Absendeknopf des einen grenzt unmittelbar an die erste Beschriftung des
   naechsten, und wer welchen Knopf drueckt, ist nicht mehr lesbar. Die
   Haarlinie oben trennt, ohne einen Kasten zu zeichnen; der erste Block
   braucht sie nicht, denn ueber ihm steht bereits die Ueberschrift
   «Fahrzeuge». Das Kennzeichen bleibt in der h3-Groesse der Designvorgabe:
   kleiner gesetzt laese es sich als weitere Feldbeschriftung und nicht als
   Blocktitel. Der untere Abstand ist Pflicht, nicht Feinschliff — die erste
   Beschriftung im Formular ist `label:first-child` und traegt darum
   `margin-top: 0`, klebte also sonst an der Ueberschrift. */
.fahrzeugblock + .fahrzeugblock {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--kante);
}
.fahrzeugblock > h3 { margin-bottom: 0.75rem; }

/* Schrittweise Offenlegung im Erfassungs- und Aenderungsformular: eine
   Feldgruppe, die eingeklappt nur ihre Aufklappzeile belegt. Dieselbe Zeile
   wie im Kalenderfilter -- Archivo 600, 0.875 rem, leise, im offenen Zustand
   in Textfarbe -- und dieselbe Trefferflaeche der Daumen-Regel. Kein display:
   flex, sonst verschwindet in Chromium der Aufklappmarker. */
.feldgruppe > summary {
  min-height: 2.75rem;
  padding: 0.75rem 0;
  cursor: pointer;
  list-style-position: inside;
  color: var(--text-neben);
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.875rem;
}
.feldgruppe[open] > summary { color: var(--text); }

.stornoformular { margin-top: 1.75rem; padding-top: 1.25rem; border-top: 1px solid var(--kante); }
/* Kartei suchen und Kartei waehlen sind der Schritt vor der Erfassungsmaske
   und werden von ihr getrennt -- sonst klebt die erste Zeile der Maske
   unmittelbar unter dem Knopf «Suchen» (gemessen null Pixel). Dasselbe
   Muster wie .fahrzeugblock und .kundenaktion. */
.kundenfinder {
  margin-bottom: 2rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--kante);
}
.kundenfinder > .verlaufsliste, .kundenfinder > .leer { margin-top: 1rem; }

.kundenaktion { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--kante); }
.kundenaktion h2 { margin-top: 0; }

/* ---- Listen ----------------------------------------------------------- */
/* Haarlinie oben und zwischen den Eintraegen, kein Rand an den Seiten. */

.verlaufsliste {
  display: grid;
  gap: 0;
  max-width: var(--spalte);
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
}
.verlaufsliste li { display: grid; align-content: center; min-height: 2.75rem; padding: 0.25rem 0; border-top: 1px solid var(--kante); }
.verlaufsliste li:first-child { border-top: 0; }
.verlaufsliste strong { font-family: var(--schrift-titel); font-weight: 700; }
/* `:not(.statusmarke)`, weil die generische Regel sonst die Marke schlaegt:
   `.verlaufsliste span` ist spezifischer als `.statusmarke--beendet`. Bis zum
   14.09.2026 wurde die Pille dadurch zu einem 684 Pixel breiten Balken, und
   ein stornierter Termin trug in der Kartei Nebengrau statt seines Fehlerrots
   — die Farbe, die den Status traegt, war ausgerechnet dort wirkungslos, wo
   man die Geschichte einer Kartei liest. */
.verlaufsliste span:not(.statusmarke) { display: block; color: var(--text-neben); font-size: 0.875rem; }
.verlaufsliste .statusmarke { justify-self: start; margin-top: 0.25rem; }
.verlaufsliste p { margin: 0.375rem 0 0; color: var(--text-neben); font-size: 0.875rem; }
.verlaufsliste a { display: inline-flex; align-items: center; min-height: 2.75rem; justify-self: start; font-family: var(--schrift-titel); font-weight: 700; text-decoration: none; }
.verlaufsliste a:hover { text-decoration: underline; }
.verlaufsliste form { margin-top: 0.5rem; }
.verlaufsliste .knopf { min-height: 2.75rem; padding: 0.5rem 1rem; font-size: 0.9375rem; }

/* ---- Verwaltung ------------------------------------------------------- */

.verwaltung-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 0.25rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--kante);
}
.verwaltung-nav a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0.5rem 0.75rem;
  color: var(--text-neben);
  text-decoration: none;
  font-family: var(--schrift-titel);
  font-weight: 600;
  font-size: 0.9375rem;
}
.verwaltung-nav a:hover { color: var(--text); }
.verwaltung-nav a.ist-aktiv { color: var(--marke); }
.verwaltung-nav a.ist-aktiv::after {
  content: "";
  position: absolute;
  left: 0.75rem; right: 0.75rem; bottom: -1px;
  height: 2px;
  background: var(--akzent);
}

.verwaltung-formular {
  margin-bottom: 1rem;
  padding: 1rem 1.25rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
}
.verwaltung-formular input, .verwaltung-formular select, .verwaltung-formular textarea { background: var(--grund); }

.wochenzeiten { display: grid; gap: 1rem; }
@media (min-width: 48rem) { .wochenzeiten { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.wochenzeit-formular {
  padding: 1rem 1.25rem;
  border-radius: var(--radius-gross);
  background: var(--flaeche);
}
.wochenzeit-formular fieldset { margin: 0; }
.wochenzeit-formular input { background: var(--grund); }
.wochenzeit-formular .knopf { margin-top: 1.25rem; }
.zeitintervall { display: grid; gap: 0 0.75rem; align-items: end; grid-template-columns: 1fr 1fr; }
.zeitintervall label { margin-top: 0.75rem; }

/* ---- Kundenliste ------------------------------------------------------ */
/* Die Suchzeile ist eine ruhende Flaeche: Off-White mit grossem Radius,
   wie Filterblock und Verwaltungsformular. Die Tabelle rollt in ihrem
   eigenen Rahmen, damit die Seite nie waagrecht rollt. */
.suchzeile {
  display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: end;
  margin: 0 0 1rem; padding: 1rem;
  border-radius: var(--radius-gross); background: var(--flaeche);
}
.suchzeile label { flex: 1 1 100%; }
.suchzeile input { flex: 1 1 16rem; max-width: var(--spalte); }
.tabellenrahmen { overflow-x: auto; }
/* Die Mindestbreite ist die Bedingung dafuer, dass `.tabellenrahmen` ueberhaupt
   etwas zu rollen hat: ohne sie quetscht `width: 100%` die fuenf Spalten in
   jede Breite, und eine Telefonnummer bricht auf fuenf Zeilen um. Mit ihr
   rollt die Tabelle in ihrem Rahmen — so, wie DESIGN.md es zusagt. */
.datentabelle { width: 100%; min-width: 42rem; border-collapse: collapse; }
.datentabelle th,
.datentabelle td {
  padding: 0.75rem; text-align: left;
  border-top: 1px solid var(--kante);
}
.datentabelle td a { display: block; margin: -0.75rem; padding: 0.75rem; }
.datentabelle th {
  font-family: var(--schrift-titel); font-weight: 600;
  font-size: 0.8125rem; color: var(--text-neben);
}
/* Telefon, Kennzeichen und Datum brechen nie um: sie sind eine Kette, die
   zerlegt nicht mehr lesbar ist («+41 / 71 / 555 / 20 / 16»). Statt zu brechen,
   macht die Tabelle den Rahmen rollen. */
.datentabelle .zeitmarke { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---- Interne Arbeitsbreite -------------------------------------------- */
/* Alles, was die Werkstatt am Bildschirm bedient, laeuft auf --bahn-intern
   statt auf der 64-rem-Bahn. Die 36-rem-Formularspalte ist damit nicht
   abgeschafft: sie wandert vom Container auf das Element. Ein Eingabefeld
   bleibt lesebreit, es stehen nur mehr davon nebeneinander.

   Der Block steht bewusst hinter allen Grundregeln. Seine Selektoren sind
   ohnehin spezifischer, aber die Reihenfolge macht die Absicht lesbar — die
   Lehre aus Teilprojekt 4b, wo ein Umschalter vor den Grundregeln lag.

   Alle Anordnungsregeln liegen ab 48 rem: unterhalb des Desktop-Breakpoints
   bleibt jede Ansicht einspaltig wie am 08.09.2026 abgenommen. Die Breitenregel
   darunter gilt dagegen auf jeder Breite — sie muss es, denn sie ist zugleich
   der Riegel gegen waagrechtes Seitenrollen: ohne sie ist die Bahn
   fit-content und wird von einer breiten Tabelle aufgeblaeht. */

/* `width: 100%` ist hier keine Zier, sondern Voraussetzung: Inhalt, Meldungen
   und Fusszeile tragen `margin: 0 auto`, und eine Auto-Marge in der Querachse
   hebt das `stretch` des Koerper-Flexrasters auf — die Bahn waere sonst
   «fit-content bis zum Deckel» statt «Deckel». Ein auto-fill-Raster in einem
   solchen Container faellt auf eine einzige Spalte zusammen, und die breite
   Bahn waere nur behauptet. */
.inhalt--intern, .meldungen--intern, .fuss--intern {
  width: 100%;
  max-width: var(--bahn-intern);
}

/* Die zwei Rasteransichten nehmen die ganze Fensterbreite. Am 10.09.2026 war
   das Gegenteil richtig: die Wochenansicht war «Zeilen sind Gruppen» und kam
   mit 120 rem aus, der Deckel kostete nichts. Seit der Transponierung vom
   17.09.2026 sind ihre Spalten Tag mal Gruppe -- fuenf Tage mal drei Gruppen
   sind 15 Bahnen a --spur-min plus Zeitachse, also 131 rem. Auf 120 rem rollt
   das Raster waagrecht, obwohl auf einem 2560-px-Schirm 640 px links und
   rechts brachliegen. Im Raster ist Breite Arbeitsflaeche, kein Lesemass.

   Getragen wird die Regel von `inhalt--voll`, weil das Markup damit schon
   genau diese zwei Ansichten auszeichnet; die Terminliste ist davon
   ausgenommen und bleibt auf der Bahn. Meldungen und Fusszeile gehen mit,
   sonst stuende die Fusszeile 320 px eingerueckt neben einem randbreiten
   Raster.

   Es faellt allein der Deckel, nicht die bestimmte Breite: `width: 100%` ist
   der Riegel gegen waagrechtes SEITENrollen (ohne ihn ist die Bahn
   fit-content und wird von einer breiten Tabelle aufgeblaeht), und darum
   gilt diese Regel auch ohne Mediaquery. Was gelesen wird -- Hinweis,
   Meldung, Formularfeld --, ist elementweise gedeckelt und bleibt lesebreit. */
body:has(> .inhalt--voll) .inhalt--intern,
body:has(> .inhalt--voll) .meldungen--intern,
body:has(> .inhalt--voll) .fuss--intern { max-width: none; }

@media (min-width: 48rem) {
  /* Fliesstext bekommt eine Lesebreite zurueck: einen Hinweis oder eine
     Meldung ueber 1900 px liest niemand. */
  .inhalt--intern .hinweis,
  .inhalt--intern .kontext,
  .inhalt--intern .leer,
  .meldungen--intern .meldung { max-width: var(--lesetext); }

  /* Formularraster: die Spalte ist gedeckelt, nicht mehr der Container. */
  .inhalt--intern .rasterformular,
  .inhalt--intern .planungsformular {
    max-width: none;
    /* `min(…, 100%)` als Boden ist Pflicht, nicht Feinschliff: ein nackter
       minmax-Boden ist eine harte Mindestbreite und laeuft in jedem engeren
       Behaelter ueber — etwa in der halben Spalte der Kundenkartei. */
    grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 20rem));
  }
  /* Das breite Feld spannt weiter alle Spalten — aber was man hineintippt,
     bleibt auf der Formularspalte. Kaestchen und Radios tragen eine feste
     Breite von 1.375 rem und bleiben davon unberuehrt. */
  .inhalt--intern .rasterformular__breit textarea,
  .inhalt--intern .rasterformular__breit input,
  .inhalt--intern .planungsformular__notiz textarea { max-width: var(--spalte); }
  /* Eine Zelle, deren Textfeld ohnehin auf der Formularspalte gedeckelt ist,
     muss nicht alle Spalten sperren: sie nimmt zwei und laesst die naechsten
     Felder daneben stehen, statt eine ganze Zeile leer zu lassen. Zwei Spalten
     sind breiter als die Formularspalte, das Feld verliert also nichts. Gilt
     nur fuer Textfelder — die vier `fieldset`-Zellen der Verwaltung tragen
     keines und spannen weiterhin die ganze Breite. */
  .inhalt--intern .rasterformular__breit:has(textarea) { grid-column: span 2; }

  /* Listen mehrspaltig, mit deutlichem Spaltenabstand: zwei Eintraege
     nebeneinander duerfen nicht als einer gelesen werden. Die Haarlinie je
     Eintrag bleibt, die Reihenfolge bleibt die des Markups. */
  .inhalt--intern .verlaufsliste {
    max-width: none;
    grid-template-columns: repeat(auto-fill, minmax(min(26rem, 100%), 1fr));
    column-gap: 2.5rem;
  }
  .inhalt--intern .seitenkopf--spalte { max-width: none; }

  /* Die Kundenkartei wird zweispaltig. Mehrspaltensatz und nicht Gitter: ein
     Gitter bindet seine Zellen an Zeilen, und eine Zeile ist so hoch wie ihr
     hoechstes Element — unter dem kurzen Stammdatenblock stuende ein Loch in
     der Hoehe des Fahrzeugblocks. Der Mehrspaltensatz laesst die Abschnitte
     stattdessen fliessen. `break-inside` haelt jeden Abschnitt zusammen; der
     Seitenkopf laeuft ueber beide Spalten. Die DOM- und damit die
     Tabreihenfolge bleibt in jedem Fall unveraendert. */
  .kundenseite {
    columns: 2;
    column-gap: 2.5rem;
  }
  .kundenseite > * { break-inside: avoid; }
  .kundenseite > .seitenkopf { column-span: all; }
}

/* Erst wenn wirklich Platz ist, bekommt die Terminansicht ihre dritte Spalte. */
@media (min-width: 90rem) {
  .inhalt--intern .terminraster { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---- Bewegungsreduktion ---------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }
}
