/* ==========================================================================
   BAUWAGEN Kasse — components.css
   Jeder wiederkehrende Baustein genau einmal.
   Regeln, die hier ohne Ausnahme gelten:
     · kein box-shadow (§1.1)
     · Radius max. 6px, keine Pillen, keine Kreise (§1.2)
     · Tiefe nur durch Tastenhub: drückbar = 3px untere Kante,
       nicht drückbar = keine untere Kante (§1.3)
     · Versalien nur auf dem 11px-Schild (§1.6)
     · Zahlen Mono, Text Atkinson (§1.7)
   ========================================================================== */

/* ==========================================================================
   1. TASTENHUB — die einzige Tiefenlösung (§5, §9)
   Gemeinsame Mechanik für alles Drückbare.

   Beim Einsinken schrumpft die Kante von 3px auf 1px. Damit die Taste dabei
   nicht 2px flacher wird und alles darunter hochrutscht, wandern genau diese
   2px in den unteren Innenabstand: padding-bottom = --pb + 2px.
   Border und Padding liegen beide außerhalb des Inhaltskastens, der obere
   Innenabstand bleibt unangetastet — der Inhalt bewegt sich dadurch
   kein Stück gegenüber der Taste. Bewegt wird nur die Taste selbst,
   um translateY(2px).

   Jede drückbare Komponente meldet ihren unteren Innenabstand als --pb an.
   ========================================================================== */
.taste,
.zeile--taste,
.chip,
.plaettchen,
.kippschalter__feld,
.ziffernblock__taste {
  position: relative;
  display: flex;
  align-items: center;
  background: var(--key);
  color: var(--ink);
  border: var(--kante-fein) solid var(--rule);
  border-bottom: var(--kante) solid var(--rule-hard);
  border-radius: var(--r-taste);
  cursor: pointer;
  transition:
    transform var(--t-taste-aus) var(--e-taste),
    border-bottom-width var(--t-taste-aus) var(--e-taste),
    padding-bottom var(--t-taste-aus) var(--e-taste),
    background-color var(--t-taste-aus) var(--e-taste);
}

.taste:active,
.zeile--taste:active,
.chip:active,
.plaettchen:active,
.kippschalter__feld:active,
.ziffernblock__taste:active,
.taste[data-gedrueckt],
.zeile--taste[data-gedrueckt],
.chip[aria-pressed="true"],
.kippschalter__feld[aria-checked="true"] {
  transform: translateY(2px);
  border-bottom-width: var(--kante-fein);
  padding-bottom: calc(var(--pb, 0px) + 2px);
  background: var(--key-down);
  transition-duration: var(--t-taste-ein);
  transition-timing-function: var(--e-linear);
}

/* Ausgeschaltet heißt nicht ausgegraut (§8.5): es gibt keine .taste[disabled]
   mit opacity. Wo etwas nicht geht, steht ein Satz oder ein PIN-Riegel.
   Einzige Ausnahme: Blindfelder im Ziffernblock.                            */
.taste[disabled] {
  cursor: default;
  color: var(--ink-muted);
  border-bottom-width: var(--kante-fein);
  padding-bottom: calc(var(--pb, 0px) + 2px);
  background: var(--panel);
}

/* --- Grundtaste, freistehend (Sheets, Formulare) -------------------------- */
.taste {
  --pb: var(--zeile-y);
  justify-content: center;
  gap: var(--s8);
  min-height: var(--h-druck);
  padding: var(--zeile-y) var(--zeile-x);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 700;
  line-height: var(--lh-eng);
  text-align: center;
}

.taste--breit { width: 100%; }

.taste--signal {
  background: var(--signal);
  color: var(--signal-ink);
  border-color: var(--signal);
  border-bottom-color: var(--rule-hard);
}
.taste--signal:active { background: var(--signal); }

.taste--gefahr { color: var(--rot); }
.taste--gut    { color: var(--gruen); }

/* --- Zapftaste — vollbreit, 96px, radiuslos (§5, §7.2) -------------------- */
.taste--zapf {
  --pb: var(--s16);
  display: flex;
  align-items: center;
  gap: var(--s12);
  width: 100%;
  min-height: var(--h-zapf);
  padding: var(--s16) max(var(--s16), env(safe-area-inset-right))
           var(--s16) max(var(--s16), env(safe-area-inset-left));
  border-left: 0;
  border-right: 0;
  border-top: 0;
  border-radius: var(--r-null);
  text-align: left;
}

.taste__name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-text);
  font-size: var(--fs-gross);
  font-weight: 700;
  line-height: var(--lh-eng);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.taste__preis {
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  font-weight: 500;
  line-height: var(--lh-eng);
  white-space: nowrap;
}

/* Harter Farbsprung beim Buchen — 0 ms, keine Transition (§8.1). */
.taste--zapf:active .taste__name,
.taste--zapf:active .taste__preis {
  color: var(--signal);
  transition: none;
}

/* Fremdes Buchungsziel: durchgehende 3px-Signal-Oberkante über den Zapftasten
   (§7.3). Als Auflage, damit sich die Höhe nicht ändert.                    */
.taste--zapf::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--kante);
  background: var(--signal);
  display: none;
}

/* ==========================================================================
   2. ZEILE — die Platte, nicht das Dokument (§5)
   .zeile        · nicht drückbar, 1px Haarlinie, keine untere Kante
   .zeile--taste · drückbar, Tastenoberfläche, 3px Kante
   ========================================================================== */
.platte {
  background: var(--panel);
}

/* Flex, nicht Grid: eine Zeile darf 2, 3 oder 4 Kinder haben, ohne dass
   irgendwer Spaltenzahlen nachziehen muss. .zeile__haupt nimmt den Rest.  */
.zeile {
  --pb: var(--zeile-y);
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s12);
  width: 100%;
  min-height: var(--h-druck);
  padding: var(--zeile-y) max(var(--zeile-x), env(safe-area-inset-right))
           var(--zeile-y) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
  text-align: left;
}

.zeile--taste {
  display: flex;
  background: var(--key);
  border: 0;
  border-bottom: var(--kante) solid var(--rule-hard);
  border-radius: var(--r-null);
}

.zeile__haupt {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  min-width: 0;
}

.zeile__name {
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 400;
  line-height: var(--lh-eng);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.zeile__name--stark { font-weight: 700; }

.zeile__meta {
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  line-height: var(--lh-eng);
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.zeile__betrag {
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  font-weight: 500;
  line-height: var(--lh-eng);
  white-space: nowrap;
}

.zeile__pfeil {
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  line-height: 1;
  color: var(--ink-muted);
}

.zeile__zeit,
.zeile__betrag,
.zeile__pfeil,
.zeile__marke {
  flex: 0 0 auto;
}

/* --- Kantenstreifen — offener Betrag (§7.5, §7.6) ------------------------- */
.kante {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--kantenstreifen);
  background: var(--rot);
  transform-origin: bottom center;
  transform: scaleY(1);
  pointer-events: none;
}

.kante--gruen { background: var(--gruen); }

/* Abrechnen: der Streifen läuft von unten heraus (§7.6).
   Die Staffelung setzt JS über --verzug per CSSOM.                          */
.kante--leert {
  transform: scaleY(0);
  transition: transform var(--t-kante-weg) var(--e-taste);
  transition-delay: var(--verzug, 0ms);
}

/* --- Typbalken — Kassenbuch (§7.7) ---------------------------------------- */
.typbalken {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--kante);
  background: var(--rule);
  pointer-events: none;
}

[data-typ="storno"]  > .typbalken { background: var(--rot); }
[data-typ="bezahlt"] > .typbalken { background: var(--gruen); }
[data-typ="leute"]   > .typbalken { background: var(--blau); }
[data-typ="preise"]  > .typbalken { background: var(--blau); }
[data-typ="pinfehler"] > .typbalken {
  width: var(--kantenstreifen);
  background: var(--rot);
}

/* ==========================================================================
   3. SCHILD — 11px, Versalien, immer über einer 1px-Linie (§3)
   Das einzige Versalien-Element der App.
   ========================================================================== */
.schild {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s8);
  padding: var(--s16) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s8) max(var(--zeile-x), env(safe-area-inset-left));
  border-bottom: var(--kante-fein) solid var(--rule);
  background: var(--bg);
  /* --ink, nicht --ink-muted: 11px ist die kleinste Schrift der App und
     --ink-muted auf --bg käme im Tagbetrieb nur auf 3,6:1. Die Hierarchie
     macht hier die Größe, nicht die Dämpfung (§3).                        */
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--fs-schild);
  font-weight: 700;
  line-height: var(--lh-eng);
  letter-spacing: var(--spur-schild);
  text-transform: uppercase;
}

/* Buchungsziel ist jemand anderes (§7.3): das Schild steht in --signal.
   Als gefüllter Streifen statt als orangefarbener Text — orange auf --bg
   sind 2,6:1, das ist bei 11px unlesbar. Gefüllt trägt es die Signalfarbe
   deutlicher und bleibt lesbar.                                           */
.schild--signal {
  background: var(--signal);
  color: var(--signal-ink);
  border-bottom-color: var(--signal);
}
.schild--signal .schild__zusatz { color: var(--signal-ink); }

/* Feldlabel: gleiche Marke, ohne Linie. */
.schild--feld {
  display: block;
  padding: 0 0 var(--s8);
  border-bottom: 0;
  background: none;
}

/* Tagestrenner im Kassenbuch: 2px statt 1px (§7.7). */
.schild--tag {
  border-bottom-width: 2px;
  border-bottom-color: var(--ink-muted);
  color: var(--ink);
  padding-top: var(--s24);
}

.schild__zusatz {
  font-family: var(--font-num);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}

/* ==========================================================================
   4. NAMENSSCHILD — Personen ohne Avatare (§6)
   44x44, zweibuchstabiges Monogramm, links ein 4px Farbbalken.
   Die Personenfarbe kommt vom Server und wird per CSSOM gesetzt:
     el.style.setProperty('--person', p.color)
   (Ein style-Attribut im HTML wäre durch die CSP blockiert.)
   ========================================================================== */
.namensschild {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--h-namensschild);
  height: var(--h-namensschild);
  background: var(--key);
  border: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-zeile);
  overflow: hidden;
}

.namensschild__balken {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--kantenstreifen);
  background: var(--person, var(--ink-muted));
}

.namensschild__mono {
  font-family: var(--font-text);
  font-size: var(--fs-monogramm);
  font-weight: 700;
  line-height: 1;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink);
  padding-left: var(--kantenstreifen);
}

.namensschild--klein {
  width: 28px;
  height: 28px;
}
.namensschild--klein .namensschild__mono {
  font-size: var(--fs-schild);
}

/* ==========================================================================
   5. NAMENSSCHIENE — wer bucht (§7.3)
   Waagerecht scrollbar, kein Timer, kein Selbstumbau.
   ========================================================================== */
.schiene {
  display: flex;
  align-items: stretch;
  gap: var(--s8);
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--bg);
}

.plaettchen {
  --pb: var(--s8);
  flex: 0 0 auto;
  display: flex;
  align-items: stretch;
  gap: var(--s8);
  min-width: 84px;
  max-width: 168px;
  min-height: var(--h-plaettchen);
  padding: var(--s8) var(--s12);
  border-radius: var(--r-taste);
}

.plaettchen__balken {
  flex: 0 0 auto;
  width: var(--kantenstreifen);
  background: var(--person, var(--ink-muted));
}

.plaettchen__text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--s4);
}

.plaettchen__name {
  max-width: 100%;
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 400;
  line-height: var(--lh-eng);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Aktives Buchungsziel: Signalrahmen, solange es gilt (§7.3). */
.plaettchen--aktiv {
  border-color: var(--signal);
  border-bottom-color: var(--signal);
}
.plaettchen--aktiv .plaettchen__name {
  font-weight: 700;
  color: var(--signal);
}

/* Person hat heute schon gebucht: 8px-Quadrat in Grün (§7.3),
   abgeleitet aus lastEntryAt — kein neues Datenfeld.                       */
.plaettchen--neu,
.plaettchen--zurueck {
  align-items: center;
  justify-content: center;
  text-align: center;
  min-width: 64px;
}
.plaettchen--neu .plaettchen__text,
.plaettchen--zurueck .plaettchen__text {
  align-items: center;
}

.plaettchen__plus {
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  font-weight: 500;
  line-height: 1;
}

.plaettchen--zurueck {
  min-width: 108px;
  border-color: var(--signal);
  border-bottom-color: var(--signal);
  color: var(--signal);
}
.plaettchen--zurueck .plaettchen__name {
  font-size: var(--fs-meta);
  font-family: var(--font-text);
  white-space: normal;
  text-align: center;
}

/* ==========================================================================
   6. ZÄHLWERK — Ziffernrolle (§7.2, §9)
   Aufbau, den mountOdometer() erzeugt:
     .zaehlwerk__betrag > .ziffer[.ziffer--fest] > .ziffer__rolle > .ziffer__glyph
   JS setzt pro Ziffer --pos (0..9) und --verzug (25ms Versatz von rechts).
   ========================================================================== */
/* Das Zählwerk sitzt auf --panel, nicht auf --bg: es ist eine Anzeige, die
   in die Maschine eingelassen ist — und --ink-muted ist erst auf --panel
   sicher lesbar (4,6:1 statt 3,6:1).                                      */
.zaehlwerk {
  display: flex;
  flex-direction: column;
  gap: var(--s8);
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s16) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
}

.zaehlwerk__kopf {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s12);
}

.zaehlwerk__betrag {
  display: flex;
  align-items: flex-start;
  font-family: var(--font-num);
  font-size: var(--fs-werk);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
  height: var(--zw-h);
}

.zaehlwerk__betrag--leer { color: var(--ink-muted); }

.zaehlwerk__zusatz {
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  line-height: var(--lh-eng);
  color: var(--ink-muted);
  white-space: nowrap;
}

.ziffer {
  position: relative;
  display: block;
  width: 1ch;
  height: var(--zw-h);
  overflow: hidden;
}

/* Komma, schmales Leerzeichen, Euro-Zeichen, Minus: stehen fest. */
.ziffer--fest {
  width: auto;
  line-height: var(--zw-h);
  text-align: center;
}

.ziffer__rolle {
  display: block;
  transform: translate3d(0, calc(var(--pos, 0) * var(--zw-h) * -1), 0);
  transition: transform var(--t-ziffer) var(--e-ziffer);
  transition-delay: var(--verzug, 0ms);
  will-change: transform;
}

.ziffer__glyph {
  display: block;
  height: var(--zw-h);
  line-height: var(--zw-h);
  text-align: center;
}

/* Kleines Zählwerk im Person-Sheet (§7.6).
   Zwei Wege zum selben Ziel: --klein am Rahmen, wenn das ganze Zählwerk
   klein ist; --klein direkt am Betrag, weil mountOdometer() nur dieses
   eine Element bekommt.                                                   */
.zaehlwerk--klein {
  gap: var(--s4);
  padding: 0;
  background: none;
  border-bottom: 0;
}
.zaehlwerk--klein .zaehlwerk__betrag,
.zaehlwerk__betrag--klein {
  --zw-h: var(--zw-h-klein);
  font-size: var(--fs-gross);
  font-weight: 500;
  height: var(--zw-h-klein);
}

/* ==========================================================================
   7. STRICHLISTE — 4er-Bündel plus Querstrich, Hohlstrich für Wartende (§7.4)
   Aufbau, den renderTally() erzeugt:
     .strichliste > .buendel > .strich (x4) + .strich--quer
   ========================================================================== */
.strichliste {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s8) var(--s12);
  min-height: var(--strich-h);
  color: var(--ink);
}

.buendel {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--strich-lueck);
  height: var(--strich-h);
}

.strich {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: var(--strich-b);
  height: var(--strich-h);
  background: currentColor;
  border: 0 solid currentColor;
  border-radius: var(--r-null);
  transition:
    background-color var(--t-fuellen) var(--e-linear),
    border-width var(--t-fuellen) var(--e-linear),
    opacity var(--t-fuellen) var(--e-linear);
}

/* Überhang, wenn mehr Striche da sind als die Zeile fasst: „+12".
   Eine Zahl, also Mono — kein weiteres Symbol.                            */
.strich-mehr {
  flex: 0 0 auto;
  align-self: center;
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  font-weight: 500;
  line-height: var(--lh-eng);
  color: var(--ink-muted);
  white-space: nowrap;
}

/* Der fünfte Strich liegt quer über dem Bündel und nimmt keinen Platz. */
.strich--quer {
  position: absolute;
  left: -2px;
  right: -2px;
  top: 50%;
  width: auto;
  height: var(--strich-b);
  margin-top: calc(var(--strich-b) / -2);
  transform: rotate(-20deg);
}

/* HOHLSTRICH: liegt noch in der Warteschlange (§7.4).
   Umriss statt Fläche. 1px Rahmen, weil ein 3px breites Element mit 2px
   Rahmen auf beiden Seiten wieder voll wäre — der Umriss ist der Punkt.  */
.strich--hohl {
  background: transparent;
  border-width: 1px;
  opacity: .55;
}

/* Neuer Strich fliegt ein (§9). */
.strich--neu {
  animation: strich-ein var(--t-strich) var(--e-strich) both;
}

@keyframes strich-ein {
  from { transform: translateX(14px); opacity: 0; }
  to   { transform: translateX(0);    opacity: 1; }
}

.strich--quer.strich--neu {
  animation-name: strich-ein-quer;
}

@keyframes strich-ein-quer {
  from { transform: rotate(-20deg) translateX(14px); opacity: 0; }
  to   { transform: rotate(-20deg) translateX(0);    opacity: 1; }
}

/* Storniert: durchgestrichen, dann weg (§8.2). */
.strich--weg {
  animation: strich-weg 200ms var(--e-linear) both;
}
.strich--weg::after {
  content: "";
  position: absolute;
  left: -3px;
  right: -3px;
  top: 50%;
  height: 1px;
  background: var(--rot);
}

@keyframes strich-weg {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* ==========================================================================
   8. STATUSLEISTE + STATUSQUADRAT (§7.1, §6)
   ========================================================================== */
/* Wie die Tab-Leiste eine Leiste: --panel, Radius 0. Dadurch ist auch
   --ink-muted im Tagbetrieb sicher lesbar.                                */
.statusleiste {
  position: relative;
  z-index: 3;
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-null);
  padding-top: env(safe-area-inset-top);
}

.statusleiste__flaeche {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s8);
  width: 100%;
  height: var(--h-status);
  padding: 0 max(var(--zeile-x), env(safe-area-inset-right))
           0 max(var(--zeile-x), env(safe-area-inset-left));
  background: none;
  border: 0;
}

/* Die Leiste ist 28px hoch (§7.1), die Trefferfläche muss 44px haben (§5).
   Deshalb wird sie unsichtbar verlängert: 6px nach oben in die Safe-Area
   hinein und 16px nach unten. 28+16 = 44 auch dann, wenn oben nichts mehr
   ist. Unter der Leiste beginnt jeder Screen mit mindestens 16px Luft
   (Schild bzw. Chipreihe), dort liegt nichts Drückbares.                   */
.statusleiste__flaeche::after {
  content: "";
  position: absolute;
  top: -6px;
  bottom: -16px;
  left: 0;
  right: 0;
}

.statusleiste__name {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-text);
  font-size: var(--fs-meta);
  font-weight: 700;
  line-height: var(--lh-eng);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.statusleiste__lage {
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  line-height: var(--lh-eng);
  color: var(--ink-muted);
  white-space: nowrap;
}

/* Admin aktiv: Wortmarke links vom Raumnamen (§8.5).
   Ein Wort, kein Piktogramm (§1.4). Kein Balken über den Bildschirm.       */
.schluesselmarke {
  padding: 2px var(--s4);
  border-radius: var(--r-zeile);
  background: var(--gelb);
  color: var(--gelb-ink);
  font-family: var(--font-text);
  font-size: var(--fs-schild);
  font-weight: 700;
  line-height: var(--lh-eng);
  letter-spacing: var(--spur-schild);
  text-transform: uppercase;
  white-space: nowrap;
}

/* Status ohne Icons: ein Quadrat, nie ein Kreis (§6). */
.statusquadrat {
  display: block;
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  background: var(--ink-muted);
  border-radius: var(--r-null);
}

.statusquadrat--gruen { background: var(--gruen); }
.statusquadrat--gelb  { background: var(--gelb); }
.statusquadrat--rot   { background: var(--rot); }

/* ==========================================================================
   9. TAB-LEISTE — die vier Marken, immer mit ihrem Wort (§6, §7.2)
   JS setzt den Index der aktiven Registerkarte per CSSOM:
     tableiste.style.setProperty('--tab', '2')
   ========================================================================== */
.tableiste {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--panel);
  border-top: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-null);
  padding-bottom: env(safe-area-inset-bottom);
}

.tableiste__knopf {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  min-height: var(--h-tab);
  padding: var(--s8) var(--s4);
  color: var(--ink-muted);
  background: none;
  border: 0;
}

.tableiste__knopf:active { background: var(--key-down); }

.tableiste__knopf[aria-current="page"] { color: var(--ink); }

.tableiste__marke {
  display: block;
  width: 24px;
  height: 24px;
}

.tableiste__marke svg {
  width: 24px;
  height: 24px;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: square;
  stroke-linejoin: miter;
  fill: none;
}

.tableiste__wort {
  font-family: var(--font-text);
  font-size: var(--fs-schild);
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--spur-schild);
  text-transform: uppercase;
}

/* Die einzige gleitende Bewegung der App (§9). */
.tableiste__balken {
  position: absolute;
  top: 0;
  left: 0;
  width: 25%;
  height: var(--kante);
  background: var(--signal);
  transform: translateX(calc(var(--tab, 0) * 100%));
  transition: transform var(--t-tab) var(--e-tab);
  pointer-events: none;
}

/* ==========================================================================
   10. STORNO-LEISTE (§7.2, §8.2)
   Fährt hoch, benennt den letzten eigenen Strich, zählt die Restzeit herunter.
   ========================================================================== */
.stornoleiste {
  position: relative;
  z-index: 2;
  background: var(--key);
  border-top: var(--kante) solid var(--rule-hard);
  border-radius: var(--r-null);
  transform: translateY(0);
  transition: transform var(--t-storno-ein) var(--e-taste);
}

.stornoleiste--aus {
  transform: translateY(100%);
  transition-duration: var(--t-storno-aus);
}

.stornoleiste__flaeche {
  display: flex;
  align-items: center;
  gap: var(--s12);
  width: 100%;
  min-height: calc(var(--h-storno) - var(--kante));
  padding: var(--s8) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s8) max(var(--zeile-x), env(safe-area-inset-left));
  background: none;
  border: 0;
}

.stornoleiste__flaeche:active { background: var(--key-down); }

.stornoleiste__text {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 400;
  line-height: var(--lh-eng);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.stornoleiste__wort {
  font-weight: 700;
  color: var(--rot);
}

.stornoleiste__zeit {
  font-family: var(--font-num);
  font-size: var(--fs-text);
  font-weight: 500;
  line-height: var(--lh-eng);
  color: var(--ink-muted);
}

/* Restzeit-Balken: transition-duration setzt JS auf die echte Restdauer. */
.stornoleiste__gleis {
  height: var(--kante);
  background: var(--rule);
}

.stornoleiste__balken {
  display: block;
  height: 100%;
  background: var(--rot);
  transform-origin: left center;
  transform: scaleX(var(--rest, 1));
  transition: transform 0ms var(--e-restzeit);
}

/* ==========================================================================
   11. SHEET (§9)
   Aufbau, den openSheet() erzeugt:
     .sheetlage > .backdrop + .sheet
   Mehrere Lagen dürfen übereinander liegen (sheetDepth()).
   Der Backdrop ist die EINZIGE dunkle Vollfläche — kein Blur, kein Schatten.
   ========================================================================== */
.sheetwurzel {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}

.sheetlage {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  pointer-events: auto;
}

.backdrop {
  position: absolute;
  inset: 0;
  background: var(--backdrop);
  opacity: 0;
  transition: opacity var(--t-backdrop) var(--e-linear);
}

.sheet {
  position: relative;
  display: flex;
  flex-direction: column;
  max-height: 88%;
  background: var(--panel);
  border-top: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-taste) var(--r-taste) var(--r-null) var(--r-null);
  transform: translateY(100%);
  transition: transform var(--t-sheet-ein) var(--e-sheet-ein);
  padding-bottom: env(safe-area-inset-bottom);
}

.sheetlage--offen .backdrop { opacity: .55; }
.sheetlage--offen .sheet    { transform: translateY(0); }

.sheetlage--zu .backdrop {
  opacity: 0;
  transition-duration: var(--t-sheet-aus);
}
.sheetlage--zu .sheet {
  transform: translateY(100%);
  transition-duration: var(--t-sheet-aus);
  transition-timing-function: var(--e-sheet-aus);
}

.sheet__kopf {
  display: flex;
  align-items: center;
  gap: var(--s12);
  padding: var(--s16) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  border-bottom: var(--kante-fein) solid var(--rule);
}

.sheet__kopftext {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}

.sheet__titel {
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 700;
  line-height: var(--lh-eng);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Der Anlass steht in der Kopfzeile (§8.5). */
.sheet__anlass {
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  line-height: var(--lh-eng);
  color: var(--ink-muted);
}

.sheet__schliessen {
  flex: 0 0 auto;
  min-width: var(--h-druck);
  padding: var(--zeile-y) var(--s12);
  font-size: var(--fs-meta);
  font-weight: 700;
}

.sheet__koerper {
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.sheet__fuss {
  display: grid;
  gap: var(--s8);
  padding: var(--s16) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s16) max(var(--zeile-x), env(safe-area-inset-left));
  border-top: var(--kante-fein) solid var(--rule);
}

/* ==========================================================================
   12. CHIPS — Filter im Kassenbuch (§7.7)
   Gesetzter Filter = eingesunkene Taste. Das ist dieselbe Mechanik wie
   der Kippschalter: eingesunken heißt „gilt gerade", erhaben heißt „drückbar".
   ========================================================================== */
/* Oben 16px, damit die verlängerte Trefferfläche der Statusleiste keinen
   Chip anknabbert — das Buch ist der einzige Screen, der oben mit etwas
   Drückbarem anfängt.                                                      */
.chipreihe {
  display: flex;
  align-items: center;
  gap: var(--s8);
  padding: var(--s16) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--bg);
}

.chip {
  flex: 0 0 auto;
  justify-content: center;
  min-height: var(--h-druck);
  padding: 0 var(--s16);
  border-radius: var(--r-zeile);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 400;
  line-height: var(--lh-eng);
  color: var(--ink-muted);
  white-space: nowrap;
}

/* Gesetzt = eingesunken + --ink. Bewusst KEIN Fettschnitt: der Chip würde
   dadurch breiter, und die ganze Reihe rutscht unter dem Finger weg.      */
.chip[aria-pressed="true"] {
  color: var(--ink);
}

/* ==========================================================================
   13. KIPPSCHALTER — Tag / Auto / Nacht (§7.8)
   ========================================================================== */
.kippschalter {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s8);
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s16) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--bg);
}

.kippschalter__feld {
  justify-content: center;
  min-height: var(--h-druck);
  padding: 0 var(--s8);
  border-radius: var(--r-taste);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 400;
  line-height: var(--lh-eng);
  color: var(--ink-muted);
}

/* Dieselbe Regel wie beim Chip: eingesunken + --ink, kein Fettschnitt. */
.kippschalter__feld[aria-checked="true"] {
  color: var(--ink);
}

/* ==========================================================================
   14. PIN-RIEGEL — statt Gefahrenstreifen (§8.5)
   Admin-Aktionen stehen an ihrer Stelle, gestrichelt gerahmt, mit der Marke
   PIN. Nicht versteckt, nicht ausgegraut. Strichlänge exakt 4px — deshalb
   Gradienten statt border-style:dashed, das die Strichlänge selbst wählt.
   ========================================================================== */
.riegel::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg, var(--rule) 0 4px, transparent 4px 8px),
    repeating-linear-gradient(90deg, var(--rule) 0 4px, transparent 4px 8px),
    repeating-linear-gradient(180deg, var(--rule) 0 4px, transparent 4px 8px),
    repeating-linear-gradient(180deg, var(--rule) 0 4px, transparent 4px 8px);
  background-size: 100% 1px, 100% 1px, 1px 100%, 1px 100%;
  background-position: left top, left bottom, left top, right top;
  background-repeat: no-repeat;
}

.riegel__marke {
  flex: 0 0 auto;
  padding: 2px var(--s4);
  border-radius: var(--r-zeile);
  background: var(--gelb);
  color: var(--gelb-ink);
  font-family: var(--font-num);
  font-size: var(--fs-schild);
  font-weight: 700;
  line-height: var(--lh-eng);
  letter-spacing: var(--spur-schild);
}

/* Wo eine Aktion ganz und gar Jojos ist, steht ein Satz statt eines Rahmens. */
.hinweis {
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s16) max(var(--zeile-x), env(safe-area-inset-left));
  font-family: var(--font-text);
  font-size: var(--fs-text);
  line-height: var(--lh-text);
  color: var(--ink-muted);
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
}

/* ==========================================================================
   15. ZIFFERNBLOCK + PIN (§8.6, §8.8)
   Eigener Block, nie die Systemtastatur. Eingabe immer in Cent.
   ========================================================================== */
.pinpunkte {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s8);
  min-height: var(--s32);
  padding: var(--s16) var(--zeile-x);
}

/* „Punkte" laut §8.6 — als Quadrat gezeichnet, weil §1.2 keine Kreise
   erlaubt. Gleiche Formensprache wie das Statusquadrat.                    */
.pinpunkt {
  display: block;
  width: var(--s12);
  height: var(--s12);
  border: 2px solid var(--ink-muted);
  border-radius: var(--r-null);
  background: transparent;
}

.pinpunkt--voll {
  background: var(--ink);
  border-color: var(--ink);
}

.ziffernblock {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s8);
  padding: 0 max(var(--zeile-x), env(safe-area-inset-right))
           var(--s16) max(var(--zeile-x), env(safe-area-inset-left));
}

.ziffernblock__taste {
  justify-content: center;
  min-height: var(--h-ziffer);
  border-radius: var(--r-taste);
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  font-weight: 500;
  line-height: 1;
}

.ziffernblock__taste--wort {
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 700;
}

.ziffernblock__taste--blind,
.ziffernblock__taste--blind[disabled] {
  background: transparent;
  border-color: transparent;
  border-bottom-color: transparent;
  cursor: default;
}

/* Gesperrt: der Block wird ERSETZT, nicht ausgegraut (§8.6). */
.pinsperre {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s12);
  padding: var(--s16) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s24) max(var(--zeile-x), env(safe-area-inset-left));
}

.pinsperre__zeit {
  font-family: var(--font-num);
  font-size: var(--fs-werk);
  font-weight: 700;
  line-height: 1;
  color: var(--rot);
}

.pinsperre__satz {
  font-family: var(--font-text);
  font-size: var(--fs-text);
  line-height: var(--lh-text);
  color: var(--ink);
}

/* ==========================================================================
   16. HALTEN STATT BESTÄTIGEN — 700 ms, immer (§8.4)
   Die Füllung liegt als Unterlage unter dem Inhalt und wächst von links.
   ========================================================================== */
/* isolation macht .halten zum Stapelkontext. Dadurch kann die Füllung mit
   z-index:-1 unter den Inhalt und trotzdem über den eigenen Hintergrund —
   ohne dass irgendein Geschwisterelement seine Positionierung ändern muss.
   (Ein `position: relative` auf alle Kinder hätte den Kantenstreifen
   plattgemacht, der absolut positioniert sein muss.)                      */
.halten {
  isolation: isolate;
}

.halten__fuellung {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--fuell, var(--signal-flaeche));
  border-radius: inherit;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--t-halten-ab) var(--e-linear);
  pointer-events: none;
}

.halten--laeuft .halten__fuellung {
  transform: scaleX(1);
  transition-duration: var(--t-halten);
}

.halten--rot   { --fuell: var(--rot-flaeche); }
.halten--gruen { --fuell: var(--gruen-flaeche); }

/* ==========================================================================
   17. WISCHEN mit Richtungssperre (§8.3)
   .wisch__inhalt folgt dem Finger; JS setzt --dx per CSSOM.
   touch-action: pan-y hält den Scroller zuständig, bis die Sperre fällt.
   ========================================================================== */
.wisch {
  position: relative;
  overflow: hidden;
  touch-action: pan-y;
}

.wisch__aktionen {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  pointer-events: none;
}

/* Eingerastet (§8.3): die freigelegte Fläche wird zur Taste. Nur dann —
   sonst läge ein unsichtbarer Streifen über jeder Zeile. Alles, was nicht
   freiliegt, verdeckt `.wisch__inhalt` ohnehin.                           */
.wisch--offen .wisch__aktionen {
  pointer-events: auto;
}

.wisch__aktion {
  flex: 1 1 50%;
  display: flex;
  align-items: center;
  padding: 0 var(--s16);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  font-weight: 700;
  line-height: var(--lh-eng);
  color: var(--auf-farbe);
  white-space: nowrap;
}

/* Sichtbar beim Wisch nach rechts (liegt links) — Storno letzter, rot (§7.5) */
.wisch__aktion--rechtswisch {
  background: var(--rot);
  justify-content: flex-start;
}
/* Sichtbar beim Wisch nach links (liegt rechts) — Abrechnen, grün (§7.5)     */
.wisch__aktion--linkswisch {
  background: var(--gruen);
  justify-content: flex-end;
}

.wisch__aktion[data-ton="rot"]    { background: var(--rot); }
.wisch__aktion[data-ton="gruen"]  { background: var(--gruen); }
.wisch__aktion[data-ton="signal"] { background: var(--signal); color: var(--signal-ink); }

.wisch__inhalt {
  position: relative;
  transform: translateX(var(--dx, 0px));
  transition: transform var(--t-wisch) var(--e-strich);
}

/* Eine wischbare Zeile ist meist auch eine Taste. Ohne diese Regel würde das
   translateY(2px) des Tastenhubs das translateX des Fingers überschreiben und
   die Zeile beim Anfassen zurückschnappen lassen. Beides muss gelten.      */
.wisch__inhalt:active,
.wisch__inhalt[data-gedrueckt] {
  transform: translateX(var(--dx, 0px)) translateY(2px);
}

/* Solange der Finger liegt: 1:1, keine Transition. */
.wisch--zieht .wisch__inhalt { transition: none; }

/* ==========================================================================
   18. DIAGNOSE-BLOCK (§7.8)
   Zweispaltig, 13px Mono, 1px gerahmt. Nicht drückbar — deshalb keine
   untere Kante. Kopiert wird über die Taste darunter.
   ========================================================================== */
.diagnose {
  margin: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
          var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  border: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-zeile);
  background: var(--panel);
}

.diagnose__gitter {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s4) var(--s12);
  padding: var(--s12);
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  line-height: var(--lh-text);
}

.diagnose__schluessel {
  color: var(--ink-muted);
  white-space: nowrap;
}

.diagnose__wert {
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* ==========================================================================
   19. FELDER (§10, §8.8)
   Ein Feld ist keine Taste: 1px Rahmen ringsum, keine untere Kante.
   ========================================================================== */
.feld {
  display: block;
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  background: var(--bg);
}

.feld__eingabe {
  display: block;
  width: 100%;
  min-height: var(--h-druck);
  padding: var(--s12) var(--s12);
  background: var(--key);
  color: var(--ink);
  border: var(--kante-fein) solid var(--rule);
  border-radius: var(--r-zeile);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  line-height: var(--lh-eng);
}

.feld__eingabe::placeholder {
  color: var(--ink-muted);
}

.feld__eingabe:focus-visible {
  border-color: var(--signal);
  outline: 2px solid var(--signal);
  outline-offset: -2px;
}

/* Anzeige einer Cent-Eingabe (§8.8): getippt wird 50, angezeigt 0,50 €. */
.feldanzeige {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  min-height: var(--h-druck);
  padding: var(--s12) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s12) max(var(--zeile-x), env(safe-area-inset-left));
  font-family: var(--font-num);
  font-size: var(--fs-werk);
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}

/* Auswahlmarke, z.B. in der Runde (§8.7). Quadrat, kein Häkchen-Icon. */
.haken {
  display: block;
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  border: 2px solid var(--ink-muted);
  border-radius: var(--r-null);
  background: transparent;
}

[aria-pressed="true"] > .haken,
[aria-checked="true"] > .haken,
.haken--an {
  background: var(--signal);
  border-color: var(--signal);
}

/* ==========================================================================
   20. ZUSTÄNDE: leer, Fehler, Wartetext (§1.5, §2)
   Kein Spinner, kein Skeleton. Jeder Wartezustand ist Text.
   ========================================================================== */
.leer {
  padding: var(--s24) max(var(--zeile-x), env(safe-area-inset-right))
           var(--s24) max(var(--zeile-x), env(safe-area-inset-left));
  font-family: var(--font-text);
  font-size: var(--fs-text);
  line-height: var(--lh-text);
  color: var(--ink-muted);
  background: var(--panel);
}

.fehlerzeile {
  position: relative;
  padding: var(--zeile-y) max(var(--zeile-x), env(safe-area-inset-right))
           var(--zeile-y) calc(var(--kantenstreifen) + var(--zeile-x));
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
  font-family: var(--font-text);
  font-size: var(--fs-text);
  line-height: var(--lh-text);
  color: var(--ink);
}

.fehlerzeile::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: var(--kantenstreifen);
  background: var(--rot);
}

/* Fehler: ±6px, 3 Zyklen, 240 ms gesamt (§9). */
.beben {
  animation: beben var(--t-beben) var(--e-linear) both;
}

@keyframes beben {
  0%   { transform: translateX(0); }
  17%  { transform: translateX(-6px); }
  33%  { transform: translateX(6px); }
  50%  { transform: translateX(-6px); }
  67%  { transform: translateX(6px); }
  83%  { transform: translateX(-6px); }
  100% { transform: translateX(0); }
}

/* Nachdrucken statt Spinner (§8.9): ein Satz, ein Zeitstempel, sonst nichts. */
.nachdruck {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--s32);
  background: var(--panel);
  border-bottom: var(--kante-fein) solid var(--rule);
  font-family: var(--font-num);
  font-size: var(--fs-meta);
  color: var(--ink-muted);
  transform: translateY(-100%);
  pointer-events: none;
}

.nachdruck--sichtbar { transform: translateY(0); }

/* ==========================================================================
   21. QR-SCHILD (§7.9)
   Die einzige reinweiße Fläche der App, weil sie gescannt werden muss.
   ========================================================================== */
.qrschild {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s16);
  padding: max(var(--s24), env(safe-area-inset-top))
           max(var(--s24), env(safe-area-inset-right))
           max(var(--s24), env(safe-area-inset-bottom))
           max(var(--s24), env(safe-area-inset-left));
  background: var(--qr-grund);
  color: var(--qr-tinte);
  text-align: center;
}

.qrschild__flaeche {
  width: min(72vw, 62vh);
  height: min(72vw, 62vh);
  background: var(--qr-grund);
  display: flex;
  align-items: center;
  justify-content: center;
}

.qrschild__flaeche svg,
.qrschild__flaeche canvas {
  width: 100%;
  height: 100%;
}

.qrschild__name {
  font-family: var(--font-text);
  font-size: var(--fs-gross);
  font-weight: 700;
  line-height: var(--lh-eng);
  color: var(--qr-tinte);
}

.qrschild__id {
  font-family: var(--font-num);
  font-size: var(--fs-gross);
  font-weight: 500;
  line-height: var(--lh-eng);
  letter-spacing: .06em;
  color: var(--qr-tinte);
}

.qrschild__zu {
  min-width: 160px;
  background: var(--qr-grund);
  color: var(--qr-tinte);
  border-color: var(--qr-tinte);
  border-bottom-color: var(--qr-tinte);
}

/* ==========================================================================
   22. BEWEGUNGSARM — Feinschliff (§9)
   Die Dauern kommen aus tokens.css. Hier nur, was sich nicht über eine
   Dauer regeln lässt.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .ziffer__rolle {
    transition: none;
  }
  .strich--neu,
  .strich--quer.strich--neu,
  .beben {
    animation: none;
  }
  .strich--weg {
    animation-duration: 1ms;
  }
  /* Sheets erscheinen mit 100 ms opacity statt zu fahren. */
  .sheet {
    transform: none;
    opacity: 0;
    transition: opacity var(--t-sheet-ein) var(--e-linear);
  }
  .sheetlage--offen .sheet { transform: none; opacity: 1; }
  .sheetlage--zu .sheet    { transform: none; opacity: 0; }
  .stornoleiste,
  .stornoleiste--aus {
    transform: none;
  }
  /* Fortschritt bleibt sichtbar, springt aber in 5-%-Schritten. */
  .halten__fuellung {
    transition-timing-function: steps(20, end);
  }
}

/* ---------------------------------------------------------------------------
   Beträge: Lücke vor dem Euro-Zeichen zusammenziehen

   `Intl.NumberFormat('de-DE', …)` trennt Zahl und Währung mit U+00A0
   (geschütztes Leerzeichen). In einer Proportionalschrift ist das schmal —
   in der Mono-Schrift, in der laut §1.7 ALLE Beträge stehen, belegt es
   dagegen eine volle Ziffernbreite (gemessen: 25,8px bei 44px Schriftgrad,
   exakt so breit wie eine "0"). Das reißt sichtbar auseinander.

   Deshalb wird die Wortlücke hier zurückgenommen — aber ausschließlich in
   Elementen, die NICHTS ausser dem Betrag enthalten. `.zeile__meta` etwa
   trägt "4,50 € · 9 Striche" und behält seine normalen Wortabstände.

   Bewusst hier und nicht in `money()`: der Formatter liefert weiterhin
   korrektes U+00A0 für Export, Teilen-Text und Zwischenablage (§7).
   --------------------------------------------------------------------------- */
.betrag,
.taste__preis,
.zeile__betrag,
.zaehlwerk__betrag {
  word-spacing: -0.34em;
}
