/* =====================================================================
   Bauwagen-Kiosk – Gestaltungssystem
   =====================================================================

   Aufbau in vier Schichten, von unten nach oben:

     1. STUFEN    – rohe Farbwerte, Abstände, Größen. Nie direkt benutzen.
     2. BEDEUTUNG – --flaeche, --text, --rand … Nur diese kommen in Regeln
                    vor. Genau deshalb ist der Dunkelmodus zwanzig Zeilen
                    und nicht ein zweites Stylesheet.
     3. GRUNDLAGE – body, Überschriften, Formularfelder.
     4. BAUSTEINE – .karte, .knopf, .liste, .marke …

   Eine Regel für das ganze Haus: **Im HTML steht kein freier Wert.**
   Kein `style="margin:.6rem"`, keine Farbe, keine Pixelzahl. Wer einen
   Abstand braucht, den es hier nicht gibt, hat entweder den falschen
   Abstand gewählt oder einen Baustein gefunden, der noch fehlt.
   ===================================================================== */

/* =====================================================================
   1. STUFEN
   ===================================================================== */
:root {
    /* --- Blau: die Leitfarbe, sauber durchgestuft ---------------------
       Vorher gab es drei Blautöne. Drei reichen für Flächen, nicht für
       Ränder, Verläufe, Zustände und einen Dunkelmodus. */
    --blau-50:  #EEF3FB;
    --blau-100: #D9E4F5;
    --blau-200: #B6C9EA;
    --blau-300: #8BA7DA;
    --blau-400: #6183C4;
    --blau-500: #3F63A8;
    --blau-600: #2F5597;   /* der bisherige Hellton */
    --blau-700: #24406F;
    --blau-800: #1F3864;   /* die bisherige Leitfarbe */
    --blau-900: #16274A;
    --blau-950: #0E1A33;

    /* --- Grau, absichtlich WARM ---------------------------------------
       Ein neutrales Grau neben tiefem Blau wirkt schmutzig. Ein Hauch
       Wärme lässt beides zusammengehören. */
    --grau-0:   #FFFFFF;
    --grau-50:  #FAFAF9;
    --grau-100: #F4F4F2;
    --grau-200: #E8E7E4;
    --grau-300: #D6D5D1;
    --grau-400: #A8A6A1;
    --grau-500: #78766F;
    --grau-600: #57554F;
    --grau-700: #3D3B36;
    --grau-800: #26251F;
    --grau-900: #1A1917;
    --grau-950: #111110;

    /* --- Marine und Türkis: die Farben des Zeichens --------------------
       Das App-Symbol besteht aus Türkis auf Marineblau – und davon stand
       bis Runde 6 nichts im Gestaltungssystem. Zeichen und Oberfläche
       hatten keine einzige gemeinsame Farbe; das Symbol auf dem
       Startbildschirm sah aus wie das einer fremden Anwendung.

       Marine ist NICHT `--blau-900`. Das Blau des Hauses ist ein
       gedecktes Königsblau für Flächen und Schrift; Marine ist deutlich
       tiefer und kühler und trägt das Türkis. Nebeneinander gestellt
       wirken beide schmutzig – deshalb steht Marine ausschließlich in der
       Fassung der Kasse und nirgends sonst. */
    --marine-950: #071322;   /* die Mulde */
    --marine-900: #0B1B2E;   /* aus dem App-Symbol – die Fassung selbst */
    --marine-800: #10283F;   /* was darin erhaben liegt */
    --marine-700: #1A3E5E;   /* Trennlinien */
    --marine-600: #245B85;
    --marine-500: #3E7FAE;   /* Ränder, die man sehen soll */

    /* HARTE REGEL: KEIN TÜRKIS AUF HELLER FLÄCHE.
       Gemessen: #22C3DE auf Weiß ergibt 2,12:1, #5FE8F5 sogar nur 1,46:1.
       Deshalb heißt das Bedeutungsmerkmal weiter unten `--zeichen` und
       nicht `--akzent` – der Name sagt, wo die Farbe trägt. Wer sie auf
       die helle Produktwand setzt, macht Schrift unsichtbar. */
    --tuerkis-300: #8AF2FB;
    --tuerkis-400: #5FE8F5;  /* aus dem App-Symbol – Schrift auf Marine */
    --tuerkis-500: #22C3DE;  /* aus dem App-Symbol – die Kante */

    /* Der Geldknopf auf der Fassung. Eigener Wert, weil `--gruen` im
       Dunkelmodus hell wird: Auf der Fassung – die in BEIDEN Modi dunkel
       ist – wäre die Fläche dann #2C4A18 und ergäbe 1,50:1 gegen den
       Grund. „Bar kassieren", der meistgedrückte Knopf des Systems, wäre
       als Form nicht mehr zu erkennen. #4C7A2E ergibt 3,41:1, weiße
       Schrift darauf 5,08:1. */
    --gruen-knopf: #4C7A2E;
    /* Der rote Knopf auf der Fassung: „Abbrechen" waehrend einer
       Kartenzahlung. #B32424 (der Hauston des Hauses) ergibt auf Marine
       nur 2,64:1 - die weisse Schrift darauf waere zwar lesbar, aber die
       FORM des Knopfes verschwaende fast im Panel. Genau der Knopf, den
       eine Kassenkraft unter Zeitdruck sofort finden muss.
       #C42F2F ergibt 3,14:1 als Flaeche und 5,53:1 fuer weisse Schrift. */
    --rot-knopf:   #C42F2F;

    /* --- Zustandsfarben, je drei Stufen ------------------------------- */
    --gruen-zart: #E3F1DC;  --gruen: #4C7A2E;  --gruen-tief: #2F5119;
    --rot-zart:   #FBE4E4;  --rot:   #B32424;  --rot-tief:   #7A1414;
    --gelb-zart:  #FDF1D8;  --gelb:  #A9740B;  --gelb-tief:  #6E4A00;

    /* --- Abstandsleiter ----------------------------------------------- */
    --raum-1: 4px;   --raum-2: 8px;   --raum-3: 12px;  --raum-4: 16px;
    --raum-5: 24px;  --raum-6: 32px;  --raum-7: 48px;  --raum-8: 64px;

    /* --- Schriftgrößen ------------------------------------------------ */
    --schrift-xs: .75rem;    /* 12 – Marken, Fußnoten */
    --schrift-s:  .875rem;   /* 14 – Nebentext */
    --schrift-m:  1rem;      /* 16 – Grundtext. NIE kleiner in Feldern:
                                iOS zoomt sonst beim Antippen hinein. */
    --schrift-l:  1.25rem;   /* 20 – Abschnittstitel */
    --schrift-xl: 1.625rem;  /* 26 – Seitentitel */
    --schrift-2xl: 2.125rem; /* 34 – Kennzahlen, Beträge */
    --schrift-3xl: 3rem;     /* 48 – NUR der Betrag im Kartendialog.
                                Er wird aus zwei Metern gelesen, während
                                der Kunde die Karte auflegt. Eine Stufe
                                mit genau einem Benutzer ist trotzdem
                                besser als ein freier Wert: Sie steht
                                dort, wo man Schriftgrößen sucht. */

    --rund-s: 6px;  --rund-m: 10px;  --rund-l: 16px;  --rund-voll: 999px;

    --tempo-schnell: 120ms;
    --tempo:         180ms;
    --kurve: cubic-bezier(.2, 0, .2, 1);

    --leiste: 264px;         /* Breite der Seitenleiste */
    --kopf:   56px;          /* Höhe der Kopfzeilen, Gerüst wie Kasse */

    /* DIE STAPELREIHENFOLGE, als Leiter statt als vier gewachsene Zahlen.
       Vorher standen 20, 30, 40 und 100 verstreut in zwei Dateien - und
       weil 40 (Kategorienband) über 20 (Kassen-Kopfzeile) lag, schob sich
       beim Scrollen die Kategorienleiste über den Zurück-Pfeil. Wer eine
       Zahl braucht, findet hier keine freie mehr. */
    --z-band:  10;           /* klebende Bänder INNERHALB des Inhalts */
    --z-kopf:  20;           /* Kopfzeilen - liegen immer über den Bändern */
    --z-korb:  30;           /* Warenkorb, Untenleiste */
    --z-blatt: 100;          /* Dialoge - über allem */
}

/* =====================================================================
   DIE BREITENLEITER - drei Stufen, zwei Grenzen.

     schmal    bis 559 px    Handy hochkant       Korb als Leiste unten
     mittel    ab  560 px    Handy quer, klein
     breit     ab  760 px    ab iPad hochkant     Korb als Spalte rechts

   900 px gehört dem GERÜST (Seitenleiste ein, Untenleiste aus) und gilt
   nur auf Seiten MIT Seitenleiste. Die Kasse läuft im Vollbild und sieht
   diese Grenze nie.

   Vorher waren es sechs Zahlen: 560, 599, 600, 759, 760, 900. Zwischen
   ihnen lagen Zonen, die nie jemand zusammen entworfen hat - und genau
   dort lag der Fehler, den der Betreiber gemeldet hat (zwischen 560 und
   759 fehlten am Tablet Rabatt, Gutschein, Guthaben und Anschreiben).

   FINGERGRÖSSE IST KEINE BREITE. Ein 1920-px-Kassenmonitor kann mit dem
   Finger bedient werden, ein 1024-px-Fenster mit der Maus. Dafür gibt es
   (pointer: coarse) - siehe .knopf.klein weiter unten.
   ===================================================================== */

/* =====================================================================
   2. BEDEUTUNG – hell
   ===================================================================== */
:root {
    color-scheme: light;

    --grund:        var(--grau-100);   /* hinter allem */
    --flaeche:      var(--grau-0);     /* Karten, Listen */
    --flaeche-hoch: var(--grau-50);    /* eingelassene Bereiche */
    --flaeche-tief: var(--blau-900);   /* Seitenleiste, Kassenkopf */

    --text:       var(--grau-900);
    /* grau-600, nicht grau-500. Gemessen: grau-500 auf Weiß ergibt 4,13:1 –
       knapp UNTER den 4,5:1, die lesbar heißt. Betroffen wäre nicht eine
       Stelle, sondern jeder Erklärtext, jede Unterzeile und jede Fußnote
       im ganzen System: genau die Sätze, die anleiten sollen. grau-600
       bringt 7,4:1 und ist immer noch deutlich leiser als der Fließtext. */
    --text-leise: var(--grau-600);
    --text-auf-tief: var(--grau-0);
    /* LEISE SCHRIFT AUF DEM DUNKLEN GRUND.
       Vorher stand in geruest.css zweimal ein von Hand gewaehltes
       `rgba(255,255,255,...)`: .45 fuer die Gruppenueberschrift und .55
       fuer die Rolle. Die .45 ergaben 4,15:1 - unter den 4,5:1 der WCAG,
       und zwar auf JEDER Seite des Systems, weil die Seitenleiste
       ueberall steht. Gemerkt hat es niemand, weil die Kontrastmessung
       die Deckkraft wegwarf und 45 % Weiss als reines Weiss rechnete.
       .6 ergibt 6,25:1 auf dem hellen Marineblau und 6,96:1 auf dem
       dunklen Grau - und bleibt gegenueber den .82 der Menuepunkte
       deutlich leiser.
       KEINE eigene Fassung fuer den Dunkelmodus: Der Wert ist Weiss mit
       Deckkraft, kein fertiger Farbwert, und traegt auf beiden Gruenden. */
    --text-auf-tief-leise: rgba(255, 255, 255, .6);
    --text-auf-akzent: var(--grau-0);

    --rand:       var(--grau-200);
    --rand-stark: var(--grau-300);

    --akzent:       var(--blau-800);
    /* WOHIN EIN GEFUELLTER KNOPF BEIM UEBERFAHREN GEHT.
       Eine eigene Marke, weil `.knopf:hover` sonst den ROHEN Ton
       `--blau-700` setzt - und der ist in beiden Modi derselbe, waehrend
       die Schrift darauf wechselt. Im Dunkeln steht dort dunkle Schrift
       (`--text-auf-akzent` ist dann `--grau-950`): #111110 auf #24406F
       ergibt 1,83:1. Der Knopf wurde beim Ueberfahren unlesbar - und
       zwar der am haeufigsten gedrueckte im Haus.
       Hell 10,3:1, dunkel 7,77:1 - beide gegen `--text-auf-akzent`. */
    --akzent-ueber: var(--blau-700);
    --akzent-hell:  var(--blau-600);
    --akzent-zart:  var(--blau-50);
    --akzent-rand:  var(--blau-200);

    /* Fuer GEFUELLTE Knoepfe. `--gruen` und `--rot` sind Schriftfarben
       auf hellem Grund; im Dunkelmodus werden sie hell, und ein grosser
       Knopf daraus leuchtet dann heller als alles andere auf der Seite -
       ausgerechnet „Bar kassieren", der am haeufigsten gedrueckt wird.
       Eine Flaeche braucht eine eigene Farbe. */
    --gruen-flaeche: var(--gruen);
    --text-auf-gruen: var(--grau-0);
    --rot-flaeche:   var(--rot);
    --text-auf-rot:  var(--grau-0);

    --schatten-1: 0 1px 2px rgba(16, 24, 40, .06);
    --schatten-2: 0 2px 8px rgba(16, 24, 40, .08);
    --schatten-3: 0 12px 32px rgba(16, 24, 40, .14);

    /* --- DIE FASSUNG ---------------------------------------------------
       Kopfzeile, Warenkorb und Zahlbereich der Kasse. „Helle Wand, dunkle
       Fassung": Die Produktwand bleibt tageslichttauglich – am Bauwagen
       steht die Sonne im Bildschirm –, und alles, was mit Geld zu tun hat,
       sitzt in einer tiefen Fassung mit türkiser Kante.

       SIE STEHT NUR HIER UND NICHT NOCH EINMAL IM DUNKELSATZ. Das ist die
       einzige Stelle im Haus, an der ein Bedeutungsmerkmal in beiden Modi
       denselben Wert hat, und das hat einen Grund: Die Fassung IST dunkel.
       Sie im Dunkeln noch einmal umzudeuten hieße, sie ein zweites Mal zu
       entwerfen – und zwei Sätze, die dasselbe meinen, laufen auseinander
       (siehe die Warnung über den beiden Dunkelblöcken).

       Wo ist dann im Dunkeln die Kante zur Wand? Gemessen: Die Fassung
       steht auf der hellen Wand mit 15,75:1 – dort trägt die Fläche. Im
       Dunkeln sind es 1,09:1 – dort trägt die türkise Haarlinie mit
       8,93:1. Die beiden Fälle ergänzen sich genau; ohne Begrenzung ist
       die Fassung in keinem der beiden. */
    --fassung:       var(--marine-900);
    --fassung-hoch:  var(--marine-800);
    --fassung-tief:  var(--marine-950);
    --fassung-rand:  var(--marine-700);
    --fassung-kante: var(--tuerkis-500);
    --zeichen:       var(--tuerkis-400);
    --text-auf-fassung:       #EAF2FA;   /* 15,35:1 */
    --text-auf-fassung-leise: #9FB4C9;   /*  8,13:1 */
}

/* =====================================================================
   2b. BEDEUTUNG – dunkel
   Nur die Zuordnung wird getauscht. Keine einzige Regel weiter unten
   weiß, dass es einen Dunkelmodus gibt.

   ZWEI Blöcke, weil CSS es nicht anders zulässt: Ein Medienabfrage-Block
   und ein Attributselektor lassen sich nicht in eine Regel schreiben. Sie
   sind deshalb **zeichengleich** zu halten, und genau das ging schon
   einmal schief: `--text-auf-akzent` stand nur im unteren. Wer sein Gerät
   auf dunkel gestellt hat – der häufigere Fall, weil dafür niemand etwas
   umschalten muss – bekam damit WEISSE Schrift auf hellblauen und
   hellgrünen Knöpfen: 1,92:1 auf „Bar kassieren". Der Knopf, der am
   meisten gedrückt wird, war der am schlechtesten lesbare.

   `tests/test_gestaltung.py` vergleicht die beiden Blöcke seither Zeile
   für Zeile.
   ===================================================================== */
@media (prefers-color-scheme: dark) {
    :root:not([data-thema="hell"]) {
        color-scheme: dark;
        --grund:        var(--grau-950);
        --flaeche:      var(--grau-900);
        --flaeche-hoch: var(--grau-800);
        --flaeche-tief: var(--grau-900);

        --text:       var(--grau-100);
        --text-leise: var(--grau-400);
        --text-auf-tief: var(--grau-100);
        /* Im Dunkeln ist der Akzent HELL – die Schrift darauf muss dunkel
           sein. Dieselbe Farbe wie im hellen Satz wäre unlesbar. */
        --text-auf-akzent: var(--grau-950);

        --rand:       #2E2D29;
        --rand-stark: #43413B;

        --akzent:       var(--blau-400);
        /* Im Dunkeln geht der Knopf beim Ueberfahren HELLER, nicht
           dunkler: Die Schrift darauf ist dann dunkel. */
        --akzent-ueber: var(--blau-300);
        --akzent-hell:  var(--blau-300);
        /* #141A27 statt #1B2436: Auf dem helleren Ton kam `--akzent` als
           Schrift nur auf 4,11:1 – die blaue Marke und der Namenskreis
           waren damit unter der Grenze. */
        --akzent-zart:  #141A27;
        --akzent-rand:  #2C3A55;

        /* Im Dunkeln trägt nicht der Schatten, sondern die Fläche. */
        --schatten-1: 0 1px 2px rgba(0, 0, 0, .5);
        --schatten-2: 0 2px 8px rgba(0, 0, 0, .55);
        --schatten-3: 0 12px 32px rgba(0, 0, 0, .6);

        --gruen-zart: #1E2E17;  --gruen: #8FCB6A;  --gruen-tief: #C4E5AE;
        --rot-zart:   #331414;  --rot:   #F08A8A;  --rot-tief:   #F8C4C4;
        --gelb-zart:  #322611;  --gelb:  #E3B25A;  --gelb-tief:  #F3D9A8;

        /* Im Dunkeln ist die FLAECHE tief und die Schrift darauf hell -
           genau umgekehrt zum hellen Satz. Gemessen: #D6EDC6 auf #2C4A18
           ergibt 8,0:1. */
        --gruen-flaeche: #2C4A18;
        --text-auf-gruen: #D6EDC6;
        --rot-flaeche:   #4A1717;
        --text-auf-rot:  #F8C4C4;
    }
}
/* Von Hand auf dunkel gestellt – gilt unabhängig vom Gerät.
   ZEICHENGLEICH zum Block darüber halten. */
:root[data-thema="dunkel"] {
    color-scheme: dark;
    --grund:        var(--grau-950);
    --flaeche:      var(--grau-900);
    --flaeche-hoch: var(--grau-800);
    --flaeche-tief: var(--grau-900);

    --text:       var(--grau-100);
    --text-leise: var(--grau-400);
    --text-auf-tief: var(--grau-100);
    --text-auf-akzent: var(--grau-950);

    --rand:       #2E2D29;
    --rand-stark: #43413B;

    --akzent:       var(--blau-400);
    /* Im Dunkeln geht der Knopf beim Ueberfahren HELLER, nicht
       dunkler: Die Schrift darauf ist dann dunkel. */
    --akzent-ueber: var(--blau-300);
    --akzent-hell:  var(--blau-300);
    --akzent-zart:  #141A27;
    --akzent-rand:  #2C3A55;

    --schatten-1: 0 1px 2px rgba(0, 0, 0, .5);
    --schatten-2: 0 2px 8px rgba(0, 0, 0, .55);
    --schatten-3: 0 12px 32px rgba(0, 0, 0, .6);

    --gruen-zart: #1E2E17;  --gruen: #8FCB6A;  --gruen-tief: #C4E5AE;
    --rot-zart:   #331414;  --rot:   #F08A8A;  --rot-tief:   #F8C4C4;
    --gelb-zart:  #322611;  --gelb:  #E3B25A;  --gelb-tief:  #F3D9A8;

    /* Im Dunkeln ist die FLAECHE tief und die Schrift darauf hell -
       genau umgekehrt zum hellen Satz. Gemessen: #D6EDC6 auf #2C4A18
       ergibt 8,0:1. */
    --gruen-flaeche: #2C4A18;
    --text-auf-gruen: #D6EDC6;
    --rot-flaeche:   #4A1717;
    --text-auf-rot:  #F8C4C4;
}

/* =====================================================================
   3. GRUNDLAGE
   ===================================================================== */
*, *::before, *::after { box-sizing: border-box; }

/* `hidden` ist eine Zusage des Browsers - kein Baustein darf sie brechen.
   Deshalb hier, ganz oben, und mit `!important`.

   DER FALL: Die Produktsuche an der Kasse setzte `k.hidden = true` auf
   jede Kachel, die nicht passt. Nur steht in kasse.css
   `.produkt-kachel { display: block }` - gleiche Spezifität wie die
   Browserregel `[hidden] { display: none }`, und Autorenregeln schlagen
   das Browser-Stilblatt ohnehin. Die Suche hat also NICHTS gefiltert:
   Man tippt, und es geschieht nichts.

   Ohne `!important` wäre es hier genauso: `stil.css` lädt vor
   `kasse.css`, bei Gleichstand gewinnt das spätere Blatt. */
[hidden] { display: none !important; }

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                 "Helvetica Neue", sans-serif;
    font-size: var(--schrift-m);
    line-height: 1.55;
    color: var(--text);
    background: var(--grund);
    -webkit-text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { color: var(--text); font-weight: 650; line-height: 1.25; }
h1 { font-size: var(--schrift-xl); margin: 0 0 var(--raum-5); letter-spacing: -.01em; }
h2 { font-size: var(--schrift-l); margin: var(--raum-6) 0 var(--raum-3); }
h3 { font-size: var(--schrift-m); margin: var(--raum-5) 0 var(--raum-2);
     color: var(--text-leise); text-transform: uppercase;
     letter-spacing: .06em; font-size: var(--schrift-xs); }
h2:first-child, h1 + h2 { margin-top: 0; }

a { color: var(--akzent); }
code {
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
    font-size: .9em; background: var(--flaeche-hoch);
    padding: 1px var(--raum-1); border-radius: var(--rund-s);
    overflow-wrap: anywhere;
}

/* Erklärtext – die Sorte, die anleitet. Muss sich absetzen, sonst führt
   sie nicht, sondern steht nur herum. */
.nebenbei {
    color: var(--text-leise);
    font-size: var(--schrift-s);
    line-height: 1.6;
    max-width: 68ch;          /* darüber wird nicht mehr gelesen, sondern überflogen */
    margin: var(--raum-2) 0 var(--raum-4);
}
.nebenbei:last-child { margin-bottom: 0; }

/* Dasselbe mitten im Satz – für ein Wort, nicht für einen Absatz. */
.leise { color: var(--text-leise); }

/* --- Formularfelder ---------------------------------------------------
   Über :not(...) und nicht über eine Liste von [type=…]: Ein
   Attributselektor greift nur bei VORHANDENEM Attribut, und 24 Felder im
   Projekt hatten gar keins. Sie fielen komplett aus der Gestaltung – 13px
   Schrift, und iOS zoomt beim Antippen hinein. So ist auch jedes künftige
   Feld automatisch dabei. */
label { display: block; font-weight: 600; font-size: var(--schrift-s);
        margin: 0 0 var(--raum-1); color: var(--text); }
label > input, label > select, label > textarea { font-weight: 400; margin-top: var(--raum-1); }
label .zusatz { font-weight: 400; color: var(--text-leise); }

input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=hidden]),
select, textarea {
    width: 100%;
    padding: var(--raum-3);
    border: 1px solid var(--rand-stark);
    border-radius: var(--rund-m);
    font-size: var(--schrift-m);     /* nie kleiner – siehe oben */
    font-family: inherit;
    color: var(--text);
    background: var(--flaeche);
    transition: border-color var(--tempo-schnell) var(--kurve),
                box-shadow var(--tempo-schnell) var(--kurve);
}
input:hover:not([type=checkbox]):not([type=radio]), select:hover, textarea:hover {
    border-color: var(--akzent-hell);
}
input[type=color] { height: 46px; padding: var(--raum-1); cursor: pointer; }
input[type=file] { background: var(--flaeche-hoch); padding: var(--raum-2); }
input:disabled, select:disabled { background: var(--flaeche-hoch); color: var(--text-leise); }
textarea { min-height: 5rem; resize: vertical; }

/* Sichtbarer Fokus auf ALLEM Bedienbaren. Vorher hatten ihn nur
   Eingabefelder – auf einer blauen Knopffläche war der Standardring des
   Browsers praktisch unsichtbar, und Tastaturbedienung damit blind. */
:where(a, button, .knopf, .kachel, .produkt-kachel, .mengenknopf,
       input, select, textarea, [tabindex]):focus-visible {
    outline: 3px solid var(--akzent-hell);
    outline-offset: 2px;
    border-radius: var(--rund-s);
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--akzent);
    box-shadow: 0 0 0 3px var(--akzent-zart);
}

/* =====================================================================
   4. BAUSTEINE
   ===================================================================== */

/* --- Karte: der eine Kasten für alles ------------------------------- */
.karte {
    background: var(--flaeche);
    border: 1px solid var(--rand);
    border-radius: var(--rund-l);
    padding: var(--raum-5);
    box-shadow: var(--schatten-1);
    margin-bottom: var(--raum-4);
}
.karte > h2:first-child, .karte > h3:first-child { margin-top: 0; }
.karte.eng { padding: var(--raum-4); }
.karte.blank { padding: 0; overflow: hidden; }

/* --- Knöpfe ----------------------------------------------------------
   Vier Arten, drei Größen. Mindestens 44 px hoch – das ist die Fläche,
   die ein Daumen sicher trifft. */
.knopf {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--raum-2);
    padding: var(--raum-3) var(--raum-5);
    min-height: 44px;
    background: var(--akzent); color: var(--text-auf-akzent);
    border: 1px solid transparent;
    border-radius: var(--rund-m);
    font-size: var(--schrift-m); font-weight: 600; font-family: inherit;
    line-height: 1.2; text-decoration: none; cursor: pointer;
    transition: background var(--tempo-schnell) var(--kurve),
                transform var(--tempo-schnell) var(--kurve),
                box-shadow var(--tempo-schnell) var(--kurve);
    /* `nowrap` allein sprengte bei 320 px jede Seite mit einem langen
       Knopftext: „Sicherungskopie herunterladen" wurde 304 px breit in
       einem 295 px schmalen Blatt, und die GANZE Seite schob sich nach
       rechts – samt Navigation.

       Deshalb drei Regeln zusammen: Nicht umbrechen, solange Platz ist
       (ein Knopf mit zwei Zeilen sieht kaputt aus), aber nie breiter als
       der Platz werden, und wenn es eng wird, doch umbrechen. Die
       Reihenfolge stimmt so: `max-width` gewinnt gegen `nowrap`, und dann
       greift `text-wrap`. */
    white-space: nowrap;
    max-width: 100%;
}
@media (max-width: 559px) {
    /* Auf schmalen Geräten lieber zwei Zeilen als eine abgeschnittene:
       Ein Knopf, dessen Aufschrift nicht ganz zu lesen ist, wird nicht
       gedrückt. */
    .knopf { white-space: normal; text-align: center; }
}
.knopf:hover  { background: var(--akzent-ueber); }
.knopf:active { transform: translateY(1px); }
.knopf:disabled, .knopf[disabled] {
    opacity: .45; cursor: not-allowed; transform: none;
}
.knopf .symbol { width: 20px; height: 20px; flex: 0 0 20px; }

.knopf.zweit {                 /* der ruhige Knopf neben dem Hauptweg */
    background: var(--flaeche); color: var(--text);
    border-color: var(--rand-stark);
}
.knopf.zweit:hover { background: var(--flaeche-hoch); border-color: var(--akzent-hell); }
/* GEFUELLTE Zustandsknoepfe tragen eine eigene Flaechenfarbe.
   `--gruen` ist eine Schriftfarbe; im Dunkelmodus wird sie hell, und ein
   grosser Knopf daraus leuchtete heller als alles andere auf der Seite -
   ausgerechnet „Bar kassieren", der am haeufigsten gedrueckt wird. */
.knopf.gruen { background: var(--gruen-flaeche); color: var(--text-auf-gruen); }
.knopf.gruen:hover { filter: brightness(1.12); }
.knopf.rot   { background: var(--rot-flaeche); color: var(--text-auf-rot); }
.knopf.rot:hover { filter: brightness(1.12); }
.knopf.stumm {                 /* sieht aus wie Text, ist aber ein Knopf */
    background: none; color: var(--text-leise);
    border-color: transparent; font-weight: 500;
}
.knopf.stumm:hover { background: var(--flaeche-hoch); color: var(--text); }

.knopf.gross { padding: var(--raum-4) var(--raum-6); font-size: var(--schrift-l);
               min-height: 56px; border-radius: var(--rund-l); }
.knopf.klein { padding: var(--raum-2) var(--raum-3); font-size: var(--schrift-s);
               min-height: 36px; }
/* Am FINGER 44 px, an der Maus 36.
   `pointer: coarse` trifft genau die Geraete, bei denen es darauf ankommt -
   Tablet und Handy. Ein Daumen ist rund 45 px breit; 36 px heisst, dass
   regelmaessig die Nachbarzeile getroffen wird, und in einer Liste steht
   daneben oft "loeschen".
   An einer Maus waeren 44 px in einer Listenzeile dagegen nur klobig: Der
   Zeiger ist einen Pixel breit und trifft immer. */
@media (pointer: coarse) {
    .knopf.klein { min-height: 44px; padding: var(--raum-3) var(--raum-4); }
}
.knopf.breit { width: 100%; }

.knopfreihe { display: flex; gap: var(--raum-3); flex-wrap: wrap;
              margin: var(--raum-5) 0 0; align-items: center; }
.knopfreihe.rechts { justify-content: flex-end; }

@media (prefers-reduced-motion: reduce) {
    * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
    .knopf:active { transform: none; }
}

/* --- Hinweise -------------------------------------------------------- */
.hinweis {
    display: flex; gap: var(--raum-3); align-items: flex-start;
    padding: var(--raum-4);
    border-radius: var(--rund-m);
    margin-bottom: var(--raum-4);
    border: 1px solid transparent;
    border-left-width: 4px;
    font-size: var(--schrift-s);
    background: var(--flaeche-hoch);
}
.hinweis .symbol { width: 20px; height: 20px; flex: 0 0 20px; margin-top: 2px; }
.hinweis.fehler  { background: var(--rot-zart);   border-left-color: var(--rot);
                   color: var(--rot-tief); }
.hinweis.warnung { background: var(--gelb-zart);  border-left-color: var(--gelb);
                   color: var(--gelb-tief); }
.hinweis.gut     { background: var(--gruen-zart); border-left-color: var(--gruen);
                   color: var(--gruen-tief); }
.hinweis.info    { background: var(--akzent-zart);border-left-color: var(--akzent-hell); }
.hinweis strong { font-weight: 650; }
/* Ein Link in einem Hinweis erbt die Schriftfarbe.
   Gemessen: Der normale Linkton kam im Dunkelmodus auf 4,06:1 statt 4,5 –
   und in `.fehler`, `.warnung`, `.gut` wäre es schlimmer, denn die setzen
   eine eigene Schriftfarbe, gegen die ein Blau gar nicht mehr abgestimmt
   ist. Der Text drumherum ist auf jeder dieser Flächen bereits geprüft;
   ihn zu übernehmen erbt diese Prüfung mit. Erkennbar bleibt der Link an
   der Unterstreichung – die trägt ohnehin weiter als Farbe allein, für
   alle, die Farben schlecht unterscheiden. */
.hinweis a {
    color: inherit; text-decoration: underline;
    text-underline-offset: 2px; font-weight: 600;
}

/* --- Marken (kleine Pillen) ------------------------------------------ */
.marke {
    display: inline-flex; align-items: center; gap: var(--raum-1);
    padding: 2px var(--raum-2); border-radius: var(--rund-voll);
    font-size: var(--schrift-xs); font-weight: 650; line-height: 1.6;
    background: var(--flaeche-hoch); color: var(--text-leise);
    white-space: nowrap;
}
.marke.rot   { background: var(--rot-zart);   color: var(--rot-tief); }
.marke.gelb  { background: var(--gelb-zart);  color: var(--gelb-tief); }
.marke.gruen { background: var(--gruen-zart); color: var(--gruen-tief); }
.marke.blau  { background: var(--akzent-zart);color: var(--akzent); }
/* Ein Symbol in einer Pille. Ohne diese Zeile kaeme es in der vollen
   Symbolgroesse und spraengte die 2px-Polsterung nach oben und unten. */
.marke .symbol { width: 14px; height: 14px; flex: 0 0 14px; }

/* --- Listen ----------------------------------------------------------
   Bewusst keine Tabellen: eine Tabelle bricht auf 390 px Breite, eine
   Liste aus Zeilen nicht. */
.zeilenliste {
    display: flex; flex-direction: column;
    background: var(--flaeche);
    border: 1px solid var(--rand); border-radius: var(--rund-l);
    overflow: hidden; margin-bottom: var(--raum-4);
}
/* `flex-wrap` und eine Mindestbreite für die Textspalte.

   Ohne beides gewinnt die rechte Spalte: Sie enthält Formulare mit festen
   Feldbreiten und gibt nicht nach, `.haupt` hat `min-width: 0` und schrumpft
   deshalb bis auf null. Zusammen mit `overflow-wrap: anywhere` am Namen
   ergab das an einem schmalen Fenster **einen Buchstaben je Zeile** –
   „Großmarkt" stand senkrecht über zehn Zeilen.

   `flex: 1 1 11rem` heißt: Unter 11 rem bricht die rechte Spalte lieber
   darunter, statt den Text zu zerquetschen. */
.listenzeile {
    display: flex; align-items: center; gap: var(--raum-4);
    padding: var(--raum-4);
    border-bottom: 1px solid var(--rand);
    transition: background var(--tempo-schnell) var(--kurve);
    flex-wrap: wrap;
}
.listenzeile:last-child { border-bottom: none; }
.listenzeile:hover { background: var(--flaeche-hoch); }
.listenzeile .haupt { flex: 1 1 11rem; min-width: 0; }
/* Als BLOCK, nicht inline: Sonst laeuft die Erklaerung hinter dem Titel
   weiter statt darunter - auf einem breiten Bildschirm wird daraus eine
   einzige lange Zeile, in der beides gleich wichtig aussieht. */
.listenzeile .haupt .n { display: block; font-weight: 600; overflow-wrap: anywhere; }
.listenzeile .haupt .u { display: block; font-size: var(--schrift-s);
                         color: var(--text-leise); overflow-wrap: anywhere; }
.listenzeile .rechts { text-align: right; display: flex; flex-direction: column;
                       align-items: flex-end; gap: var(--raum-2);
                       flex: 0 1 auto; min-width: 0; }
.listenzeile .rechts form { margin: 0; }
/* Ein Knopf in der rechten Spalte darf nicht schrumpfen, bis seine
   Beschriftung senkrecht steht.
   Gemessen bei 320 px auf „Offene Zahlungen": 42 px breit, 108 px hoch -
   „Abbrechen" lief Buchstabe für Buchstabe untereinander. Das ist kein
   Schönheitsfehler: Der Knopf ist der einzige Ausweg aus einer
   festhängenden Kartenzahlung, und auf dem Handy war er unlesbar.
   `min-width: 0` an der Spalte bleibt - sonst sprengt ein langer Name die
   Seite; der Knopf selbst nimmt sich seine Breite. */
.listenzeile .rechts .knopf { white-space: nowrap; flex: 0 0 auto; }
/* Ausgleichen: Betrag, Topf und Knopf in einer Reihe – und auf dem Telefon
   umbrechend statt schrumpfend. Ein 40 px breites Betragsfeld ist auf einem
   Touchscreen nicht zu treffen, deshalb eine feste Mindestbreite. */
.ausgleichsform { display: flex; flex-wrap: wrap; justify-content: flex-end;
                  gap: var(--raum-2); align-items: center; }
.ausgleichsform input[type="text"] { width: 6.5rem; min-width: 5rem; }
.ausgleichsform select { width: auto; min-width: 6rem; }
/* Am schmalen Gerät nimmt das Formular die ganze Zeile – daneben ist kein
   Platz, und daneben gequetscht ist es unbedienbar. */
@media (max-width: 559px) {
    .listenzeile .rechts { width: 100%; align-items: stretch; text-align: left; }
    .ausgleichsform { justify-content: flex-start; }
    .ausgleichsform input[type="text"] { flex: 1 1 5rem; width: auto; }
    .ausgleichsform select { flex: 1 1 6rem; }
}
/* Ausgegraut, aber lesbar: `opacity: .5` drückte den Kontrast auf 2,4:1 –
   nötig sind 4,5:1. Deshalb eine echte Farbe statt Durchsichtigkeit. */
/* Dichter, wo viele kurze Zeilen untereinander stehen und der Platz
   knapp ist - im Warenkorb sind es bis zu einem Dutzend auf einem Handy.
   Nur das Polster wird kleiner; Schriftgroessen und Trefferflaechen
   bleiben, sonst waere es eine zweite Liste statt derselben. */
.zeilenliste.dicht .listenzeile { padding: var(--raum-2) var(--raum-3);
                                  gap: var(--raum-3); }

.listenzeile.inaktiv .haupt .n { color: var(--text-leise); font-weight: 500; }
.listenzeile.inaktiv .produktbild { filter: grayscale(1); opacity: .7; }
.listenzeile.summe { background: var(--flaeche-hoch); font-weight: 650; }

/* --- Leerer Zustand ---------------------------------------------------
   Sagt IMMER, was als Nächstes zu tun ist. Ein leerer Kasten, der nur
   „nichts vorhanden" meldet, lässt jemanden stehen. */
.leer {
    text-align: center; padding: var(--raum-7) var(--raum-4);
    color: var(--text-leise);
}
.leer .symbol { width: 40px; height: 40px; opacity: .35; margin-bottom: var(--raum-3); }
.leer p { margin: 0 0 var(--raum-4); font-size: var(--schrift-s); }
/* Derselbe leere Zustand auf engem Raum - im Warenkorb, wo darunter noch
   die Zahlleiste steht. Nicht weniger Inhalt, nur weniger Polster: Auch
   hier gehoert ein Satz dazu, der sagt, was zu tun ist. */
.leer.eng { padding: var(--raum-5) var(--raum-4); }
.leer.eng .symbol { width: 28px; height: 28px; margin-bottom: var(--raum-2); }

/* --- Mengenwippe: weniger, wieviel, mehr ------------------------------
   Drei Dinge, die zusammengehoeren, also auch als eine Einheit gebaut -
   sonst treiben sie beim naechsten Umbau auseinander.

   44 px, weil hier mit dem Daumen getippt wird und ein Vertippen bares
   Geld kostet: Ohne Minus muesste man den ganzen Korb leeren, um ein
   Stueck zurueckzunehmen.

   Ausser im Warenkorb wird das auch in der Inventur gebraucht - deshalb
   steht es hier und nicht in kasse.css. */
.mengenwippe {
    display: flex; align-items: center; gap: var(--raum-1);
    flex: 0 0 auto;
}
.mengenwippe .mengenknopf {
    width: 44px; height: 44px; flex: 0 0 44px;
    display: grid; place-items: center;
    border: 1px solid var(--rand-stark); border-radius: var(--rund-m);
    background: var(--flaeche); color: var(--text);
    font-size: var(--schrift-l); font-weight: 650; line-height: 1;
    cursor: pointer;
    transition: background var(--tempo-schnell) var(--kurve);
}
.mengenwippe .mengenknopf:hover { background: var(--flaeche-hoch); }
.mengenwippe .mengenknopf:active { background: var(--akzent-zart); }
.mengenwippe .menge {
    min-width: 2ch; text-align: center; font-weight: 680;
    font-variant-numeric: tabular-nums;
}

/* --- Kennzahl --------------------------------------------------------- */
.kennzahlen {
    display: grid; gap: var(--raum-3); margin-bottom: var(--raum-5);
    grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
}
.kennzahl {
    background: var(--flaeche); border: 1px solid var(--rand);
    border-radius: var(--rund-l); padding: var(--raum-4);
    box-shadow: var(--schatten-1);
}
.kennzahl .was { font-size: var(--schrift-xs); color: var(--text-leise);
                 text-transform: uppercase; letter-spacing: .06em; font-weight: 650; }
.kennzahl .zahl { font-size: var(--schrift-2xl); font-weight: 680;
                  line-height: 1.15; margin-top: var(--raum-1);
                  letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.kennzahl .dazu { font-size: var(--schrift-s); color: var(--text-leise); }

/* --- Anklickbare Kennzahlen ------------------------------------------
   Was sich anfassen lässt, muss danach aussehen. Eine Kachel, die
   aussieht wie Text und ein Verweis ist, findet niemand; eine, die
   aussieht wie ein Knopf und keiner ist, ärgert jeden.

   `display: block` ist Pflicht: Ein `<a>` ist von Haus aus inline, und
   dann greifen weder das Polster noch die Rahmenrundung.

   `color: inherit` und `text-decoration: none`, damit die Kachel nicht
   plötzlich blau und unterstrichen ist – die Farbe trägt hier die Zahl,
   nicht der Verweis. */
a.kennzahl {
    display: block; color: inherit; text-decoration: none;
    transition: box-shadow .12s ease, transform .12s ease;
}
a.kennzahl:hover {
    box-shadow: var(--schatten-2);
    transform: translateY(-2px);
    border-color: var(--akzent);
}
a.kennzahl.betont:hover { border-color: var(--akzent); }
/* Der Pfeil sagt „hier geht es weiter", ohne ein Wort zu kosten. Nur bei
   Zeigergeräten: Am Handy zeigt ein Wischen ohnehin nichts an, und der
   Platz auf einer 320-px-Kachel ist knapp. */
@media (hover: hover) {
    a.kennzahl .dazu::after { content: " ›"; font-weight: 700; }
}

/* --- Die eigene nächste Schicht --------------------------------------
   Ganz oben auf der Startseite. Für die meisten, die sich anmelden, ist
   das die Frage, mit der sie gekommen sind. */
.naechste-schicht {
    display: block; text-decoration: none; color: inherit;
    background: var(--flaeche); border: 1px solid var(--rand);
    border-left: 4px solid var(--akzent);
    border-radius: var(--rund-l); padding: var(--raum-4);
    margin-bottom: var(--raum-4);
    box-shadow: var(--schatten-1);
    transition: box-shadow .12s ease;
}
.naechste-schicht:hover { box-shadow: var(--schatten-2); }
.naechste-schicht .was {
    font-size: var(--schrift-xs); color: var(--text-leise);
    text-transform: uppercase; letter-spacing: .06em; font-weight: 650;
}
.naechste-schicht .zahl {
    font-size: var(--schrift-xl); font-weight: 680;
    line-height: 1.2; margin-top: var(--raum-1);
    font-variant-numeric: tabular-nums;
}
.naechste-schicht .dazu {
    font-size: var(--schrift-s); color: var(--text-leise);
}
/* Heute: derselbe Kasten, nur der Streifen wird zur Ampel. Kein zweites
   Farbschema – wer heute Dienst hat, soll es sehen, nicht erschrecken. */
.naechste-schicht.heute { border-left-color: var(--gruen); }
.kennzahl.betont { background: var(--akzent); border-color: var(--akzent); }
/* OHNE DECKKRAFT.
   `opacity: .78` ergab im Dunkelmodus 3,81:1 - die Beschriftung "ZU
   ZAHLEN" ueber dem faelligen Betrag war damit die schlechtest lesbare
   Stelle des Warenkorbs. Die Rangordnung braucht die Deckkraft auch
   nicht: Die Zahl darueber steht in --schrift-2xl bei Gewicht 680, die
   Beschriftung in --schrift-xs in Grossbuchstaben. Groesse und Gewicht
   tragen den Unterschied; Deckkraft nahm nur Lesbarkeit weg. */
.kennzahl.betont .was, .kennzahl.betont .dazu { color: var(--text-auf-akzent); }
.kennzahl.betont .zahl { color: var(--text-auf-akzent); }

/* --- Felder nebeneinander -------------------------------------------- */
/* `minmax(0, 1fr)` statt `1fr`: `1fr` ist in Wahrheit `minmax(auto, 1fr)`
   und laesst sich von einem langen Wort im Feld aufdruecken - dann wird das
   Raster breiter als sein Platz und schiebt die Seite nach rechts. */
.feldpaar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: var(--raum-4); margin-bottom: var(--raum-4); }
.feldpaar.drei { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 559px) {
    .feldpaar, .feldpaar.drei { grid-template-columns: 1fr; }
}
form .feldpaar:last-of-type { margin-bottom: 0; }

/* --- Abschnitt -------------------------------------------------------- */
.abschnitt { margin-bottom: var(--raum-6); }
.abschnittskopf {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--raum-4); margin-bottom: var(--raum-3);
    /* UMBRECHEN statt ueberlaufen.
       Der Kopf „Angeschrieben" traegt drei Dinge: Ueberschrift, Summe und
       einen Verweis. Bei 320 px passte das nicht mehr nebeneinander und
       schob die Seite um 5 px nach rechts - eine Startseite, die sich
       seitwaerts schieben laesst, wirkt auf einem Handy kaputt. */
    flex-wrap: wrap;
}
.abschnittskopf h2 { margin: 0; }

/* Zahlen in Listen und Berichten laufen sonst nicht untereinander. */
.zahl, .listenzeile .rechts, .kennzahl .zahl { font-variant-numeric: tabular-nums; }

.fuss { text-align: center; color: var(--text-leise);
        font-size: var(--schrift-xs); padding: var(--raum-6) var(--raum-4); }

/* --- Systemzustand ----------------------------------------------------
   Vier Stufen, und die vierte ist die wichtige: `unbekannt` heißt NICHT
   gemessen. Sie bekommt deshalb eine eigene Farbe und nicht Grau, das man
   für „unwichtig" liest – wer nicht weiß, ob die Datenbank antwortet, hat
   kein kleineres Problem als jemand mit knappem Plattenplatz.

   Die Stufe steht als FARBIGER STREIFEN links, nicht als Hintergrund: Eine
   Liste aus vierzehn getönten Kästen ist ein Flickenteppich, und der rote
   darin fällt weniger auf als in einer ruhigen Liste mit einem roten
   Streifen. Die Marke daneben trägt das Wort – Farbe allein ist keine
   Auskunft, wer sie nicht unterscheiden kann, liest die Marke. */
.zustandsampel {
    display: flex; align-items: center; gap: var(--raum-3);
    background: var(--flaeche); border: 1px solid var(--rand);
    border-left: 4px solid var(--rand-stark);
    border-radius: var(--rund-l); padding: var(--raum-4);
    margin-bottom: var(--raum-4);
}
.zustandsampel .n { font-size: var(--schrift-l); font-weight: 650; }
.zustandsampel .u { color: var(--text-leise); font-size: var(--schrift-s); }
.zustandsliste { margin-bottom: var(--raum-5); }
.zustandszeile { border-left: 4px solid var(--rand-stark); }
/* Der Fehlertext ist der Grund, warum diese Seite mehr ist als eine Ampel.
   Nichtproportional, damit `sqlite3.OperationalError: database is locked`
   als das lesbar ist, was es ist: eine Meldung aus der Maschine, nicht ein
   Satz. `overflow-wrap`, weil eine Fehlermeldung ein 300 Zeichen langes
   Wort ohne Leerzeichen sein kann und die Seite sonst seitwärts schiebt. */
.fehlertext {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--schrift-xs);
    overflow-wrap: anywhere;
    margin-top: var(--raum-1);
}
.stufe-gruen     { border-left-color: var(--gruen); }
.stufe-gelb      { border-left-color: var(--gelb); }
.stufe-rot       { border-left-color: var(--rot); }
.stufe-unbekannt { border-left-color: var(--akzent); }

/* --- Angabenliste (Begriff/Wert) -------------------------------------- */
/* Benutzt vom Baustein „Über das System". Eine `<dl>` und kein Raster aus
   `<div>`: Begriff und Wert gehoeren zusammen, und ein Vorleser sagt das
   auch so. Jedes Paar steckt in einem eigenen `<div>` - ohne das ist eine
   Definitionsliste als Flex- oder Rasterkasten nicht sinnvoll zu setzen.

   Zwei Spalten erst ab 560 px. Darunter untereinander: Bei 320 px blieben
   fuer den Wert sonst rund 150 px, und „Kassen- und Verwaltungssystem"
   braucht dort drei Zeilen. */
.ueberliste { display: grid; gap: var(--raum-3); margin: 0 0 var(--raum-4); }
.ueberliste > div { display: grid; gap: var(--raum-1); }
.ueberliste dt { color: var(--text-leise); font-size: var(--schrift-xs);
                 text-transform: uppercase; letter-spacing: .06em; }
/* `<dd>` bringt im Browser 40 px linken Abstand mit. Ohne diese Zeile
   haengt jeder Wert eingerueckt unter seinem Begriff. */
.ueberliste dd { margin: 0; }
@media (min-width: 560px) {
    .ueberliste > div { grid-template-columns: minmax(min(9rem, 40%), 11rem) minmax(0, 1fr);
                        align-items: baseline; gap: var(--raum-4); }
}

/* --- Anmeldung -------------------------------------------------------- */
.mitte {
    min-height: 100dvh; display: flex; align-items: center;
    justify-content: center; padding: var(--raum-4);
    background: linear-gradient(160deg, var(--blau-900), var(--blau-950));
}
.mitte .karte { width: 100%; max-width: 400px; margin: 0; }
.markenkopf { text-align: center; margin-bottom: var(--raum-5); }
.markenkopf .zeichen {
    width: 56px; height: 56px; margin: 0 auto var(--raum-3);
    display: grid; place-items: center;
    background: var(--akzent); color: var(--text-auf-akzent);
    border-radius: var(--rund-l);
}
.markenkopf .zeichen .symbol { width: 30px; height: 30px; }
.markenkopf .gross { font-size: var(--schrift-l); font-weight: 680; color: var(--text); }
.markenkopf .klein { color: var(--text-leise); font-size: var(--schrift-s); }

/* --- Kleine Helfer, damit im HTML kein freier Wert steht -------------- */
.kastenfeld { width: auto; flex: 0 0 auto; accent-color: var(--akzent);
              width: 20px; height: 20px; }
label.mit-kasten { display: flex; align-items: flex-start; gap: var(--raum-2);
                   font-weight: 550; }
label.mit-kasten input[type=text], label.mit-kasten input:not([type]) { margin-top: var(--raum-2); }
.formende { display: flex; align-items: flex-end; }
.wahlzeile { cursor: pointer; }
.wahlzeile:has(input:checked) { background: var(--akzent-zart); }
.eng-oben { margin-top: var(--raum-4); }

/* --- Rollen und Rechte ------------------------------------------------ */
.kreis-klein {
    width: 36px; height: 36px; flex: 0 0 36px; border-radius: var(--rund-voll);
    background: var(--akzent-zart); color: var(--akzent);
    display: grid; place-items: center; font-weight: 700;
    font-size: var(--schrift-s);
}
.zeilenform { display: flex; gap: var(--raum-2); align-items: center;
              margin-top: var(--raum-2); flex-wrap: wrap; }
.zeilenform select { max-width: 18rem; }
.einmalpasswort { font-size: var(--schrift-l); user-select: all;
                  letter-spacing: .04em; }

.rollenkarte summary {
    display: flex; align-items: center; gap: var(--raum-2);
    cursor: pointer; list-style: none; flex-wrap: wrap;
}
.rollenkarte summary::-webkit-details-marker { display: none; }
.rollenkarte .rollenname { font-size: var(--schrift-l); font-weight: 680;
                           margin-right: auto; }
.rollenkarte[open] summary { margin-bottom: var(--raum-4);
                             padding-bottom: var(--raum-3);
                             border-bottom: 1px solid var(--rand); }

.rechteraster {
    display: grid; gap: var(--raum-2); margin-bottom: var(--raum-4);
    grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
}
.rechtefeld {
    display: flex; gap: var(--raum-3); align-items: flex-start;
    padding: var(--raum-3); border: 1px solid var(--rand);
    border-radius: var(--rund-m); cursor: pointer; font-weight: 400;
    margin: 0;
}
.rechtefeld:hover { background: var(--flaeche-hoch); }
.rechtefeld:has(input:checked) { border-color: var(--akzent);
                                 background: var(--akzent-zart); }
/* Rechte, deren Missbrauch unmittelbar Geld kostet – beim Verteilen soll
   man hier zweimal hinsehen. */
.rechtefeld.heikel { border-left: 3px solid var(--gelb); }
.rechtefeld .n { display: block; font-weight: 650; font-size: var(--schrift-s); }
.rechtefeld .u { display: block; font-size: var(--schrift-xs);
                 color: var(--text-leise); line-height: 1.45; }

/* --- Gutscheincodes zum Notieren -------------------------------------- */
.codeliste { display: grid; gap: var(--raum-3); margin-bottom: var(--raum-4);
             grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr)); }
.codekarte {
    padding: var(--raum-4); text-align: center;
    background: var(--akzent-zart); border: 2px dashed var(--akzent-rand);
    border-radius: var(--rund-l);
}
.codekarte .wert { font-size: var(--schrift-xl); font-weight: 700;
                   color: var(--akzent); }
.codekarte .code { font-family: ui-monospace, Consolas, monospace;
                   font-size: var(--schrift-l); font-weight: 700;
                   letter-spacing: .08em; user-select: all;
                   margin-top: var(--raum-1); }
.codekarte .bis { font-size: var(--schrift-xs); color: var(--text-leise); }

/* --- Grafiken ---------------------------------------------------------
   Im Server als SVG erzeugt. Keine Diagrammbibliothek: Ein Balken ist ein
   Rechteck, und eine Bibliothek wäre ein Baustein mehr, den bei der
   Übergabe jemand pflegen muss. */
.balken { display: block; width: 100%; overflow: visible; }
.achse {
    display: flex; justify-content: space-between;
    font-size: var(--schrift-xs); color: var(--text-leise);
    margin-top: var(--raum-2); overflow: hidden;
}
.achse span { flex: 1; text-align: center; white-space: nowrap; }
.achse span:first-child { text-align: left; }
.achse span:last-child { text-align: right; }

/* --- Storno in der Belegliste -----------------------------------------
   Aufgeklappt statt als eigene Seite: Der Grund ist Pflicht, und ein
   Formular direkt an der Zeile lässt keinen Zweifel, WELCHER Verkauf
   gemeint ist. Eine Bestätigungsseite mit „Sind Sie sicher?" hätte den
   Verkauf nur aus dem Blick genommen. */
.belegknoepfe { display: flex; gap: var(--raum-2); justify-content: flex-end;
                flex-wrap: wrap; margin-top: var(--raum-1); }
.stornofeld summary {
    cursor: pointer; list-style: none; font-size: var(--schrift-s);
    color: var(--rot); font-weight: 600;
    padding: var(--raum-2) var(--raum-3); border-radius: var(--rund-s);
    min-height: 36px; display: inline-flex; align-items: center;
}
.stornofeld summary::-webkit-details-marker { display: none; }
.stornofeld summary:hover { background: var(--rot-zart); }
.stornofeld form {
    margin-top: var(--raum-2); text-align: left;
    background: var(--flaeche-hoch); border: 1px solid var(--rand);
    border-radius: var(--rund-m); padding: var(--raum-3);
    min-width: min(20rem, 70vw);
}


/* --- Katalogauswahl ---------------------------------------------------
   Eine Auswahl, die zwei Felder darunter VORBELEGT und sie beschreibbar
   laesst. Der Katalog ist ein Vorschlag, keine Sperre: Ein Grund, der nicht
   im Katalog steht, muss trotzdem eintragbar sein - sonst wird der naechste
   Abzug gar nicht erfasst.

   Optisch abgesetzt, damit klar ist, dass sie selbst nichts abschickt. */
.katalogwahl {
    border-style: dashed;
    background: var(--flaeche-hoch);
}

/* --- Große Zahl im Abschnittskopf -------------------------------------
   Der Kontostand steht neben der Überschrift, nicht darunter: Wer einen
   Kontoauszug öffnet, will genau eine Zahl wissen, und die soll ohne
   Blicksprung dastehen. */
.abschnittskopf .grosse-zahl {
    font-size: var(--schrift-xl);
    font-variant-numeric: tabular-nums;
    font-weight: 700;
}

/* --- Auszahlung mit Herkunftsfrage -----------------------------------
   Auswahl, Notiz und Knopf in einer Zeile: Die Frage „woher kommt das
   Geld" gehört an den Knopf, nicht auf eine eigene Seite. Wer sie
   wegklicken muss, klickt sie weg. */
.auszahlform {
    display: flex; gap: var(--raum-1); align-items: center;
    flex-wrap: wrap; justify-content: flex-end;
}
.auszahlform select,
.auszahlform input { font-size: var(--schrift-s); padding: var(--raum-1); }
.auszahlform input { max-width: 10rem; }

/* ======================================================================
   DER BERICHT
   ======================================================================
   Eine stumpfe Schleife über die Berichtsstruktur braucht Regeln, die für
   JEDEN Abschnitt gelten – nicht für einen bestimmten. Deshalb steht hier
   nichts, was nur zu Abschnitt 7 passt. */

.berichtskopf { border-left: 4px solid var(--akzent); }

.berichtsabschnitt { scroll-margin-top: var(--raum-6); }

/* Der Absichtssatz unter jeder Überschrift. Kursiv und leise: Er ist eine
   Einordnung, keine Aussage – wer die Zahlen sucht, soll ihn überspringen
   können, wer auf Seite 27 einsteigt, findet ihn trotzdem. */
.absicht {
    color: var(--text-leise); font-style: italic;
    margin: 0 0 var(--raum-3); max-width: 60ch;
}

.inhaltsliste {
    columns: 2; column-gap: var(--raum-6);
    margin: 0; padding-left: var(--raum-5);
}
.inhaltsliste li { break-inside: avoid; margin-bottom: var(--raum-1); }
.inhaltsliste a { color: inherit; }

/* Tabellen scrollen in ihrem EIGENEN Rahmen. Ohne das schiebt eine breite
   Tabelle die ganze Seite nach rechts, und dann ist auf dem Handy auch die
   Navigation weg. */
.tabellenrahmen { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Der Rahmen allein reicht nicht.
   Eine Tabelle nimmt sich von selbst die Breite ihres Behälters und
   quetscht dafür die Spalten – bei 320 px so weit, dass „1× Cola 0,5 l"
   in einer 33 px schmalen Spalte SENKRECHT läuft, ein Buchstabe je Zeile.
   Genau das hat der Betreiber schon einmal gemeldet.
   Bisher hing der Schutz an `.berichtstabelle`; wer eine Tabelle ohne
   diese Klasse schrieb, bekam den Fehler zurück. Also gilt er jetzt für
   JEDE Tabelle im Rahmen – dafür ist der Rahmen ja da. */
.tabellenrahmen table { width: 100%; }
.tabellenrahmen th, .tabellenrahmen td { white-space: nowrap; }
/* Ausnahme für Freitext: Ein langer Grund darf umbrechen, sonst wäre die
   Tabelle meterbreit. Aber erst ab einer Breite, bei der noch Wörter
   nebeneinander stehen – das ist der Unterschied zum Zerquetschen. */
.tabellenrahmen td.freitext { white-space: normal; min-width: 11rem; }

.berichtstabelle {
    width: 100%; border-collapse: collapse;
    font-size: var(--schrift-s);
}
.berichtstabelle th,
.berichtstabelle td {
    padding: var(--raum-2); text-align: left;
    border-bottom: 1px solid var(--rand);
    white-space: nowrap;
}
.berichtstabelle th {
    font-weight: 650; color: var(--text-leise);
    font-size: var(--schrift-xs); text-transform: uppercase;
    letter-spacing: .03em;
}
/* Zebrastreifen statt Gitternetz: Ein volles Gitter zerlegt eine Tabelle in
   Kästchen, und das Auge verliert die Zeile. */
.berichtstabelle tbody tr:nth-child(even) { background: var(--flaeche-hoch); }
.berichtstabelle tfoot td {
    font-weight: 700; border-top: 2px solid var(--rand); border-bottom: none;
}
.berichtstabelle .rechts { text-align: right; font-variant-numeric: tabular-nums; }

/* --- Balken ---------------------------------------------------------
   Ohne Zeichenfläche: drei Kästchen nebeneinander. Das sieht in HTML und
   im PDF gleich aus, und genau darum geht es. */
.balkenreihe { display: flex; flex-direction: column; gap: var(--raum-1); }
.balkenzeile {
    display: grid;
    /* `min(6rem, 100%)` statt `6rem`: Bei 320 px Breite und einem langen
       Artikelnamen sprengte eine harte Untergrenze sonst die Zeile, und die
       ganze Seite schöbe sich nach rechts. */
    grid-template-columns: minmax(min(6rem, 100%), 12rem) 1fr auto;
    gap: var(--raum-2); align-items: center; font-size: var(--schrift-s);
}
.balkenname { color: var(--text-leise); overflow: hidden;
              text-overflow: ellipsis; white-space: nowrap; }
.balkenspur { background: var(--flaeche-hoch); border-radius: var(--rund-s);
              height: 1.1rem; overflow: hidden; }
.balkenfuellung { display: block; height: 100%; background: var(--akzent);
                  border-radius: var(--rund-s); }
.balkenwert { font-variant-numeric: tabular-nums; font-weight: 650; }

.lueckenliste { padding-left: var(--raum-5); color: var(--text-leise); }
.lueckenliste li { margin-bottom: var(--raum-2); max-width: 70ch; }

/* --- Unterschriften -------------------------------------------------
   Ein Bericht, der zur Kenntnis genommen werden soll, braucht eine Stelle
   dafür. Auf Papier ist das eine Linie; am Bildschirm sieht sie genauso
   aus, damit die Druckvorschau nicht überrascht. */
.unterschriftsfeld {
    display: flex; flex-direction: column; gap: var(--raum-1);
    margin-top: var(--raum-6);
}
.unterschriftsfeld .linie {
    display: block; border-bottom: 1px solid var(--text-leise);
    height: 2rem;
}
.unterschriftsfeld .beschriftung {
    font-size: var(--schrift-xs); color: var(--text-leise);
}
.unterschriften { break-inside: avoid; }

@media (max-width: 559px) {
    .inhaltsliste { columns: 1; }
    .balkenzeile { grid-template-columns: minmax(min(4rem, 100%), 7rem) 1fr auto; }
}


/* =====================================================================
   FUNKTIONSKATALOG — „Was kann das System?"
   =====================================================================
   Der Anlass steht in app/dienste/funktionen.py: 92 Adressen, an denen
   man etwas tun kann, gegen 26 Menüpunkte. Karten statt einer Liste,
   weil man hier sucht und nicht liest. */
.funktionssuche {
    display: flex; align-items: center; gap: var(--raum-2);
    margin-block: var(--raum-4) var(--raum-5);
    max-width: 32rem;
}
.funktionssuche .symbol { width: 20px; height: 20px; color: var(--text-leise);
                          flex: 0 0 20px; }
.funktionsgruppe { margin-bottom: var(--raum-6); }
.funktionsraster {
    display: grid; gap: var(--raum-3);
    grid-template-columns: repeat(auto-fill, minmax(min(17rem, 100%), 1fr));
}
.funktionskarte {
    display: flex; flex-direction: column; gap: var(--raum-1);
    padding: var(--raum-4);
    background: var(--flaeche); border: 1px solid var(--rand);
    border-radius: var(--rund-m); box-shadow: var(--schatten-1);
    text-decoration: none; color: inherit;
    transition: border-color var(--tempo-schnell) var(--kurve);
}
.funktionskarte:hover { border-color: var(--akzent); }
.funktionskarte .n { font-weight: 650; }
.funktionskarte .s { font-size: var(--schrift-s); color: var(--text-leise); }
/* Der WEG dorthin – das ist der eigentliche Zweck dieser Seite. */
.funktionskarte .w {
    margin-top: var(--raum-1); font-size: var(--schrift-xs);
    color: var(--akzent); font-weight: 600;
}

/* Der Hinweis auf der Startseite. Ein Katalog, den man nicht findet, hilft
   niemandem – deshalb steht der Weg dorthin genau dort, wo jeder Tag
   anfängt. Kein Menüpunkt unter zwanzig, sondern ein eigener Streifen. */
.entdecken {
    display: flex; align-items: center; gap: var(--raum-3);
    padding: var(--raum-4); margin-bottom: var(--raum-5);
    background: var(--akzent-zart); border: 1px solid var(--akzent-rand);
    border-radius: var(--rund-m);
    text-decoration: none; color: inherit;
}
.entdecken .symbol { width: 24px; height: 24px; flex: 0 0 24px;
                     color: var(--akzent); }
.entdecken .t { font-weight: 650; }
.entdecken .u { font-size: var(--schrift-s); color: var(--text-leise); }
.entdecken .pfeil { margin-left: auto; color: var(--akzent); flex: 0 0 auto; }
.entdecken:hover { border-color: var(--akzent); }

/* --- „Geht zur Neige" auf der Startseite ------------------------------
   Karten statt einer Tabelle: Die Frage ist nicht „wie viele Artikel",
   sondern „welcher zuerst" – und dafür muss jeder Artikel einzeln ins
   Auge fallen. Eine Tabellenzeile tut das nicht.

   Der Zustand steht als Marke da und nicht nur als Farbe: Rot und Gelb
   allein unterscheidet nicht jeder. */
.neigeraster {
    display: grid; gap: var(--raum-3);
    grid-template-columns: repeat(auto-fill, minmax(min(13rem, 100%), 1fr));
}
/* Bild LINKS, Text rechts. Das Foto stand vorher gar nicht auf der
   Kachel - der Betreiber: "auf der startseite bei geht zur neige fehlt
   das produkt bild". Es gehoert dorthin aus demselben Grund wie an der
   Kasse: Wer einkaufen faehrt, sucht im Regal nach einem Aussehen.

   `align-items: center` und keine feste Hoehe: Die Kachel ist so hoch
   wie ihr laengster Text, und ein 46px-Bild daneben bleibt mittig -
   auch wenn ein Produktname umbricht. */
.neigekarte {
    display: flex; flex-direction: row; align-items: center;
    gap: var(--raum-3);
    padding: var(--raum-3);
    background: var(--flaeche); border: 1px solid var(--rand);
    border-left: 4px solid var(--gelb);
    border-radius: var(--rund-m);
}
/* `min-width: 0` ist hier Pflicht, kein Feinschliff: Ein Flex-Kind
   schrumpft sonst nicht unter seinen Inhalt, und ein langer Produktname
   ohne Leerzeichen schoebe die Kachel aus dem Raster. Bei 320 px faellt
   das sofort auf. */
.neigekarte .neigetext {
    display: flex; flex-direction: column; gap: var(--raum-1);
    min-width: 0; flex: 1 1 auto;
}
.neigekarte .produktbild { flex: 0 0 auto; }
.neigekarte.leer { border-left-color: var(--rot); }
.neigekarte .n { font-weight: 650; overflow-wrap: anywhere; }
.neigekarte .u { font-size: var(--schrift-xs); color: var(--text-leise); }

/* Eine lange Adresse, die umbrechen darf.
   Eine Datenbankadresse wie mysql+pymysql://kiosk:GEHEIM@127.0.0.1/… hat
   keine Leerzeichen. Ohne diese Regel schiebt sie bei 320 px die ganze
   Seite nach rechts - gemessen: 33 px Überlauf auf der Systemseite. */
code.umbrechend { overflow-wrap: anywhere; word-break: break-all; }


/* =====================================================================
   AUS kasse.css UMGEZOGEN (Runde 5)

   Diese drei Bloecke standen in `kasse.css` und werden AUSSERHALB der
   Kasse gebraucht: das Produktbild auf /produkte und im Produktformular,
   das Zaehlraster im Tagesabschluss und in der Tresorpruefung, das
   Sortenfeld im Produktformular.

   Genau deshalb musste `kasse.css` bisher auf JEDER Seite mitladen - 46 KB
   fuer drei Bloecke. Und weil es nach `stil.css` laedt, gewann es bei
   Gleichstand; die Feldregel im Zaehlfeld musste den ganzen vierfachen
   `:not(...)`-Selektor nachbauen, nur um dieselbe Spezifitaet zu erreichen.
   Hier steht sie an ihrem Platz und braucht das nicht mehr.

   UMGEZOGEN, nicht kopiert: `test_keine_klasse_bedeutet_zweierlei` verbietet
   zwei Grundregeln fuer denselben Namen - und zu Recht. Zwei Wahrheiten
   ueber dieselbe Klasse laufen auseinander, sobald jemand eine davon
   anfasst.
   ===================================================================== */

/* =================================================================
   PRODUKTBILDER
   ================================================================= */
/* Die Bildflaeche ist IMMER quadratisch, egal was hochgeladen wurde.
   `aspect-ratio` allein hat dafuer nicht gereicht: Solange das <img> die
   Attribute width/height trug, galt eine festgelegte Hoehe und die Regel
   wurde uebergangen - die Kachel wurde ueber 500 px hoch. Die Attribute sind
   raus (siehe teile/produktbild.html), und `height: auto` steht hier
   ausdruecklich - genau das ist die Bedingung, unter der `aspect-ratio`
   ueberhaupt wirkt. Wer eines von beiden wieder anfasst, bricht es erneut;
   deshalb haelt eine Pruefung die Kachelhoehen fest.

   `contain` statt `cover`: Getraenke sind hochkant. Ein quadratischer
   Zuschnitt zeigte vom Etikett nur die Mitte - auf einer kleinen Kachel
   nicht mehr erkennbar. Gespeichert ist das Bild ohnehin schon quadratisch
   mit weissem Rand (app/dienste/bilder.py). */
.produktbild {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    border-radius: 8px;
    background: var(--flaeche-hoch);
}
/* Ersatzfeld, wenn kein Foto da ist: Kategoriefarbe + Initialen.
   Nichts wird erzeugt, nichts nachgeladen – ein Produkt ohne Bild
   kostet null zusätzliche Abrufe. */
.produktbild.ersatz {
    background: linear-gradient(160deg, rgba(255,255,255,.20), rgba(0,0,0,.20)),
                var(--kat, #2F5597);
    color: var(--schrift, #fff);
    display: grid; place-items: center;
    font-weight: 700; font-size: 1.6rem; letter-spacing: .02em;
}
.produktbild.klein { width: 46px; height: 46px; border-radius: 6px; }
.produktbild.klein.ersatz { font-size: .8rem; }

/* =================================================================
   ZÄHLRASTER (Kassenprüfung)
   Vierzehn Nominale, die mit dem Daumen zu treffen sein müssen.
   ================================================================= */
.zaehlraster {
    display: grid; gap: .5rem; margin: 1rem 0;
    grid-template-columns: repeat(auto-fill, minmax(min(5.5rem, 100%), 1fr));
}
/* Bezeichnung OBEN, Eingabefeld darunter über die ganze Zellbreite.

   Vorher standen beide nebeneinander: Die Bezeichnung beanspruchte
   3,4 rem, und vom Rest der 6,5-rem-Zelle blieben dem Feld **26 px**.
   Darin steckten noch die Pfeilchen von `type=number` – zum Tippen blieb
   ein Streifen von wenigen Pixeln, und die eingegebene Zahl verschwand
   dahinter. Man KONNTE tippen; sehen und treffen konnte man es nicht.

   Beim Kassenzählen tippt jemand vierzehn Zahlen hintereinander ein. Das
   Feld ist hier die Hauptsache, nicht die Beschriftung. */
.zaehlfeld {
    display: flex; flex-direction: column; align-items: stretch; gap: .25rem;
    /* Nicht #fff: Das war im Dunkelmodus ein grelles weißes Feld in einer
       dunklen Seite, und `--akzent` darauf kam auf 3,78:1. Vierzehn davon
       nebeneinander – beim Kassenzählen sieht man auf nichts anderes. */
    background: var(--flaeche); border: 1px solid var(--rand);
    border-radius: var(--rund-m); padding: .45rem .55rem;
}
.zaehlfeld .nominal {
    font-weight: 700; font-size: .8rem; color: var(--akzent);
    white-space: nowrap;
}
/* Gleiche Gewichtung wie die Feldregel in stil.css – sonst gewinnen deren
   `padding` und `border` und die Zelle wird doppelt gerahmt. */
.zaehlfeld input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=hidden]) {
    width: 100%; min-width: 0; border: 0; padding: .1rem .15rem;
    min-height: 40px; background: none;
    font-size: 1.25rem; font-weight: 650; font-family: inherit;
    text-align: right; font-variant-numeric: tabular-nums;
}
.zaehlfeld input:focus { outline: 2px solid var(--akzent-hell); border-radius: 4px; }
/* Die Pfeilchen weg: Bei dieser Feldbreite waren sie zehn Pixel breit,
   verdeckten die Ziffern und liessen sich mit dem Finger ohnehin nicht
   treffen. Am Handy blenden Browser sie von sich aus aus – am Rechner
   standen sie im Weg. Getippt wird hier, nicht geklickt. */
.zaehlfeld input::-webkit-outer-spin-button,
.zaehlfeld input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.zaehlfeld input[type=number] { -moz-appearance: textfield; appearance: textfield; }

/* Sorten und Mengenrabatt im Produktformular – aufklappbar, weil beides
   die Ausnahme ist: Die meisten Produkte haben weder das eine noch das
   andere, und zwei Dauerfelder dafür machten das Formular länger, ohne
   irgendwem zu helfen. */
.sortenfeld {
    border: 1px solid var(--rand); border-radius: var(--rund-m);
    padding: var(--raum-3); margin-block: var(--raum-3);
    background: var(--flaeche-hoch);
}
.sortenfeld > summary {
    cursor: pointer; font-weight: 600; font-size: var(--schrift-s);
    padding: var(--raum-1) 0;
}
.sortenfeld[open] > summary { margin-bottom: var(--raum-3); }
