/* Oberfläche für zwei Orte: iPad am Tresen (stehend, eine Hand) und Mac im
   Büro. Die Gestaltung folgt drei Regeln:

   1. Eine Größenleiter, keine zufälligen Werte. Schrift 13/14/16/20/28,
      Abstände in Vielfachen von 4. Vorher lagen die Schriftgrößen zwischen
      12,5 und 17 px dicht beieinander — dadurch gab es keine Hierarchie,
      alles wirkte gleich wichtig, und genau das liest sich als „unfertig".
   2. Eine Hauptaktion je Bildschirm. Vorher war jeder Knopf gefüllt und
      braun, auch „Suchen" neben einer Suche, die ohnehin beim Tippen sucht.
   3. Ruhige Werkzeugleisten. Filter sind Werkzeug, nicht Inhalt: kleiner,
      leiser, in einer Zeile.                                              */

/* Woher die Farben kommen: von der Website der Werkstatt
   (geigenbau-lieberwirth.de). Dort sind sechs Werte eingestellt —

     #ae213a   der Akzent, dort die Kopfleiste
     #e0dad5   die warme Grundfarbe
     #4e4e4e   dunkles Grau
     #9a9a9a   mittleres Grau
     #000000 · #ffffff

   Der Kunde sieht am Tresen beides: die Website auf dem Telefon und diese
   Anwendung über die Schulter. Zwei Betriebe sollen daraus nicht werden.

   Die beiden Farben stehen unten unverändert. Die Grautöne geben nur die
   Richtung — als Fließtext gelesen brauchen sie mehr Abstand zur Fläche,
   als eine Website ihnen abverlangt; die Werte unten sind deshalb dunkler.

   Übernommen ist, was die Anwendung *aussehen* lässt: Fläche, Linie,
   Schrift, Akzent. Nicht übernommen sind die Statusfarben weiter unten.
   Grün, Bernstein, Blau und Rot bedeuten etwas — eine Website hat für
   „Zahlung stockt" keine Farbe, und sich eine auszudenken hieße, eine
   fachliche Aussage der Gestaltung zu überlassen. */
:root {
  /* Ohne diese Zeile bleiben Kästchen, Auswahlfelder und vor allem der
     Datumswähler hell, während alles um sie herum dunkel ist — ein weißer
     Kalender, der beim Antippen aufspringt, ist im Dunkelmodus nicht bloß
     hässlich, sondern blendet. Der Browser färbt sie nur, wenn die Seite
     sagt, dass sie beides kann. */
  color-scheme: light dark;

  /* Fläche und Linie sind dieselbe Farbe in drei Stufen. #e0dad5 selbst ist
     als ganzseitiger Grund zu schwer — sie trägt die Linien, und die Fläche
     ist ihre helle Stufe. Auf der Website steht der Inhalt auf Weiß; hier
     tut er das auch, in den Karten. */
  --grund: #f4f2f0;
  --karte: #ffffff;
  --linie: #e0dad5;
  --linie-zart: #f1eeec;
  /* Schrift in den Grautönen der Website. Vorher hatten Text und Nebentext
     einen Braunstich (#26221e, #787067) — der gehörte zum braunen Akzent und
     sieht neben dem Rot schmutzig aus. */
  --text: #262524;
  --leise: #6f6d6b;
  /* #8f8d8b lag auf dem Grund (#f4f2f0) bei 3,1:1 und damit unter den 4,5:1,
     die WCAG AA für Fließtext verlangt. Benutzt wird die Farbe für
     Platzhalter und Hilfstexte — also für genau das, was jemand liest, der
     unsicher ist, was in ein Feld gehört. #767472 kommt auf 4,6:1. */
  --leiser: #767472;
  /* Der Akzent der Website, unverändert: gefüllte Hauptaktion, aktiver
     Eintrag, Fokusrahmen. */
  --akzent: #ae213a;
  --akzent-tief: #8b1a2e;
  /* Die helle Stufe des Akzents ist **kein** helles Rot, sondern die
     Grundfarbe mit einem Hauch davon. Ein rosa Streifen unter dem Finger
     und der rosa Kasten einer Fehlermeldung (--rot-hell) sind auf
     Armlänge nicht zu unterscheiden — und diese Stufe liegt unter jeder
     Zeile, die man antippt. Sie darf nach nichts aussehen. */
  --akzent-hell: #eadfde;
  --gut: #2f6b46;
  --gut-hell: #e6f1ea;
  --warn: #94600f;
  --warn-hell: #fbf1de;
  /* Der Rahmen der Hinweiskarte. Stand als #f0dcb8 mitten in der Regel und
     blieb deshalb im Dunkelmodus hell — ein heller Rand um eine dunkle
     Fläche, der aussah, als sei die Karte noch am Laden. */
  --warn-rand: #f0dcb8;
  --gut-rand: #bcdcc9;
  --rot-rand: #f0c4c0;
  --rot-hell-flaeche: #fbeceb;
  --rot: #8d2f26;
  --rot-hell: #fbeceb;
  /* Vier Töne, die es als Variable noch nicht gab. Ohne sie standen ihre
     Farben fest im Regelwerk, und jede brauchte für den Dunkelmodus eine
     eigene Handregel — sieben allein für „ruht". Wer eine Marke hinzufügte,
     musste daran denken; wer es vergaß, merkte es erst im Dunkeln. */
  /* Nicht mehr ``var(--leise)``: Als Schrift auf ``--ruhe-hell`` (#ecebea)
     kam #6f6d6b auf 4,4:1 und verfehlte AA um eine Zehntelstufe — und die
     Marke „stillgelegt" ist keine Zierde, sondern die Auskunft, warum ein
     Kunde am Tresen nicht mehr auftaucht. #5f5d5b kommt auf 5,3:1. */
  --ruhe: #5f5d5b;           /* erledigt, stillgelegt, verworfen */
  --ruhe-hell: #ecebea;
  --info: #35507d;           /* reserviert — eine Ankündigung, keine Warnung */
  --info-hell: #e6ecf5;
  --werkstatt: #7a5320;      /* in Arbeit */
  --werkstatt-hell: #efe6d8;
  /* Der fünfte Ton, und der einzige, der aus dem Farbwechsel entstanden ist.
     „Unterwegs" hing bisher am Akzent — solange der braun war, ging das.
     Als Rot ginge es nicht mehr: 499 von 826 Artikeln sind verliehen, das
     ist der Normalfall und keine Meldung. Eine rote Marke daneben hieße
     „sieh her", und in der Spalte darunter steht „stockt" in genau diesem
     Rot. Der Holzton bleibt also — er bedeutet ab hier nur noch dies. */
  --unterwegs: #6f3a1e;      /* verliehen, in Umlauf */
  --unterwegs-hell: #f4e9e1;

  --r1: 4px;  --r2: 8px;  --r3: 12px; --r4: 16px;
  --r5: 24px; --r6: 32px; --r7: 48px;
  /* Die eine begründete Ausnahme: Abstand zwischen einem Symbol und seiner
     Beschriftung. 4px klebt, 8px trennt sie zu zwei Dingen. Als Variable,
     damit es eine Entscheidung bleibt und nicht dreimal dieselbe krumme
     Zahl. */
  --r-symbol: 6px;
  /* Breiten. Vier Stufen, mehr braucht diese Anwendung nicht.
   *
   * Nicht an der Karte — die folgt der Seite. Sondern am Inhalt: Ein
   * Eingabefeld über 1200 px ist unbrauchbar, eine Tabelle über 1200 px
   * nicht. Innerhalb einer Karte soll es **eine** rechte Kante geben; jede
   * weitere sieht aus wie ein Versehen, und drei sahen auch so aus.
   *
   * --mass ist die Spalte: Formularzeilen und der Fließtext daneben. Die drei
   * kurzen Stufen sitzen darin, für Felder, deren Inhalt schmal ist — ein
   * Fälligkeitstag ist zweistellig, eine Straße nicht. */
  --breit-knapp: 160px;   /* zweistellige Zahl */
  --breit-schmal: 280px;  /* Name, Ort, kurzer Begriff */
  --breit-mittel: 420px;  /* IBAN, E-Mail */
  --mass: 880px;          /* die Spalte */
  /* Schriftgrößen. Acht Stufen, benannt.
   *
   * Vorher achtzehn Werte, darunter die Paare 12/12,5, 13/13,5, 14/14,5 und
   * 22/23/24 — Unterschiede, die niemand sieht und die trotzdem jedes Mal neu
   * entschieden werden mussten. Dieselbe Beliebigkeit wie vorher bei den
   * Kartenbreiten, eine Ebene tiefer.
   *
   * Die häufigen Größen waren schon einig (14px neunmal, 15px achtmal); was
   * ausscherte, waren die Einzelfälle. Sie sind in die nächstliegende Stufe
   * gerückt — höchstens um zweieinhalb Pixel, und das an einem Sortierpfeil. */
  --s-klein: 12.5px;    /* Tabellenkopf, Marken, Zähler */
  --s-zusatz: 13.5px;   /* Zusatzzeile, Fußnote, Beschriftung */
  --s-fein: 14px;       /* Nebenbedienung, Reiter, Blätterung */
  --s-text: 15px;       /* Fließtext, Navigation */
  --s-hervor: 17px;     /* h3, Summe in der Tabelle, abgetippter Schlüssel */
  --s-titel: 20px;      /* h2 */
  --s-kopf: 23px;       /* h1, Kachelwert */
  --s-zahl: 30px;       /* die eine große Zahl: Monatsmiete */
  /* Höhe von Bedienelementen. Zwei Stufen.
   *
   * Vorher vier Werte — 32, 34, 40, 44 —, und welche ein Element bekam, wirkte
   * zufällig. Am iPad ist das keine Geschmacksfrage: Ein 32 px hoher Knopf
   * wird mit dem Daumen danebengetroffen, während der Kunde wartet.
   *
   * Als Variable und nicht als Zahl, damit die Touch-Regel weiter unten sie
   * **einmal** anheben kann. Vorher zählte sie die Elemente einzeln auf und
   * vergaß dabei zwei: das Mietfeld in der Positionszeile und den Schließer an
   * einer Meldung blieben bei 34 und 32 px. */
  --hoehe-bedien: 40px;   /* der Normalfall */
  --hoehe-knapp: 34px;    /* in einer Tabellenzelle, wo 40 die Zeile sprengt */
  --rund: 9px;
  --rund-karte: 12px;
  --schatten: 0 1px 2px rgba(38,37,36,.05), 0 1px 1px rgba(38,37,36,.04);
  --leiste: 236px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 16px/1.55 "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--text);
  background: var(--grund);
  -webkit-font-smoothing: antialiased;
}

.ueberspringen {
  position: absolute; left: -999px; top: 0; z-index: 100;
  background: var(--karte); padding: var(--r3) var(--r4); border-radius: var(--rund);
}
.ueberspringen:focus { left: var(--r3); top: var(--r3); }

/* --------------------------------------------------------------------------
   Gerüst: Leiste links, Inhalt rechts
   -------------------------------------------------------------------------- */
.huelle { display: flex; min-height: 100vh; align-items: stretch; }

.seitenleiste {
  flex: 0 0 var(--leiste); width: var(--leiste);
  background: var(--karte); border-right: 1px solid var(--linie);
  padding: var(--r5) var(--r4);
  display: flex; flex-direction: column; gap: var(--r5);
  position: sticky; top: 0; height: 100vh; overflow-y: auto;
}
.seitenleiste .marke { font-size: var(--s-hervor); font-weight: 650; letter-spacing: -.015em; }
.seitenleiste .marke a { color: var(--text); text-decoration: none;
  display: inline-block; padding: var(--r1) var(--r2); margin: calc(-1 * var(--r1))
  calc(-1 * var(--r2)); border-radius: var(--rund); }
/* Der Name ist der einzige Weg zur Übersicht, seit sie keine eigene Zeile
   mehr hat. Dass er ein Ziel ist, muss man sehen können — und auf der
   Übersicht muss er sagen, dass man dort ist. Sonst zeigt dort nichts auf
   sich selbst, und die Leiste sieht aus, als sei man nirgends. */
.seitenleiste .marke a:hover { background: var(--grund); }
.seitenleiste .marke a.aktiv { background: var(--akzent-hell); }
.seitenleiste .marke span { color: var(--akzent); }
/* Das Logo der Werkstatt, wo eines hinterlegt ist. Es steht über „Verleih"
   und nicht daneben: In einer 150 Pixel breiten Leiste liegen sonst beide
   gequetscht nebeneinander, und ein Schriftzug, den man zusammenkneift, ist
   schlechter als keiner.

   Begrenzt über die **Höhe** und nicht über die Breite. Mit `width: 100%`
   sah es in der Leiste richtig aus und sprengte unter 960 px die Kopfzeile:
   Dort ist die Marke ein Flex-Element, und 100 % heißt dann die ganze
   Zeile — der Schriftzug lief quer über den Bildschirm und aus ihm heraus.
   Ein Logo ist so breit, wie es hoch sein darf. */
.seitenleiste .marke a:has(img) { display: block; }
.seitenleiste .marke img { display: block; width: auto; height: auto;
  max-width: 100%; max-height: 44px; margin-bottom: var(--r1); }
.seitenleiste .marke img + span { display: block; font-size: var(--s-klein);
  font-weight: 500; letter-spacing: .04em; text-transform: uppercase; }

main.anmeldung .marke img { display: block; width: auto; height: auto;
  max-width: min(300px, 80%); margin: 0 auto var(--r2); }
main.anmeldung .marke img + span { display: block; font-size: var(--s-klein);
  letter-spacing: .06em; text-transform: uppercase; }

.seitenleiste nav { display: flex; flex-direction: column; gap: var(--r1);
  flex: 1 1 auto; }
/* Einrichtung am Fuß: Werkstatt und Mein Zugang.
 *
 * ``margin-top: auto`` schiebt den Block ans Ende der Leiste, solange Platz
 * ist — und fällt in sich zusammen, sobald keiner mehr da ist. Dann rutschen
 * genau diese beiden unter den Rand, und das ist die richtige Reihenfolge:
 * Wofür man scrollen muss, ist das, was man am seltensten braucht.
 *
 * Der Strich darüber ist die ganze Überschrift. Ein Wort mehr („Einrichtung")
 * kostete eine Zeile in einer Leiste, die auf dem iPad quer ohnehin schon
 * neunzig Pixel zu lang war; für die Sprachausgabe steht es trotzdem da. */
.seitenleiste .fussgruppe { margin-top: auto; padding-top: var(--r4);
  border-top: 1px solid var(--linie-zart); }
.seitenleiste .fussgruppe a { color: var(--leise); font-weight: 500; }
.seitenleiste .fussgruppe a:hover, .seitenleiste .fussgruppe a.aktiv {
  color: var(--akzent-tief); }
.seitenleiste .gruppe {
  margin: var(--r4) 0 var(--r1); padding: 0 var(--r3);
  font-size: var(--s-klein); font-weight: 650; letter-spacing: .08em;
  text-transform: uppercase; color: var(--leise);
}
.seitenleiste nav .gruppe:first-child { margin-top: 0; }
.seitenleiste ul { list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--r1); }
.seitenleiste nav a {
  display: flex; align-items: center; gap: var(--r2);
  padding: var(--r2) var(--r3); border-radius: var(--rund);
  color: var(--text); text-decoration: none; font-size: var(--s-text); font-weight: 500;
  min-height: var(--hoehe-bedien);
}
.seitenleiste nav a:hover { background: var(--grund); }
.seitenleiste nav a.aktiv {
  background: var(--akzent-hell); color: var(--akzent-tief); font-weight: 620;
}
.seitenleiste .abmelden {
  padding-top: var(--r4); border-top: 1px solid var(--linie-zart);
  display: flex; align-items: center; justify-content: space-between; gap: var(--r2);
}
.seitenleiste .wer { font-size: var(--s-zusatz); color: var(--leise); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }

main { flex: 1 1 auto; min-width: 0; padding: var(--r6) var(--r6) var(--r7);
  max-width: 1240px; }

/* Die Leiste in Daumenreichweite gibt es nur am Telefon — dort bekommt sie
   weiter unten ``display: flex``. Oben steht sie hier, damit sie auf jedem
   breiteren Schirm von vornherein weg ist und nicht erst, nachdem eine
   Medienabfrage sie wieder eingesammelt hat. */
.daumenleiste, .tablett-kopf { display: none; }

/* Seit ``viewport-fit=cover`` (siehe basis.html) reicht die Seite auf dem
   iPhone bis unter die Ecken und die Kamerainsel. Quer gehalten liegt dann
   die erste Spalte jeder Tabelle unter der Insel — lesbar bleibt sie nur,
   wenn die Seite den Einzug selbst hält. Hochkant und auf jedem anderen
   Gerät sind beide Werte 0, die Regel kostet dort also nichts. */
body { padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px); }

/* --------------------------------------------------------------------------
   Typografie
   -------------------------------------------------------------------------- */
h1 { font-size: var(--s-zahl); font-weight: 650; letter-spacing: -.025em; margin: 0 0 var(--r1); }
h2 { font-size: var(--s-titel); font-weight: 620; letter-spacing: -.015em; margin: var(--r6) 0 var(--r3); }
/* Luft über einer angesprungenen Überschrift.
 *
 * Ohne sie klebt sie an der oberen Fensterkante, und was darüber steht — die
 * Meldung des gerade gelaufenen Vorgangs zum Beispiel — ist weg, ohne dass
 * man sieht, dass da etwas war. Betrifft alle sechs Sprungmarken: die drei
 * auf der Datenpflege, den Rückstand und die beiden im Zahlungseingang, auf
 * die jetzt jede Weiterleitung nach einem Lauf zeigt. */
h2[id] { scroll-margin-top: var(--r5); }
h3 { font-size: var(--s-hervor); font-weight: 620; margin: 0 0 var(--r2); }
/* Fließtext steht in derselben Spalte wie die Felder — nicht in einer eigenen.
   Vorher waren es 68ch und 72ch: zwei Kanten für dieselbe Art Text, und keine
   von beiden traf die Feldkante. In einer Karte standen dadurch drei rechte
   Ränder übereinander, und der Infotext brach mitten in der Zeile um, obwohl
   rechts noch ein Viertel der Karte frei war. */
.unterzeile { color: var(--leise); margin: 0 0 var(--r5); font-size: var(--s-text);
  max-width: var(--mass); }
.fussnote { color: var(--leise); font-size: var(--s-zusatz); margin: var(--r2) 0 0;
  max-width: var(--mass); }
/* Eine Fußnote steht mal hinter etwas, mal davor. Sie hatte nur einen Rand
   nach oben — deshalb klebte der erklärende Satz auf acht Seiten ohne einen
   einzigen Pixel Abstand auf der Karte, der Werkzeugleiste oder dem Knopf,
   den er ankündigt. Der Rand nach unten gilt nur, wenn wirklich etwas folgt:
   als letzte Zeile einer Karte stünde unten sonst mehr Luft als oben. */
.fussnote:not(:last-child) { margin-bottom: var(--r3); }
.zusatz { color: var(--leise); font-size: var(--s-zusatz); }

/* Fließtext bekommt eine Zeilenlänge.
 *
 * ``--mass`` ist als Spaltenbreite gesetzt und galt für Formulare und Karten,
 * nicht für die erklärenden Sätze daneben. Auf einem breiten Bildschirm liefen
 * Unterzeile und Fußnote über 110 Zeichen je Zeile — das Auge findet den
 * Anfang der nächsten Zeile dann nicht mehr zuverlässig, und genau diese Sätze
 * sind die, die etwas erklären. 78ch ist die obere Kante des Üblichen und
 * bleibt schmaler als die Karten, auf denen sie stehen.
 *
 * Aber nur für Text, der ohnehin umbricht. Ein Satz, der in die Spalte passt,
 * bekommt die Spalte (``.einzeilig``, gesetzt von ``formular.js``): Sonst brach
 * „Der Vertrag nennt ein Objekt … weicht ab." bei 663 px um, und „Mietername
 * weicht ab." stand allein in der zweiten Zeile, während rechts davon ein
 * Viertel der Karte frei war. Gemessen über alle Vorlagen: 31 von 188
 * erklärenden Sätzen brachen so — ohne Gewinn, denn wer nur eine Zeile liest,
 * muss den Anfang der nächsten nicht finden. Und weil ``ch`` an der Schriftgröße hängt, stand
 * die Fußnote dabei auf einer anderen Kante als die Unterzeile darüber.
 *
 * Als Variable, nicht als zweites ``max-width``: ``.rechtliches`` hebt die
 * Breite mit ``none`` auf und muss das weiterhin können. */
.unterzeile, .fussnote, p.stand { --lesebreite: 78ch; max-width: var(--lesebreite); }
.einzeilig { --lesebreite: var(--mass); }
/* Wo nur noch die Endzeile bricht, nicht ein Wort allein darunter stehen
   lassen. Browser ohne ``pretty`` umbrechen wie bisher. */
.unterzeile, .fussnote, p.stand { text-wrap: pretty; }

/* Seitenkopf: Titel links, Hauptaktion rechts — eine Zeile, nie umbrechend. */
.seitenkopf { display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--r4); flex-wrap: wrap; }
.seitenkopf .taten { display: flex; gap: var(--r2); align-items: center; flex: 0 0 auto; }

/* --------------------------------------------------------------------------
   Bedienelemente
   -------------------------------------------------------------------------- */
/* Kein width:100% an der Stelle: Das ist eine Frage des Formularaufbaus, nicht
   des Bedienelements. Vorher gewann diese Regel wegen ihrer vier :not() über
   jede Werkzeugleisten-Regel — deshalb spannte sich das Monatsfeld des
   Monatslaufs über die gesamte Kartenbreite. Volle Breite gibt es jetzt dort,
   wo sie gemeint ist: in Formularen. */
:where(input:not([type=checkbox]):not([type=radio]):not([type=submit]):not([type=button]),
textarea, select) {
  font: inherit; font-size: var(--s-text);
  padding: var(--r2) var(--r4); border: 1px solid var(--linie);
  border-radius: var(--rund);
  background: var(--karte); color: var(--text); min-height: var(--hoehe-bedien); max-width: 100%;
}
.formular input, .formular textarea, .formular select,
.feld input, .feld textarea, .feld select { width: 100%; }
/* Keine Mindesthöhe: Das rows-Attribut sagt, wie viele Zeilen gemeint sind.
   Mit min-height 76px blieben unter der zweiten Zeile 13px leer, während oben
   8px polsterten — das Feld sah aus, als sei es unten dreimal so weit. */
textarea { resize: vertical; line-height: 1.5; }
select {
  appearance: none; padding-right: var(--r5); cursor: pointer;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1.5 6 6.5l5-5' fill='none' stroke='%236f6d6b' stroke-width='1.6' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat; background-position: right var(--r2) center;
}
input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--akzent); outline-offset: -1px; border-color: transparent;
}
label { font-size: var(--s-zusatz); font-weight: 600; color: var(--leise); }

button, .knopf {
  font: inherit; font-size: var(--s-text); font-weight: 600; line-height: 1;
  padding: var(--r2) var(--r4); border-radius: var(--rund);
  border: 1px solid transparent;
  min-height: var(--hoehe-bedien); cursor: pointer; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--r-symbol);
  background: var(--karte); color: var(--text); border-color: var(--linie);
}
button:hover, .knopf:hover { background: var(--grund); }
/* Genau eine gefüllte Aktion je Bildschirm.
 *
 * ``.formular > button[type=submit]`` steht hier, weil das Absenden eines
 * Formulars in aller Regel *die* Aktion der Seite ist. Bei drei Formularen auf
 * einer Seite stimmt das nicht mehr: Auf der Vertragsseite machte die Regel
 * „Kündigung vermerken" zum lautesten Knopf, obwohl daneben „Rücknahme
 * beginnen" steht und darunter „Versicherung umstellen" — drei gleichrangige
 * Vorgänge, von denen einer rot gefüllt war, weil sein Formular die Klasse
 * ``formular`` trug. Wer schnell greift, greift nach dem roten.
 *
 * ``:not(.leise)`` gibt die Möglichkeit zurück, das im Einzelfall abzustellen,
 * ohne die Regel zu verlieren. */
button[type=submit].haupt, .knopf.haupt,
.formular > button[type=submit]:not(.leise), .seitenkopf .knopf.haupt {
  background: var(--akzent); color: #fff; border-color: var(--akzent);
}
button[type=submit].haupt:hover, .knopf.haupt:hover,
.formular > button[type=submit]:not(.leise):hover { background: var(--akzent-tief); border-color: var(--akzent-tief); }
/* Und die Gegenregel für den Einzelfall — sie muss nach der gefüllten stehen,
   sonst gewinnt die Spezifität wieder. */
.formular > button[type=submit].leise {
  background: var(--karte); color: var(--text); border-color: var(--linie);
}
.formular > button[type=submit].leise:hover { background: var(--grund); }
.knopf.breit { width: 100%; }
.knopf.still, button.still {
  background: transparent; border-color: transparent; color: var(--leise);
  font-weight: 500; font-size: var(--s-zusatz); padding: var(--r1) var(--r2); min-height: var(--hoehe-knapp);
}
.knopf.still:hover, button.still:hover { color: var(--text); background: var(--grund); }
.knopf-leise { background: var(--karte); border: 1px solid var(--linie); color: var(--text);
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--hoehe-bedien); padding: var(--r2) var(--r4); border-radius: var(--rund);
  text-decoration: none; font-weight: 600; font-size: var(--s-text); }
.knopf-leise:hover { background: var(--grund); }
.knopf-weg { background: transparent; color: var(--leise); border: 1px solid var(--linie); }
.knopf-weg:hover { color: var(--rot); border-color: #e6b8b3; background: var(--karte); }
button:disabled { opacity: .5; cursor: default; }

/* --------------------------------------------------------------------------
   Werkzeugleiste — Filter sind Werkzeug, nicht Inhalt
   -------------------------------------------------------------------------- */
form.suche {
  display: flex; gap: var(--r2); margin: 0 0 var(--r4);
  flex-wrap: wrap; align-items: center;
  background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--rund-karte); padding: var(--r3);
}
/* Eine Höhe für die ganze Zeile. Vorher rechneten drei Elemente sie
   verschieden aus: Der Knopf hat line-height 1 und wurde 38px, die Felder
   haben 1,55 und wurden 39,7 bzw. 41,25px. Die Kanten liefen sichtbar
   auseinander — auf „Offene Posten" um über 5px. */
form.suche { --h: 40px; }
form.suche input, form.suche select, form.suche button {
  height: var(--h); min-height: var(--h);
}
/* Das Suchfeld nimmt allen freien Platz, die Filter stehen als Block am
   rechten Rand. Beides zusammen geht nur, wenn genau ein Element wächst —
   deshalb hier flex-grow und bei der Filtergruppe keins. */
.suchfeld { position: relative; flex: 1 1 320px; min-width: 200px;
  display: flex; align-items: center; }
.suchfeld input[type=search] { width: 100%; min-width: 0; }
form.suche .filter { display: flex; flex: 0 0 auto; flex-wrap: wrap;
  gap: var(--r2); align-items: center; margin-left: auto; }
/* Auswahlfelder so breit wie ihr Inhalt, nicht 180 px jedes. Fünf Filter
   passen dadurch in eine Zeile, statt in die zweite zu rutschen. */
form.suche select { flex: 0 0 auto; width: auto; min-width: 0; font-size: var(--s-fein);
  padding: var(--r2) var(--r5) var(--r2) var(--r3); }
/* Auch das Suchfeld folgt der Polsterung der Filter daneben — sonst beginnt
   der eingetippte Text 4px weiter innen als deren Beschriftung. */
form.suche input { padding: var(--r2) var(--r3); }
form.suche input[type=month], form.suche input[type=date] { flex: 0 0 auto; width: auto; }
form.suche button { font-size: var(--s-fein); padding: var(--r2) var(--r3); }
form.suche .rechts { margin-left: auto; }
form.suche label:not(.nur-lesbar) { flex: 0 0 auto; font-size: var(--s-zusatz); }
/* Gesucht wird beim Tippen. Der Knopf bleibt im Markup — ohne JavaScript ist
   das Formular ein gewöhnliches GET und braucht ihn. Mit JavaScript wäre er
   ein Knopf, der nichts tut, was nicht ohnehin schon geschehen ist. */
html.js .ohne-js { display: none; }
/* Die Ladeanzeige sitzt im Suchfeld statt daneben: Sonst rückt sie beim
   Erscheinen die ganze Filtergruppe um ihre Breite nach rechts. */
.suchfeld .laeuft { position: absolute; right: var(--r3); pointer-events: none;
  background: var(--karte); padding-left: var(--r2); }
/* ACHTUNG, ungeschützter Name: Diese Klasse gehört der Ladeanzeige und setzt
   ``opacity: 0``. Ein Statuston hieß versuchsweise ebenfalls „laeuft" — die
   Marken waren daraufhin unsichtbar, mit richtiger Farbe und richtigem
   Hintergrund. Wer hier einen Namen vergibt, vergibt ihn für das ganze
   Stylesheet. */
.laeuft { opacity: 0; color: var(--leise); font-size: var(--s-zusatz); align-self: center;
  transition: opacity .12s; }
.htmx-request .laeuft, .htmx-request.laeuft { opacity: 1; }

/* --------------------------------------------------------------------------
   Karten, Kacheln, Tabellen
   -------------------------------------------------------------------------- */
.karte { background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--rund-karte); overflow: hidden; box-shadow: var(--schatten); }
.karte.polster { padding: var(--r5); }
/* Das overflow:hidden hält die Tabelle in den runden Ecken — es schnitt aber
   auch ab, was nicht mehr hineinpasste: In der Warteschlange fehlten bei
   900 px Fensterbreite die letzten 48 px der Zeile, also der Knopf am Ende,
   und nichts wies darauf hin. Wandern ist besser als verschwinden. */
.karte:has(> table) { overflow-x: auto; }

.kacheln { display: grid; grid-template-columns: repeat(auto-fit,minmax(200px,1fr));
  gap: var(--r3); margin-bottom: var(--r5); }
.kachel { background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--rund-karte); padding: var(--r5);
  box-shadow: var(--schatten); }
.kachel .titel { color: var(--leise); font-size: var(--s-klein); font-weight: 620;
  text-transform: uppercase; letter-spacing: .06em; }
.kachel .wert { font-size: var(--s-zahl); font-weight: 650; letter-spacing: -.03em;
  margin-top: var(--r1); font-variant-numeric: tabular-nums; }
.kachel .zusatz { margin-top: var(--r1); }
/* Eine anklickbare Kachel ist eine Fläche, kein Verweis im Fließtext: Sie
   trägt Beschriftung, Zahl und Zusatz übereinander, und die alle zu
   unterstreichen sähe aus wie ein Fehler. Der Zeiger und der Rand im Akzent
   sagen deutlich genug, dass hier etwas passiert; der Zusatz nennt das Ziel.
   Die Ausnahme steht unten bei den Verweisen mit — sonst gewönne ``a:hover``
   nach Reihenfolge. */
a.kachel { display: block; text-decoration: none; color: inherit; }
a.kachel:hover { border-color: var(--akzent); }
a.kachel:hover .zusatz { color: var(--akzent); }
/* Die eine Kachel, die keine Auskunft ist, sondern eine Aufgabe: der
   Rückstand. Gefärbt wird die Zahl und nicht die Fläche — eine rote Kachel
   zwischen vier ruhigen liest sich als Störung der Anwendung und nicht als
   Zustand des Geschäfts. Sie steht ohnehin nur da, wenn es etwas zu tun gibt. */
.kachel.warnend .wert { color: var(--rot); }

table { width: 100%; border-collapse: collapse; }
th {
  text-align: left; font-size: var(--s-klein); font-weight: 620; letter-spacing: .02em;
  color: var(--leise); padding: var(--r3) var(--r4);
  border-bottom: 1px solid var(--linie); background: var(--karte);
}
td { padding: var(--r3) var(--r4); border-bottom: 1px solid var(--linie-zart);
  font-size: var(--s-text); }
tr:last-child td { border-bottom: 0; }
tbody tr:hover td { background: var(--grund); }
tr[data-ziel], tr[data-absenden] { cursor: pointer; }
tr[data-ziel]:focus-within td, tr[data-absenden]:focus-within td { background: var(--grund); }

/* Eine anklickbare Zeile sieht überall gleich aus.
 *
 * Beide Arten — ``data-ziel`` führt zu einem Datensatz, ``data-absenden``
 * schickt das Formular in der Zeile ab — sind für den Benutzer dasselbe: Man
 * tippt die Zeile an, und es geschieht etwas. Also dasselbe Hervorheben.
 * Vorher hoben sich die einen in Holzton und die anderen in Grau, weil die
 * Regel für die eine Art geschrieben und für die andere vergessen wurde.
 *
 * **Ohne Marke am Zeilenanfang.** Dort stand ein Chevron („›"). Es ist das
 * Zeichen, mit dem überall sonst etwas *aufgeklappt* wird, und genau so wurde
 * es gelesen — als Versprechen auf Ausklappen, das keine dieser Zeilen
 * einlöst. Dass die Zeile anklickbar ist, sagt der Zeiger und die Tönung beim
 * Überfahren; auf dem iPad, wo es kein Überfahren gibt, sagt es das Antippen.
 * Der Verweis in der ersten Zelle bleibt ohnehin stehen — für Tastatur und
 * Bildschirmleser. */
tbody tr[data-ziel]:hover td, tbody tr[data-absenden]:hover td {
  background: var(--akzent-hell); }
/* Auf dem iPad gibt es kein Überfahren — dort zählt der Moment des Antippens. */
tr[data-ziel]:active td, tr[data-absenden]:active td { background: var(--akzent-hell); }

/* Wohin die Zeile führt, wenn das nicht aus ihr selbst hervorgeht — „Mandat
   erfassen" auf einer Zahlungszeile, die zum Kunden springt. Als ruhiger Text
   und nicht als Knopf: Ein Knopf neben einer anklickbaren Zeile ist das
   zweite Angebot für dieselbe Sache, das hier gerade abgeschafft wurde. */
.zeilenziel { color: var(--leise); font-size: var(--s-zusatz); white-space: nowrap; }
tr:hover .zeilenziel { color: var(--akzent); }

/* Sortierbare Spaltenköpfe. */
th.sortierbar { padding: 0; }
th.sortierbar a {
  display: flex; align-items: center; gap: var(--r-symbol); justify-content: inherit;
  padding: var(--r3) var(--r4); color: inherit; text-decoration: none;
  font: inherit; white-space: nowrap;
}
th.sortierbar.zahl a { justify-content: flex-end; }
th.sortierbar a:hover { color: var(--text); background: var(--grund); }
th.sortierbar .pfeil { opacity: 0; font-size: var(--s-klein); }
th.sortierbar a:hover .pfeil { opacity: .45; }
th.sortierbar.an a { color: var(--text); }
th.sortierbar.an .pfeil { opacity: 1; color: var(--akzent); }
/* Ein Betrag bricht nicht um. „2.400,00" in einer Zeile und „€" in der
   nächsten liest sich wie zwei Zahlen. */
td.zahl, th.zahl { text-align: right; font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.inv { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--s-zusatz); }
/* Inventarnummern sind kurz, Idempotenzschlüssel nicht: „rechnung:1042:versand"
   enthält keine Stelle, an der ein Browser von sich aus umbricht, und schob
   die Warteschlange am Telefon 103 px über den Rand. Nur dieser Schlüssel
   darf überall umbrechen — er wird gelesen, nicht abgeschrieben. Eine
   Vertragsnummer darf es nicht: „D2024/“ am Zeilenende wäre eine andere. */
.zusatz.inv { overflow-wrap: anywhere; }

.marke-status { display: inline-block; padding: var(--r1) var(--r2);
  border-radius: 999px; font-size: var(--s-klein); font-weight: 600; white-space: nowrap;
  line-height: 1.15; }
.verliehen { background: var(--unterwegs-hell); color: var(--unterwegs); }
.verfuegbar { background: var(--gut-hell); color: var(--gut); }
.offen { background: var(--warn-hell); color: var(--warn); }

/* Der Auslastungsbalken auf der Übersicht.
 *
 * Er sah aus, als sei er kaputt: acht Zeilen, acht gleich lange braune
 * Striche. Zwei Gründe, und beide standen so seit der ersten Fassung.
 *
 * **Die Spur war unsichtbar.** ``--linie-zart`` (#f1eeec) auf einer weißen
 * Karte, sechs Pixel hoch — der ungefüllte Teil verschwand, und damit fehlte
 * dem Auge der Bezug, an dem sich eine Länge überhaupt ablesen lässt. Ohne
 * ihn ist jeder Balken nur ein Strich. Jetzt ``--linie`` und acht Pixel.
 *
 * **Die Spur war zu kurz.** Neunzig Pixel für hundert Prozent, und die Werte
 * liegen alle zwischen 63 % und 80 % — das sind fünfzehn Pixel Unterschied
 * über die ganze Tabelle. Sie wächst jetzt mit der Spalte; bei achtzig Prozent
 * Kartenbreite sind es gut zweihundert Pixel und damit ein sichtbarer
 * Abstand zwischen 63 % und 80 %. Nach oben begrenzt, damit die Spur auf
 * einem breiten Bildschirm nicht die halbe Zeile einnimmt. */
.balken { height: 8px; background: var(--linie); border-radius: 4px;
  overflow: hidden; min-width: 90px; flex: 1 1 auto; max-width: 240px; }
.balken i { display: block; height: 100%; background: var(--akzent);
  border-radius: 4px; }
.mit-balken { display: flex; align-items: center; gap: var(--r2); }
.mit-balken .zahl { flex: 0 0 auto; font-variant-numeric: tabular-nums; }

.hinweis { background: var(--warn-hell); border: 1px solid var(--warn-rand);
  border-radius: var(--rund-karte); padding: var(--r3) var(--r4);
  margin-bottom: var(--r5); font-size: var(--s-text); }
.hinweis.gut { background: var(--gut-hell); border-color: var(--gut-rand); color: var(--gut); }
.hinweis.fehler { background: var(--rot-hell-flaeche); border-color: var(--rot-rand); color: var(--rot); }
.leer { padding: var(--r6) var(--r5); text-align: center; color: var(--leise);
  display: grid; justify-items: center; gap: var(--r3); }
.leer a { margin-left: 0; }

.blaettern { display: flex; gap: var(--r2); align-items: center; justify-content: center;
  margin-top: var(--r4); color: var(--leise); font-size: var(--s-fein); }
.blaettern a { color: var(--text); text-decoration: none;
  padding: var(--r2) var(--r3); border: 1px solid var(--linie);
  border-radius: var(--rund); background: var(--karte); }
.blaettern a:hover { background: var(--grund); }

.nur-lesbar { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; }
.anzahl { font-size: var(--s-klein); font-weight: 620; color: var(--leise);
  background: var(--grund); padding: var(--r1) var(--r2); border-radius: 999px;
  margin-left: var(--r2); border: 1px solid var(--linie-zart); }
h2 .anzahl { position: relative; top: -2px; }
a { color: var(--akzent); }
a:hover { text-decoration: underline; }
nav a, .knopf, .knopf-leise, .marke-status, .blaettern a,
a.kachel, a.kachel:hover { text-decoration: none; }

/* Reiter halten selbst nach beiden Seiten Abstand. Nur ein unterer Rand
   ließ die Filter am Kommentarformular kleben: Die Kartenregel kennt keine
   Bedienleisten, und eine weitere Liste von Nachbarpaaren vergisst den
   nächsten Fall wieder. Der Abstand gehört deshalb zur Leiste selbst. */
.reiter { display: flex; flex-wrap: wrap; gap: var(--r2); margin: var(--r4) 0; }
.reiter a {
  display: inline-flex; align-items: center; gap: var(--r-symbol);
  padding: var(--r2) var(--r3); border: 1px solid var(--linie); border-radius: 999px;
  background: var(--karte); font-size: var(--s-fein); font-weight: 600;
  text-decoration: none; color: var(--text);
}
.reiter a:hover { background: var(--grund); }
.reiter a.aktiv { background: var(--akzent); border-color: var(--akzent); color: #fff; }
.reiter a .anzahl { background: transparent; border: 0; color: inherit;
  opacity: .75; padding: 0; margin-left: var(--r1); }

.marke-zahl { display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; margin-left: auto; padding: 0 var(--r1);
  border-radius: 999px; background: var(--rot); color: #fff;
  font-size: var(--s-klein); font-weight: 650; }

/* Bedienelemente in Tabellenzellen sind kompakt. Sonst addiert sich ihre Höhe
   auf die Zellenpolsterung: Eine Zeile mit „Tauschen" wird 64 px hoch, die
   Zeile darüber ist 46 px — die Tabelle bekommt einen Rhythmus, den nichts im
   Inhalt rechtfertigt. Auf Zeigegeräten ohne Maus hebt der Block darunter das
   wieder auf; dort geht die Trefferfläche vor.  */
td button, td .knopf, td .knopf-leise, td .knopf-weg, td .knopf.still {
  min-height: var(--hoehe-knapp); padding: var(--r1) var(--r3); font-size: var(--s-fein);
}

/* --------------------------------------------------------------------------
   Touch: auf Zeigegeräten ohne Maus alles auf 44 px
   -------------------------------------------------------------------------- */
@media (pointer: coarse) {
  /* Beide Stufen auf 44 px — die Aufzählung von vorher hatte zwei Elemente
     vergessen, und niemand sah es, weil sie am Bürorechner richtig aussahen.
     Eine Variable kann man nicht vergessen. */
  :root { --hoehe-bedien: 44px; --hoehe-knapp: 44px; }
  /* Was seine Höhe nicht aus der Variablen zieht, hier einzeln — Eingabefelder
     und die Navigation bringen ihre eigene mit. */
  .seitenleiste nav a { min-height: 44px; display: flex; align-items: center; }
  input:not([type=checkbox]):not([type=radio]), select, textarea { min-height: 44px; }
  .knopf.still, button.still { padding: var(--r2) var(--r3); }
  form.suche { --h: 44px; }
  /* Am iPad gibt es kein Überfahren. Eine sortierbare Spalte war dort von
     einer festen nicht zu unterscheiden — der einzige Hinweis stand in
     ``:hover``, und den bekommt ein Finger nie zu sehen. Der Pfeil steht
     deshalb dauerhaft da, blass genug, um die Überschrift nicht zu stören.

     Hier und nicht in einem zweiten ``(pointer: coarse)``-Block: Die
     Touch-Regel steht an genau einer Stelle, und ein Test wacht darüber. */
  th.sortierbar .pfeil { opacity: .35; }
}

/* --------------------------------------------------------------------------
   Tablett: dieselbe Seitenleiste bei Bedarf über dem Inhalt
   --------------------------------------------------------------------------
   Die umgebrochene Kopfzeile nahm im Hochformat mehrere Reihen ein, bevor
   der erste Treffer kam. Seit dem mit Johann abgestimmten Entwurf vom
   19.10.2026 bleibt oben nur Menü, Seitenname und Neuer Vertrag. Die Leiste
   überlagert den Vorgang: Öffnen darf weder Felder verschieben noch eine
   schon gezeichnete Unterschrift durch einen Seitenwechsel verlieren.

   Wie am Telefon schaltet ein natives details die vorhandene Leiste frei.
   Damit bleiben alle Ziele auch ohne Skript erreichbar; der Menüschalter
   schließt dann wieder. Unter 761 px bzw. bei einem flachen Touchschirm
   gehört die Leiste weiterhin dem Telefonmenü. Beim Schließen nimmt sie
   sofort keine Tipps mehr an: Sonst trifft ein schneller Tipp nach dem
   Drehen noch die hinausfahrende Marke statt den Menüschalter darunter. */
@media (min-width: 761px) and (min-height: 501px) and (max-width: 960px) {
  .huelle { flex-direction: column; }
  .tablett-kopf {
    display: flex; align-items: center; gap: var(--r5);
    padding: var(--r3) var(--r5); min-height: calc(var(--hoehe-bedien) + 2 * var(--r3));
    background: var(--karte); border-bottom: 1px solid var(--linie);
  }
  .tablett-menue { height: var(--hoehe-bedien); }
  .tablett-menue summary {
    display: flex; align-items: center; gap: var(--r2);
    height: var(--hoehe-bedien); padding: 0; cursor: pointer;
    list-style: none;
  }
  .tablett-menue summary::-webkit-details-marker { display: none; }
  .tablett-menue .menue-auf { display: inline-flex; align-items: center; gap: var(--r2); }
  .tablett-menue .menue-zu { display: none; }
  /* Derselbe native Schalter wird zum Schließen-Knopf im Blatt. Ein eigener
     Skriptknopf ließe das Menü ohne formular.js offen und unerreichbar. */
  .tablett-menue[open] summary {
    position: fixed; top: calc(var(--r5) + env(safe-area-inset-top, 0px));
    left: calc(288px - var(--r4) - var(--hoehe-bedien)); z-index: 46;
    width: var(--hoehe-bedien); height: var(--hoehe-bedien);
    justify-content: center; padding: 0; border-radius: var(--rund);
    background: var(--karte);
  }
  .tablett-menue[open] .menue-auf,
  .tablett-menue[open] .marke-zahl { display: none; }
  .tablett-menue[open] .menue-zu { display: inline-flex; }
  .tablett-seite {
    flex: 1 1 auto; min-width: 0; color: var(--leise);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .tablett-kopf > .knopf { flex: 0 0 auto; display: inline-flex;
    align-items: center; gap: var(--r2); }
  .seitenleiste {
    position: fixed; top: 0; bottom: 0; left: 0; z-index: 45;
    width: 288px; max-width: 85vw; height: 100dvh;
    padding-top: calc(var(--r5) + env(safe-area-inset-top, 0px));
    padding-bottom: calc(var(--r5) + env(safe-area-inset-bottom, 0px));
    transform: translateX(-105%); visibility: hidden; pointer-events: none;
    transition: transform .22s ease, visibility .22s ease;
    box-shadow: 8px 0 28px rgba(38,37,36,.18);
    overscroll-behavior: contain;
  }
  .huelle:has(.tablett-menue[open]) .seitenleiste {
    transform: none; visibility: visible; pointer-events: auto;
  }
  .huelle:has(.tablett-menue[open])::before {
    content: ""; position: fixed; inset: 0; z-index: 44;
    background: rgba(38,37,36,.45);
  }
  html:has(.tablett-menue[open]) { overflow: hidden; }
  .seitenleiste .marke { padding-right: var(--hoehe-bedien); }
  main { padding: var(--r6) var(--r5) var(--r7); }
}

/* --------------------------------------------------------------------------
   Telefon: Inhalt von oben, Menü am unteren Rand
   --------------------------------------------------------------------------
   Das Telefon ist nicht der Tresen — dort steht das iPad. Es ist das Gerät
   für unterwegs: nachsehen, ob ein Bogen frei ist, während man im Laden
   steht; nachschauen, wer im Rückstand ist, bevor man zurückruft. Dafür
   zählt, wie schnell der erste Inhalt kommt und wie wenig man dafür greifen
   muss.

   Vorher war die Kopfzeile des Tabletts auch hier im Einsatz, nur enger:
   elf Verweise, fünf umgebrochene Reihen, 273 der 852 Punkte belegt, bevor
   die Überschrift der Seite kam. Ohne Gruppenüberschriften — die sind in
   der Reihe ausgeblendet — stand die tägliche Arbeit neben der Anschrift
   der Werkstatt, und das Ganze klebte nicht, war also aus einer langen
   Liste heraus nur über den Weg nach ganz oben zu erreichen.

   Stattdessen: vier Ziele und „Mehr" auf einer Leiste am unteren Rand, wo
   der Daumen hinreicht, und das vollständige Menü als Blatt darüber. Die
   Leiste ist die **Seitenleiste selbst** — dieselben Einträge, dieselben
   Gruppen, dieselben Zähler; sie liegt hier nur unten statt links und
   fährt auf Tipp herein. Ein zweites Menü zu schreiben hieße, es bei jeder
   neuen Seite zweimal zu pflegen, und die zweite Fassung ist die, die man
   vergisst.

   Geschaltet wird über ``details.mehr`` in der Leiste: ein Schalter, den
   der Browser selbst umlegt. Das Blatt hängt damit **nicht** an JavaScript
   — das Skript schließt es nur, wenn daneben getippt wird.

   Die zweite Bedingung ist das Telefon im Querformat: 852 px breit, aber
   nur 393 px hoch. Nach der Breite allein bekäme es die Kopfzeile des
   Tabletts, und die belegte dort 205 der 393 Punkte. ``pointer: coarse``
   hält Bürofenster heraus, die jemand flach gezogen hat — mit Maus ist
   eine Leiste in Daumenreichweite eine Leiste im Weg.                  */
@media (max-width: 760px), (max-height: 500px) and (pointer: coarse) {
  /* Die Höhe der Leiste steht an einer Stelle: Sie trägt sich selbst, hält
     das Blatt darüber auf Abstand und ist der Platz, den der Inhalt unten
     frei lassen muss. Drei Zahlen wären zwei Gelegenheiten, dass die letzte
     Zeile einer Liste unter der Leiste verschwindet. */
  :root { --daumen: 60px; }

  .daumenleiste {
    display: flex; align-items: stretch;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    min-height: var(--daumen);
    /* Die Fläche reicht bis an jede Blattkante, die Kacheln nicht: Quer
       gehalten liegt links oder rechts die Kamerainsel, und „Übersicht"
       stünde zur Hälfte darunter. Die Einzüge sitzen deshalb an der Leiste
       und nicht an ihrem Rand — ein fest gesetzter Kasten weiß vom Polster
       am ``body`` nichts. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
    border-top: 1px solid var(--linie);
    /* Zwei Zeilen für einen Hintergrund: Die erste deckt, die zweite macht
       ihn durchscheinend. Ein Browser, der ``color-mix`` nicht kennt,
       behält die erste — und eine halbdurchsichtige Leiste ohne Unschärfe
       dahinter wäre schlechter als eine deckende. */
    background: var(--karte);
    background: color-mix(in srgb, var(--karte) 90%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
    backdrop-filter: saturate(180%) blur(18px);
  }
  /* Zeichen über Wort, mittig, in einer Kachel — für den Verweis wie für
     den Schalter „Mehr". */
  .daumenleiste a, .daumenleiste summary {
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: var(--r1);
    /* Seitlich **kein** Polster: Es käme zur Grundbreite 0 hinzu und machte
       jede Kachel um seine Breite breiter als die, die keines hat — die
       vier Verweise standen dadurch auf 80 px, der Schalter „Mehr" auf 72.
       Den Abstand zur Nachbarin hält die Beschriftung selbst (weiter
       unten), und die ist das einzige, was hier breit werden kann. */
    position: relative; padding: var(--r2) 0;
    min-height: var(--hoehe-bedien);
    color: var(--leise); font-size: var(--s-klein); font-weight: 600;
    line-height: 1.2;
    text-decoration: none; cursor: pointer;
    /* Ohne das blitzt beim Tippen ein graues Rechteck über die ganze
       Kachel — die Rückmeldung gibt eine Zeile tiefer ``:active``. */
    -webkit-tap-highlight-color: transparent;
    list-style: none;
  }
  /* Fünf gleich breite Kacheln über ``flex-basis: 0``. Mit ``auto`` teilt
     sich nur der *übrige* Platz gleichmäßig auf, die Grundbreite bleibt die
     des Wortes: „Übersicht" bekam so 97 px und „Mehr" 32 — die letzte
     Kachel stand halb jenseits des Randes, mitsamt ihrem Zähler.

     Und zwar **nach** der Regel darüber: Beide wiegen gleich schwer
     (0-1-1), also gewinnt die spätere. Stand sie davor, setzte die Kachel
     ihre Breite gleich wieder auf den Wortbedarf zurück — genau so ist der
     abgeschnittene Rand entstanden. */
  .daumenleiste > a, .daumenleiste > .mehr { flex: 1 1 0; min-width: 0; }
  .daumenleiste > .mehr { display: flex; }
  .daumenleiste summary { flex: 1 1 auto; }
  .daumenleiste summary::-webkit-details-marker { display: none; }
  .daumenleiste a:active, .daumenleiste summary:active { background: var(--akzent-hell); }
  .daumenleiste .aktiv { color: var(--akzent); }
  /* Die Beschriftung hält den Abstand zur Nachbarkachel und kürzt sich
     notfalls selbst — „Lastschrifteinzug" stünde sonst quer über drei. */
  .daumenleiste span:not(.marke-zahl) { max-width: calc(100% - var(--r3));
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .daumenleiste svg { width: 24px; height: 24px; flex: 0 0 auto;
    fill: none; stroke: currentColor; stroke-width: 1.6;
    stroke-linecap: round; stroke-linejoin: round; }
  /* Der Zähler sitzt am Zeichen und nicht hinter der Beschriftung: In einer
     65 px breiten Kachel schöbe er „Mehr" aus der Mitte. ``margin-left:
     auto`` aus der Grundregel muss dafür weg — in einer Spalte drückt es
     ihn nach unten statt nach rechts. */
  .daumenleiste .marke-zahl { position: absolute; top: var(--r1); left: 50%;
    margin-left: var(--r2); }

  /* Die Seitenleiste ist hier das Blatt hinter „Mehr“. Aus dem Fluss
     genommen, sonst bliebe an ihrer Stelle eine Lücke über dem Inhalt. */
  .seitenleiste {
    /* ``top: auto`` ist keine Zierde: Die Grundregel setzt ``top: 0`` für
       die klebende Leiste am Bürorechner. Bliebe es stehen, wäre der Kasten
       oben *und* unten angeschlagen — dann gewinnt ``top``, und das Blatt
       hinge von der Oberkante herab statt vom unteren Rand. */
    position: fixed; left: 0; right: 0; top: auto; z-index: 30;
    bottom: calc(var(--daumen) + env(safe-area-inset-bottom, 0px));
    /* Hoch genug, dass Tresen und Büro zusammen dastehen — darunter beginnt
       das Blatt mit einer Liste, die schon beim Aufklappen abgeschnitten
       ist, und man scrollt in einem Menü, statt es zu lesen. Die letzten
       beiden Zeilen (Einrichtung, Abmelden) dürfen dabei unter die Kante
       rutschen: Sie sind genau das, wofür man scrollen darf. */
    width: auto; height: auto; max-height: 80vh; overflow-y: auto;
    padding: var(--r4) calc(var(--r4) + env(safe-area-inset-right, 0px))
      var(--r5) calc(var(--r4) + env(safe-area-inset-left, 0px));
    gap: var(--r4);
    border-right: 0; border-top: 1px solid var(--linie);
    border-radius: var(--rund-karte) var(--rund-karte) 0 0;
    box-shadow: 0 -8px 28px rgba(38,37,36,.18);
    /* Geschlossen steht es unter der Leiste, nicht bloß durchsichtig:
       Ein durchsichtiges Blatt fängt weiterhin jeden Tipp ab, und der
       Inhalt darunter wäre nicht mehr zu bedienen. */
    transform: translateY(105%); visibility: hidden; pointer-events: none;
    transition: transform .22s ease, visibility .22s ease;
  }
  .huelle:has(.mehr[open]) .seitenleiste {
    transform: none; visibility: visible; pointer-events: auto;
  }
  /* Der Schleier über dem Inhalt. Er sagt, dass das Blatt jetzt dran ist,
     und ist zugleich die Fläche, die es schließt — ``formular.js`` hört auf
     den Tipp daneben. */
  .huelle:has(.mehr[open])::before {
    content: ""; position: fixed; inset: 0; z-index: 25;
    background: rgba(38,37,36,.45);
  }
  /* Sonst scrollt hinter dem offenen Blatt die Seite mit, und nach dem
     Schließen steht man woanders als vorher. */
  html:has(.mehr[open]) { overflow: hidden; }

  /* Unten so viel Luft, wie die Leiste hoch ist: Ohne sie liegt die letzte
     Zeile jeder Liste dahinter — und das ist am Telefon die Zeile, für die
     gescrollt wurde. Die Regel steht hier und nicht bei den übrigen
     Telefonmaßen weiter unten, weil sie zur Leiste gehört: Wer sie ändert,
     ändert sie zusammen mit ihr. */
  main { padding: var(--r4) var(--r3)
    calc(var(--daumen) + var(--r6) + env(safe-area-inset-bottom, 0px)); }
}

/* Wer „Bewegung reduzieren“ eingestellt hat, bekommt das Blatt ohne Fahrt —
   sichtbar wird es trotzdem, die Regel nimmt nur den Weg dorthin. */
@media (prefers-reduced-motion: reduce) {
  .seitenleiste { transition: none; }
}

@media (max-width: 760px) {
  h1 { font-size: var(--s-kopf); }
  h2 { font-size: var(--s-titel); margin-top: var(--r5); }
  .kachel { padding: var(--r3) var(--r4); }
  .kachel .wert { font-size: var(--s-kopf); }
  form.suche { padding: var(--r2); }
  form.suche input[type=search] { flex: 1 1 100%; }
  form.suche select { flex: 1 1 calc(50% - 4px); }
  /* Die Filtergruppe war „flex: 0 0 auto" — sie hätte auch dann nicht
     nachgegeben, wenn ihre fünf Auswahlfelder es täten. Auf dem Inventar
     stand sie deshalb 338 px jenseits des Bildschirmrandes und schob die
     ganze Seite seitwärts; die Regel darüber lief ins Leere, weil 50 % sich
     auf eine Gruppe bezogen, die selbst zu breit war. Hier bekommt sie eine
     eigene Zeile, in der die Felder paarweise umbrechen dürfen. */
  form.suche .filter { flex: 1 1 100%; min-width: 0; margin-left: 0; }

  /* Auf schmalen Schirmen ist jede Zeile eine Karte. Die Hülle darum darf
     dann keine zweite zeichnen — sonst sitzt ein Rahmen im Rahmen, mit zwei
     Radien und zwei Schatten. */
  .karte { border: 0; background: transparent; box-shadow: none;
    border-radius: 0; overflow: visible; }
  .karte.polster { border: 1px solid var(--linie); background: var(--karte);
    border-radius: var(--rund-karte); }
  /* Die Auswahl im Entwurf ebenso: Die Hülle fällt weg, also braucht das
     Suchfeld seinen Rahmen zurück — sonst steht es als weißer Streifen ohne
     Kante über den Trefferkarten. */
  .karte.auswahl > form.suche,
  .karte.auswahl:has(#treffer > *, #kundentreffer > *) > form.suche { border: 1px solid var(--linie);
    border-radius: var(--rund-karte); margin-bottom: var(--r3); }
  .auswahl-titel { padding-left: 0; padding-right: 0; }
  /* tfoot gehörte nicht dazu und blieb als Tabellenfuß stehen, während die
     Tabelle darüber ein Block wurde: Die Summenzeile des Vertrags stand
     danach als halbbreiter Kasten mit zwei losen Strichen links unter den
     Karten, statt selbst eine zu sein. */
  table, tbody, tfoot, tr, td { display: block; width: 100%; }
  thead { display: none; }
  tr { border: 1px solid var(--linie); border-radius: var(--rund-karte);
    margin: 0 0 var(--r2); padding: var(--r3); background: var(--karte); }
  tbody tr:hover td { background: transparent; }
  /* Eine leere Zelle ist in der Tabelle eine Lücke in der Spalte, in der
     Karte eine leere Zeile mit Polsterung ringsum. */
  td:empty { display: none; }
  td { display: flex; justify-content: space-between; align-items: baseline;
    gap: var(--r3); padding: var(--r1) 0; border: 0; text-align: right; }
  td::before { content: attr(data-label); font-size: var(--s-klein); text-transform: uppercase;
    letter-spacing: .04em; color: var(--leise); font-weight: 620;
    text-align: left; flex: 0 0 auto; }
  td[data-label="Bezeichnung"], td[data-label="Wert"] { display: none; }
  td[data-label="Instrument"] { font-size: var(--s-hervor); padding-bottom: var(--r1);
    justify-content: flex-start; text-align: left; }
  td[data-label="Instrument"]::before { display: none; }
  td[data-label="Inv.-Nr."] { order: -1; }
  /* Ein Zusatz ist die zweite Zeile eines Wertes, keine dritte Spalte. Als
     Flex-Element neben Beschriftung und Wert blieben ihm auf dem Vertrag
     74 px, und sein Text stand jenseits der Zellenkante; der
     Idempotenzschlüssel der Warteschlange brach dreimal mitten im Wort um.
     Eigene Zeile, ausgerichtet wie der Wert, zu dem er gehört. */
  td:has(> .zusatz) { flex-wrap: wrap; }
  td > .zusatz { flex: 1 1 100%; }
  .mit-balken { justify-content: flex-end; }
  .balken { min-width: 60px; }
  .blaettern a { flex: 1; justify-content: center; }
}

@media (prefers-color-scheme: dark) {

  /* Ein Logo ist für Papier gemacht: dunkle Tinte auf Weiß, mit
     durchsichtigem Grund. Auf dunklem Grund bliebe von „LIEBERWIRTH" in
     Schwarz nichts übrig. Also bekommt es hier sein Blatt mit — schmal
     umrandet, damit es nicht wie ein Fehldruck aussieht. */
  .marke img { background: #fff; padding: var(--r2); border-radius: var(--rund); }

  /* Dieselbe Palette, umgedreht. Grund und Karte verlieren den Braunstich
     mit — sie waren die dunkle Seite von #26221e, und der ist oben weg.
     Das Rot der Website ist hier nicht zu gebrauchen: #ae213a auf einem
     dunklen Grund kommt auf 2,0 und ist als Text nicht mehr zu lesen.
     Aufgehellt bleibt es dieselbe Farbe (Ton 349°) und kommt auf 5,7. */
  :root {
    --grund: #141312; --karte: #1c1b1a; --linie: #302e2c; --linie-zart: #252423;
    --text: #efedeb; --leise: #a09d9a; --akzent: #e07386; --akzent-tief: #f0a0ac;
    --akzent-hell: #33292b; --gut: #7fc79b; --gut-hell: #1e3327;
  --rot-hell: #3a201d;
  --ruhe: #a29b91; --ruhe-hell: #2a2724;
  --info: #adc4e6; --info-hell: #26303f;
  --werkstatt: #e2c48d; --werkstatt-hell: #3b3020;
  --unterwegs: #d99b6c; --unterwegs-hell: #3a2a1d;
    --warn: #e0b05a; --warn-hell: #37301c; --rot: #e08b80;
    /* Die Rahmen als Token, wie im Hellmodus. Der Warnrahmen fehlte hier ganz
       und blieb deshalb auf #f0dcb8 stehen — ein heller Rand um eine dunkle
       Fläche, der aussah, als sei die Karte noch am Laden. */
    --warn-rand: #4a4028; --gut-rand: #2f5540; --rot-rand: #5c2f29;
    --rot-hell-flaeche: #3a201d;
    /* Der Hellmodus musste ``--leiser`` und ``--ruhe`` anheben, um AA zu
       halten. Hier gilt das Gegenteil: Auf dunklem Grund tragen die hellen
       Töne, und der Kommentar oben rechnet sie vor. */
    --leiser: #8b8885;
    --schatten: none;
  }
  th { background: var(--karte); }
  .marke-zahl { background: #8d2f26; color: #fff; }
  .reiter a.aktiv { color: #1c1b1a; }
  .knopf.haupt, button[type=submit].haupt,
  .formular > button[type=submit]:not(.leise) { color: #1c1b1a; }
}

/* --- Detailansichten und Formulare ------------------------------------- */
.zurueck { margin: 0 0 var(--r3); }
.zurueck a { color: var(--leise); text-decoration: none; font-size: var(--s-fein); }
.zurueck a:hover { color: var(--akzent); }

.spalten { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: var(--r5); align-items: start; }
.spalten section > h2:first-child { margin-top: 0; }

/* Karten füllen die Seite. Alle, überall, ohne Ausnahme.
 *
 * Vorher trug die Karte die lesbare Breite: ein Formular 860 px, eine
 * gepolsterte Karte 900 px, eine Karte um eine Tabelle gar keine Grenze —
 * dazu drei Ausnahmen für die Stellen, an denen das störte. Jede Regel für
 * sich begründet, zusammen standen auf einer Seite drei verschiedene
 * Kartenbreiten übereinander, und keine sah aus, als sei sie gemeint.
 *
 * Der Denkfehler war die Zuständigkeit. Eine Karte ist ein Behälter und folgt
 * der Seite. Das Maß schuldet der **Inhalt**: ein Eingabefeld, das über die
 * ganze Breite läuft, ist unbrauchbar — eine Tabelle, die es nicht tut,
 * verschenkt Platz. Deshalb steht die Grenze ab hier an der Formularzeile und
 * nirgends sonst. */
.formular { background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--rund-karte); padding: var(--r5); display: grid;
  gap: var(--r4); }
.karte.polster .formular { border: 0; padding: 0; background: transparent; box-shadow: none; }
/* Trägt eine Karte die Formularzeilen selbst, statt sie einem Formular darin
   zu überlassen, dann ist sie der Stapel und schuldet den Abstand. Ohne diese
   Regel lag auf der Werkstattseite jede Zeile ohne einen Pixel Luft auf der
   vorigen: die Beschriftung der einen klebte am Feld der anderen, zehnmal
   hintereinander. Die Ränder der Einzelteile werden dabei ausgeräumt — im
   Raster addieren sie sich sonst zum Abstand, und derselbe Zwischenraum
   fiele je nach Nachbar verschieden aus. */
.karte.polster:has(> .feld, > .feld-paar, > fieldset.stueck, > label.wahl) {
  display: grid; gap: var(--r4); align-content: start;
}
.karte.polster:has(> .feld, > .feld-paar, > fieldset.stueck, > label.wahl) > * {
  margin-block: 0;
}
/* Die Karte polstert schon. Ein erstes Kind mit eigenem Rand oben addiert
   sich darauf, und die Karte sieht oben weiter aus als unten. */
.karte.polster > :first-child { margin-top: 0; }
.karte.polster > :last-child { margin-bottom: 0; }
/* Das Maß einer beschrifteten Zeile — vererbt, nicht aufgezählt.
 *
 * Der erste Versuch listete die Elternkontexte auf: ``.formular > .feld``,
 * ``.karte.polster > .feld``, und für jede Verschachtelung eine Zeile mehr.
 * Das ist dieselbe Sonderbehandlung wie vorher, nur an einer anderen Stelle —
 * der nächste Behälter hätte wieder gefehlt.
 *
 * Stattdessen setzt der Behälter eine Variable, und die Zeile liest sie.
 * Eigenschaften vererben sich durch den ganzen Baum: Ein Feld findet ihren
 * Wert, gleich wie tief es liegt und in welchem Formular. Steht es außerhalb
 * eines Formulars, greift der Rückfall ``none`` — dann meint es jemand
 * ausdrücklich anders.
 *
 * Breiter wird nur, was es sagt: ``.voll``. Nicht jeder Textbereich von
 * selbst — die erste Fassung tat das, und dann lief das zweizeilige Notizfeld
 * auf der Kundenseite breiter als jede Zeile darüber und brach die rechte
 * Kante. Ein Vertragswortlaut will die ganze Breite, eine Notiz nicht. Den
 * Unterschied kennt die Vorlage, nicht das Stylesheet. */
.formular, .karte.polster { --zeilenmass: var(--mass); }
/* ``min-width: 0`` ist hier keine Vorsichtsmaßnahme, sondern die Reparatur
   eines sichtbaren Schadens. Ein Raster- oder Flex-Kind hat von sich aus
   ``min-width: auto`` und schrumpft nie unter seinen Mindestinhalt. Für die
   Feldzeile, die selbst ein Raster mit ``auto-fit`` ist, hieß das: Sie legte
   vier Spalten zu 180 px an, obwohl nur drei hineinpassten, wurde 768 px
   breit in einem 688 px breiten Formular und schob die ganze Seite zur
   Seite. Am iPad im Hochformat — dem Gerät am Tresen — stand die
   Kundenseite 41 px quer: „Firma", „Ort" und „Mobil" halb abgeschnitten,
   die Überschrift links aus dem Bild. Dieselbe Falle wie bei ``main``
   weiter oben, nur eine Ebene tiefer. */
.feld, .feld-paar { max-width: var(--zeilenmass, none); min-width: 0; }
.feld.voll, .feld-paar.voll { --zeilenmass: none; }

.feld { display: grid; gap: var(--r1); align-content: start; }
/* Felder bekommen die Breite, die ihr Inhalt braucht — nicht alle dieselbe.
   Ein Fälligkeitstag ist zweistellig, eine Straße nicht. */
.feld-paar { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr)); gap: var(--r4); }
/* Die Stufen. Vier Breiten, benannt, überall dieselben — statt einer Zahl je
   Stelle. Wer eine fünfte braucht, braucht meistens eine der vier. */
.feld.kurz { max-width: var(--breit-knapp); }
.feld.mittel { max-width: var(--breit-schmal); }
.formular button { justify-self: start; }

tr.beendet td { opacity: .55; }
tr.zusatzposten td { background: var(--grund); }
tfoot td { border-top: 2px solid var(--linie); border-bottom: 0;
  padding-top: var(--r3); padding-bottom: var(--r3); font-size: var(--s-hervor); }
/* Beide Regeln darüber sprechen von Spalten, und auf schmalen Schirmen gibt
   es keine mehr — die Zeile ist dort eine Karte. Der Nachtrag steht hier und
   nicht oben im Breitenblock: Er muss die zwei Regeln überschreiben, und die
   stehen weiter unten in der Datei als jener. */
@media (max-width: 760px) {
  /* Die Tönung gehört auf die Karte, nicht in sie: als Hintergrund der
     einzelnen Zellen ließ sie ringsum einen weißen Rand von Polsterbreite
     stehen — ein grauer Block in einer weißen Karte. */
  tr.zusatzposten { background: var(--grund); }
  tr.zusatzposten td { background: transparent; }
  /* Die 2px-Linie trennt Spalten von ihrer Summe. Als Karte hat der Fuß
     keine Spalten mehr über sich — die Linie zerfiel dort in lose Striche
     quer durch die Karte, einen je Zelle. */
  tfoot td { border-top: 0; padding-top: var(--r1); padding-bottom: var(--r1); }
}
/* Auch nach unten ein Rand: Unter dem Zitat steht auf der Vertragsseite der
   Satz, der es einordnet, und der stand 8 px darunter — näher an der
   Zitatfläche als an der eigenen Zeile darüber. Steht das Zitat am Ende
   einer Karte, räumt die Karte den Rand selbst wieder weg. */
.vertragstext {
  margin: var(--r4) 0; padding: var(--r3) var(--r4);
  border-left: 3px solid var(--akzent);
  background: var(--grund); border-radius: 0 var(--rund-karte) var(--rund-karte) 0;
  font-size: var(--s-fein);
}
.protokoll { list-style: none; margin: 0; padding: 0; }
.protokoll li { padding: var(--r3) var(--r4); border-bottom: 1px solid var(--linie-zart);
  display: grid; gap: var(--r1); }
.protokoll li:last-child { border-bottom: 0; }
.protokoll time { font-size: var(--s-klein); color: var(--leise); font-variant-numeric: tabular-nums; }
.protokoll .wer { font-size: var(--s-klein); color: var(--akzent); font-weight: 600; }
.protokoll .was { font-size: var(--s-fein); }
.protokoll li.vertragskommentar {
  border-left: 3px solid var(--akzent); background: var(--akzent-hell);
}
.protokoll .kommentartext {
  white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--s-text);
}

@media (max-width: 900px) { .spalten { grid-template-columns: 1fr; gap: var(--r6); } }

/* --- Vertragsabschluss -------------------------------------------------- */
form.inline { display: inline; margin: 0; }
form.inline button { padding: var(--r2) var(--r3); font-size: var(--s-fein); }

/* Die Trennlinie darunter gehört zur Summe, nicht zum Formular dahinter:
   12 px über der Linie, 16 px darunter — vorher waren es 8, und die Linie
   saß sichtbar näher am Formular als an dem, was sie abschließt. */
.summe { display: flex; gap: var(--r6); flex-wrap: wrap; margin-bottom: var(--r4); }
.summe .titel { display: block; font-size: var(--s-klein); text-transform: uppercase; letter-spacing: .06em; color: var(--leise); }
.summe strong { font-size: var(--s-kopf); }
.summe .gross { font-size: var(--s-zahl); color: var(--akzent); }
.summe { padding-bottom: var(--r3); border-bottom: 1px solid var(--linie-zart); }

.unterschriftfeld { display: grid; gap: var(--r2); justify-items: start; }
#feld-unterschrift {
  width: 100%; height: 200px; background: var(--karte);
  border: 2px dashed var(--linie); border-radius: var(--rund-karte);
  touch-action: none; cursor: crosshair;
}
#abschliessen:disabled { background: var(--linie); color: var(--leise); cursor: not-allowed; }

/* Die Höhe war begrenzt, die Breite nicht: Am Telefon ragte die Unterschrift
   223 px über den Bildschirmrand hinaus und schob die ganze Seite seitwärts. */
.unterschrift-anzeige { max-height: 90px; max-width: 100%; }


/* --- Anmeldung ---------------------------------------------------------- */
body.anmeldeseite { display: grid; place-items: center; min-height: 100vh; }
main.anmeldung { width: min(380px, 92vw); display: grid; gap: var(--r4); }
main.anmeldung .marke { font-size: var(--s-titel); text-align: center; }

.zweispaltig { display: grid; grid-template-columns: 1fr 1fr; gap: var(--r5); }
.zweispaltig h3 { font-size: var(--s-hervor); margin: 0 0 var(--r2); }
/* Kein eigener Rand nach unten: Der Block steht immer in einem Raster, und
   dort addierte sich sein Rand auf dessen Abstand — über dem Block lagen 16,
   darunter 28 px. Den Abstand schuldet der Stapel, nicht das Einzelteil. */
fieldset.stueck { border: 1px solid var(--linie); border-radius: var(--rund-karte);
  padding: var(--r4); margin: 0; display: grid; gap: var(--r3); }
fieldset.stueck legend { font-weight: 600; padding: 0 var(--r2); }
label.wahl { display: flex; align-items: center; gap: var(--r2); font-weight: 500;
  color: var(--text); }
label.wahl input { width: 20px; height: 20px; flex: none; }
/* Eine Wahlmöglichkeit mit Erläuterung: Der Knopf gehört an die erste Zeile,
   nicht in die Mitte des Blocks — sonst zeigt er auf nichts. */
label.wahl.mehrzeilig { align-items: flex-start; }
label.wahl.mehrzeilig > span { display: grid; gap: var(--r1); }
label.wahl.mehrzeilig .fussnote { margin: 0; font-weight: 400; }

/* Datei auswählen.
   Der eingebaute Wähler beschriftet sich selbst — „Choose File", „No file
   chosen", in der Sprache des Browsers und nicht der Seite. Ändern lässt sich
   dieser Text nicht; ersetzen schon. Läuft JavaScript, wird das Feld
   unsichtbar, bleibt aber im Tabulatorlauf und behält seinen Fokusring über
   die eigene Beschriftung. Ohne JavaScript bleibt der eingebaute Wähler
   stehen — dann ist englische Beschriftung immer noch besser als keine. */
.einlesen { display: grid; gap: var(--r4); }
.beschriftung { font-weight: 500; color: var(--text); }
.nur-js { display: none; }
html.js .nur-js { display: flex; align-items: center; gap: var(--r3);
  flex-wrap: wrap; }
/* Der Bezugsrahmen für das ausgeblendete Feld. Ohne ihn richtete es sich am
   nächsten positionierten Vorfahren aus — und der Browser scrollte beim
   Fokussieren an eine ganz andere Stelle der Seite. */
.dateiwahl { position: relative; }
html.js .dateiwahl > input[type=file] { position: absolute; width: 1px;
  height: 1px; opacity: 0; pointer-events: none; }
.dateiwahl label.knopf { margin: 0; cursor: pointer; }
.dateiwahl input[type=file]:focus-visible + .nur-js label.knopf {
  outline: 2px solid var(--akzent); outline-offset: 2px; }
.dateiname { color: var(--leise); overflow-wrap: anywhere; }
.dateiname.gewaehlt { color: var(--text); font-weight: 500; }

/* Ohne JavaScript: der eingebaute Wähler, wenigstens in der Form des Hauses. */
.einlesen input[type=file] { padding: var(--r2); cursor: pointer; }
.einlesen input[type=file]::file-selector-button {
  font: inherit; margin-right: var(--r3); padding: var(--r2) var(--r3);
  border: 1px solid var(--linie); border-radius: var(--rund);
  background: var(--grund); color: var(--text); cursor: pointer; }
.einlesen input[type=file]:hover::file-selector-button { background: var(--linie-zart); }
@media (max-width: 760px) { .zweispaltig { grid-template-columns: 1fr; gap: var(--r5); } }

/* htmx: Rückmeldung während der Suche. Ohne Anzeige wirkt eine Verzögerung
   wie ein Fehler — mit ihr wie Arbeit. */
#ergebnis, #treffer { transition: opacity .12s; }
.htmx-swapping #ergebnis { opacity: .5; }

/* Warteschlange: Zähler in der Navigation und die zwei Handgriffe je Zeile.
   Der Zähler steht nur dort, wo er stört — eine Arbeitsliste, die man
   aufsuchen muss, sieht niemand. */
/* Handgriffe in einer Tabellenzeile — Eingabefeld und Knopf nebeneinander.
 *
 * Der Flex-Behälter ist ein ``div`` **in** der Zelle und nicht die Zelle
 * selbst. Das ist der Unterschied, an dem ein sichtbarer Fehler hing: Ein
 * ``<td>`` mit ``display: flex`` ist kein Tabellenzellenkasten mehr, und die
 * Tabelle rechnet die Spaltenbreite dann ohne seinen Inhalt aus. Im Klärkorb
 * ergab das eine Zelle, die 269 px über die Karte hinausragte — als weißer
 * Kasten unten rechts, der aus der abgerundeten Ecke herauslief, weil die
 * Karte von dieser Breite nichts wusste und deshalb auch nicht scrollte.
 *
 * Die Zelle polstert ohnehin; die Handgriffe darin brauchen senkrecht
 * weniger, sonst wird die Zeile doppelt so hoch wie die daneben. */
td:has(> .taten) { padding-top: var(--r2); padding-bottom: var(--r2); }
.taten { display: flex; flex-wrap: wrap; gap: var(--r2); align-items: center; }
td .taten form.inline { display: flex; gap: var(--r2); align-items: center;
  min-width: 0; }
td .taten button { white-space: nowrap; }
/* Breit genug für einen Grund, schmal genug zum Schrumpfen. ``min-width``
   allein hielt die Spalte auf 11 rem fest, auch wenn daneben nichts mehr
   übrig war. */
td .taten input[type=text] { width: 11rem; min-width: 0; }
@media (max-width: 640px) {
  td .taten { flex-direction: column; align-items: stretch; }
  td .taten form.inline { flex-direction: column; align-items: stretch; }
  td .taten input[type=text] { width: auto; }
}



/* --------------------------------------------------------------------------
   Nachträge aus der Oberflächenprüfung
   -------------------------------------------------------------------------- */

/* Statusmarken: sieben Töne.
 *
 * Vorher stand hier für jeden Zustand eine eigene Regel — zweiunddreißig für
 * sieben Bedeutungen, weil jede Fachlichkeit ihr eigenes Präfix mitbrachte:
 * vertrag-aktiv, posten-ausgeglichen, zahlung-zugeordnet, anfrage-uebernommen.
 * Vier Namen, ein Grün.
 *
 * Welcher Zustand welchen Ton bekommt, entscheidet jetzt app.py. Das ist die
 * richtige Stelle: „Ein gekündigter Vertrag läuft noch" ist eine fachliche
 * Aussage und keine Frage der Darstellung. Hier steht nur noch, wie ein Ton
 * aussieht — und eine neue Marke braucht keine Zeile mehr. */
.marke-status.gut        { background: var(--gut-hell);       color: var(--gut); }
.marke-status.wartet     { background: var(--warn-hell);      color: var(--warn); }
.marke-status.unterwegs  { background: var(--unterwegs-hell);  color: var(--unterwegs); }
.marke-status.ruht       { background: var(--ruhe-hell);      color: var(--ruhe); }
.marke-status.stockt     { background: var(--rot-hell);       color: var(--rot); }
.marke-status.reserviert { background: var(--info-hell);      color: var(--info); }
.marke-status.werkstatt  { background: var(--werkstatt-hell); color: var(--werkstatt); }

/* Statusmarken für alle sechs Zustände, die die Datenbank kennt. Vorher gab es
   zwei, und „Werkstatt", „Reserviert", „Verkauft" und „Ausgemustert" wurden
   allesamt als „Verfügbar" angezeigt — die Liste sagte dem Kunden ein
   Instrument zu, das in der Werkstatt lag. */


/* Zweiter Faktor in der Zugangsliste: an oder aus. In der Vorlage stand
   class="marke" — eine Klasse, die es in dieser Datei nie gab. Die Spalte
   zeigte deshalb nacktes „ja"/„nein" ohne Fläche und ohne Polsterung,
   zwischen lauter Marken die einzige Stelle, die keine war. */
/* Eine Zwischenüberschrift, die auf ein Formular folgt, braucht Luft nach
   oben — sonst liest sie sich wie eine Beschriftung des Knopfes darüber. */
h3.abgesetzt { margin-top: var(--r5); padding-top: var(--r4);
  border-top: 1px solid var(--linie-zart); }

/* Die Auswahl im Entwurf: Suchfeld oben, darunter die Liste, in einer Karte.
   Das Suchfeld verliert dort seinen eigenen Rahmen und trennt sich mit einer
   Linie von der Liste. ``overflow-x``: Die Tabelle steht nicht direkt in der
   Karte, deshalb greift ``.karte:has(> table)`` hier nicht. */
.karte.auswahl { overflow-x: auto; }
.karte.auswahl > form.suche { margin: 0; border: 0; border-radius: 0;
  box-shadow: none; }
.karte.auswahl:has(#treffer > *, #kundentreffer > *) > form.suche { border-bottom: 1px solid var(--linie); }
.auswahl-titel { margin: 0; padding: var(--r3) var(--r3) var(--r2);
  font-size: var(--s-zusatz); color: var(--leise); }
.auswahl-titel strong { color: var(--text); font-weight: 600; }
.auswahl-titel.warnend { background: var(--warn-hell); }

/* Ein vereinbarter Stand — kein Formularfeld, sondern ein Satz. Was
   unterschrieben ist, soll auch so aussehen. */
.stand { margin: 0 0 var(--r3); }

/* Und der Weg, ihn zu ändern: zugeklappt, weil er die Ausnahme ist. */
details.umstellen { margin-top: var(--r5); padding-top: var(--r4);
  border-top: 1px solid var(--linie-zart); }
details.umstellen summary { cursor: pointer; font-weight: 500; min-height: var(--hoehe-bedien);
  padding: var(--r2) 0; color: var(--leise); }
details.umstellen[open] summary { margin-bottom: var(--r2); }
/* Der äußere Bereich hat bereits Linie und Abstand. Ein zweiter Rand am
   Aufklapper darin machte aus einer seltenen Aktion zwei leere Trennzonen. */
.entscheidung > details.umstellen { margin: 0; padding: 0; border: 0; }
.karte.polster > details.umstellen:first-child { padding-top: 0; border-top: 0; }


/* Werkstatteinstellungen. Das Sternchen an den Feldern, die im Vertrag
   stehen — bei den übrigen ist Leerlassen eine gültige Antwort. */
.pflicht { color: var(--rot); font-weight: 600; }
.platzhalter { margin: 0 0 var(--r4); }
.platzhalter summary { cursor: pointer; font-weight: 500; padding: var(--r2) 0; }
.platzhalter table { margin: var(--r2) 0; }
.platzhalter td { padding: var(--r1) var(--r3) var(--r1) 0; border: 0; }
.platzhalter code { background: var(--grund); padding: 1px var(--r-symbol);
  border-radius: var(--r1); }
.logo-vorschau { max-height: 64px; max-width: 100%; display: block;
  border: 1px solid var(--linie); border-radius: var(--rund);
  padding: var(--r2); background: #fff; }

/* Briefpapier zeigt sich ohne Polster: Der Bogen läuft im PDF bis an die
   Blattkante, und eine Vorschau mit Innenabstand verspräche einen Rand, den
   der Ausdruck nicht hat. Ein ganzes A4-Blatt braucht Höhe, sonst erkennt
   man den Fuß nicht mehr — deshalb hoch und schmal statt breit. */
.briefpapier-vorschau { max-height: 420px; max-width: 100%; display: block;
  border: 1px solid var(--linie); border-radius: var(--rund);
  background: #fff; }

/* Ein Formular, das selbst Karten enthält, darf keine Karte sein — sonst
   steht eine Karte in einer Karte und der Blick findet keinen Rand mehr.
   Der Name ist mit Bedacht nicht „offen": Das gibt es schon als Statusmarke
   für unbezahlte Posten, und die Farbe färbte prompt die Überschriften. */
.formular.rahmenlos { background: transparent; border: 0; padding: 0;
  box-shadow: none; display: grid; gap: var(--r4); max-width: none; }
/* Der Abstand null galt vorher für alle rahmenlosen Formulare. Gemeint war
   aber nur das eine, das ganze Abschnitte trägt: Dort bringen die
   Überschriften den Rhythmus schon mit, und ein zweiter Abstand verdoppelte
   ihn. Wo dasselbe Formular bloße Zeilen trägt — „Kennwort ändern", der
   Code des zweiten Faktors —, klebten Feld und Knopf dadurch aneinander. */
.formular.rahmenlos:has(> h2) { gap: 0; }
/* Eine IBAN steht in Vierergruppen: 27 Zeichen, die nicht abreißen dürfen. */
.feld.breit { max-width: var(--breit-mittel); }
/* Vier kurze Beträge nebeneinander statt drei plus einer. */
.feld-paar.schmal { grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }

/* Zweiter Faktor. Der Code wird abgetippt, während man ihn vom Telefon
   abliest — große Ziffern mit Abstand sind hier kein Zierrat. */
.codefeld { font-size: var(--s-kopf); letter-spacing: .18em; text-align: center;
  font-variant-numeric: tabular-nums; }
label.wahl.bleiben { align-items: flex-start; font-weight: 500; }
label.wahl.bleiben > span { display: grid; gap: var(--r1); }
label.wahl.bleiben .fussnote { margin: 0; font-weight: 400; }

/* Eigener Zugang. Die Notfallcodes werden abgeschrieben, nicht angeklickt.
   Darum nummeriert — man muss sagen können „den dritten habe ich benutzt" —
   und mit fester Zeichenbreite. Vor allem aber nie ein Umbruch mitten im
   Code: ein Bindestrich am Zeilenende ist beim Abschreiben nicht von einer
   Silbentrennung zu unterscheiden. Da alle Codes gleich lang sind, umschließt
   die Fläche den Code, statt die Rasterzelle zu füllen — das ergibt gleiche
   Kästchen ohne eine einzige Breitenangabe. */
.notfallcodes { list-style: none; counter-reset: nfc; padding: 0;
  margin: var(--r4) 0; display: grid; gap: var(--r2) var(--r4);
  grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
  justify-items: start; }
.notfallcodes li { counter-increment: nfc; display: flex;
  align-items: baseline; gap: var(--r-symbol); }
.notfallcodes li::before { content: counter(nfc) "."; flex: none;
  min-width: 1.4em; text-align: right; color: var(--leiser);
  font-size: var(--s-klein); font-variant-numeric: tabular-nums; }
.notfallcodes code { flex: none; white-space: nowrap; user-select: all;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--s-hervor);
  background: var(--grund); border: 1px solid var(--linie-zart);
  padding: var(--r2) var(--r3); border-radius: var(--rund); }

/* Der TOTP-Schlüssel wird abgetippt, wenn das Antippen nicht geht. Er darf
   umbrechen — aber nur zwischen den Vierergruppen, und die trennt ein
   Leerzeichen. */
.geheimnis { display: inline-block; user-select: all;
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--s-hervor);
  letter-spacing: .04em; background: var(--grund);
  padding: var(--r2) var(--r3); border-radius: var(--rund); }

/* Auf Papier druckt der Browser die Flächen nicht mit — ohne Rahmen stünden
   die Codes konturlos auf dem Blatt. */
@media print {
  .notfallcodes code { background: #fff; border-color: #999; }
  /* Ein A4-Blatt ist nach Abzug der Ränder knapp 700 px breit — für den
     Browser also ein schmaler Schirm, und die Leiste am unteren Rand liegt
     fest. Fest heißt beim Drucken: auf **jeder** Seite, quer über dem Text. */
  .daumenleiste, .tablett-kopf { display: none; }
}
.schritte { margin: 0; padding-left: var(--r5); display: grid; gap: var(--r5); }
.schritte > li { padding-left: var(--r1); }
.knopfreihe { display: flex; flex-wrap: wrap; gap: var(--r3); }
/* Der Knopf, der etwas wegnimmt: ausmustern, verwerfen, stilllegen.
   Ungefüllt und in Rot — die gefüllte Fläche gehört der einen Hauptaktion des
   Bildschirms.

   Die Auswahl ist umständlicher, als sie aussehen müsste, und das hat einen
   Grund: ``.formular > button[type=submit]`` weiter oben macht **jeden**
   Absendeknopf in einem Formular zur Hauptaktion, und zwar mit höherem Gewicht
   (0-2-1) als ein schlichtes ``button.gefahr`` (0-1-1). „Artikel ausmustern"
   stand deshalb seit jeher als gefüllter brauner Knopf da — dieselbe Farbe wie
   „Vertrag abschließen", nur eben mit der gegenteiligen Wirkung. Auffallen
   konnte das nicht: Auf der Seite steht kein zweiter Knopf daneben, mit dem
   sich vergleichen ließe.

   Dieselbe Falle gilt für ``.knopf-weg``; die Zeile darunter nimmt sie
   gleich mit, damit sie nicht beim nächsten Formular wieder aufgeht. */
button.gefahr, .formular > button[type=submit].gefahr {
  background: transparent; color: var(--rot); border-color: var(--linie);
}
button.gefahr:hover, .formular > button[type=submit].gefahr:hover {
  background: var(--akzent-hell); border-color: var(--linie);
}
.formular > button[type=submit].knopf-weg {
  background: transparent; color: var(--leise); border-color: var(--linie);
}

/* Der Platz für die Entscheidung über den ganzen Datensatz — Entwurf
   verwerfen, Kunden stilllegen, Artikel ausmustern. Immer ganz unten, mit
   reichlich Luft und einer Linie darüber. Am Tresen liegt das iPad flach und
   der Daumen fährt von unten herein; stünde so ein Knopf dicht an „Vertrag
   abschließen", träfe ihn irgendwann jemand, der unterschreiben wollte. */
.entscheidung { margin-top: var(--r6); padding-top: var(--r4);
  border-top: 1px solid var(--linie); }

/* Die Miete am Entwurf ist ein Feld, kein Text — sie wird von Hand gesetzt.
   Schmal gehalten, damit die Spalte eine Zahlenspalte bleibt und nicht wie
   ein Formular aussieht. */
.mietfeld { display: flex; flex-wrap: wrap; gap: var(--r1); justify-content: flex-end;
  align-items: center; }

/* Der Vermerk eines Feldes, das sich selbst speichert (formular.js,
   ``data-feld-speichern``): „gespeichert" oder der Grund der Ablehnung,
   direkt darunter. Eine eigene Zeile, damit eine Zahlenspalte schmal
   bleibt; eine Ablehnung bricht um, statt die Tabelle zu verbreitern. */
.feld-stand { display: block; flex-basis: 100%; max-width: 18em; margin-top: 2px;
  font-size: var(--s-zusatz); line-height: 1.3; text-align: inherit; }
.mietfeld .feld-stand { text-align: right; margin-left: auto; }
.feld-stand.gut { color: var(--gut); }
.feld-stand.gut::before { content: "✓ "; }
.feld-stand.fehler { color: var(--rot); }
.feld-stand.laeuft { color: var(--leise); }
[aria-invalid="true"] { border-color: var(--rot); }
.mietfeld input[name="betrag"] { width: 5.5em; text-align: right;
  font-variant-numeric: tabular-nums; min-height: var(--hoehe-knapp); padding: 2px var(--r2); }

/* Wertepaare — Beschriftung links, Wert rechts. Für das Mandat und alles
   Weitere, was sich als Liste aus Merkmal und Angabe liest. Auf schmalem
   Schirm untereinander, weil zwei Spalten dort nur noch Silben ergäben. */
.paare { display: grid; grid-template-columns: max-content 1fr;
  gap: var(--r2) var(--r4); margin: var(--r4) 0; }
.paare dt { color: var(--leise); font-size: var(--s-fein); }
.paare dd { margin: 0; }
/* Zwei Paare nebeneinander, sobald die Karte es hergibt. Vier Angaben
   untereinander in einer 800 px breiten Karte ließen rechts die halbe Fläche
   leer und die Karte doppelt so hoch aussehen, wie sie sein müsste —
   auffällig auf der Zahlungsseite, wo darunter gleich die nächste Karte
   kommt. Vier Spalten und die abwechselnde Folge dt, dd, dt, dd füllen eine
   Zeile mit zwei Paaren; dafür ist keine Änderung an der Auszeichnung nötig.

   ``.paare.untereinander`` schaltet es ab — für Listen, deren Werte lang sind
   (Vertragswortlaut, Anschrift) und die nebeneinander nur umbrechen würden. */
@media (min-width: 720px) {
  .paare:not(.untereinander) {
    grid-template-columns: max-content minmax(0, 1fr) max-content minmax(0, 1fr);
  }
}
@media (max-width: 560px) {
  .paare { grid-template-columns: 1fr; gap: 0; }
  .paare dt { margin-top: var(--r3); }
}

/* Trennstrich mit „oder" dazwischen. Nur auf der Anmeldeseite: Zwei
   gleichwertige Wege hinein, und keiner soll wie der Notausgang aussehen. */
.oder { display: flex; align-items: center; gap: var(--r3);
  color: var(--leiser); font-size: var(--s-zusatz); margin: var(--r4) 0; }
.oder::before, .oder::after { content: ""; flex: 1;
  border-top: 1px solid var(--linie); }

/* Meldungen der Passkey-Schaltflächen. Leer, bis es etwas zu sagen gibt —
   ein leerer Kasten auf jeder Seite wäre Lärm. */
#passkey-meldung:empty { display: none; }

/* Auswahlspalte in einer Tabelle. Schmal, damit sie die Zahlenspalten nicht
   verschiebt — und auf dem Telefon ohne Beschriftung, weil das Häkchen für
   sich spricht. */
.wahlspalte { width: 1%; white-space: nowrap; }
/* In der Entwurfsliste bleibt die Zeile anklickbar — sie öffnet den Entwurf,
   und das ist es, was man mit einem angefangenen Vertrag meistens tut. Damit
   das Ankreuzen daneben nicht zum Zielschießen wird, füllt die Beschriftung
   die ganze Zelle: Wer irgendwo in die Spalte tippt, setzt das Häkchen und
   blättert nicht weg. Ohne das bliebe rings um ein 20 px großes Kästchen eine
   Fläche, die die Seite verlässt und die Auswahl mitnimmt. */
td.wahlspalte:has(> label.wahl.fuellend) { position: relative; padding: 0;
  width: 56px; }
label.wahl.fuellend { position: absolute; inset: 0; margin: 0; padding: 0;
  justify-content: center; }
@media (max-width: 760px) {
  td.wahlspalte::before { content: none; }
  /* In der Kartenansicht ist die Zelle keine Spalte mehr, sondern eine Zeile
     im Stapel. Absolut gesetzt hätte sie keine Höhe, und das Kästchen läge
     über der Zeile darunter. */
  td.wahlspalte:has(> label.wahl.fuellend) { position: static; width: auto;
    padding: var(--r3) var(--r4); }
  label.wahl.fuellend { position: static; justify-content: flex-start; }
}

/* Der Stand eines Vertrags. Eigene Farben und nicht die der Artikelzustände:
   Ein Vertrag ist nicht „verfügbar", und die alte Bedingung mit zwei
   Ausgängen — aktiv braun, alles andere grün — färbte gekündigt und beendet
   wie einen guten Zustand. Aktiv ist grün, ein Entwurf will noch etwas
   (bernstein), gekündigt läuft aus (braun), und was vorbei ist, tritt
   zurück. */

/* Der Vertragswortlaut auf dem Entwurf, vor der Unterschrift.

   Festbreitenschrift, und zwar aus einem Grund und nicht aus Geschmack: § 1
   wird in ``regeln.vertragstext`` mit Leerzeichen auf feste Spalten gesetzt
   (58 Zeichen Bezeichnung, 12 rechtsbündig für den Betrag), und die
   Gesamtwertzeile ist ebenso von Hand ausgerichtet. In einer
   Proportionalschrift streuen die Beträge über die halbe Seite.

   Begrenzte Höhe: Sechs Paragraphen sind rund hundert Zeilen. Offen
   geschoben schöben sie die Unterschrift so weit nach unten, dass niemand
   sie mehr fände. */
details.vertrag-lesen { border: 1px solid var(--linie); border-radius: var(--rund-karte);
  padding: var(--r3) var(--r4); background: var(--grund); }
details.vertrag-lesen summary { cursor: pointer; font-weight: 600; padding: var(--r1) 0; }
details.vertrag-lesen[open] summary { margin-bottom: var(--r3); }
.vertragswortlaut {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: var(--s-klein); line-height: 1.5; margin: 0;
  white-space: pre-wrap; overflow-wrap: anywhere;
  max-height: 55vh; overflow-y: auto;
  background: var(--karte); border: 1px solid var(--linie-zart);
  border-radius: var(--rund); padding: var(--r4);
}

/* Zwei Kästen hintereinander brauchen Luft dazwischen.
 *
 * Ohne sie stoßen sie aneinander und sehen aus wie ein einziger mit einem
 * Strich in der Mitte — auf dem Entwurf die Positionen und das Suchfeld
 * darunter, auf der Zugangsseite die Passkey-Liste und ihr Formular. Wo eine
 * Überschrift dazwischensteht, bringt die den Abstand schon mit; wo keine
 * steht, fehlte er.
 *
 * Als Nachbarschaftsregel und nicht als Klasse: Eine Klasse muss jemand
 * setzen, und genau das wird vergessen — dreimal in dieser Anwendung, an drei
 * verschiedenen Stellen. Die Regel kann man nicht vergessen.
 *
 * Kasten heißt: Karte, Formular oder Suchformular — alles, was als weiße
 * Fläche mit Rand steht. Das Suchformular fehlte in der Liste, obwohl der
 * erste Absatz genau seinen Fall meint; die Regel zählte zwei Klassen auf und
 * traf ``form.suche`` nie. Auf dem Entwurf klebte deshalb „Noch nichts
 * gewählt" am Suchfeld darunter. Es steht nur rechts vom Plus: Nach unten
 * hält es seinen Abstand selbst (``form.suche`` in der Werkzeugleiste), und
 * der trägt auch durch die htmx-Hülle um die Trefferliste hindurch, die ein
 * Nachbarschaftsselektor nicht durchdringt. */
:is(.karte, .formular) + :is(.karte, .formular, form.suche) { margin-top: var(--r5); }

/* Eine Knopfreihe in einem Hinweis. Ohne Abstand klebte sie am Satz darüber;
   der Abstand gehört in die Leiter und nicht als style-Attribut ins Markup —
   sonst steht die nächste bei 10 px und die übernächste bei 14. */
.hinweis .knopfreihe { margin-top: var(--r3); }

/* Der Bildschirm, den man dem Kunden über den Tresen schiebt. Wie die
   Anmeldung eine eigene Seite ohne Leiste — nur breiter, weil hier ein
   Formular steht und kein Kasten mit zwei Feldern. Zentriert und begrenzt:
   Ein Formular, das sich am iPad quer über 1180 px spannt, liest sich als
   Datenblatt und nicht als Frage an eine Person. */
main.angaben { max-width: 780px; margin: 0 auto; padding: var(--r6) var(--r4) var(--r7); }
main.angaben h1 { margin-bottom: var(--r2); }


/* --------------------------------------------------------------------------
   Die Seiten, die Fremde sehen: Anfrageformular, Impressum, Datenschutz
   -------------------------------------------------------------------------- */
/* Gerüst und Mittigkeit kommen von ``.anmeldeseite``/``.anmeldung`` — dieselbe
   eine Spalte ohne Navigation. Nur die Breite ist eine andere: Die
   Anmeldemaske hat zwei Felder, das Anfrageformular hat vierzehn in Dreier-
   gruppen. Auf 380 px stünde jedes davon unter dem vorigen, und die Seite
   wäre zwei Bildschirme lang, bevor jemand den Absendeknopf sieht. */
main.oeffentlich { width: min(720px, 94vw); }
main.oeffentlich h1 { margin-bottom: 0; }
main.oeffentlich h2 { font-size: var(--s-hervor); margin: var(--r5) 0 var(--r2); }
main.oeffentlich .karte { padding: var(--r5); }
main.oeffentlich .karte > *:first-child { margin-top: 0; }
main.oeffentlich dl.paare { margin-top: 0; }

/* Impressum und Datenschutzhinweis müssen „leicht erkennbar, unmittelbar
   erreichbar und ständig verfügbar" sein (§ 5 DDG). Deshalb im Fuß jeder
   öffentlichen Seite und nicht nur unter dem Formular — und sichtbar, nicht
   als graue Zeile am Rand des Erkennbaren.

   ``max-width: none`` ist hier kein Beiwerk, sondern die eigentliche
   Zentrierung. Der Fuß erbt von ``.fussnote`` die Spaltenbreite ``--mass`` —
   richtig für Fließtext, für drei Verweise bedeutungslos. Damit war der
   Absatz aber schmaler als die Seite und stand als Block links:
   ``text-align: center`` zentrierte den Text dann innerhalb einer
   linksbündigen Kiste, und die Zeile saß auf 1280 px um 58 px zu weit links —
   sichtbar schief unter der mittigen Marke darüber. Auf einem Telefon fiel es
   nicht auf, weil die Seite dort ohnehin schmaler ist als die Spalte: Der
   Fehler zeigte sich ausgerechnet am Bürorechner.

   (Der Kommentar nannte früher ``72ch``. Die Zahl gibt es nicht mehr — die
   Ursache schon, und sie bleibt dieselbe.)

   Nebenbei nimmt der Trennstrich damit die volle Breite ein, statt als
   kurzer Strich in der Mitte zu hängen. */
.rechtliches { text-align: center; margin-top: var(--r5); max-width: none;
  padding-top: var(--r4); border-top: 1px solid var(--linie); }
.rechtliches a { color: var(--leise); }
.rechtliches a:hover { color: var(--text); }

/* Der Köder gegen einfache Massenskripte. Nicht ``display: none``: Manche
   Skripte prüfen darauf und lassen das Feld dann in Ruhe. Aus dem Sehfeld
   geschoben ist es für Menschen ebenso unsichtbar — und für die Sprachausgabe
   sorgen ``aria-hidden`` und ``tabindex=-1`` in der Vorlage. */
.versteckt { position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; }

/* Der Stand einer Mietanfrage. Eigene Leiter wie bei Vertrag und Forderung:
   „Offen" macht Arbeit (Bernstein), „Übernommen" ist der gute Ausgang (Grün),
   „Verworfen" ist erledigt und darf verblassen. Die Klassen der
   Artikelzustände zu leihen wäre hier falsch — eine Anfrage ist nicht
   „verfügbar". */
/* Der Schließer an einer flüchtigen Meldung. Rechts außen, damit er den Text
   nicht umbricht, und erst beim Überfahren deutlich — er soll die Meldung
   nicht wichtiger aussehen lassen, als sie ist. */
.hinweis.fluechtig { position: relative; padding-right: var(--r7); }
.meldung-zu { position: absolute; top: var(--r2); right: var(--r2);
  min-height: var(--hoehe-knapp); min-width: var(--hoehe-knapp); padding: 0; line-height: 1;
  background: transparent; border-color: transparent; color: inherit;
  opacity: .5; font-size: var(--s-titel); }
.meldung-zu:hover { opacity: 1; background: rgba(38,37,36,.06); }

/* Ein knapper Ablauf über einer Seite, die man selten benutzt. Anders als
   ``.schritte`` (Zugangsseite, große Abstände zwischen ausführlichen
   Schritten): Hier sind es vier kurze Zeilen, die einordnen, was die Seite
   tut und was danach kommt — die brauchen keine Luft, sondern Nähe. */
ol.schritte-knapp { margin: 0 0 var(--r5); padding-left: var(--r5);
  color: var(--leise); font-size: var(--s-fein); max-width: 72ch; }
ol.schritte-knapp li { margin-bottom: var(--r1); }
ol.schritte-knapp li:last-child { margin-bottom: 0; }

/* Die Übernahmeseite: was nach einer getroffenen Wahl nicht mehr gilt.
 *
 * Die Richtung ist Absicht. Vorgabe ist **sichtbar**; ausgeblendet wird nur,
 * was eine bereits getroffene Entscheidung ausschließt. Andersherum — erst
 * versteckt, per :has() eingeblendet — wäre die Seite auf jedem Browser ohne
 * :has() eine Sackgasse: kein Zahlungsteil, kein Absenden, kein Hinweis
 * warum. Diese Seite geht an dreihundert fremde Telefone, darunter alte; sie
 * darf nicht davon abhängen, wie neu das Gerät ist.
 *
 * Deshalb auch kein Skript, anders als überall sonst in dieser Anwendung: Am
 * Tresen steht ein bekanntes iPad, hier steht irgendetwas. */
.entscheidung:has(#e-nein:checked) .wenn-ja { display: none; }
.wenn-ja:has(#za-d:checked) .wenn-lastschrift { display: none; }

.wenn-ja { margin-top: var(--r5); border-top: 1px solid var(--linie);
  padding-top: var(--r4); }
.wenn-ja h3 { font-size: var(--s-hervor); margin: 0 0 var(--r3); }
.wenn-lastschrift { margin-top: var(--r4); display: grid; gap: var(--r4); }

/* Der Pflichtwortlaut des Mandats. Abgesetzt, weil er etwas anderes ist als
   die Beschriftungen daneben: Er wird nicht ausgefüllt, sondern erklärt. */
.karte.mandat { padding: var(--r4); background: var(--grund); }
.karte.mandat h4 { margin: 0 0 var(--r2); font-size: var(--s-text); }
.karte.mandat p { margin: 0 0 var(--r2); }
.karte.mandat p:last-child { margin-bottom: 0; }

/* Der Datenschutzhinweis der Übernahme kommt als fertig gesetzter Fließtext
   aus ``regeln`` — derselbe Wortlaut wie auf der Briefrückseite. Er bringt
   seine Umbrüche mit; ``pre`` darf sie hier trotzdem nicht wörtlich nehmen,
   sonst steht der Text auf einem Telefon in einer Spalte von 90 Zeichen. */
pre.fliesstext { white-space: pre-wrap; word-wrap: break-word;
  font: inherit; margin: 0; max-width: 72ch; }

.bereichsname { margin: 0; color: var(--leise); font-size: var(--s-klein);
  font-weight: 650; letter-spacing: .08em; text-transform: uppercase; }
.kundensuche-kopf { display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: 8px; margin: 20px 0 12px; }
.kundensuche-kopf h2 { margin: 0; }
.auswahl .kundensuche-kopf { margin: 0; }
.kundenstart-leer { padding: 24px; }
.kundenstart-leer h2 { margin-top: 0; }
.kundenstart-neu { margin-top: 28px; scroll-margin-top: 24px; }
.kundenstart-neu > summary { padding: 20px; cursor: pointer; border: 1px solid var(--linie);
  border-radius: 12px; background: var(--karte); font-weight: 650; }
.kundenstart-neu > summary .zusatz { display: block; margin-top: 4px; font-weight: 400; }
.kundenstart-neu > .formular { margin-top: 16px; }
.kundenstart-bank { margin: 12px 0; }
.kundenstart-bank > summary { padding: 12px 0; cursor: pointer; font-weight: 650; }
.kundenstart-bank .feld { margin-top: 12px; }
/* Die Kundendaten verschwanden beim Scrollen zur Unterschrift. Am Tresen
   muss klar bleiben, wessen Vertrag gerade auf dem iPad liegt. */
.vertragsweg { position: sticky; top: 0; z-index: 20; margin: var(--r4) 0 var(--r5);
  padding: var(--r3); background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--rund-karte); box-shadow: var(--schatten); }
.vertragsweg-kunde { display: flex; justify-content: space-between; flex-wrap: wrap;
  gap: var(--r2); margin: 0 0 var(--r2); font-size: var(--s-zusatz); }
.vertragsweg-kunde span { color: var(--leise); }
.vertragsweg ol { display: grid; grid-template-columns: repeat(3,minmax(0,1fr));
  list-style: none; gap: var(--r2); margin: 0; padding: 0; }
.vertragsweg li > a, .vertragsweg li > span { display: flex; align-items: center;
  gap: var(--r2); min-height: max(var(--hoehe-bedien), var(--r7));
  padding: var(--r2) var(--r3); border-radius: var(--rund); color: var(--leise);
  font-size: var(--s-fein); text-decoration: none; }
.vertragsweg b { display: inline-grid; place-items: center; flex: 0 0 var(--r5);
  width: var(--r5); height: var(--r5); border-radius: 50%; background: var(--grund); }
.vertragsweg [aria-current] { color: var(--akzent); background: var(--akzent-hell); font-weight: 650; }
.vertragsweg a:hover { background: var(--grund); color: var(--text); }
.vertragsweg .ausstehend { color: var(--leiser); }
#entwurf-oben, #abschluss-anzeige { scroll-margin-top: calc(var(--r7) + var(--r7) + var(--r5)); }
@media (max-width: 600px) {
  .vertragsweg li > a, .vertragsweg li > span { padding: var(--r2); gap: var(--r1); font-size: var(--s-zusatz); }
}

.vermerk-vorschlaege { display: flex; flex-wrap: wrap; gap: var(--r2); margin-top: var(--r2); }
.vermerk-vorschlaege button { min-height: max(var(--hoehe-bedien), var(--r7)); }

.fristwahl { display: flex; flex-wrap: wrap; gap: var(--r2); margin-top: var(--r2); }
.fristwahl button { min-height: max(var(--hoehe-bedien), var(--r7)); }

/* Feste Zeichenbreite hält Text und Arbeitszähler auch in langen Menüs ruhig. */
.navi-symbol { width: 20px; height: 20px; flex: 0 0 20px; }
.seitenleiste > .knopf.haupt { align-items: center; justify-content: center; gap: var(--r2); }

.bedienhilfe { margin: var(--r3) 0 var(--r5); color: var(--leise); font-size: var(--s-zusatz); }
.bedienhilfe > summary { cursor: pointer; padding: var(--r2) 0; }

.instrumentengeschichte { list-style: none; padding: 0; display: grid; gap: var(--r3); }
.instrumentengeschichte h2 { font-size: var(--s-hervor); margin: var(--r2) 0; }
.instrumentengeschichte p { margin: var(--r2) 0; }
.instrumentengeschichte time { color: var(--leise); font-size: var(--s-zusatz); }

.ruecknahme-bilanz { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr));
  gap: 20px; margin: 28px 0 16px; padding: 20px; border: 1px solid var(--linie);
  border-radius: 12px; background: var(--grund); }
.ruecknahme-bilanz ul { padding-left: 18px; margin: 8px 0 0; }
.ruecknahme-bilanz .bereichsname { margin: 0 0 8px; }
.ruecknahme-miete { font-size: var(--s-kopf); font-variant-numeric: tabular-nums; }
.ruecknahme-abschluss { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* Nicht mitgebrachte Stücke bleiben sichtbar, ihre Zustandsfelder lenken
   aber von den tatsächlich auf dem Tresen liegenden Stücken ab. Vermerke
   bleiben im Formular erhalten, wenn das Stück wieder angehakt wird. */
/* Ein Werkstattvermerk darf nicht versehentlich an den Kunden gehen.
 * Die Auswahl zeigt am selben Feld, wann sein Text im Beleg abgedruckt wird. */
.stueck .notiz-mieter { display: none; }
.stueck:has(option[value="werkstatt_notiz"]:checked) .notiz-intern { display: none; }
.stueck:has(option[value="werkstatt_notiz"]:checked) .notiz-mieter { display: inline; }
.stueck:has(option[value="werkstatt_notiz"]:checked) p.notiz-mieter { display: block; }
.rueckgabe-nein { display: none; }
.stueck:has(input[name="zurueck"]:not(:checked)) { background: var(--grund); }
.stueck:has(input[name="zurueck"]:not(:checked)) > .feld,
.stueck:has(input[name="zurueck"]:not(:checked)) .rueckgabe-ja { display: none; }
.stueck:has(input[name="zurueck"]:not(:checked)) .rueckgabe-nein { display: inline; }

.tauschrahmen { scroll-margin-top: 24px; margin: 32px 0; border-top: 1px solid var(--linie); padding-top: 24px; }
.tauschueberblick { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr));
  gap: 20px; padding: 20px; margin: 20px 0; background: var(--grund); border: 1px solid var(--linie); border-radius: 12px; }
.tauschueberblick .bereichsname { margin: 0 0 8px; }
.tauschueberblick strong { font-size: var(--s-hervor); }

/* Die Einrichtung braucht einen nächsten Schritt statt eines langen Formulars.
   Hinterlegt heißt dabei ausdrücklich nicht fachlich freigegeben. */
.einrichtungsliste { display: grid; grid-template-columns: repeat(2,minmax(0,1fr));
  gap: var(--r4); margin: var(--r5) 0; }
.einrichtungsliste h2 { margin: var(--r2) 0 var(--r3); }
.einrichtungsliste > section.karte { min-width: 0; margin: 0; }
.einrichtungspreise { margin: var(--r3) 0; }
.einrichtungspreise div { display: flex; justify-content: space-between; gap: var(--r3); }
.einrichtungspreise dd { margin: 0; font-variant-numeric: tabular-nums; }
.einrichtung-weiter { border-color: var(--akzent); }
@media (max-width: 700px) { .einrichtungsliste { grid-template-columns: 1fr; } }

/* Die ganze CSV bleibt vor dem Schreiben prüfbar. Die bestehende Tabellen-
   darstellung bricht am iPad um; Zuordnung und Freigabe sind getrennt. */
.importzuordnung { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: var(--r3); padding-top: var(--r4); }
.importzuordnung .feld { min-width: 0; }
.importzuordnung button { align-self: end; }
.importzahlen { margin-top: var(--r5); }
.importfehler { margin: 0; color: var(--rot); }
@media (max-width: 600px) { .importzuordnung { grid-template-columns: 1fr; } }

/* Werkstattseite: ein Knopf je Abschnitt, die Meldung gleich daneben.
   Vorher stand ein einziger Knopf unter neun Abschnitten und die Meldung
   oben auf der Seite — vom Knopf aus zwei Bildschirmhöhen entfernt. */
.werkstattabschnitt { margin-top: var(--r5); }
.werkstattabschnitt > h2 { margin-top: 0; }
.abschnittsfuss { display: flex; flex-wrap: wrap; align-items: center; gap: var(--r3); }
.abschnittsfuss .hinweis { margin: 0; flex: 1 1 260px; }
.ungespeichert { color: var(--rot); font-size: .92em; }
.dateiformular { display: grid; gap: var(--r4); }

/* Ein Vorlagenentwurf, der nur im Tab liegt, steht unter dem Feld. */
.entwurfsstand { color: var(--rot); margin: 0; }
.verweisknopf { background: none; border: 0; padding: 0; min-height: 0;
  color: var(--akzent, inherit); text-decoration: underline; cursor: pointer; font: inherit; }

/* Die Adresse braucht ihre eigene Zeile. Neben dem Neustartknopf drückte
   sie sonst auf dem iPad den Knopf aus der Ausgangskarte hinaus. */
td .taten form.ausgang-neustart {
  flex-direction: column; align-items: stretch; max-width: 100%; width: 18rem;
}
.ausgang-neustart label { min-width: 0; }
.ausgang-neustart input[type=email] { width: 100%; min-width: 0; }

@media (max-width: 960px) {
  /* Auch der zweite Handgriff muss im Hochformat vollständig sichtbar sein. */
  td .ausgang-aktionen { flex-direction: column; align-items: stretch; }
  td .ausgang-aktionen form.inline {
    flex-direction: column; align-items: stretch; width: 14rem; max-width: 100%;
  }
  td .ausgang-aktionen input[type=text] { width: auto; }
}
