/* AI Inventar — Aufnahme-App
   Mobile first: Die App wird auf dem Handy in der Wohnung bedient, oft
   einhändig, oft mit der anderen Hand am Türrahmen. Grosse Ziele, wenig
   Text, nichts Wichtiges am oberen Bildschirmrand. */

:root {
  --grund: #f6f7f9;
  --karte: #ffffff;
  --text: #111827;
  --gedaempft: #6b7280;
  --linie: #e5e7eb;
  --primaer: #1d4ed8;
  --primaer-dunkel: #1e40af;
  --warn: #b45309;
  --warn-grund: #fef3c7;
  --gefahr: #b91c1c;
  --ok: #047857;
  --radius: 14px;
  /* Die Ecke fuer Felder, Marken, Knoepfe: weich, aber eckig. Die
     Pillenform (999px) ist weg -- «die ertrage ich nicht mehr»: Ein Feld,
     das ueber drei Zeilen laeuft, sieht als Pille nach Wurst aus. Rund
     bleiben nur Spuren, Balken, Punkte und Kreise. */
  --eck: .55rem;
  /* Wie hoch die klebende Kopfleiste ist.
     Sie ist `.kopf`: oben `max(.7rem, safe-area)`, unten `.7rem`, dazwischen
     rund 2.75rem Inhalt. Gemessen 65 px ohne Einzug -- auf einem iPhone mit
     Notch entsprechend mehr. Alles, was sich darunter haengt oder dorthin
     springt, rechnet mit dieser einen Zahl; sonst verschwindet es bei
     jedem zweiten Geraet zur Haelfte unter dem schwarzen Balken. */
  --leiste: calc(4.15rem + max(0px, env(safe-area-inset-top) - .7rem));
  --schatten: 0 1px 2px rgba(0, 0, 0, .06), 0 4px 16px rgba(0, 0, 0, .06);
}

@media (prefers-color-scheme: dark) {
  :root {
    --grund: #0b1120;
    --karte: #111827;
    --text: #f3f4f6;
    --gedaempft: #9ca3af;
    --linie: #1f2937;
    --primaer: #3b82f6;
    --primaer-dunkel: #2563eb;
    --warn: #fbbf24;
    --warn-grund: #422006;
    --gefahr: #f87171;
    --ok: #34d399;
    --schatten: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 16px rgba(0, 0, 0, .3);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0 0 5rem;
  background: var(--grund);
  color: var(--text);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

main { max-width: 46rem; margin: 0 auto; padding: 0 .75rem; }

/* --- Kopf --- */
.kopf {
  /* `sticky` ist zugleich der Bezugspunkt fuer die Menuetafel: Sie haengt
     sich mit `top: 100%` an die Unterkante der Leiste. */
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between; gap: .75rem;
  padding: .7rem .9rem; padding-top: max(.7rem, env(safe-area-inset-top));
  /* Dunkler Balken wie die Navigation auf ai-inventar.ch. Nebenbei loest das
     die Logofrage: die gelieferte Marke ist weiss und braucht dunklen Grund. */
  background: #070b14;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
  color: #e8eefb;
}
.kopf .auftrag-name { color: #9fb0cd; }
.kopf .knopf, .kopf button.klein {
  background: rgba(255, 255, 255, .08);
  border: 1px solid rgba(255, 255, 255, .16);
  color: #e8eefb;
  border-radius: var(--eck);
}
.kopf .knopf:hover, .kopf button.klein:hover { background: rgba(255, 255, 255, .14); }
/* Im dunklen Balken gilt immer die weisse Fassung. */
.kopf .marke img.logo-voll { display: none; }
.kopf .marke img.logo-voll-hell { display: block; }
/* Die Wort-Bild-Marke liegt als austauschbare Datei in assets/logo.svg.
   Wer sie ersetzt, muss hier nichts anpassen -- nur das Seitenverhaeltnis
   von rund 3.9 zu 1 sollte ungefaehr stimmen. */
.marke { display: flex; align-items: center; flex: none; }
.marke img { height: 26px; width: auto; display: block; }
.marke-text { font-weight: 700; letter-spacing: -.01em; }

/* Auf sehr schmalen Geraeten wird der Schriftzug beschnitten -- der
   Auftragsname ist dort wichtiger. */
/* Auf schmalen Geraeten wird die Marke kleiner -- aber nie beschnitten.
   Hier stand "overflow: hidden; width: 30px", und genau das hat sie
   abgeschnitten: Sichtbar blieben das Haus und ein angeschnittener Rest des
   Trennstrichs, der wie ein weisser Balken aussah. Eine Wort-Bild-Marke
   darf skaliert werden, nicht zerschnitten. */
@media (max-width: 400px) {
  .marke img { height: 22px; }
}
.kopf-rechts { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.auftrag-name {
  color: var(--gedaempft); font-size: .875rem; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* Die Nummer der Aufnahme, neben dem Titel.
   Kleiner und blasser als er -- sie ist eine Kennung, keine Ueberschrift.
   Aber `nowrap` und `flex: none`: Ein Titel darf abgeschnitten werden, eine
   Nummer nicht. Halb sichtbar waere sie schlimmer als gar nicht, weil man
   sie am Telefon abliest und weitergibt. */
.auftrag-nr {
  flex: none; font-size: .78rem; white-space: nowrap;
  color: var(--gedaempft); opacity: .8;
  font-variant-numeric: tabular-nums;
}
.kopf .auftrag-nr { color: #7d8db0; }
/* In der Liste steht sie vor allem anderen -- dort ist sie das, wonach
   jemand sucht. */
.auftragsliste .nr { font-variant-numeric: tabular-nums; }

.kopf-rechts { flex: 1; justify-content: flex-end; gap: .5rem; }

/* --- Der Menüknopf ---
   Dieselbe Form wie auf ai-inventar.ch: drei Striche, die beim Öffnen zum
   Kreuz werden. Über 880 px gar nicht da -- dort steht die Reihe. */
.burger {
  display: none; background: none; border: 0; cursor: pointer;
  width: 42px; height: 42px; padding: 9px; flex: none;
  flex-direction: column; justify-content: center; gap: 6px;
}
.burger span {
  display: block; height: 2.5px; width: 100%; background: #fff;
  border-radius: 2px;
  transition: transform .25s ease, opacity .2s ease;
}

@media (max-width: 880px) {
  .burger { display: flex; }

  /* Aus der Reihe wird eine Tafel unter der Leiste.
     `visibility` statt `display`, damit der Übergang läuft -- und damit
     Vorleseprogramme das geschlossene Menü nicht vorlesen. */
  .kopf .kopf-rechts {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: rgba(7, 11, 20, .97);
    backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid rgba(148, 180, 255, .14);
    padding: .35rem .9rem 1rem;
    opacity: 0; visibility: hidden; transform: translateY(-10px);
    transition: opacity .25s ease, transform .25s ease, visibility .25s;
    /* Über allem, was auf der Seite steht -- sonst schiebt sich eine
       Karte mit eigenem Stapelwert davor. */
    z-index: 20;
    /* Nicht laenger als der Schirm. `calc(100dvh - 100%)` stand hier und
       loeste sich zu Unsinn auf: Das Prozent bezieht sich auf die Hoehe
       des Bezugsrahmens, nicht auf die der Leiste -- heraus kam
       `calc(-100% + 1269px)`. */
    max-height: 80dvh;
    /* Nur senkrecht. `overflow-y: auto` allein macht auch die Waagrechte
       zu `auto`, und drei Pixel Ueberstand ergaben einen Rollbalken quer
       unter dem Menue. */
    overflow-y: auto; overflow-x: hidden;
  }
  .kopf.menue-offen .kopf-rechts { opacity: 1; visibility: visible; transform: none; }

  /* In der Tafel ist jeder Eintrag eine Zeile, keine Pille. */
  .kopf .kopf-rechts .knopf,
  .kopf .kopf-rechts button.klein {
    /* Kein `width: 100%`: Die Tafel ist eine Spalte mit `align-items:
       stretch`, die Zeilen sind dadurch schon so breit wie sie darf.
       Beides zusammen ergab drei Pixel Ueberstand. */
    justify-content: flex-start; gap: .6rem;
    background: none; border: 0; border-radius: 0;
    border-bottom: 1px solid rgba(148, 180, 255, .09);
    padding: .85rem .2rem; font-size: 1rem; text-align: left;
  }
  .kopf .kopf-rechts .knopf:hover,
  .kopf .kopf-rechts button.klein:hover { background: rgba(255, 255, 255, .06); }
  .kopf .kopf-rechts > *:last-child { border-bottom: 0; }

  /* Die Beschriftung, die in der engen Leiste wegfiel, gehört hier hin:
     In einer Zeile ist ein Symbol ohne Wort eine Ratefrage. */
  .kopf .kopf-rechts .nur-breit {
    position: static; width: auto; height: auto; overflow: visible;
    clip-path: none;
  }

  /* Abmelden ganz unten und abgesetzt -- es ist die einzige Zeile, die
     etwas beendet. */
  .kopf .kopf-rechts .abmelden { margin-top: .4rem; color: #ffb4b4; }

  /* Die Seite, auf der man steht, ist kein Weg. */
  .kopf .kopf-rechts .hier { opacity: .55; }

  /* Offen wird aus den drei Strichen ein Kreuz -- dasselbe Zeichen wie auf
     ai-inventar.ch. Es sagt, was der zweite Druck tut. */
  .kopf.menue-offen .burger span:nth-child(1) { transform: translateY(8.5px) rotate(45deg); }
  .kopf.menue-offen .burger span:nth-child(2) { opacity: 0; }
  .kopf.menue-offen .burger span:nth-child(3) { transform: translateY(-8.5px) rotate(-45deg); }
}

/* Wer Bewegung abbestellt hat, bekommt keine. */
@media (prefers-reduced-motion: reduce) {
  .burger span, .kopf .kopf-rechts { transition: none; }
}

/* Der Name der Aufnahme steht in der Leiste, nicht im Menü. Er darf sie
   aber nicht sprengen: lieber gekürzt als über der Marke. */
@media (max-width: 880px) {
  .kopf .auftrag-name { flex: 1; max-width: 42vw; }
}


/* --- Karten --- */
.karte {
  background: var(--karte); border-radius: var(--radius);
  box-shadow: var(--schatten); padding: 1rem; margin: .75rem 0;
}
.karte h2 {
  margin: 0 0 .75rem; font-size: 1rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--gedaempft);
}
.zaehler {
  display: inline-block; min-width: 1.6em; padding: 0 .4em; margin-left: .3em;
  background: var(--primaer); color: #fff; border-radius: var(--eck);
  font-size: .8rem; text-align: center;
}

/* --- Knöpfe --- */
button, .knopf {
  font: inherit; border: 0; border-radius: 10px; cursor: pointer;
  padding: .7rem 1rem; background: var(--linie); color: var(--text);
  text-decoration: none; display: inline-block; text-align: center;
}

/* hidden muss wirken -- auch auf Knoepfen.
   Der Browser bringt [hidden] { display: none } selbst mit, aber das ist
   eine Regel seines eigenen Stylesheets, und jede Regel von uns schlaegt
   sie. Die Zeile darueber setzt display auf Knoepfe -- damit war das
   Attribut auf jedem Knopf der Anwendung wirkungslos. "Wieder oeffnen"
   stand deshalb auch bei Aufnahmen, die gar nicht abgeschlossen waren,
   und dasselbe galt fuer "Entfernen" und "Anmeldelink senden" bei einem
   Benutzer, den es noch gar nicht gibt.

   !important ist hier richtig: Es geht nicht um Aussehen, sondern darum,
   dass etwas nicht da ist. Das darf keine spaetere Regel versehentlich
   aufheben. */
[hidden] { display: none !important; }
button:active, .knopf:active { transform: translateY(1px); }
.primaer { background: var(--primaer); color: #fff; }
.primaer:hover { background: var(--primaer-dunkel); }
.sekundaer { background: transparent; border: 1px solid var(--linie); color: var(--text); }
.klein { padding: .4rem .7rem; font-size: .875rem; }
.gross { display: block; width: 100%; padding: 1rem; font-size: 1.05rem; font-weight: 600; }
.gross + .gross { margin-top: .5rem; }
button[disabled] { opacity: .5; cursor: not-allowed; }

.aktionen label.gross { cursor: pointer; }

/* --- Kamera --- */
/* Die Kamera ist der Arbeitsbereich -- sie darf so gross wie moeglich sein.
   Die Karte drumherum verliert dafuer ihren Innenabstand, und im Querformat
   nutzt das Bild praktisch die ganze Hoehe. */
#aufnahme:has(.kamera-huelle:not([hidden])) { padding: 0; overflow: hidden; }

.kamera-huelle {
  position: relative; border-radius: var(--radius); overflow: hidden;
  background: #000;
}

/* Im echten Vollbild gilt dasselbe wie im Querformat: Der Sucher ist der
   ganze Schirm, ohne Ecken und ohne Rand. Die Regeln stehen getrennt, weil
   die beiden Faelle sich nur meistens decken -- hochkant im Vollbild gibt
   es kein Querformat, und quer gibt es Vollbild nicht immer. */
.kamera-huelle:fullscreen {
  border-radius: 0; margin: 0; width: 100%; height: 100%;
}
.kamera-huelle:fullscreen #video {
  width: 100%; height: 100%; max-height: none; object-fit: cover;
}
/* Und die Bedienleiste an den unteren Rand, mit Platz fuer die
   Gestenleiste des Telefons. */
.kamera-huelle:fullscreen .kamera-leiste {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding-bottom: max(.6rem, env(safe-area-inset-bottom));
}
#video {
  display: block; width: 100%; height: 72vh; max-height: 72vh;
  object-fit: cover;
}

/* Das Info-Band oben im Sucher.
   Links das Zimmer, rechts der Hinweis aufs Querformat. Ein dunkler
   Verlauf darunter, kein Balken: Ueber einer hellen Wand waere weisse
   Schrift sonst nicht zu lesen, und ein voller Balken naehme Bild weg.
   Klicks gehen hindurch -- darunter liegt das Sucherbild, und wer
   danebentippt, will nicht das Band treffen. */
.kamera-info {
  position: absolute; inset: 0 0 auto; z-index: 2;
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: .8rem; pointer-events: none;
  /* Rechts Platz fuer den Vollbildknopf in der Ecke -- sonst laeuft der
     Hinweis "Handy quer halten" darunter durch. */
  padding: calc(.55rem + env(safe-area-inset-top)) 3.2rem 1.6rem .8rem;
  background: linear-gradient(#000000a8, #0000);
  color: #fff; font-size: .8rem; line-height: 1.3;
  text-shadow: 0 1px 3px #000c;
}
.kamera-info-raum { font-weight: 700; }
.kamera-info-tipp {
  display: inline-flex; align-items: center; gap: .35rem;
  flex: none; opacity: .92;
}
.kamera-info-tipp svg {
  width: 15px; height: 15px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Auf schmalen Geraeten hat der Hinweis keinen Platz neben dem Zimmernamen
   -- dann steht er darunter statt den Namen abzuschneiden. */
@media (max-width: 380px) {
  .kamera-info { flex-direction: column; gap: .25rem; }
}

/* Der Zoomregler, als erste Zeile der Ausloeserleiste.
   Dort, wo der Daumen ohnehin ist: Wer den Ausschnitt aendert, tut es kurz
   vor dem Ausloesen und will die Hand nicht umsetzen.
   Dezent: eine duenne Linie mit einem weissen Griff. Sie liegt ueber dem
   Sucherbild und darf ihm nichts wegnehmen -- der Wert daneben sagt
   ohnehin, wo man steht. */
.zoom-leiste {
  display: flex; align-items: center; gap: .6rem;
  width: min(100%, 17rem);
}
.zoom-wert {
  flex: none; min-width: 2.6rem; text-align: right;
  color: #fff; font-size: .78rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 3px #000c;
}
/* Der Halter traegt hochkant die Breite, quer die Hoehe fuer die Drehung.
   Ohne ihn hinge der gedrehte Regler in der Luft und ueberliefe seine
   Nachbarn -- eine Drehung aendert das Aussehen, nicht den Platzbedarf. */
.zoom-halter { flex: 1; min-width: 0; display: flex; }

.zoom-regler {
  flex: 1; appearance: none; -webkit-appearance: none;
  height: 22px; margin: 0; background: none; cursor: pointer;
}
/* Die Schiene. Der eingefaerbte Teil links zeigt, wie weit es noch nach
   aussen geht -- dieselbe Sprache wie beim Preisrechner der Startseite. */
.zoom-regler::-webkit-slider-runnable-track {
  height: 3px; border-radius: 999px;
  background: linear-gradient(90deg, #ffffffe6 var(--fortschritt, 0%),
                              #ffffff40 var(--fortschritt, 0%));
}
.zoom-regler::-moz-range-track {
  height: 3px; border-radius: 999px; background: #ffffff40;
}
.zoom-regler::-moz-range-progress {
  height: 3px; border-radius: 999px; background: #ffffffe6;
}
/* Der Griff. Gross genug fuer einen Daumen, auch wenn die Schiene duenn
   ist -- getroffen wird der Griff, gesehen die Linie. */
.zoom-regler::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; margin-top: -7.5px;
  border: 0; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 4px #0009;
}
.zoom-regler::-moz-range-thumb {
  width: 18px; height: 18px; border: 0; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 4px #0009;
}
.zoom-regler:focus-visible { outline: 2px solid #67e8f9; outline-offset: 4px; }

/* Querformat: der Sucher nimmt den ganzen Bildschirm.
   Vorher waren es 88 Prozent der Hoehe -- klingt nach viel, aber Kopfzeile
   und Leiste kamen obendrauf, und man musste scrollen, um den Auslöser zu
   sehen. Beim Fotografieren ist das der falsche Handgriff.
   Kein echter Vollbildmodus: Der braucht eine Nutzergeste, laesst sich nicht
   beim Drehen des Geraets ausloesen und wird auf iOS nur halb unterstuetzt.
   Ein fest sitzender Kasten tut dasselbe und funktioniert ueberall. */
@media (orientation: landscape) and (max-height: 560px) {
  .kamera-huelle:not([hidden]) {
    position: fixed; inset: 0; z-index: 60;
    border-radius: 0; margin: 0;
  }
  #video { width: 100%; height: 100%; max-height: none; }

  /* Der Hinweis aufs Querformat hat sich hier erledigt -- das Telefon ist
     gedreht. Das Zimmer bleibt: Im Vollbild ist der Kopf darueber verdeckt,
     und dann ist dieses Band die einzige Stelle, die es noch nennt. */
  .kamera-info-tipp { display: none; }

  /* Quer wandert der Zoomregler an den rechten Rand -- senkrecht.
     So macht es die Kamera-App des Telefons, und aus zwei Gruenden:
     Waagrecht liegt er mitten im Bild und zerschneidet genau das, was man
     beurteilen will; und der Daumen der haltenden Hand ist am Rand, nicht
     in der Mitte.
     Gedreht statt `writing-mode: vertical`: Das kennt Safari erst spaet,
     und eine Drehung koennen alle. Die Huelle ist quadratisch, damit die
     Drehung sie nicht aus dem Bild schiebt. */
  .zoom-leiste {
    /* `fixed`, nicht `absolute`.
       Der Regler steht im Markup in `.kamera-leiste` -- der Knopfreihe am
       unteren Rand --, und die ist selbst `position: absolute`. Ein
       `absolute` Kind haengt damit an ihr und landete unten rechts statt
       auf halber Hoehe. Quer deckt der Sucher den ganzen Schirm, also ist
       der Schirm der richtige Bezug. */
    position: fixed; right: max(.6rem, env(safe-area-inset-right));
    top: 50%; transform: translateY(-50%);
    flex-direction: column-reverse; align-items: center;
    width: auto; padding: 0; background: none; gap: .5rem; z-index: 3;
  }
  .zoom-leiste .zoom-regler { width: 9.5rem; }
  /* Der Platz, den die Drehung braucht -- sonst ueberlappt sie die
     Beschriftung darunter. */
  .zoom-leiste .zoom-halter {
    /* `flex: none` ist hier keine Feinheit, sondern die Bedingung.
       Hochkant traegt der Halter mit `flex: 1` die Breite der Reihe. Quer
       ist die Leiste eine Spalte -- dann meint `flex: 1` die Hoehe, und
       `flex-basis: 0` schlaegt jedes `height`. Der Halter fiel damit auf
       22 px zusammen, der gedrehte Regler ragte ins Nichts, und im Bild
       stand nur noch das Schild. */
    flex: none; width: 2.6rem; height: 9.5rem;
    /* `position: relative` statt Grid-Zentrierung.
       `place-items: center` zentriert ein Kind NICHT, wenn es breiter ist
       als sein Platz -- die Ausrichtung faellt dann auf "start" zurueck,
       damit nichts abgeschnitten wird. Der 152 px breite Regler in einer
       42 px schmalen Spalte lief damit nach rechts aus dem Fenster: Seine
       Kante lag bei 824 px auf einem 812 px breiten Schirm.
       Mit einer ausdruecklichen Mitte kann das nicht passieren. */
    position: relative;
  }
  .zoom-leiste .zoom-regler {
    position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%) rotate(-90deg);
    margin: 0;
  }
  .zoom-wert {
    background: rgba(7, 11, 20, .6); border-radius: var(--eck);
    padding: .15rem .55rem;
  }
  .kamera-info { padding-left: max(.8rem, env(safe-area-inset-left)); }

  /* Solange der Sucher offen ist, gibt es nichts zu scrollen. */
  body.kamera-offen { overflow: hidden; }

  .kamera-leiste { padding: .5rem 1rem; gap: .35rem; }
  .kamera-leiste { padding-bottom: max(.5rem, env(safe-area-inset-bottom)); }
  .kamera-reihe { gap: 1.6rem; }
  .ausloeser { width: 56px; height: 56px; border-width: 3px; }
  .rund { width: 40px; height: 40px; }
  .kamera-ecke { width: 34px; height: 34px; }
}

.kamera-leiste {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: column; align-items: center; gap: .5rem;
  padding: 1rem; padding-bottom: max(1rem, env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgba(0, 0, 0, .55));
}
/* Die Knopfreihe. Sie war frueher die Leiste selbst -- jetzt ist sie deren
   zweite Zeile, damit die Zoomstufen darueber Platz haben und nicht auf dem
   Ausloeser liegen. */
.kamera-reihe {
  display: flex; align-items: center; justify-content: center; gap: 2rem;
}
.ausloeser {
  width: 66px; height: 66px; border-radius: 50%; padding: 0;
  background: #fff; border: 0;
  /* Der weisse Zierrand von frueher ist weg: Er lag genau dort, wo jetzt
     der Segmentring liegt, und zwei Ringe uebereinander lesen sich als
     einer -- die Segmente gingen darin unter. Der dunkle Saum bleibt,
     damit die weisse Scheibe auch vor einer hellen Wand steht. */
  box-shadow: 0 0 0 2px rgba(0, 0, 0, .25);
}
.ausloeser:active { background: #d1d5db; }

/* --- Der Ring um den Auslöser ---
   Ein Segment je Foto, wie bei der Fingerabdruck-Erfassung: Der Ring sagt,
   wie viele Ansichten das Zimmer hat und wie viele noch gehen. Er ist
   Auskunft, nicht Zierde -- deshalb ist er auch sparsam animiert. */
.ausloeser-huelle {
  position: relative; width: 104px; height: 104px; flex: none;
  display: grid; place-items: center;
}
.ausloeser-ring {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* Oben anfangen statt rechts -- so liest sich der Ring wie eine Uhr. */
  transform: rotate(-90deg);
  pointer-events: none;
}
.ausloeser-ring circle {
  fill: none; stroke-width: 5; stroke-linecap: round;
}
.ring-spur { stroke: rgba(255, 255, 255, .22); }

/* Das gefüllte Segment liegt über der Spur und wird eingeblendet. Kein
   Aufziehen der Länge: Bei kurzen Segmenten sieht das nach Ruckeln aus. */
.ring-voll {
  stroke: #fff; opacity: 0;
  transition: opacity .28s ease, stroke .35s ease;
}
.ring-voll.an { opacity: 1; }

/* Ab dem Minimum wechselt der Ring die Farbe: von «noch nicht genug» zu
   «du darfst aufhören». Beim Fotografieren schaut niemand auf
   Beschriftungen -- das muss im Augenwinkel ankommen. */
.ausloeser-ring.genug .ring-voll.an { stroke: #34d399; }

/* Das eben dazugekommene Segment bekommt einen Schlag -- einmal, kurz.
   Ohne ihn ist nicht zu spüren, dass der Druck gewirkt hat. */
.ring-voll.frisch { animation: segmentSchlag .45s ease-out; }
@keyframes segmentSchlag {
  0%   { opacity: 0; stroke-width: 5; }
  35%  { opacity: 1; stroke-width: 9; }
  100% { opacity: 1; stroke-width: 5; }
}

/* Der Auslöser selbst atmet mit: ein kurzes Einsinken beim Druck. */
.ausloeser { transition: transform .12s ease, background .12s ease; }
.ausloeser:active { transform: scale(.92); }

/* Voll heisst zu. Der Knopf bleibt sichtbar -- wer drückt, soll erfahren
   warum -- aber er sieht nicht mehr nach Aufforderung aus. */
.ausloeser:disabled { opacity: .45; transform: none; }

/* Der Knopf leuchtet einmal auf, wenn das Zimmer abschliessbar wird --
   der einzige Zustandswechsel, den man leicht verpasst. */
.frisch-bereit { animation: bereitLeuchten .6s ease-out; }

/* Und noch einmal beim Auslösen, kräftiger: Der Blick springt in dem
   Moment hierher und soll sehen, worauf er gesprungen ist. */
.blitzt { animation: knopfBlitz .65s ease-out; }
@keyframes knopfBlitz {
  0%   { transform: scale(1);    box-shadow: 0 0 0 0 rgba(52, 211, 153, .7); }
  30%  { transform: scale(1.04); box-shadow: 0 0 0 10px rgba(52, 211, 153, .35); }
  100% { transform: scale(1);    box-shadow: 0 0 0 20px rgba(52, 211, 153, 0); }
}
@keyframes bereitLeuchten {
  0%   { box-shadow: 0 0 0 0 rgba(52, 211, 153, .55); }
  100% { box-shadow: 0 0 0 14px rgba(52, 211, 153, 0); }
}

/* Wer Bewegung abbestellt hat, bekommt die Auskunft trotzdem -- nur ohne
   Bewegung. Das Segment erscheint, es springt bloss nicht. */
@media (prefers-reduced-motion: reduce) {
  .ring-voll, .ausloeser { transition: none; }
  .ring-voll.frisch, .frisch-bereit, .blitzt { animation: none; }
  .ausloeser:active { transform: none; }
}

.rund {
  width: 46px; height: 46px; border-radius: 50%; padding: 0;
  background: rgba(255, 255, 255, .22); color: #fff; font-size: 1.1rem;
  display: grid; place-items: center;
}
/* Gezeichnete Sinnbilder statt Schriftzeichen.
   ⟲ und ✕ kamen aus der Schrift des Geraets: auf dem einen Telefon zart,
   auf dem naechsten fett, und in der Groesse nie gleich. Eine Zeichnung
   sieht ueberall gleich aus und laesst sich genau so dick setzen, wie sie
   neben dem weissen Ausloeser stehen soll. */
.knopf-bild {
  width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Das Vollbild sitzt in der oberen rechten Ecke des Suchers -- unten
   schoebe es den Ausloeser aus der Mitte. Etwas kleiner als die Knoepfe
   unten: Es ist eine Ansichtssache, keine Handlung an der Aufnahme. */
.kamera-ecke {
  position: absolute; z-index: 3;
  top: calc(.5rem + env(safe-area-inset-top));
  right: max(.6rem, env(safe-area-inset-right));
  width: 38px; height: 38px;
  background: rgba(0, 0, 0, .38);
}
.kamera-ecke .knopf-bild { width: 19px; height: 19px; }
/* Das Zahnrad: unter dem Vollbild, kleiner und blasser -- eine Einstellung,
   keine Handlung. */
.kamera-zahnrad.kamera-ecke {
  top: calc(.5rem + env(safe-area-inset-top) + 3rem);
  width: 32px; height: 32px; opacity: .72;
}
.kamera-zahnrad.kamera-ecke:hover, .kamera-zahnrad.kamera-ecke:focus-visible { opacity: 1; }
.kamera-zahnrad .knopf-bild { width: 16px; height: 16px; }

/* --- Zimmer ---
   Die Zimmerwahl steht dort, wo vorher der Auswahlkasten "Raum" stand: vor
   dem ersten Foto. Ein Zimmer ist die Einheit, in der aufgenommen wird --
   mehrere Fotos, ein Aufruf, eine Teilliste. */
/* Die Namensliste klappt auf, wenn jemand sie will. Vorher stand sie
   offen da: 22 Knoepfe zwischen Absicht und Startknopf. */
.zimmerwahl {
  padding: .8rem 0 .2rem; margin-bottom: .6rem;
  border-bottom: 1px solid var(--linie);
}
.zimmerwahl-titel {
  margin: 0 0 .7rem; font-size: .78rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--gedaempft);
}
#btnZimmerAuto { margin-top: .7rem; }

/* «Wird automatisch erkannt» ist eine Zusage, kein Name -- sie soll nicht
   aussehen wie einer. */
.erkannt-wird { font-weight: 500; color: var(--gedaempft); font-size: .95rem; }

/* Die bekannten Zimmernamen zum Antippen. Auf dem Telefon ist ein Knopf
   ein Griff, ein Auswahlkasten drei. */
.zimmer-knoepfe {
  display: flex; flex-wrap: wrap; gap: .45rem; margin-bottom: .9rem;
}
.zimmer-knopf {
  padding: .5rem .8rem; font-size: .9rem; border-radius: var(--eck);
  background: transparent; border: 1px solid var(--linie); color: var(--text);
}
.zimmer-knopf:active { background: var(--linie); }

/* Der Nachtrag: zwei Fragen, ein Schirm.
   Die gewaehlte Antwort traegt der Knopf selbst -- ausgefuellt statt
   umrandet. Wer den Dialog nach dem Zimmerklick wieder anschaut, sieht
   ohne Suchen, was gilt. */
.nachtrag-frage {
  margin: 0 0 .5rem; font-size: .82rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--gedaempft);
}
.nachtrag-frage + .zimmer-knoepfe { margin-bottom: .7rem; }
.zimmer-knopf[aria-pressed="true"] {
  background: var(--text); border-color: var(--text); color: var(--grund);
}
.nachtrag-wege { display: flex; gap: .5rem; flex-wrap: wrap; }
.nachtrag-wege button { flex: 1 1 10rem; }
.nachtrag-hinweis {
  margin: .7rem 0 0; font-size: .85rem; line-height: 1.45; color: var(--gedaempft);
}
.nachtrag-hinweis:empty { display: none; }
#dlgNachtrag .zimmer-eigen { margin-bottom: .9rem; }

/* Wohin die naechste Position geht. */
.katalog-ziel {
  margin: 0 0 .6rem; font-size: .88rem; color: var(--gedaempft);
}

.zimmer-eigen { display: flex; gap: .5rem; align-items: stretch; }
.zimmer-eigen input { flex: 1; min-width: 0; }
.zimmer-eigen button { white-space: nowrap; padding: .7rem 1.1rem; }

/* Der Kopf des laufenden Zimmers: Name, Nummer, Fotostand. Steht immer
   sichtbar -- wer durch eine Wohnung geht, verliert sonst den Faden. */
.zimmer-kopf {
  margin-bottom: .9rem; padding: .7rem .85rem;
  background: var(--grund); border: 1px solid var(--linie); border-radius: 10px;
}
/* Der Kopf traegt zwei Zeilen: oben Nummer, Name und Knoepfe, darunter das
   Packmaterial. Zwei getrennte Kaesten uebereinander sahen aus wie zwei
   Karten und schoben die Kamera vom Schirm -- und die Kamera ist der Grund,
   warum jemand hier ist. */
.zimmer-kopf-zeile {
  display: flex; align-items: center; gap: .55rem; flex-wrap: nowrap;
}
.zimmer-kopf-name { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* Ein langer Zimmername bricht um, statt abgeschnitten zu werden.
   Hier stand `text-overflow: ellipsis`, und aus "Wird automatisch erkannt"
   wurde "Wird auto…" -- eine Zusage, die man nicht zu Ende lesen kann, ist
   keine. Dasselbe traefe "Mansarde hinten links". */
.zimmer-kopf-name strong { line-height: 1.25; overflow-wrap: anywhere; }
.zimmer-kopf #btnZimmerAendern { flex: none; padding: .4rem .7rem; }
.zimmer-kopf .zimmer-fotos { flex: none; }

/* "Bleibt hier" -- das Moebel faehrt nicht mit, sein Inhalt schon.
   Eine eigene Farbe braucht es nicht: Die durchgestrichene Zahl daneben
   sagt schon alles, und ein drittes Buntes in einer Zeile mit Massen,
   Mengen und Marken waere eines zu viel. */
.marke-bleibt { color: var(--gedaempft); font-weight: 600; }
.pos-detail s { opacity: .55; }

/* Die Zeile laesst sich antippen -- dort steht, was mit ihr geschieht. */
.pos-text[role="button"] { cursor: pointer; }
.pos-text[role="button"]:focus-visible {
  outline: 2px solid var(--primaer); outline-offset: 2px; border-radius: 6px;
}

/* Titel und Kreuz im Positionsfenster. Der Titel ist ein Moebelname und
   kann lang sein -- er bricht um, das Kreuz bleibt oben rechts stehen. */
.pos-kopf {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: .75rem; margin-bottom: .2rem;
}
.pos-kopf h2 { margin: 0; }

/* Die Zimmerwahl im Positionsfenster. Beschriftung darueber statt
   daneben: Ein Zimmername kann lang sein, und daneben bliebe fuer ihn auf
   einem Handy nichts uebrig. */
.pos-zimmer { display: block; padding: .2rem 0 .6rem; }
.pos-zimmer > span {
  display: block; font-size: .82rem; font-weight: 600;
  color: var(--gedaempft); margin-bottom: .3rem;
}
.pos-zimmer select {
  width: 100%; padding: .6rem .7rem; font: inherit;
  border: 1px solid var(--linie); border-radius: 10px;
  background: var(--karte); color: var(--text);
}

/* Der Schalter im Positionsfenster. Beschriftung und Erklaerung
   uebereinander: Was er tut, ist in drei Worten nicht zu sagen. */
.pos-schalter {
  display: flex; gap: .6rem; align-items: flex-start;
  padding: .6rem 0; cursor: pointer;
}
.pos-schalter input { width: 1.2rem; height: 1.2rem; margin-top: .1rem; accent-color: var(--primaer); }
.pos-schalter small { display: block; margin-top: .2rem; color: var(--gedaempft); }

/* Der Weg zurueck von einer gesetzten zu einer gerechneten Zahl.
   Als Text und nicht als Knopf: Er steht mitten in einer Zeile mit
   Angaben, und ein Knopf daneben saehe aus wie eine Hauptsache. Die
   Trefferflaeche ist trotzdem gross genug -- er traegt Polsterung nach
   oben und unten, die im Fluss nicht auftraegt. */
.pack-zurueck {
  border: 0; background: none; padding: .25rem 0; min-height: 0;
  color: var(--primaer); font: inherit; text-decoration: underline;
  text-underline-offset: 2px;
}

/* Die lose Kleinware in der Zimmerueberschrift. Zurueckhaltend: Sie ist
   eine Erklaerung fuer die Kartonzahl daneben, keine eigene Position --
   und sie zaehlt bewusst nicht in die Summe des Zimmers. */
.raum-lose {
  font-style: normal; font-size: .78rem; font-weight: 500;
  color: var(--gedaempft); margin-left: .5rem;
  /* Die Ueberschrift steht in Grossbuchstaben; eine Erlaeuterung darin
     nicht. "+ 1.6 M³ LOSE KLEINWARE" schreit, wo es erklaeren soll. */
  text-transform: none; letter-spacing: 0;
}

/* --- Packmaterial: Schalter und Regler, je Zimmer ---
   Eine eigene Zeile unter dem Zimmerkopf, nicht darin: Der Kopf ist voll
   (Nummer, Name, Zaehler, Aendern, Hilfe), und dies ist eine Entscheidung
   ueber das Zimmer, keine Beschriftung. */
.pack-leiste {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  /* Kein eigener Rahmen und kein eigener Grund: Sie sitzt im Zimmerkopf
     und ist dessen zweite Zeile, keine zweite Karte. Eine Trennlinie
     reicht, um zu zeigen, dass hier etwas anderes anfaengt. */
  margin: .5rem 0 0; padding: .5rem 0 0;
  border-top: 1px solid var(--linie);
}
.pack-schalter {
  display: flex; align-items: center; gap: .4rem;
  font-size: .85rem; font-weight: 600;
  /* Die ganze Beschriftung ist Trefferflaeche. Ein Kaestchen von 16 Pixeln
     trifft niemand mit dem Daumen, waehrend er im Zimmer steht. */
  cursor: pointer; padding: .2rem 0;
}
.pack-schalter input { width: 1.05rem; height: 1.05rem; accent-color: var(--primaer); }

/* Wenig -- mittel -- viel. Drei Felder statt eines Schiebers: Auf dem
   Handy ist ein Schieber mit drei Rasten ein Zielen, drei Knoepfe sind ein
   Tippen. Und man sieht die gewaehlte Stufe, ohne sie abzulesen. */
.pack-stufen {
  display: inline-flex; margin-left: auto;
  border: 1px solid var(--linie); border-radius: var(--eck);
  background: var(--karte); overflow: hidden;
}
.pack-stufen button {
  border: 0; background: none; color: var(--gedaempft);
  /* Klein: Das ist eine Nebeneinstellung, kein Hauptknopf. Gross gesetzt
     wog sie auf dem Schirm schwerer als der Ausloeser darunter. Die
     Trefferflaeche bleibt mit 1.7rem Hoehe und der Polsterung daumentauglich. */
  font-size: .74rem; font-weight: 600; padding: .25rem .55rem; min-height: 1.7rem;
}
.pack-stufen button + button { border-left: 1px solid var(--linie); }
.pack-stufen button[aria-pressed="true"] {
  background: var(--primaer); color: #fff;
}
.pack-fuss {
  flex-basis: 100%; margin: 0; font-size: .72rem; line-height: 1.3;
}

/* In der Zimmerliste steht derselbe Schalter noch einmal -- dort ist er
   nach der Aufnahme erreichbar, ohne ins Scanfenster zurueckzugehen. */
/* Loeschen ganz unten und allein.
   Es ist der einzige unwiderrufliche Griff an der Karte -- er gehoert
   nicht zwischen "Umbenennen" und einer Einstellung, wo der Daumen ihn
   beilaeufig trifft. Halbe Breite statt voller: gross genug zum Treffen,
   klein genug, um nicht wie der Hauptknopf auszusehen.
   Etwas Luft darueber trennt ihn von dem, was harmlos ist. */
.raum-weg { margin-top: .55rem; }
.raum-weg button { width: 50%; padding: .4rem .6rem; font-size: .8rem; }

/* Packmaterial steht eine Zeile fuer sich -- es ist eine Einstellung am
   Zimmer und keine Handlung wie Umbenennen oder Loeschen. Etwas Luft
   darueber macht den Unterschied sichtbar, ohne eine Linie zu ziehen. */
.raum-pack {
  display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
  margin-top: .45rem;
}
.raum-pack .pack-stufen { margin-left: 0; }
.raum-aktionen button[data-raum-pack][aria-pressed="true"] {
  border-color: var(--primaer); color: var(--primaer);
}

/* Der Fragezeichen-Knopf im Zimmerkopf.
   Rund und gleich gross wie hoch, damit er neben "Ändern" nicht wie ein
   zweiter Textknopf aussieht -- er ist eine Auskunft, keine Handlung am
   Zimmer. Zurueckhaltend, aber mit voller Trefferflaeche: Wer ihn sucht,
   sucht ihn auf einem Handy, mit dem Daumen. */
.hilfe-knopf {
  flex: none; width: 2.1rem; height: 2.1rem; padding: 0;
  border-radius: var(--eck); border: 1px solid var(--linie);
  background: var(--karte); color: var(--gedaempft);
  font-size: 1rem; font-weight: 700; line-height: 1;
}
.hilfe-knopf:active { background: var(--linie); color: var(--text); }

/* Die Anleitung waehrend der Arbeit.
   Sie ist lang -- also scrollt der Rumpf, waehrend Kopf und Fuss stehen
   bleiben. Ohne das steht der Schliessen-Knopf irgendwo weit unten, und
   auf einem Handy sucht man ihn. */
/* Die Tafel -- ein gewoehnliches Overlay, kein <dialog>.
   z-index 200: Ueber dem Sucher, der im Querformat auf 60 liegt. Damit
   gilt die Schichtung auch dann, wenn die Kamera doch noch laufen sollte.
   Und `dvh` statt `vh`: `vh` rechnet auf Android mit dem grossen Fenster,
   dem ohne Adressleiste. Solange die Leiste steht, ragt die Tafel oben
   hinaus und das ✕ liegt ausserhalb des Bildes. */
.tafel {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center; padding: 1rem;
  background: rgba(0, 0, 0, .55);
}
.tafel[hidden] { display: none; }
.tafel-blatt {
  width: min(38rem, 100%); max-height: 88dvh;
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--karte); color: var(--text);
  border-radius: var(--radius); box-shadow: var(--schatten);
}
@supports not (height: 1dvh) { .tafel-blatt { max-height: 80vh; } }
body.tafel-offen { overflow: hidden; }

/* Die Einladung im Sucher.
   Zurueckhaltend -- sie steht ueber dem Bild und darf es nicht zerschneiden
   --, aber lesbar auf jedem Untergrund: dunkler Grund, heller Text. */
.weit-einladen {
  align-self: center; margin: .1rem 0 .35rem;
  padding: .4rem .9rem; border-radius: var(--eck);
  border: 1px solid rgba(255, 255, 255, .3);
  background: rgba(7, 11, 20, .6); color: #e8eefb;
  font-size: .8rem; backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.weit-einladen[hidden] { display: none; }
.weit-einladen:active { background: rgba(7, 11, 20, .85); }

/* Der Hinweis am weiten Ende blendet sich ein, statt zu erscheinen.
   Ein Kasten, der ueber dem Sucher aufpoppt, wirkt wie eine Stoerung;
   derselbe Kasten, der aufzieht, wirkt wie eine Auskunft. */
@media (prefers-reduced-motion: no-preference) {
  #btnWeitAnders { animation: einblenden .25s ease-out; }
}

/* Der Sucher in der Einrichtung. Schwarz hinterlegt, damit ein noch
   leeres Bild nicht wie ein Fehler aussieht. */
.weit-sucher {
  position: relative; margin: .8rem 0;
  border-radius: 10px; overflow: hidden; background: #000;
  /* 4:3 als Wunsch, nicht als Gesetz.
     Quer gehalten ist das Fenster 375 px hoch, und ein 4:3-Bild ueber die
     ganze Breite schiebt die Kameraknoepfe unter den Rand -- man muesste
     scrollen, um zu waehlen, waehrend oben "Sehen Sie sie kurz an" steht.
     Der Deckel laesst dem Bild, was da ist, und den Knoepfen ihren Platz.
     Das Bild selbst leidet nicht: object-fit deckt den Rahmen ab. */
  /* 30dvh, nicht 38.
     Auf einem 812 px hohen Schirm sind 38 % dreihundert Pixel Bild -- und
     die Kameraknoepfe darunter lagen ausserhalb. Auf dem Schirm, der sich
     von selbst aufmacht, ist das der ganze Unterschied: Man sieht Text,
     das Wichtigste liegt drunter, und man tippt "Spaeter". */
  aspect-ratio: 4 / 3; max-height: 30dvh;
}
@supports not (height: 1dvh) { .weit-sucher { max-height: 30vh; } }
.weit-sucher video { display: block; width: 100%; height: 100%; object-fit: cover; }
.weit-fehler {
  margin: 0 0 .6rem; padding: .5rem .65rem; border-radius: 8px;
  background: color-mix(in srgb, var(--gefahr) 10%, transparent);
  color: var(--gefahr); font-size: .85rem; line-height: 1.45;
}
.weit-fehler:empty { display: none; }

/* Der Knopf mitten im Anleitungstext. Eine eigene Zeile, damit er nicht
   zwischen den Woertern klemmt, und mit Luft darueber. */
#btnWeitAusHilfe { display: block; margin: .5rem 0 .1rem; }

/* Der Satz bei der Frage, die von selbst aufgeht. Abgesetzt, damit man ihn
   vor dem Bild liest -- er beantwortet "warum jetzt". */
.weit-erstmal {
  padding: .6rem .75rem; border-radius: 8px;
  background: var(--grund); border: 1px solid var(--linie);
}
.weit-erstmal[hidden] { display: none; }
#btnWeitSpaeter { margin-top: .5rem; }
#btnWeitSpaeter[hidden] { display: none; }

/* Die Zimmerzeile fuehrt zu ihren Gegenstaenden -- also sieht sie auch
   danach aus. Kein Knopf, aber ein Zeiger und eine Reaktion beim Tippen. */
/* Berechnete Zeilen -- die Kartons. Sie stehen in der Liste wie
   Gegenstaende, denn im Wagen stehen sie auch. Aber sie sind gerechnet,
   nicht gesehen, und das darf man ihnen ansehen: ohne Knoepfe, mit einer
   Marke, die sagt, woher die Zahl kommt. */
.pos-berechnet { background: color-mix(in srgb, var(--primaer) 4%, transparent); }
.pos-menge-fest {
  display: grid; place-items: center; min-width: 2.6rem;
  font-variant-numeric: tabular-nums; font-weight: 700;
}
.marke-berechnet { color: var(--primaer); }

.raum-springen {
  cursor: pointer; border-radius: 8px; margin: -.2rem; padding: .2rem;
}
.raum-springen:active { background: var(--linie); }
.raum-springen:focus-visible { outline: 2px solid var(--primaer); outline-offset: 2px; }

/* Und das Ziel leuchtet kurz auf. Ohne das landet man mitten in einer
   langen Liste und weiss nicht, ob man am richtigen Ort steht -- eine
   Ueberschrift sieht aus wie jede andere. */
@media (prefers-reduced-motion: no-preference) {
  .raum-kopf.angesprungen { animation: angesprungen 1.4s ease-out; }
}
@keyframes angesprungen {
  from { background: color-mix(in srgb, var(--primaer) 22%, transparent); }
  to   { background: transparent; }
}

/* Die Kameraknoepfe im Fuss. Eine gewickelte Reihe mit Luft nach unten,
   damit sie sich nicht am Merken-Knopf reibt. */
.weit-liste {
  display: flex; flex-wrap: wrap; gap: .45rem; margin-bottom: .6rem;
}

/* Quer: Die Ueberschrift stellt die Frage schon ("Welche Kamera zeigt am
   meisten?"), und bei 375 px Hoehe ist jede Textzeile eine Entscheidung
   gegen etwas Wichtigeres. Der Warnhinweis bleibt: Der hat eine Folge,
   die Einleitung nur eine Begruendung.
   Dieselbe Schwelle wie beim Sucher (max-height: 560px) -- es geht nicht
   um das Seitenverhaeltnis, sondern darum, dass die Hoehe knapp ist. */
/* Quer stehen Bild und Bedienung nebeneinander.
 *
 * Untereinander ging es nicht auf: Der Fuss traegt die Kameraknoepfe, den
 * Merken- und den Spaeter-Knopf -- zusammen ueber 130 px. Bei 375 px Hoehe
 * blieb fuer den scrollenden Rumpf nichts uebrig, und das Vorschaubild
 * schrumpfte auf null. Man sah eine Frage, zwei Kameranamen und keinen
 * Anhaltspunkt, wonach man waehlen soll -- gemeldet mit Bildschirmfoto.
 *
 * Nebeneinander hat beides Platz: links das Bild ueber die volle Hoehe,
 * rechts die Wahl. Und der Kopf darueber, weil die Frage zu beidem
 * gehoert. */
@media (orientation: landscape) and (max-height: 560px) {
  #weitTafel .tafel-blatt {
    display: grid; max-height: 94dvh;
    grid-template-columns: 1.1fr 1fr;
    grid-template-rows: auto 1fr;
    grid-template-areas: "kopf kopf" "bild wahl";
  }
  /* Der Kopf gedrungener: Quer sind die 1 rem oben und die .8 rem unten
     zusammen fast eine Knopfhoehe -- und die fehlt unten bei "Spaeter". */
  #weitTafel .hilfe-kopf { grid-area: kopf; padding: .55rem .9rem .45rem; }
  #weitTafel .hilfe-kopf h2 { font-size: .98rem; }
  #weitTafel .hilfe-rumpf {
    grid-area: bild; overflow: hidden; min-height: 0;
    padding: .6rem .4rem .8rem .9rem; display: flex;
  }
  #weitTafel .hilfe-fuss {
    grid-area: wahl; border-top: 0;
    padding: .6rem .9rem .8rem .4rem;
    display: flex; flex-direction: column; justify-content: center;
    /* `min-height: 0` ist hier die ganze Sache.
       Ein Rasterfeld ist von sich aus mindestens so hoch wie sein Inhalt --
       auch wenn die Zeile `1fr` heisst und weniger Platz hat. Die Spalte
       wuchs damit ueber das Blatt hinaus, und "Spaeter" lag unter dem
       unteren Rand. Erst `min-height: 0` erlaubt das Schrumpfen, und
       `overflow-y` gibt dem Rest einen Weg. */
    min-height: 0; overflow-y: auto;
  }

  /* Das Bild fuellt seine Spalte, statt sein Seitenverhaeltnis zu
     erzwingen -- `object-fit: cover` sorgt dafuer, dass es trotzdem nicht
     verzerrt. */
  #weitTafel .weit-sucher {
    margin: 0; flex: 1; aspect-ratio: auto; max-height: none;
  }
  /* Der Warnhinweis und die Einleitung treten zurueck: Die Ueberschrift
     stellt die Frage schon, und jede Zeile ginge vom Bild ab. */
  #weitErstmal, #weitSonst, #weitTafel .hilfe-warnung { display: none; }

  /* Und die Knoepfe gedrungener.
     `.gross` ist fuer einen Daumen auf einem hochkant gehaltenen Telefon
     gedacht -- quer sind 260 px Hoehe das Ganze, und dieselbe Hoehe kostet
     dort den "Spaeter"-Knopf. Die Trefferflaeche bleibt ueber 40 px. */
  #weitTafel .hilfe-fuss .gross { padding: .6rem .9rem; font-size: .95rem; }
  #weitTafel .weit-liste { margin-bottom: .4rem; }
  #weitTafel #btnWeitSpaeter { margin-top: .35rem; padding: .45rem .8rem; }
}
.weit-liste button {
  padding: .5rem .8rem; font-size: .9rem; border-radius: var(--eck);
  background: transparent; border: 1px solid var(--linie); color: var(--text);
}
.weit-liste button[aria-pressed="true"] {
  background: var(--text); border-color: var(--text); color: var(--grund);
}

/* Das Notfallfeld unter ?diag=1. */
.hilfe-diag {
  margin: .6rem 1.1rem 1rem; padding: .6rem .7rem;
  background: var(--grund); border: 1px solid var(--linie); border-radius: 8px;
  font-size: .7rem; line-height: 1.5; white-space: pre-wrap; overflow-x: auto;
}
dialog.hilfe[open] { display: flex; }
.hilfe-kopf {
  display: flex; align-items: center; gap: .8rem;
  padding: 1rem 1.1rem .8rem; border-bottom: 1px solid var(--linie);
}
.hilfe-kopf h2 { margin: 0; flex: 1; font-size: 1.05rem; }
/* 2.75rem, nicht 2.1: Das sind 44 px, die kleinste Flaeche, die ein Daumen
   zuverlaessig trifft. Es ist der Weg aus einem Fenster heraus -- da ist
   Danebentippen keine Kleinigkeit. */
.hilfe-zu {
  flex: none; width: 2.75rem; height: 2.75rem; padding: 0; border-radius: 999px;
  border: 1px solid var(--linie); background: var(--karte); color: var(--gedaempft);
  font-size: 1.05rem; line-height: 1;
}
.hilfe-zu:active { background: var(--linie); color: var(--text); }
.hilfe-rumpf { overflow-y: auto; padding: .2rem 1.1rem 0; }
.hilfe-rumpf section { padding: 1rem 0; border-bottom: 1px solid var(--linie); }
.hilfe-rumpf section:last-child { border-bottom: 0; }
.hilfe-rumpf h3 {
  display: flex; align-items: center; gap: .5rem;
  margin: 0 0 .5rem; font-size: .82rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--gedaempft);
}
/* Ein Sinnbild je Abschnitt. Nicht Schmuck: Wer die Anleitung oeffnet,
   hat eine bestimmte Frage und sucht den Abschnitt, nicht den Satz --
   und ein Bild findet das Auge beim Scrollen, eine Zeile Grossbuchstaben
   nicht. */
.hilfe-symbol {
  flex: none; width: 1.15rem; height: 1.15rem;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}

/* --- Nachgebaute Bedienelemente in der Anleitung ---

   Statt Screenshots. Ein Bildschirmfoto ist in einer Woche falsch -- diese
   Oberflaeche hat sich an einem Tag sechsmal geaendert --, und jedes waere
   dreissig Kilobyte, die auf einer Kellertreppe geladen werden wollen.

   Was hier steht, ist dieselbe Auszeichnung mit demselben Stil wie in der
   App. Es kann nicht veralten, es wiegt nichts, und es sieht der Sache
   nicht aehnlich: Es ist die Sache.

   Angefasst wird nichts davon -- `pointer-events: none` und `tabindex=-1`.
   Ein Knopf in einer Anleitung, der nichts tut, ist schlimmer als ein
   Bild. */
.hilfe-schau {
  margin: .1rem 0 .8rem; padding: .7rem .75rem;
  border: 1px solid var(--linie); border-radius: 10px;
  background: var(--grund);
  pointer-events: none;
}
.hilfe-schau-text {
  margin: .5rem 0 0; font-size: .78rem; line-height: 1.4;
  color: var(--gedaempft);
}
/* Die Zeilen darin tragen echte Katalogbilder. Ein grauer Platzhalter
   sparte einen Netzabruf und sah aus wie ein Bild, das nicht geladen hat
   -- in einer Anleitung der falsche Ort zum Sparen. */
.hilfe-rumpf p { margin: 0 0 .6rem; line-height: 1.55; }
.hilfe-rumpf p:last-child { margin-bottom: 0; }
.hilfe-rumpf em { font-style: normal; font-weight: 600; }

/* Der Satz, der eine Folge hat -- doppelte Positionen, ein geloeschtes
   Zimmer. Er steht abgesetzt, nicht in Rot: Es ist kein Fehler, sondern
   eine Bedingung. */
.hilfe-warnung {
  padding: .6rem .75rem; border-radius: 8px;
  background: var(--warn-grund); color: var(--warn);
  border: 1px solid color-mix(in srgb, var(--warn) 25%, transparent);
}

.hilfe-liste { list-style: none; margin: 0 0 .7rem; padding: 0; }
.hilfe-liste li {
  display: flex; gap: .7rem; align-items: flex-start;
  padding: .45rem 0; line-height: 1.5;
}
.hilfe-liste.hilfe-schmal li { display: block; padding: .35rem 0; }
.hilfe-liste.hilfe-schmal li + li { border-top: 1px solid var(--linie); }

/* Die Zeichen links sind dieselben wie im Sucher -- nachgebaut, nicht
   beschrieben. Wer "das runde Ding unten" sucht, erkennt es hier wieder. */
.hilfe-zeichen {
  flex: none; width: 2rem; height: 2rem; display: grid; place-items: center;
  color: var(--gedaempft); font-size: 1.05rem;
}
.hilfe-punkt {
  border-radius: 999px; background: var(--text);
  box-shadow: 0 0 0 3px var(--karte), 0 0 0 4px var(--linie);
  width: 1.5rem; height: 1.5rem; margin: .25rem;
}
.hilfe-ring {
  border-radius: 999px;
  border: 3px solid var(--primaer); border-right-color: var(--linie);
  border-bottom-color: var(--linie);
}
.hilfe-regler {
  height: 4px; border-radius: 999px; background: var(--linie);
  position: relative; align-self: center;
}
.hilfe-regler::after {
  content: ""; position: absolute; left: .25rem; top: 50%;
  width: .7rem; height: .7rem; margin-top: -.35rem;
  border-radius: 999px; background: var(--text);
}

.hilfe-fuss {
  padding: .8rem 1.1rem 1rem; border-top: 1px solid var(--linie);
  background: var(--karte);
}
.zimmer-nummer {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--gedaempft);
}
.zimmer-kopf-name strong { font-size: 1.02rem; }
.zimmer-fotos {
  font-size: .82rem; color: var(--gedaempft);
  font-variant-numeric: tabular-nums;
}

/* Am Maximum ist auch die Dateiauswahl zu. Sie ist ein <label>, kein
   Knopf -- disabled wirkt darauf nicht, also uebernimmt das die Anzeige. */
.aktionen.voll label { opacity: .45; pointer-events: none; }

/* Der Rückzieher im Hinweis. Bewusst klein und unauffällig: Der Normalfall
   ist, dass man ihn nicht braucht -- er soll da sein, nicht drängen. */
.hinweis-weg {
  background: none; border: 0; padding: 0; font: inherit;
  color: var(--primaer); text-decoration: underline; cursor: pointer;
}

.zimmer-hinweis {
  margin: .6rem 0 0; font-size: .85rem; color: var(--gedaempft);
  text-align: center;
}

/* Die Nummer auf der Miniatur. Sie ist nicht Zierde: Das Modell bekommt
   die Fotos nummeriert und meldet zurueck, auf welchem ein unbekannter
   Gegenstand steht. */
.mini-nr {
  position: absolute; left: 4px; bottom: 4px;
  min-width: 18px; height: 18px; padding: 0 4px;
  display: grid; place-items: center; border-radius: 9px;
  background: rgba(0, 0, 0, .6); color: #fff;
  font-size: .7rem; line-height: 1; font-variant-numeric: tabular-nums;
}

/* --- Die Zimmer der Aufnahme --- */
.raeume { margin-bottom: 1rem; }
.raeume h3 {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--gedaempft); margin: 0 0 .5rem;
}
.raum-liste { list-style: none; margin: 0 0 .7rem; padding: 0;
  display: flex; flex-direction: column; gap: .4rem; }
.raum {
  padding: .6rem .75rem; border: 1px solid var(--linie);
  border-radius: 10px; background: var(--karte);
}
/* Nicht `.raum-kopf` -- die Klasse gehoert seit je den Zwischen-
   ueberschriften der Positionsliste weiter unten. Zwei Regeln unter
   demselben Namen faerben sich gegenseitig ein: Der Zimmername kam in
   Grossbuchstaben und Grau daher, weil die andere Regel mitgriff. */
.raum-zeile-kopf { display: flex; align-items: baseline; gap: .1rem .5rem; flex-wrap: wrap; }
/* Der Name darf NICHT schmaler werden als sein eigenes Wort.
   Hier stand `min-width: 0`. Das erlaubt dem Kasten, unter die Breite
   seines Inhalts zu schrumpfen -- und ein einzelnes Wort wie "Homeoffice"
   kann nirgends umbrechen, also lief es rechts heraus, quer ueber die
   Zahlen. Gemeldet mit Bildschirmfoto, nachgestellt bei 20px Grundschrift:
   Der Kasten war 30 Pixel breit, das Wort dreimal so lang.
   Ohne die Zeile bestimmt das laengste Wort die Mindestbreite, die Zeile
   bricht um, und die Zahlen ruecken darunter. `break-word` bleibt als
   letzte Rettung fuer "Mansardenzimmerhintenlinks" -- es erlaubt den
   Bruch, ohne die Mindestbreite kaputtzumachen (`anywhere` taete das). */
.raum-zeile-kopf strong { flex: 1 1 auto; overflow-wrap: break-word; font-size: 1rem; }
/* Die Zimmernummer als Anker.
   Ein Name zwischen vier Knoepfen ist Text unter Text -- das Auge findet
   ihn nicht. Ein Kaestchen davor gibt ihm eine Kante, an der es
   haengenbleibt, und macht nebenbei die Reihenfolge der Aufnahme sichtbar.
   Bewusst ohne Farbe: Rot, Blau und Gelb sind in dieser App vergeben --
   "pruefen", "bleibt hier", Kartons, der Hauptknopf. Wer Farbe fuer eine
   Ueberschrift ausgibt, hat sie fuer die Bedeutung nicht mehr. */
.raum-nr {
  flex: none; width: 1.85rem; height: 1.85rem; border-radius: 8px;
  display: grid; place-items: center;
  background: var(--grund); border: 1px solid var(--linie);
  font-size: .85rem; font-weight: 700; color: var(--gedaempft);
  font-variant-numeric: tabular-nums;
}
.raum-zahlen {
  /* `0 1 auto`, nicht `0 0 auto`.
     Ohne das Schrumpfen laeuft "10 Gegenstaende · 5.5 m³" auf einem
     schmalen Schirm aus seinem Kasten heraus und unter das +. Gemeldet
     vom Fold 4 zugeklappt: Dort sind es rund 280 CSS-Pixel, und mit
     grosser Systemschrift noch weniger.
     Umbrechen darf es auch -- lieber zwei kurze Zeilen als eine, die
     unter einem Knopf verschwindet. */
  flex: 0 1 auto; overflow-wrap: break-word;
  font-size: .82rem; color: var(--gedaempft); font-variant-numeric: tabular-nums;
}
/* Ein noch offenes Zimmer ist kein Fehler, aber es fehlt etwas -- und das
   soll man beim Durchsehen erkennen, ohne zu suchen. */
.raum.offen { border-left: 3px solid var(--warn); }
.raum.offen .raum-zeile-kopf strong::after {
  content: " · noch nicht aufgenommen";
  font-weight: 400; font-size: .8rem; color: var(--warn);
}
/* Die drei Handgriffe am Zimmer als Raster, nicht als Fluss.
   Im Fluss haengt es von den Wortlaengen ab, wo umgebrochen wird -- bei
   grosser Schrift stand "Loeschen" allein auf einer Zeile und
   "Packmaterial" allein auf der naechsten. Das sieht nach Versehen aus,
   nicht nach Ordnung.
   Als Raster fuellen sie die Zeile immer ganz: drei nebeneinander, wo es
   passt, sonst zwei, sonst einer -- und sie sind gleich breit. Die Schrift
   bleibt unangetastet: Wer sein Telefon gross eingestellt hat, hat das so
   gewollt. */
.raum-aktionen {
  display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .5rem;
}
/* Sie wachsen, bis die Zeile voll ist.
   Ohne das Wachsen haengt es an den Wortlaengen, wo umgebrochen wird: Bei
   grosser Schrift stand "Loeschen" allein und halb so breit auf einer
   eigenen Zeile -- das sieht nach Versehen aus, nicht nach Ordnung. Mit
   `flex: 1 1 auto` fuellt jede Zeile sich ganz, bei drei nebeneinander so
   gut wie bei einem allein.
   Ein Raster mit fester Mindestbreite taete dasselbe, muesste diese Breite
   aber raten -- und ratet man zu knapp, quillt "Neu scannen" aus seinem
   Knopf. So bestimmt der Text seine Breite selbst. */
.raum-aktionen button { flex: 1 1 auto; padding: .4rem .6rem; font-size: .8rem; }
.gefahr { color: var(--gefahr); border-color: var(--gefahr); }

/* Nur fuer Vorleseprogramme -- ein Feld ohne sichtbare Beschriftung
   braucht trotzdem eine. */
.nur-vorleser {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

select, input[type="text"], input[type="search"], input[type="password"], input[type="number"] {
  width: 100%; padding: .7rem; font: inherit; color: var(--text);
  background: var(--grund); border: 1px solid var(--linie); border-radius: 10px;
}

/* --- Miniaturen --- */
.miniaturen {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: .5rem; margin-bottom: .9rem;
}
.mini { position: relative; aspect-ratio: 1; border-radius: 10px; overflow: hidden; background: var(--linie); }
.mini img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mini .weg {
  position: absolute; top: 3px; right: 3px; width: 26px; height: 26px;
  border-radius: 50%; background: rgba(0, 0, 0, .65); color: #fff;
  font-size: .85rem; line-height: 1; padding: 0;
}

/* --- Fortschritt --- */
.fortschritt { margin-top: .9rem; text-align: center; }

/* Der Weg aus dem Warten heraus. Zurückhaltend: Zusehen ist genauso
   richtig wie weitermachen, und ein kräftiger Knopf hier läse sich wie
   eine Aufforderung, das Ergebnis nicht abzuwarten. */
#btnFortschrittWeiter { margin-top: .9rem; font-size: .9rem; }

/* Das Logo dreht sich, solange die Analyse laeuft. Ohne dieses Zeichen
   wirken 20 Sekunden Wartezeit wie ein Absturz. */
.spinner {
  width: 60px; height: 60px; margin: .2rem auto .9rem; position: relative;
  display: flex; align-items: center; justify-content: center;
  /* Dunkle Scheibe hinter der Marke. Die gelieferte Fassung ist weiss --
     auf der hellen Karte war sie schlicht unsichtbar, der Spinner sah aus
     wie ein leerer Ring. Eingefaerbt wird sie nicht, sie bekommt den
     Untergrund, fuer den sie gemacht ist. */
  background: #070b14;
  border-radius: 50%;
}

/* Die Marke im drehenden Ring: vollstaendig, nur in der Groesse angepasst.
   Kein Ausschnitt, keine Einfaerbung. Das Seitenverhaeltnis von rund 3.5
   zu 1 bleibt, deshalb passt sie in die Breite. */
.spinner-logo {
  width: 42px; height: auto; display: block;
  animation: puls 1.6s ease-in-out infinite;
}
/* Im dunklen Kreis gilt immer die helle Fassung. */
.spinner img.logo-voll { display: none; }
.spinner img.logo-voll-hell { display: block; }

@media (prefers-reduced-motion: reduce) {
  .spinner-logo { animation: none; }
}

.spinner::before {
  content: ""; position: absolute; inset: -7px;
  border: 3px solid var(--linie); border-top-color: var(--primaer);
  border-radius: 50%; animation: dreh 1.1s linear infinite;
}
/* Ein zweiter Ring, langsamer und gegenlaeufig. Zwei Geschwindigkeiten
   wirken beschaeftigt; einer allein wirkt wie ein haengendes Rad. */
.spinner::after {
  content: ""; position: absolute; inset: -13px;
  border: 2px solid transparent; border-bottom-color: #22d3ee;
  border-radius: 50%; opacity: .8;
  animation: dreh 2.4s linear infinite reverse;
}

@keyframes dreh { to { transform: rotate(360deg); } }
@keyframes puls { 50% { opacity: .45; } }

@media (prefers-reduced-motion: reduce) {
  .spinner::before { animation-duration: 3s; }
  .spinner::after { animation-duration: 6s; }
}
.balken {
  height: 8px; background: var(--linie); border-radius: 999px;
  overflow: hidden; position: relative;
}
/* Der Balken laeuft asymptotisch und wuerde sonst wie eingefroren wirken.
   Der wandernde Glanz zeigt: Es arbeitet noch, auch wenn die Breite kaum
   mehr waechst. */
.balken-fuellung {
  height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--primaer), #22d3ee);
  transition: width .45s cubic-bezier(.22, .9, .3, 1);
  position: relative; overflow: hidden;
}
.balken-fuellung::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent, rgba(255, 255, 255, .55), transparent);
  transform: translateX(-100%);
  animation: glanz 1.5s ease-in-out infinite;
}
@keyframes glanz { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  .balken-fuellung::after { animation: none; }
}
.fortschritt p { margin: .5rem 0 0; font-size: .875rem; color: var(--gedaempft); }

/* --- Summen --- */
.summe {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem;
  text-align: center; margin-bottom: 1rem;
}
.summe div { background: var(--grund); border-radius: 10px; padding: .7rem .3rem; }
.summe strong { display: block; font-size: 1.5rem; line-height: 1.1; }
.summe span { font-size: .75rem; color: var(--gedaempft); }

/* --- Positionen ---
   Auf 375 px Breite konkurrieren Bild, Name, Zahlen, Mengensteuerung und
   Papierkorb um denselben Platz. Deshalb zwei Zeilen: oben Bild, Name und
   Menge, darunter die Details über die volle Breite. Der Name bekommt so
   genug Raum und bricht nicht mehr mitten im Wort um. */
.positionen { list-style: none; margin: 0; padding: 0; }

/* --- Die Zimmerueberschrift in der Positionsliste ---

   Sie war eine Fussnote: klein, grau, gesperrt gesetzt -- zwischen fetten
   Moebelnamen mit Bild und drei Knoepfen daneben ging sie unter. Wer durch
   achtzig Zeilen scrollt, verliert damit die Orientierung, welches Zimmer
   er gerade liest.

   Drei Sachen zusammen machen daraus eine Abschnittsmarke:

     1. **Luft davor.** Was einen Abschnitt trennt, ist der Abstand, nicht
        die Schriftgroesse. Oben doppelt so viel wie unten -- die
        Ueberschrift gehoert zu dem, was unter ihr steht.
     2. **Die Textfarbe** statt Grau, und eine Spur groesser. Sie darf
        gelesen werden, nicht bloss geahnt. Gesperrt und in Versalien
        bleibt sie trotzdem: So konkurriert sie nicht mit den Moebelnamen,
        sondern ordnet sie.
     3. **Sie bleibt stehen.** Beim Scrollen durch ein langes Zimmer klebt
        sie unter der Kopfleiste, bis das naechste Zimmer sie wegschiebt.
        Damit steht immer da, wo man ist -- das ist der eigentliche Gewinn,
        und es kostet keine Zeile Skript.

   Der Grund muss dabei decken: Eine durchsichtige Ueberschrift, unter der
   Moebelnamen durchlaufen, ist schlimmer als gar keine. */
.raum-kopf {
  position: sticky; top: var(--leiste); z-index: 3;
  /* `center` statt `baseline`: Seit ein runder Knopf in der Zeile steht,
     zoege eine Grundlinie den Text an ihm hoch. */
  /* `wrap`, seit neben dem Namen eine Nummer, m³ UND kg stehen: Bei
     grosser Schrift bricht die Zeile um, statt auszulaufen. */
  display: flex; justify-content: space-between; align-items: center;
  gap: .15rem .5rem; flex-wrap: wrap;
  /* Die Luft davor als Polsterung, nicht als Aussenabstand.
     Ein Aussenabstand wird nicht mitgemalt: Klebt die Ueberschrift oben,
     scheint im Abstand darueber die vorige Zeile durch und wandert unter
     dem schwarzen Balken hindurch. Als Polsterung gehoert er zur
     Ueberschrift und traegt ihren Grund mit. */
  /* Der gefuellte Grund -- der eine Zug aus dem dritten Vorschlag.
     Aus einer Textzeile zwischen Textzeilen wird damit ein Trenner. Er
     laeuft bis an die Kartenkanten: Ein Band, das vor dem Rand aufhoert,
     sieht aus wie ein Kasten, der nicht passt. Die 1rem sind die
     Polsterung der Karte -- aussen abgezogen, innen wieder zugegeben. */
  margin: 0 -1rem; padding: .6rem 1rem .5rem;
  background: var(--grund);
  font-size: .88rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em; color: var(--text);
  border-bottom: 1px solid var(--linie);
}
/* Die erste braucht die Luft nicht -- ueber ihr steht schon der Kartenrand. */
.raum-kopf:first-child { padding-top: .1rem; }
/* Die Zahl daneben ordnet sich unter: Sie ist eine Angabe, keine
   Ueberschrift, und in Versalien gesetzt waere sie ohnehin unlesbar. */
.raum-kopf .raum-kopf-m3 {
  font-size: .82rem; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--gedaempft);
}
/* Angesprungen bleibt sie unter der Kopfleiste sichtbar.
   Die Leiste klebt oben (`position: sticky`) und ist rund 56 Pixel hoch --
   ohne diesen Abstand landet die Ueberschrift genau darunter, und wer
   "Anschauen" drueckt, sieht die Zeile, die er sucht, nicht. */
.raum-kopf { scroll-margin-top: calc(var(--leiste) + .4rem); }
/* Dieselbe Nummer unten in der Liste -- gefuellt statt umrandet.
   Oben steht sie neben Knoepfen und muss sich zurueckhalten; hier traegt
   sie die Ueberschrift und darf. Dass es dieselbe Zahl ist, verbindet
   Scanfenster, Zimmerkarte und Liste ohne ein Wort. */
.raum-kopf-nr {
  flex: none; width: 1.5rem; height: 1.5rem; border-radius: 6px;
  display: grid; place-items: center;
  background: var(--text); color: var(--karte);
  font-size: .75rem; font-weight: 700; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
/* `1 1 auto` statt `1`: `flex: 1` bedeutet `1 1 0%` und erlaubt dem
   Kasten, schmaler zu werden als sein laengstes Wort -- dann laeuft
   "SCHLAFEN ELTERN" aus ihm heraus. Mit `auto` bestimmt der Inhalt die
   Mindestbreite, und die Zahlen daneben ruecken in die naechste Zeile. */
.raum-kopf-name { flex: 1 1 auto; }
.raum-kopf-name[role="button"] { cursor: pointer; }
.raum-kopf-name[role="button"]:focus-visible {
  outline: 2px solid var(--primaer); outline-offset: 3px; border-radius: 4px;
}
/* Das Plus traegt in genau dieses Zimmer nach. Klein und rund: Es ist eine
   Abkuerzung zu "Position hinzufuegen" weiter unten, kein zweiter
   Hauptknopf -- und es steht achtmal auf dem Schirm, einmal je Zimmer. */
/* Die Kopfzeile der Zimmerkarte: Sprungziel links, Plus rechts. */
.raum-zeile { display: flex; align-items: center; gap: .5rem; }
.raum-zeile .raum-zeile-kopf { flex: 1; min-width: 0; }

.raum-kopf-plus {
  flex: none; width: 1.9rem; height: 1.9rem; padding: 0; margin-left: .5rem;
  border-radius: 999px; border: 1px solid var(--linie);
  background: var(--karte); color: var(--gedaempft);
  font-size: 1.05rem; font-weight: 600; line-height: 1;
}
.raum-kopf-plus:active { background: var(--linie); color: var(--text); }
/* Die lose Kleinware neben dem Namen bleibt eine Nebenbemerkung. */
.raum-kopf .raum-lose { font-weight: 500; text-transform: none; letter-spacing: 0; }
.raum-kopf .raum-kopf-m3 { flex: none; }

/* Auch die Zimmerkarte oben leuchtet auf, wenn man von unten hochspringt --
   und bleibt dabei unter der klebenden Kopfleiste sichtbar. */
.raum { scroll-margin-top: calc(var(--leiste) + .4rem); }
/* Damit eine angesprungene Zeile nicht unter der Leiste klebt --
   dieselbe Rechnung wie beim Zimmerkopf. */
[data-pos-fenster] { scroll-margin-top: calc(var(--leiste) + .4rem); }
@media (prefers-reduced-motion: no-preference) {
  .raum.angesprungen { animation: angesprungen 1.4s ease-out; }
}
.raum-kopf:first-child { padding-top: 0; }

.pos {
  display: grid;
  grid-template-columns: 40px 1fr auto auto;
  grid-template-areas:
    "bild name menge weg"
    "bild detail detail detail";
  align-items: center;
  column-gap: .6rem;
  padding: .7rem 0;
  border-bottom: 1px solid var(--linie);
}
.pos:last-child { border-bottom: 0; }

.pos-bild {
  grid-area: bild; width: 40px; height: 40px;
  border-radius: 8px; background: var(--grund);
  object-fit: contain; padding: 2px;
}
.pos-text { display: contents; }
.pos-name {
  grid-area: name; font-weight: 600; line-height: 1.25;
  /* `break-word`, nicht `anywhere`.
     `anywhere` setzt die Mindestbreite der Spalte auf ein Zeichen -- das
     Raster gibt dem Namen dann fast nichts, und "Beistell-Tisch 0" bricht
     mitten im Wort um. Sichtbar wird das erst bei grosser Schrift, wo die
     Knoepfe daneben mehr Platz nehmen; auf einem Telefon mit
     Standardeinstellung faellt es nie auf.
     `break-word` erlaubt denselben Bruch, laesst der Spalte aber ihr
     laengstes Wort als Mindestmass. */
  overflow-wrap: break-word;
}
.pos-detail {
  grid-area: detail; font-size: .8rem; color: var(--gedaempft);
  margin-top: .15rem;
}
/* Die Bemerkung der KI ist Zusatzinfo -- sie darf die Zeile nicht sprengen. */
.pos-notiz {
  grid-area: detail; display: none;
}
.pos-detail + .pos-notiz {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; grid-area: auto / 2 / auto / 5;
  font-size: .78rem; color: var(--gedaempft); opacity: .8;
  margin-top: .1rem; font-style: italic;
}

.pos-menge {
  grid-area: menge; display: flex; align-items: center; gap: .15rem; flex: none;
}
.pos-menge button {
  width: 32px; height: 32px; padding: 0; font-size: 1.1rem; line-height: 1;
  background: var(--grund); border: 1px solid var(--linie);
}
.pos-menge .wert {
  min-width: 1.6em; text-align: center; font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.pos .weg-pos {
  grid-area: weg; background: transparent; color: var(--gedaempft);
  padding: .35rem .1rem .35rem .45rem; font-size: 1rem;
}
.pos .weg-pos:hover { color: var(--gefahr); }

/* --- Sehr schmale Schirme ---

   Der Fold 4 zugeklappt sind rund 280 CSS-Pixel, mit grosser
   Systemschrift noch weniger. In einer Zeile stehen dort Bild, Name,
   Menge und Loeschen nicht mehr nebeneinander: Der Name bekommt 25 Pixel,
   sein kuerzestes Wort braucht 130, und die Zeile laeuft aus der Karte.

   Statt die Knoepfe zu verkleinern -- sie werden mit dem Daumen bedient --
   bekommt die Zeile eine dritte Ebene: Name und ✕ oben, die Masse
   darunter, der Mengenschalter zuletzt. Dieselben Elemente, gestapelt. */
@media (max-width: 22rem) {
  .pos {
    grid-template-columns: 40px 1fr auto;
    grid-template-areas:
      "bild name   weg"
      "bild detail detail"
      "bild menge  menge";
    align-items: start;
  }
  /* Hier ist `anywhere` richtig -- und nur hier.
     Ueberall sonst waere es die Falle von vorhin: Es setzt die
     Mindestbreite auf ein Zeichen, und das Raster quetscht den Namen zu
     einer Saeule. Bei 280 Pixeln gibt es diese Wahl aber nicht mehr:
     "Kommode/Sideboard" ist laenger als die Spalte, und ein harter Bruch
     ist besser als eine Zeile, die aus der Karte laeuft. */
  .pos-name { overflow-wrap: anywhere; }
  .pos-menge { justify-self: start; margin-top: .4rem; }
  .pos .weg-pos { align-self: start; }
  /* Und die Handgriffe am Zimmer untereinander statt gequetscht. */
  .raum-aktionen button { flex: 1 1 100%; }
}

.unsicher { border-left: 3px solid var(--warn); padding-left: .55rem; }
.marke-unsicher { color: var(--warn); font-weight: 600; }

.breit { display: block; width: 100%; margin-top: 1rem; }
.ergebnis-aktionen { display: flex; gap: .5rem; margin-top: .5rem; }
.ergebnis-aktionen > * { flex: 1; }

/* --- Hinweise --- */
.hinweis {
  background: var(--warn-grund); color: var(--warn); border-radius: 10px;
  padding: .8rem 1rem; margin: .75rem; font-size: .9rem;
}
.hinweis code { background: rgba(0, 0, 0, .08); padding: 0 .25em; border-radius: 4px; }

/* Die Probeansicht auf der Kontoseite. Deutlich abgesetzt: Wer hier steht,
   soll auf einen Blick sehen, dass die Leere ein Zustand ist und kein
   Fehler. */
.probe-hinweis {
  background: rgba(180, 83, 9, .1); border-color: rgba(180, 83, 9, .35);
  margin-bottom: 1.2rem;
}
main .hinweis { margin: .9rem 0 0; }

/* --- Vorschläge für fehlende Katalog-Einträge --- */
#fehlend {
  background: var(--karte); color: inherit; border: 1px solid var(--warn);
  border-radius: var(--radius); padding: .9rem;
}
.vorschlag-titel {
  margin: 0 0 .2rem; font-size: .85rem; text-transform: uppercase;
  letter-spacing: .05em; color: var(--warn);
}
.vorschlag-hilfe { margin: 0 0 .8rem; font-size: .82rem; color: var(--gedaempft); }

.vorschlag {
  display: grid; grid-template-columns: 62px 1fr;
  gap: .6rem; padding: .7rem 0; border-top: 1px solid var(--linie);
}
.v-bild {
  width: 62px; height: 62px; border-radius: 8px; object-fit: cover;
  background: var(--grund);
}
.v-bild.leer {
  display: grid; place-items: center; color: var(--gedaempft); font-size: 1.4rem;
}
.v-felder { min-width: 0; }
.v-name { width: 100%; font-weight: 600; padding: .45rem .5rem; }

.v-zahlen {
  display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .4rem;
  align-items: center;
}
.v-zahlen label {
  display: flex; align-items: center; gap: .3rem;
  font-size: .78rem; color: var(--gedaempft);
}
.v-zahlen input[type="number"] {
  width: 4.6rem; padding: .35rem .4rem; font-size: .9rem;
}
.v-zahlen .v-dem { gap: .25rem; }
.v-zahlen input[type="checkbox"] { width: 1rem; height: 1rem; }

.v-knoepfe {
  grid-column: 1 / -1; display: flex; gap: .5rem; margin-top: .1rem;
}
.v-knoepfe button { flex: 1; }

/* --- Dialoge --- */
dialog {
  border: 0; border-radius: var(--radius); padding: 1.25rem;
  background: var(--karte); color: var(--text);
  width: min(34rem, 94vw); max-height: 86vh; box-shadow: var(--schatten);
}
dialog::backdrop { background: rgba(0, 0, 0, .55); }
dialog h2 { margin: 0 0 .9rem; font-size: 1.1rem; }
.neu-zeile { display: flex; gap: .5rem; margin-bottom: 1rem; }
.neu-zeile input { flex: 1; }
.auftragsliste, .katalogliste { list-style: none; margin: 0 0 1rem; padding: 0; max-height: 52vh; overflow: auto; }
.auftragsliste li, .katalogliste li {
  display: flex; align-items: center; gap: .7rem;
  padding: .7rem 0; border-bottom: 1px solid var(--linie); cursor: pointer;
}
.auftragsliste li:hover, .katalogliste li:hover { background: var(--grund); }
.auftragsliste .titel, .katalogliste .titel { flex: 1; min-width: 0; }
.auftragsliste .meta, .katalogliste .meta { font-size: .8rem; color: var(--gedaempft); }
.katalogliste img { width: 40px; height: 40px; object-fit: contain; flex: none; }

/* --- Anmeldung --- */
.anmeldung {
  max-width: 22rem; margin: 15vh auto; padding: 2rem 1.5rem;
  background: var(--karte); border-radius: var(--radius); box-shadow: var(--schatten);
}
.marke-gross img { width: 100%; max-width: 15rem; height: auto; display: block; }
.marke-gross h1 { margin: 0; font-size: 1.5rem; }
.anmeldung h1 { margin: 0; font-size: 1.5rem; }
.untertitel { margin: .25rem 0 1.5rem; color: var(--gedaempft); font-size: .9rem; }
.anmeldung label { display: block; font-size: .8rem; color: var(--gedaempft); margin-bottom: .3rem; }
.anmeldung button { width: 100%; margin-top: .9rem; background: var(--primaer); color: #fff; padding: .8rem; }
.fehler { color: var(--gefahr); font-size: .9rem; }

/* --- Toast --- */
.toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
  background: var(--text); color: var(--karte); padding: .7rem 1.1rem;
  border-radius: var(--eck); font-size: .9rem; z-index: 100;
  box-shadow: var(--schatten); max-width: 90vw;
}

/* --- Die Anleitung ---
   Ein Grundriss von oben und vier Schritte. Von oben, weil sich nur so
   zeigen laesst, dass sich die Blickfelder ueberschneiden -- und das ist
   der Kern: Derselbe Schrank auf drei Bildern bleibt einer. */
.anleitung { width: min(32rem, 94vw); }
.anleitung-plan {
  width: 100%; height: auto; display: block;
  margin: .2rem 0 1rem; border-radius: 10px;
  background: var(--grund);
}
.plan-wand path { fill: none; stroke: var(--text); stroke-width: 3; }
/* Die Tuerluecke deckt die Wand wieder auf -- darum in der Farbe des
   Untergrunds, nicht "keine Linie": Sie liegt darueber. */
.plan-luecke { stroke: var(--grund) !important; stroke-width: 5 !important; }
.plan-blatt { stroke: var(--linie) !important; stroke-width: 1.5 !important; }
.plan-fenster { stroke: var(--primaer) !important; stroke-width: 5 !important; }

.plan-moebel * { fill: var(--linie); stroke: var(--gedaempft); stroke-width: 1.2; }
.plan-kegel polygon { fill: var(--primaer); opacity: .13; }
.plan-kamera circle { fill: var(--primaer); }
.plan-nummer text {
  fill: #fff; font-size: 13px; font-weight: 700; text-anchor: middle;
}

.anleitung-kern {
  margin: 0 0 1.1rem; font-size: .95rem; line-height: 1.55;
}
/* Der Querformat-Hinweis in der Anleitung. Abgesetzt, weil er eine
   Handhabung erklaert und keinen Schritt in der Reihenfolge. */
.anleitung-quer {
  display: flex; gap: .6rem; align-items: flex-start;
  margin: .9rem 0 0; padding: .7rem .85rem;
  border-radius: 10px; background: var(--warn-grund); color: var(--warn);
  font-size: .875rem; line-height: 1.5;
}
.anleitung-quer svg {
  width: 20px; height: 20px; flex: none; margin-top: .1rem;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}

.anleitung-schritte {
  margin: 0 0 1.2rem; padding-left: 1.3rem;
  display: flex; flex-direction: column; gap: .7rem;
  font-size: .92rem; line-height: 1.5;
}
.anleitung-schritte strong { display: block; }
.anleitung-fuss { position: sticky; bottom: 0; background: var(--karte); }

/* --- Zurück ins Scanfenster ---
   Unten in der Mitte, wo der Daumen ohnehin liegt. Er erscheint erst,
   wenn der Sucher aus dem Bild gescrollt ist: Solange man davorsteht,
   wäre er ein Knopf vor dem Auslöser. */
.weiter-scannen {
  position: fixed; z-index: 88;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 1rem);
  left: 50%; transform: translate(-50%, 10px);
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .75rem 1.3rem; border: 0; border-radius: var(--eck);
  background: var(--primaer); color: #fff;
  font: inherit; font-size: .95rem; font-weight: 600;
  box-shadow: 0 6px 22px rgba(0, 0, 0, .28);
  opacity: 0; visibility: hidden;
  transition: opacity .2s ease, transform .2s ease, visibility .2s;
}
.weiter-scannen.da { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
.weiter-scannen:hover { background: var(--primaer-dunkel); }
.weiter-scannen svg { width: 17px; height: 17px; }

/* Im Querformat sitzt der Sucher fest über allem -- dann gibt es nichts,
   wohin dieser Knopf noch führen könnte, und er laege ueber dem Bild.
   Hochkant gilt das NICHT: Dort ist der Sucher ein Element wie jedes
   andere, man scrollt daran vorbei zur Liste hinunter -- und genau dann
   wird der Weg zurueck gebraucht.
   Die Regel stand hier ohne Bedingung und blendete ihn auch hochkant aus,
   sobald die Kamera lief. Gemeldet: "nach dem speichern geht er direkt zur
   liste runter und genau dort fehlt der button". Die Ursache war nicht die
   Logik, die den Knopf zeigt -- die stimmte --, sondern diese Zeile, die
   ihn danach wieder wegnahm. */
@media (orientation: landscape) and (max-height: 560px) {
  body.kamera-offen .weiter-scannen { display: none; }
}

/* --- Der eingeblendete Hinweis ---
   Oben, unter der Leiste: Dort schaut man hin, nachdem man den Auslöser
   gedrückt hat -- und dort steht er weder dem Sucher noch dem Daumen im
   Weg. */
.merkzettel {
  position: fixed; z-index: 90;
  top: calc(env(safe-area-inset-top, 0px) + 3.7rem);
  left: 50%; transform: translate(-50%, -8px);
  width: min(30rem, calc(100vw - 1.6rem));
  display: grid; grid-template-columns: auto 1fr auto; gap: .1rem .6rem;
  padding: .8rem .9rem 1rem;
  background: #070b14; color: #e8eefb;
  border-radius: 12px; box-shadow: 0 6px 28px rgba(0, 0, 0, .3);
  opacity: 0; visibility: hidden; overflow: hidden;
  transition: opacity .25s ease, transform .25s ease, visibility .25s;
}
.merkzettel.da { opacity: 1; visibility: visible; transform: translate(-50%, 0); }

.merk-zeichen { width: 19px; height: 19px; flex: none; color: #7dd3fc; margin-top: .1rem; }
.merk-text { margin: 0; font-size: .92rem; line-height: 1.45; }
.merk-knoepfe { grid-column: 2; }
.merk-knoepfe { display: flex; align-items: center; gap: .9rem; flex-wrap: wrap; }
.merk-aus {
  background: none; border: 0; padding: .35rem 0 0; font: inherit;
  font-size: .82rem; color: #8fa6c8; text-decoration: underline;
}
/* Der Knopf, der irgendwohin führt. Kräftiger als «Nicht mehr anzeigen»:
   Das eine ist der Weg, das andere die Notbremse. */
.merk-hin {
  margin-top: .35rem; padding: .4rem .8rem; border-radius: var(--eck);
  background: rgba(125, 211, 252, .16); border: 1px solid rgba(125, 211, 252, .4);
  color: #bae6fd; font: inherit; font-size: .85rem; font-weight: 600;
}
.merk-hin:hover { background: rgba(125, 211, 252, .26); }
.merk-weg {
  grid-row: 1; grid-column: 3; align-self: start;
  width: 26px; height: 26px; padding: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .1); border: 0; color: #e8eefb;
  font-size: .8rem; line-height: 1;
}

/* Der Balken läuft ab. Er sagt: Das hier geht von selbst weg, du musst
   nichts tun. Ohne ihn wartet man darauf, etwas tun zu müssen. */
.merk-balken {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px;
  background: #7dd3fc; transform-origin: left center;
}

@media (prefers-reduced-motion: reduce) {
  .merkzettel { transition: opacity .01s; }
  .weiter-scannen { transition: opacity .01s; transform: translate(-50%, 0); }
  .merk-balken { transition: none !important; }
}

/* --- Konto löschen ---
   Ganz unten und in der Warnfarbe: Niemand sucht danach, aber jeder muss
   es finden — und niemand soll versehentlich darauf tippen. */
.gefahr-karte { border: 1px solid var(--gefahr); }
.gefahr-karte h2 { color: var(--gefahr); }
.konto-weg-aktionen { margin-top: .9rem; }
.gefahr-knopf {
  background: var(--gefahr); color: #fff; border: 0;
  padding: .7rem 1.2rem; border-radius: var(--eck); font-weight: 600;
}
.gefahr-knopf:disabled { opacity: .5; }
.konto-weg-frage { margin: 1rem 0 .6rem; }
.konto-weg-frage label {
  display: block; font-size: .85rem; color: var(--gedaempft);
  margin-bottom: .35rem;
}
.dialog-knoepfe { display: flex; gap: .6rem; justify-content: flex-end; }
#kWegFolgen { font-size: .93rem; line-height: 1.55; color: var(--text); }

/* Die Seite nach dem Löschen. Sie ersetzt alles -- alles andere führte in
   eine Anwendung, in der es diese Person nicht mehr gibt. */
.konto-weg-ende {
  max-width: 32rem; margin: 4rem auto; padding: 0 1.2rem;
  font: 16px/1.6 system-ui, -apple-system, sans-serif; color: var(--text);
}
.konto-weg-ende h1 { font-size: 1.4rem; margin: 0 0 .8rem; }

.fuss { text-align: center; padding: 1.5rem; font-size: .8rem; color: var(--gedaempft); }
.fuss a { color: inherit; }

/* --- Foto-Kontrolle vor dem Scannen --- */
.vorschau { border-radius: var(--radius); overflow: hidden; }
.vorschau img {
  display: block; width: 100%; max-height: 62vh; object-fit: contain;
  background: #000;
}
.vorschau-knoepfe {
  display: flex; gap: .5rem; margin-top: .6rem;
  /* Luft beim Heranscrollen.
     Nach dem Foto wird auf diese Reihe gescrollt. Mit `block: "end"` legt
     der Browser ihre Unterkante genau auf die Fensterkante -- gemessen
     560.4 px in einem 560 px hohen Fenster, also einen Hauch darunter, und
     auf einem Geraet mit Gestenleiste noch etwas mehr. */
  scroll-margin-bottom: 1.2rem;
}
.vorschau-knoepfe > * { flex: 1; margin-top: 0; }

/* Quer steht das Bild links, die Entscheidung rechts.
 *
 * Untereinander passt es nicht: 62vh Bild plus zwei Knopfreihen sind mehr
 * als 375 px. Gemessen lagen "Nochmals" und "Übernehmen" bei 401 bis 458 --
 * unter dem Rand. Und Scrollen half nicht, weil die ganze Vorschau höher
 * war als der Schirm.
 *
 * Dieselbe Aufteilung wie bei der Kamerawahl, aus demselben Grund: Quer ist
 * Breite da und Höhe knapp. */
@media (orientation: landscape) and (max-height: 560px) {
  .vorschau {
    display: grid; grid-template-columns: 1fr auto;
    gap: .7rem; align-items: center;
  }
  .vorschau img { max-height: 74dvh; }
  .vorschau-knoepfe {
    flex-direction: column; margin-top: 0; min-width: 9rem;
  }
  .vorschau-knoepfe > * { flex: none; }
}
@supports not (height: 1dvh) {
  @media (orientation: landscape) and (max-height: 560px) {
    .vorschau img { max-height: 70vh; }
  }
}

/* --- Phasen während der Analyse --- */
.phasen {
  list-style: none; margin: .6rem auto 0; padding: 0;
  max-width: 22rem; text-align: left;
}
.phasen li {
  position: relative; padding: .28rem 0 .28rem 1.6rem;
  font-size: .88rem; color: var(--gedaempft); opacity: .5;
}
.phasen li::before {
  content: "○"; position: absolute; left: 0; top: .28rem;
}
.phasen li {
  transition: opacity .35s ease, color .35s ease;
}
/* Der laufende Schritt schiebt sich leicht nach rechts und traegt einen
   pulsierenden Punkt -- damit auf den ersten Blick klar ist, wo es steht. */
.phasen li.laeuft {
  opacity: 1; color: var(--text); font-weight: 600;
  transform: translateX(2px);
}
.phasen li.laeuft::before {
  content: ""; width: .52rem; height: .52rem; border-radius: 50%;
  background: var(--primaer); top: .62rem; left: .1rem;
  box-shadow: 0 0 0 0 rgba(29, 78, 216, .45);
  animation: phasenpuls 1.4s ease-out infinite;
}
.phasen li.fertig { opacity: .8; }
.phasen li.fertig::before {
  content: "✓"; color: var(--ok);
  animation: phasenhaken .32s ease-out;
}
@keyframes phasenpuls {
  0%   { box-shadow: 0 0 0 0 rgba(29, 78, 216, .45); }
  70%  { box-shadow: 0 0 0 .55rem rgba(29, 78, 216, 0); }
  100% { box-shadow: 0 0 0 0 rgba(29, 78, 216, 0); }
}
@keyframes phasenhaken {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .phasen li.laeuft::before { animation: none; }
  .phasen li.fertig::before { animation: none; }
}

/* --- Abschluss --- */
.abschluss { margin-top: 1.2rem; padding-top: 1rem; border-top: 1px solid var(--linie); }
#btnAbschliessen {
  background: var(--ok); color: #fff;
}
.abschluss-hilfe {
  margin: .5rem 0 0; font-size: .82rem; color: var(--gedaempft); text-align: center;
}
.abgeschlossen-band {
  background: rgba(4, 120, 87, .1); border: 1px solid var(--ok);
  color: var(--ok); border-radius: var(--radius);
  padding: .9rem 1rem; margin-top: 1rem; font-size: .9rem;
}
/* Der Knopf im Band gehört zum Band, nicht in dessen Fliesstext -- sonst
   sitzt er mitten im Satz und liest sich wie ein verunglückter Link. */
#btnWiederOeffnen { display: block; margin-top: .7rem; }

/* --- Dasselbe Zimmer ein zweites Mal --- */
.rg-warnung {
  background: rgba(180, 83, 9, .1); border: 1px solid rgba(180, 83, 9, .35);
  border-radius: 10px; padding: .7rem .8rem; margin: .9rem 0 0;
  font-size: .85rem; line-height: 1.45;
}
.rg-knoepfe { display: flex; gap: .6rem; margin-top: 1rem; flex-wrap: wrap; }
.rg-knoepfe button { flex: 1 1 9rem; }

/* --- Nach der Zahlung dazugescannt ---
   Der Name bleibt lesbar, die Zahlen nicht. Die Zeile soll sagen "das habe
   ich erkannt, dafür ist noch nicht bezahlt" -- nicht "hier ist etwas
   kaputt". Also gedämpft, nicht durchgestrichen. */
.pos.nicht-bezahlt { opacity: .78; }
.pos.nicht-bezahlt .pos-bild { filter: blur(4px); }
.verwischt { filter: blur(2.5px); user-select: none; }

/* Ist die Liste fest, verschwinden die Bedienelemente zum Ändern. */
body.gesperrt .pos-menge,
body.gesperrt .weg-pos,
body.gesperrt #warteschlange { display: none; }


/* --- Anmeldung per Link --- */
.bestaetigung {
  background: rgba(4, 120, 87, .1); border: 1px solid var(--ok);
  color: var(--ok); border-radius: 10px; padding: .7rem .9rem;
  font-size: .9rem; margin: 0 0 .6rem;
}
.anmeldung-hilfe { margin-top: 1.2rem; font-size: .82rem; }
.leise { color: var(--gedaempft); font-size: .85rem; }

/* --- Die Wort-Bild-Marke ----------------------------------------------------
   Zwei Dateien: eine fuer hellen, eine fuer dunklen Grund. Es darf immer nur
   eine sichtbar sein.

   Frueher stand das weiter oben mit ".logo-voll-hell { display: none }" --
   und wurde von ".marke-gross img { display: block }" ueberstimmt, weil das
   spezifischer ist. Ergebnis: beide Fassungen uebereinander, das Logo sah
   veraendert aus. Der zweite Anlauf mit "img.logo-voll-hell" hatte dieselbe
   Spezifitaet wie ".marke img" und gewann nur durch die Reihenfolge -- das
   traegt nicht. Jetzt steht der Container davor und schlaegt beide sicher.
   Das Logo selbst wird nie skaliert, beschnitten oder eingefaerbt. */
.marke img.logo-voll-hell,
.marke-gross img.logo-voll-hell { display: none; }
@media (prefers-color-scheme: dark) {
  .marke img.logo-voll,
  .marke-gross img.logo-voll { display: none; }
  .marke img.logo-voll-hell,
  .marke-gross img.logo-voll-hell { display: block; }
}

/* --- Stoerungsmeldung -------------------------------------------------------
   Bleibt stehen, bis man sie wegklickt. Auffaellig genug, um nicht ueber-
   sehen zu werden, aber ohne Alarmfarbe: meistens ist es nur eine
   abgelaufene Anmeldung. */
.stoerung {
  background: var(--karte); border-left: 4px solid var(--gefahr);
  border-radius: var(--radius); box-shadow: var(--schatten);
  padding: .9rem 1rem; margin: .75rem 0;
}
.stoerung-text { margin: 0; font-weight: 600; }
.stoerung-rat { margin: .4rem 0 0; color: var(--gedaempft); font-size: .9rem; }
.stoerung-knoepfe { display: flex; gap: .5rem; margin-top: .8rem; flex-wrap: wrap; }

/* Hinweis im Sucher, waehrend im Hintergrund gescannt wird. */
/* --- Der Scan im Sucher ---------------------------------------------------
   Legt sich mitten aufs Live-Bild, waehrend im Hintergrund erkannt wird.
   Das Bild wird dabei bewusst abgedunkelt: Die Sekunden gehoeren dem
   Zimmer, nicht dem naechsten Foto. Wer trotzdem weiterknipsen will,
   kommt an den Ausloeser -- die Flaeche laesst Klicks durch. */
.kamera-arbeit {
  position: absolute; inset: 0;
  display: grid; place-content: center; justify-items: center;
  gap: 1.1rem;
  background: rgba(7, 11, 20, .55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  pointer-events: none;
  animation: einblenden .35s ease-out;
}
.kamera-arbeit[hidden] { display: none; }

.kamera-scheibe {
  position: relative;
  width: min(46vw, 190px); aspect-ratio: 1;
  display: grid; place-items: center;
}
/* Die gelieferte helle Fassung, unveraendert -- sie ist fuer genau diesen
   dunklen Grund gemacht. Kein Ausschnitt, keine Einfaerbung. */
.kamera-marke {
  width: 52%; height: auto; display: block;
  filter: drop-shadow(0 2px 14px rgba(0, 0, 0, .55));
  animation: markenpuls 2s ease-in-out infinite;
}
/* Ein Ring, der sich zeichnet und wieder aufloest. Anders als ein
   Fortschrittsbalken behauptet er nichts ueber die Restzeit -- die kennen
   wir nicht. */
.kamera-ring {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  transform: rotate(-90deg);
  overflow: visible;
}
.kamera-ring circle {
  fill: none; stroke: #22d3ee; stroke-width: 3; stroke-linecap: round;
  stroke-dasharray: 283;
  stroke-dashoffset: 212;
  filter: drop-shadow(0 0 6px rgba(34, 211, 238, .55));
  animation: ringlauf 1.4s linear infinite,
             ringlaenge 2.6s ease-in-out infinite;
  transform-origin: 50% 50%;
}
.kamera-arbeit-text {
  margin: 0; color: #e8eefb; font-size: 1.02rem; font-weight: 600;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .7);
  letter-spacing: .01em;
}
/* Im Querformat sitzt der Ausloeser rechts und der Platz ist knapp --
   dann faellt die Scheibe kleiner aus, statt die Leiste zu ueberdecken. */
@media (orientation: landscape) and (max-height: 520px) {
  .kamera-scheibe { width: min(28vw, 140px); }
  .kamera-arbeit { gap: .7rem; }
  .kamera-arbeit-text { font-size: .9rem; }
}

@keyframes ringlauf { to { transform: rotate(360deg); } }
@keyframes ringlaenge {
  0%, 100% { stroke-dashoffset: 240; }
  50%      { stroke-dashoffset: 140; }
}
@keyframes markenpuls {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .72; transform: scale(.94); }
}
@keyframes einblenden { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .kamera-marke { animation: none; }
  .kamera-ring circle {
    animation: ringlauf 3s linear infinite;
    stroke-dashoffset: 190;
  }
  .kamera-arbeit { animation: none; }
}

/* ============================================================================
   Anmeldung -- im Stil von ai-inventar.ch

   Von dort uebernommen: der dunkle Grund #070B14, der Verlauf von Blau nach
   Cyan, die Pillenform der Knoepfe und Inter als Schrift. Die Seite ist
   senkrecht wie waagrecht zentriert.

   Dunkel ist hier nicht Geschmack, sondern Notwendigkeit: Die Wort-Bild-Marke
   liegt als weisse Fassung vor, und die braucht dunklen Grund. Eingefaerbt
   oder beschnitten wird sie nicht.
   ========================================================================= */

.anmeldeseite {
  min-height: 100dvh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 1.25rem;
  background:
    radial-gradient(1100px 620px at 50% -10%, rgba(59, 130, 246, .16), transparent 60%),
    radial-gradient(760px 420px at 90% 110%, rgba(34, 211, 238, .10), transparent 60%),
    #070b14;
  color: #e8eefb;
  font-family: Inter, "Helvetica Neue", Arial, system-ui, sans-serif;
}

.anmeldung {
  width: 100%;
  max-width: 25rem;
  margin: 0;
  padding: 2.25rem 1.75rem 1.75rem;
  text-align: center;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .09);
  border-radius: 22px;
  box-shadow: 0 30px 70px rgba(0, 0, 0, .45);
  backdrop-filter: blur(6px);
}

.anmeldung .marke-gross { margin-bottom: 1.1rem; }
.anmeldung .marke-gross img {
  width: 100%; max-width: 15rem; height: auto;
  margin: 0 auto; display: block;
}
.anmeldung h1 { margin: 0; font-size: 1.5rem; color: #fff; }

.anmeldung .untertitel {
  margin: 0 0 1.9rem;
  color: #9fb0cd;
  font-size: .92rem;
}

.anmeldung form { text-align: left; }

.anmeldung label {
  display: block;
  font-size: .78rem; letter-spacing: .02em; text-transform: uppercase;
  color: #8fa2c2; margin-bottom: .45rem;
}

.anmeldung input[type="email"],
.anmeldung input[type="text"],
.anmeldung input[type="password"] {
  width: 100%;
  padding: .85rem 1rem;
  font-size: 1rem;
  color: #fff;
  background: rgba(255, 255, 255, .06);
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--eck);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.anmeldung input::placeholder { color: #6f819f; }
.anmeldung input:focus {
  border-color: rgba(59, 130, 246, .8);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, .22);
}

.anmeldung button[type="submit"] {
  width: 100%;
  margin-top: 1.1rem;
  padding: .9rem 1.2rem;
  font-size: 1rem; font-weight: 700;
  color: #06101f;
  background: linear-gradient(92deg, #3b82f6, #22d3ee);
  border: 0; border-radius: var(--eck);
  cursor: pointer;
  transition: transform .12s, filter .12s;
}
.anmeldung button[type="submit"]:hover { filter: brightness(1.06); }
.anmeldung button[type="submit"]:active { transform: translateY(1px); }

.anmeldung .leise,
.anmeldung .anmeldung-hilfe { color: #8496b4; font-size: .84rem; }
.anmeldung .anmeldung-hilfe { margin-top: 1.4rem; line-height: 1.55; }

.anmeldung .bestaetigung {
  margin: 0 0 1rem;
  padding: .7rem .9rem;
  color: #bff3e0;
  background: rgba(34, 211, 238, .10);
  border: 1px solid rgba(34, 211, 238, .28);
  border-radius: 14px;
  font-size: .9rem;
}

.anmeldung .fehler {
  margin: 0 0 1rem;
  padding: .7rem .9rem;
  color: #ffd0d0;
  background: rgba(239, 68, 68, .12);
  border: 1px solid rgba(239, 68, 68, .32);
  border-radius: 14px;
  font-size: .9rem;
}

.anmeldung .fuss { margin: 1.6rem 0 0; font-size: .85rem; }
.anmeldung .fuss a { color: #7fb0ff; text-decoration: none; }
.anmeldung .fuss a:hover { text-decoration: underline; }

/* Auf dem dunklen Grund gilt immer die weisse Fassung der Marke -- unabhaengig
   davon, was das Geraet sonst eingestellt hat. */
.anmeldeseite .marke-gross img.logo-voll { display: none; }
.anmeldeseite .marke-gross img.logo-voll-hell { display: block; }

/* Hinweisband, solange ein Administrator die Kundenansicht benutzt.
   Auffaellig, damit niemand vergisst, dass er gerade eingeschraenkt ist. */
.probeansicht {
  display: flex; align-items: center; justify-content: center;
  gap: .75rem; flex-wrap: wrap;
  padding: .55rem .9rem;
  background: linear-gradient(92deg, #3b82f6, #22d3ee);
  color: #06101f; font-size: .85rem; font-weight: 600;
  text-align: center;
}
.probeansicht .knopf {
  background: rgba(6, 16, 31, .82); color: #e8eefb;
  border: 0; border-radius: var(--eck); padding: .25rem .8rem;
  text-decoration: none; font-weight: 600; white-space: nowrap;
}
.probeansicht .knopf:hover { background: #06101f; }

/* --- Der Fuellstand ---------------------------------------------------------
   Kubikmeter sind abstrakt, ein Fahrzeug ist es nicht. Wer die Zahl sieht,
   weiss noch nicht, ob ein Wagen reicht -- wer den Laderaum sieht, schon.

   Die Staffelung kommt aus der Praxis: bis 23 m3 der Moebeltransporter,
   darueber der 7-m-Grossraumwagen mit 18 t. Passt auch der nicht mehr,
   werden mehrere gezeigt. */
.wagen {
  padding: .7rem .85rem .75rem;
  margin: 0 0 .85rem;
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  background: var(--grund);
}
.wagen-kopf {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: .5rem; flex-wrap: wrap; margin-bottom: .45rem;
}
.wagen-zahlen { display: flex; align-items: baseline; gap: .35rem; }
.wagen-zahlen strong {
  font-size: 1.45rem; font-weight: 700; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}
.wagen-zahlen span { color: var(--gedaempft); font-size: .85rem; }
.wagen-typ {
  font-size: .75rem; font-weight: 600; letter-spacing: .04em;
  color: var(--primaer); background: rgba(59, 130, 246, .12);
  border-radius: var(--eck); padding: .2rem .7rem;
}

/* Die Zeichnung darf nicht die halbe Ansicht fuellen. Auf einem schmalen
   Geraet -- ein zusammengeklapptes Foldable ist keine 350 Pixel breit --
   sass die Liste sonst unter dem Falz. Deshalb eine Deckelung der Hoehe;
   die Breite passt sich weiterhin an. */
.wagen-bild {
  display: flex; gap: .45rem; align-items: flex-end; justify-content: center;
}
/* Ein Fahrzeug nimmt die Breite, mehrere teilen sie sich -- so sieht man
   auf einen Blick, dass es zwei Fahrten braucht, ohne eine Zahl zu lesen. */
/* `flex-grow` setzt die Zeichnung selbst -- nach ihrem
   Seitenverhaeltnis, damit alle gleich hoch stehen. */
.wagen-bild .wagen-rahmen { flex-shrink: 1; flex-basis: 0; min-width: 0; }

.wagen-fuss {
  margin: .45rem 0 0; font-size: .8rem; color: var(--gedaempft);
  font-variant-numeric: tabular-nums;
}
.wagen-fuss b { color: var(--text); font-weight: 600; }
.wagen-fuss.knapp b { color: var(--warn); }

/* Die Bewegung der Ladung steht bei `.wagen-laderaum` -- sie fuellt jetzt
   in die Breite und nicht mehr in die Hoehe. */

/* --- Neue Gegenstaende laufen ein --------------------------------------------
   Nur nach einem Scan, nicht bei jeder Mengenaenderung -- sonst waere die
   Bewegung kein Hinweis mehr, sondern Unruhe. */
/* Wichtig: die Klasse selbst macht nichts unsichtbar.
   Hier stand "opacity: 0" plus eine Animation, die es zurueckholt. Laeuft
   die Animation nicht -- reduzierte Bewegung im System, ein Browser, der
   sie verschluckt --, bleibt die Zeile fuer immer weg. Genau das ist auf
   einem Z Fold passiert: Platz belegt, nichts zu sehen.

   Mit "backwards" liegt der Startwert in der Animation, nicht auf dem
   Element. Faellt sie aus, ist die Zeile schlicht sofort da. */
.pos.kommt {
  animation: posRein .4s cubic-bezier(.2,.7,.3,1) backwards;
}
@keyframes posRein {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* --- Der Haken beim Abschliessen ------------------------------------------- */
.haken { width: 62px; height: 62px; display: block; margin: .2rem auto 1rem; }
/* Auch hier: ohne Animation muss der Haken sichtbar sein, nicht weg.
   Der Startwert steckt in den Keyframes, nicht auf dem Element. */
.haken circle { fill: none; stroke: var(--ok); stroke-width: 3; }
.haken path {
  fill: none; stroke: var(--ok); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
}
.haken.an circle { animation: hakenKreis .55s ease-out backwards; }
.haken.an path   { animation: hakenZug .35s .42s ease-out backwards; }
@keyframes hakenKreis {
  from { stroke-dasharray: 195; stroke-dashoffset: 195; }
  to   { stroke-dasharray: 195; stroke-dashoffset: 0; }
}
@keyframes hakenZug {
  from { stroke-dasharray: 48; stroke-dashoffset: 48; }
  to   { stroke-dasharray: 48; stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .pos.kommt { animation: none; }
  .haken.an circle, .haken.an path { animation: none; }
}

/* --- Was dieser Scan gebracht hat -------------------------------------------
   Zurueckhaltend: ein Strich am Rand und ein kleines Wort. Das Aufleuchten
   dauert eine gute Sekunde und verschwindet, der Strich bleibt bis zum
   naechsten Scan -- so findet man seinen Gegenstand auch noch, wenn man
   zwischendurch weggescrollt hat. */
.pos.neu {
  position: relative;
  border-left: 3px solid var(--primaer);
  padding-left: calc(.75rem - 3px);
}
.pos.neu::after {
  content: "neu";
  position: absolute; top: .5rem; right: .6rem;
  font-size: .62rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--primaer);
  background: rgba(29, 78, 216, .12);
  border-radius: 999px; padding: .1rem .45rem;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .pos.neu { animation: frischAufleuchten 1.4s ease-out .2s 1; }
}
@keyframes frischAufleuchten {
  0%   { background: rgba(29, 78, 216, .16); }
  100% { background: transparent; }
}

@media (prefers-color-scheme: dark) {
  .pos.neu::after { background: rgba(96, 165, 250, .18); }
  @media (prefers-reduced-motion: no-preference) {
    .pos.neu { animation-name: frischAufleuchtenDunkel; }
  }
}
@keyframes frischAufleuchtenDunkel {
  0%   { background: rgba(96, 165, 250, .22); }
  100% { background: transparent; }
}

/* Der Hinweis waehrend des Scans. Er beantwortet die Frage, die man mit dem
   Telefon in der Hand hat: Muss ich warten? */
#fortschrittText {
  margin: 0 0 .8rem; text-align: center;
  font-size: .92rem; line-height: 1.45; color: var(--text);
  text-wrap: balance;
}
#fortschrittText .leise { display: block; font-size: .82rem; color: var(--gedaempft); }

/* --- Angebot, die App zu installieren ---------------------------------------
   Zurueckhaltend: Es ist ein Angebot, keine Aufforderung. Wer die App im
   Browser benutzt, soll nicht bedraengt werden. */
.installieren {
  margin: 1.4rem 0 0;
  padding: .85rem .95rem;
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  background: var(--karte);
  text-align: left;
}
.installieren.schmal { margin: 0 .75rem 1rem; }

.installieren-text {
  margin: 0 0 .6rem;
  font-size: .85rem; line-height: 1.5; color: var(--gedaempft);
}
.installieren-knopf {
  width: 100%;
  padding: .6rem 1rem;
  font: inherit; font-size: .88rem; font-weight: 600;
  color: #06101f;
  background: linear-gradient(92deg, #3b82f6, #22d3ee);
  border: 0; border-radius: var(--eck); cursor: pointer;
}
.installieren-knopf:disabled { opacity: .6; cursor: default; }
.installieren-knopf:focus-visible { outline: 2px solid var(--primaer); outline-offset: 2px; }

/* Auf der dunklen Anmeldeseite gelten die Farben von dort. */
.anmeldeseite .installieren {
  background: rgba(255, 255, 255, .04);
  border-color: rgba(255, 255, 255, .12);
}
.anmeldeseite .installieren-text { color: #8496b4; }

/* --- Freischalten -----------------------------------------------------------
   Steht dort, wo sonst die Ausgabeknoepfe sind. Kein Sperrbildschirm, kein
   Verwischen: Die Summen darueber bleiben sichtbar, und die ersten
   Positionen auch. Was fehlt, ist die Liste -- und die ist das Produkt. */
.freischalten {
  margin: 1rem 0 0;
  padding: 1.1rem 1rem;
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  background:
    radial-gradient(420px 160px at 20% 0%, rgba(59, 130, 246, .09), transparent 70%),
    var(--grund);
  text-align: center;
}
.freischalten-text { margin: 0 0 .9rem; font-size: .95rem; color: var(--gedaempft); }
.freischalten-text strong { color: var(--text); font-size: 1.25rem; font-weight: 700; }
.freischalten-knopf {
  width: 100%; max-width: 22rem;
  padding: .85rem 1.4rem;
  font: inherit; font-size: 1rem; font-weight: 700;
  color: #06101f;
  background: linear-gradient(92deg, #3b82f6, #22d3ee);
  border: 0; border-radius: var(--eck); cursor: pointer;
}
.freischalten-knopf:disabled { opacity: .65; cursor: default; }
.freischalten-knopf:focus-visible { outline: 2px solid var(--primaer); outline-offset: 3px; }
.freischalten-fuss { margin: .7rem 0 0; font-size: .78rem; color: var(--gedaempft); }

/* Verschlossene Masse.
   Volumen und Gewicht kommen erst mit der bezahlten Liste. Statt einer
   Zahl stehen dort Punkte -- man sieht, dass es etwas gibt, ohne es zu
   bekommen. Bewusst ruhig gehalten: Das ist kein Fehler, sondern ein
   Zustand. */
.summe strong.gesperrt {
  color: var(--gedaempft);
  letter-spacing: .08em;
  cursor: help;
}

/* "offen" neben einer Aufnahme, die noch nicht bezahlt ist.
   Kein Warnzeichen -- offen ist der normale Zustand, solange jemand noch
   dabei ist. Es beantwortet nur die Frage, welche der Aufnahmen in der
   Liste noch auf etwas wartet. */
.auftragsliste .offen {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gedaempft);
  border: 1px solid currentColor;
  border-radius: var(--eck);
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: middle;
}

/* Das Team einer Firma.
   Bewusst dieselbe Zeilenform wie die Aufnahmenliste -- es ist derselbe
   Handgriff: durchsehen, eine Zeile antippen, weiter. */
.team-neu {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 8px;
  margin: 16px 0;
}
.teamliste { list-style: none; margin: 0; padding: 0; }
.teamliste li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--linie);
}
.teamliste li:last-child { border-bottom: 0; }
.teamliste .titel { flex: 1; min-width: 0; }
.teamliste .meta { font-size: .82rem; color: var(--gedaempft); margin-top: 3px; }
.team-tasten { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

/* Woran jemand in der Liste zu erkennen ist. Kein Warnzeichen -- das sind
   Zustaende, keine Fehler. */
.teamliste .rolle {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  border: 1px solid currentColor;
  border-radius: var(--eck);
  padding: 1px 7px;
  margin-left: 7px;
  vertical-align: middle;
  color: var(--primaer);
}
.teamliste .rolle.gesperrt { color: var(--gedaempft); }

@media (max-width: 480px) {
  .team-neu { grid-template-columns: 1fr; }
  .teamliste li { flex-direction: column; align-items: stretch; }
  .team-tasten { justify-content: flex-start; }
}

/* Der Rollenwähler.
   Ein Administrator kann die App in jeder Rolle ansehen, ohne sich
   abzumelden oder ein zweites Gerät zu holen. Solange er in seiner eigenen
   Sicht ist, bleibt die Leiste ruhig; sobald er eine Rolle probt, muss sie
   auffallen -- sonst vergisst man, dass man nicht sich selbst sieht. */
.probeleiste {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 8px 14px;
  font-size: .84rem;
  background: var(--karte);
  border-bottom: 1px solid var(--linie);
}
.probeleiste.aktiv {
  background: #3d2f10;
  border-bottom-color: #6b5418;
  color: #ffd98a;
}
.probe-titel { color: var(--gedaempft); }
.probeleiste.aktiv .probe-titel { color: #ffd98a; font-weight: 600; }

.probe-wahl { display: flex; gap: 4px; flex-wrap: wrap; }
.probe-wahl a {
  padding: 4px 11px;
  border-radius: var(--eck);
  color: var(--gedaempft);
  border: 1px solid transparent;
  white-space: nowrap;
}
.probe-wahl a:hover {
  color: var(--text);
  background: var(--grund);
}

/* In der aktiven Leiste ist der Grund dunkelbraun. Dort wuerde --text
   (fast schwarz) den Namen beim Darueberfahren verschlucken -- man faehrt
   hin und der Eintrag verschwindet. Hier also aufhellen statt abdunkeln. */
.probeleiste.aktiv .probe-wahl a { color: #e5c894; }
.probeleiste.aktiv .probe-wahl a:hover {
  color: #1a1405;
  background: #f0d9a8;
  border-color: #f0d9a8;
}
.probeleiste.aktiv .probe-wahl a:focus-visible {
  outline: 2px solid #ffd98a;
  outline-offset: 2px;
}
.probe-wahl a.gewaehlt {
  color: var(--text);
  border-color: var(--linie);
  background: var(--grund);
}
.probeleiste.aktiv .probe-wahl a.gewaehlt {
  color: #1a1405;
  background: #ffd98a;
  border-color: #ffd98a;
}

.probe-firma, .probe-firma-name {
  font-size: .82rem;
  margin-left: auto;
}
.probe-firma {
  background: var(--grund);
  color: inherit;
  border: 1px solid var(--linie);
  border-radius: 8px;
  padding: 4px 8px;
}
.probe-firma-name { color: inherit; opacity: .85; }

@media (max-width: 560px) {
  .probeleiste { font-size: .78rem; padding: 7px 10px; }
  .probe-firma, .probe-firma-name { margin-left: 0; width: 100%; }
}

/* Die Marke ist jetzt ein Link zur Startseite.
   Ein <a> ist von Haus aus inline -- damit greift der Abstand darunter
   nicht mehr und ein Fallback-Titel bekaeme Linkfarbe samt Unterstrich.
   Am Logo selbst aendert das nichts, es wird nur anklickbar. */
a.marke-gross {
  display: block;
  color: inherit;
  text-decoration: none;
}
a.marke-gross:focus-visible {
  outline: 2px solid var(--primaer);
  outline-offset: 6px;
  border-radius: 8px;
}

/* Impressum und Datenschutz.
   Sie muessen da sein und auffindbar, aber sie sind nicht der Grund, warum
   jemand die Seite geöffnet hat -- also leise, unten, und nicht groesser
   als noetig. */
.rechtliches {
  margin: 2.2rem 0 0;
  text-align: center;
  font-size: .8rem;
  color: var(--gedaempft);
}
.rechtliches a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.rechtliches a:hover { color: var(--text); }
.rechtliches span { margin: 0 .45rem; opacity: .6; }

/* Auf der Anmeldeseite gelten diese Farben nicht.
   Sie ist immer dunkel, auch wenn das Geraet auf Hell steht -- und --text
   ist dann fast schwarz. Beim Zeigen darauf verschwand die Schrift im
   Hintergrund. Also dieselben festen Werte wie im Rest dieser Seite. */
.anmeldeseite .rechtliches { color: #8496b4; }
.anmeldeseite .rechtliches a:hover { color: #e8eefb; }

/* In der App steht dasselbe in der Fusszeile. Die ist zentriert und kein
   Flexkasten -- ein margin-left:auto liefe dort ins Leere. Also eine
   eigene Zeile darunter, damit es sich nicht mit dem Abmelden vermischt. */
.fuss-recht { display: block; margin-top: .55rem; opacity: .85; }
.fuss-recht a { text-decoration: underline; text-underline-offset: 3px; }
.fuss-recht span { margin: 0 .35rem; opacity: .6; }

/* Ein eingeladener Kunde steht in derselben Liste wie das Team, gehoert
   aber nicht dazu -- er nimmt eine einzige Wohnung auf, seine eigene. */
.teamliste .rolle.kunde { color: var(--ok); }

/* Der Weg zurueck in die Verwaltung.
   Er steht vor dem Auftragsnamen, nicht dahinter: Man liest von links,
   und was zurueckfuehrt, gehoert nach vorn. Zurueckhaltend gehalten --
   er ist ein Ausgang, kein Angebot. */
#btnVerwaltung {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: transparent;
  border: 1px solid var(--linie);
  color: var(--gedaempft);
  padding: .35rem .7rem;
  font-size: .82rem;
}
#btnVerwaltung:hover { color: var(--text); border-color: var(--gedaempft); }
#btnVerwaltung svg { flex: none; }

@media (max-width: 560px) {
  /* Auf dem Telefon nur der Pfeil -- der Kopf ist dort knapp. */
  #btnVerwaltung { padding: .35rem .5rem; font-size: 0; gap: 0; }
  #btnVerwaltung svg { width: 17px; height: 17px; }
}

/* Der zweite Schritt des Anmeldelinks.
   Wer hier landet, hat schon geklickt und will hinein -- also ein grosser
   Knopf und ein Satz, sonst nichts. */
.bestaetigen { margin: 1.6rem 0 0; }
.bestaetigen button { width: 100%; padding: .95rem; font-size: 1.02rem; }
.bestaetigen .leise { margin: .8rem 0 0; text-align: center; }

/* Angemeldet bleiben.
   Ueber dem Knopf, nicht darunter: Was die Anmeldung veraendert, gehoert
   gelesen, bevor man sie abschliesst. Die ganze Zeile ist anklickbar --
   ein Kaestchen von achtzehn Pixeln trifft man mit dem Daumen nicht.

   Die Anmeldeseite setzt jedes `label` in gesperrte Grossbuchstaben und in
   ein dunkles Blaugrau -- richtig fuer die zwei Woerter ueber einem
   Eingabefeld, falsch fuer einen ganzen Satz. Auf dem dunklen Grund war er
   praktisch unlesbar. Darum wird hier alles davon zurueckgenommen. */
.anmeldung .bestaetigen .bleiben {
  display: flex; align-items: center; gap: .7rem;
  margin: 0 0 1rem; padding: .75rem .9rem;
  border: 1px solid rgba(148, 180, 255, .22); border-radius: 12px;
  background: rgba(148, 180, 255, .05);
  font-size: .92rem; line-height: 1.4;
  letter-spacing: 0; text-transform: none;
  color: #dbe6f7; cursor: pointer; text-align: left;
}
.anmeldung .bestaetigen .bleiben:hover {
  border-color: rgba(148, 180, 255, .45);
  background: rgba(148, 180, 255, .09);
}
.anmeldung .bestaetigen .bleiben input {
  width: 20px; height: 20px; flex: none; margin: 0;
  accent-color: var(--primaer); cursor: pointer;
}
.anmeldung .bestaetigen .bleiben span { display: block; }

/* Die Nummern der Firma -- ein Kasten, kein Klappfach.
   Zugeklappt sah man nur "Projektnummer erfassen" und klickte daran
   vorbei; ein Pflichtfeld, das man aufklappen muss, ist keines. */
.nummern-titel {
  margin: 0 0 .6rem; font-weight: 700; font-size: .92rem;
}
/* Der Hinweis, solange keine Aufnahme angelegt ist.
   Er steht dort, wo sonst "Kamera starten" steht, und traegt denselben
   Knopf -- nur fuehrt er einen Schritt frueher hin. */
.nummern-sperre {
  display: flex; flex-direction: column; gap: .8rem;
  padding: 1rem; border-radius: var(--radius);
  border: 1px solid var(--warn); background: var(--warn-grund);
}
.nummern-sperre p {
  margin: 0; font-size: .92rem; line-height: 1.5; color: var(--warn);
}

/* Der Startknopf im Nummernkasten -- volle Breite, weil er das Ende des
   Formulars ist und nicht eine Wahl neben anderen. `.breit` gibt es schon
   weiter oben; hier braucht es nur den Abstand zum Hilfetext darueber. */
.nummern .primaer { margin-top: .3rem; }

/* Der Loeschknopf in der Teamliste.
   Zurueckhaltend, nicht rot: Er steht neben "Sperren", und Sperren ist in
   den meisten Faellen das Richtige. Rot wuerde ihn zur naheliegenden Wahl
   machen -- er ist die endgueltige. Erst beim Zeigen faerbt er sich. */
/* Zwei Listen, dieselbe Taste: die im Aufnahme-Dialog der App und die im
   Konto. Beide zeigen dasselbe Team, also soll auch der Knopf gleich
   aussehen. */
.team-tasten .weg,
#kTeam .weg {
  border-color: var(--linie); color: var(--gedaempft); background: none;
}
.team-tasten .weg:hover,
#kTeam .weg:hover {
  border-color: var(--gefahr); color: var(--gefahr);
}

.pflicht {
  font-size: .74rem; font-weight: 700; letter-spacing: .03em;
  color: var(--warn); background: var(--warn-grund);
  padding: .1rem .4rem; border-radius: var(--eck); vertical-align: .06em;
}

/* --- Kontingent der Firma ------------------------------------------------
   Steht im Team-Dialog ueber der Liste. Drei Zustaende: normal, knapp,
   leer -- die Farbe kommt aus den vorhandenen Tokens, damit sie zum Rest
   der Anwendung passt. */
.kontingent {
  border: 1px solid var(--linie);
  border-radius: var(--radius);
  padding: .85rem 1rem;
  margin-bottom: 1.1rem;
  background: var(--grund);
}
.kontingent p {
  margin: .55rem 0 0;
  font-size: .9rem;
  color: var(--gedaempft);
}
.kontingent strong { color: var(--text); }
.kontingent .balkenspur {
  height: 8px;
  border-radius: 999px;
  background: var(--linie);
  overflow: hidden;
}
.kontingent .balken {
  height: 100%;
  border-radius: 999px;
  background: var(--primaer);
  transition: width .3s ease;
}
.kontingent.knapp { border-color: var(--warn); background: var(--warn-grund); }
.kontingent.knapp .balken { background: var(--warn); }
.kontingent.knapp p, .kontingent.knapp strong { color: var(--warn); }
.kontingent.leer { border-color: var(--gefahr); background: #fef2f2; }
.kontingent.leer .balken { background: var(--gefahr); }
.kontingent.leer p, .kontingent.leer strong { color: var(--gefahr); }

/* --- Was mit dem Foto passiert -------------------------------------------
   Steht unter der Raumwahl, also genau dort, wo jemand gleich die Wohnung
   eines Kunden fotografiert. Leise gehalten: eine Zusage, die schreit,
   klingt wie eine Ausrede. */
.fotohinweis {
  display: flex;
  align-items: flex-start;
  gap: .55rem;
  margin: 1rem 0 0;
  font-size: .82rem;
  line-height: 1.5;
  color: var(--gedaempft);
}
.fotohinweis svg {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin-top: .1rem;
  fill: none;
  stroke: var(--ok);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.fotohinweis a { color: var(--primaer); }

/* Der Kostenhinweis -- gleiche Form wie der Datenschutzhinweis darunter,
   nur staerker: Er beantwortet die Frage, die jemanden sonst abspringen
   laesst, und darf darum nicht wie eine Fussnote aussehen.
   Etwas Flaeche und ein blauer Rand links, damit das Auge ihn findet, bevor
   der Finger den Ausloeser trifft. */
.kostenhinweis {
  display: flex; align-items: flex-start; gap: .55rem;
  margin: 1rem 0 0; padding: .7rem .85rem;
  border-radius: 10px; border-left: 3px solid var(--primaer);
  background: var(--grund);
  font-size: .86rem; line-height: 1.5; color: var(--gedaempft);
}
.kostenhinweis strong { color: var(--text); }
.kostenhinweis svg {
  flex: 0 0 auto; width: 17px; height: 17px; margin-top: .1rem;
  fill: none; stroke: var(--primaer); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}

/* Derselbe Hinweis auf der Anmeldeseite. Die steht auf dunklem Grund und
   erbt die Farbtokens nicht -- ohne eigene Werte waere der Text dort
   praktisch unsichtbar. */
.anmeldung .fotohinweis-anmeldung {
  margin-top: 1.4rem;
  padding-top: 1.2rem;
  border-top: 1px solid rgba(148, 180, 255, .14);
  font-size: .8rem;
  line-height: 1.55;
  color: #8496b4;
  text-align: left;
}
.anmeldung .fotohinweis-anmeldung strong { color: #cfe0ff; font-weight: 600; }
.anmeldung .fotohinweis-anmeldung svg { stroke: #22d3ee; }
.anmeldung .fotohinweis-anmeldung a {
  color: #67e8f9;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.anmeldung .fotohinweis-anmeldung a:hover { color: #a5f3fc; }

/* Der Weg zur nächsten Stufe, direkt im Kontingent-Kasten. */
.abo-angebot {
  margin-top: .9rem;
  padding-top: .8rem;
  border-top: 1px solid var(--linie);
}
.kontingent.knapp .abo-angebot { border-top-color: rgba(180, 83, 9, .3); }
.kontingent.leer .abo-angebot { border-top-color: rgba(185, 28, 28, .3); }
.abo-angebot-titel {
  margin: 0 0 .5rem;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--gedaempft);
}
.abo-angebot-stufe {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: .7rem;
  align-items: baseline;
  padding: .55rem .75rem;
  border: 1px solid var(--linie);
  border-radius: 10px;
  background: var(--karte);
  color: var(--text);
  text-decoration: none;
  font-size: .88rem;
}
.abo-angebot-stufe + .abo-angebot-stufe { margin-top: .4rem; }
.abo-angebot-stufe:hover { border-color: var(--primaer); }
.abo-angebot-stufe strong { color: var(--primaer); white-space: nowrap; }

/* Der Umfang der Testphase auf der Anmeldeseite. Zurückhaltend, aber
   vorhanden: Wer sich anmeldet, soll wissen, was er bekommt. */
.anmeldung .anmeldung-umfang {
  margin-top: .9rem;
  font-size: .8rem;
  line-height: 1.55;
  color: #8496b4;
}
.anmeldung .anmeldung-umfang strong { color: #cfe0ff; font-weight: 600; }

/* --- Projekt- und Auftragsnummer beim Anlegen ----------------------------
   Zugeklappt, weil die meisten Aufnahmen keine Nummer brauchen. Kommt der
   Inspektor über einen Link aus der Firmensoftware, klappt es von selbst
   auf und die Nummern stehen drin. */
/* Die Nummern der Firma.
   War ein zugeklapptes <details>; der Rahmen bleibt, das Aufklappen faellt
   weg. Ein bisschen angefaerbt, damit der Kasten sich vom Titelfeld
   darueber abhebt -- er gehoert zur Aufnahme, ist aber nicht dasselbe. */
.nummern {
  margin: .8rem 0 0;
  padding: .75rem .85rem .3rem;
  border: 1px solid var(--linie);
  border-left: 3px solid var(--primaer);
  border-radius: var(--radius);
  background: var(--grund);
}
.nummern-felder {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .7rem;
}
.nummern-felder label {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  font-size: .82rem;
  color: var(--gedaempft);
}
/* Die Innenpolsterung sitzt jetzt am Kasten selbst -- hier bleibt nur der
   Abstand nach oben. */
.nummern .hilfe { padding: 0; margin: .6rem 0 .5rem; }
@media (max-width: 480px) {
  .nummern-felder { grid-template-columns: 1fr; }
}

/* Nach der Bezahlung. Steht über dem Anmeldeformular -- wer eben ein Abo
   gekauft hat, soll nicht als Erstes ein leeres Feld sehen. */
.anmeldung .willkommen {
  margin: 0 0 1.4rem;
  padding: 1rem 1.1rem;
  border: 1px solid rgba(34, 211, 238, .3);
  background: rgba(34, 211, 238, .08);
  border-radius: 14px;
  font-size: .88rem;
  line-height: 1.55;
  color: #cfe0ff;
  text-align: left;
}
.anmeldung .willkommen p { margin: 0 0 .5rem; }
.anmeldung .willkommen p:last-child { margin-bottom: 0; }
.anmeldung .willkommen-titel {
  font-weight: 700;
  color: #bff3e0;
  font-size: .96rem;
}
.anmeldung .willkommen .leise { color: #8496b4; font-size: .82rem; }

/* Wer über einen Kauf-Knopf hierherkommt, sieht was er kauft. */
.anmeldung .kaufhinweis {
  margin: 0 0 1.2rem;
  padding: .85rem 1rem;
  border: 1px solid rgba(34, 211, 238, .3);
  background: rgba(34, 211, 238, .08);
  border-radius: 14px;
  font-size: .9rem;
  line-height: 1.55;
  color: #cfe0ff;
  text-align: left;
}
.anmeldung .kaufhinweis strong { color: #bff3e0; }
.anmeldung .kaufhinweis .leise { color: #8496b4; font-size: .82rem; }

/* Nach der Bezahlung, in der App. Verschwindet auf Klick -- ein Band, das
   bleibt, wird nach dem dritten Mal zur Tapete. */
.hinweis.danke {
  position: relative;
  background: rgba(4, 120, 87, .08);
  border: 1px solid var(--ok);
  color: var(--ok);
  padding-right: 2.6rem;
}
.hinweis.danke strong { display: block; margin-bottom: .2rem; }
.danke-weg {
  position: absolute;
  top: .5rem;
  right: .5rem;
  background: transparent;
  border: 0;
  color: inherit;
  font-size: 1rem;
  line-height: 1;
  padding: .3rem .45rem;
  cursor: pointer;
  opacity: .6;
}
.danke-weg:hover { opacity: 1; }

/* --- Mein Konto ----------------------------------------------------------
 *
 * Eine Seite, die zeigt statt bedient zu werden: Zahlen, Listen, ein paar
 * Felder. Die Abschnitte sind Karten wie überall sonst -- neu ist nur der
 * Wegweiser darüber und die Tabelle der Zahlungen.
 */
.konto {
  max-width: 52rem; margin: 0 auto; padding: 1rem 1rem 4rem;
  display: flex; flex-direction: column; gap: 1rem;
}
.konto-titel { margin: .4rem 0 0; font-size: 1.5rem; }

/* Eine Reihe, keine Spalte: Auf dem Telefon kostet eine Seitenleiste die
   halbe Breite, und dort wird diese Seite vor allem geöffnet. Bei zu
   wenig Platz schiebt sie sich seitwärts, statt umzubrechen. */
/* Hier standen die Knoepfe des Kontowegs. Sie sind jetzt die Seitenleiste
   -- siehe unten, «Die Seitenleiste». */

.konto-werte { display: grid; gap: .6rem; margin: 0 0 1rem; }
.konto-werte > div {
  display: flex; justify-content: space-between; gap: 1rem;
  padding-bottom: .5rem; border-bottom: 1px solid var(--linie);
}
.konto-werte > div:last-child { border-bottom: 0; padding-bottom: 0; }
.konto-werte dt { color: var(--gedaempft); font-size: .875rem; margin: 0; }
.konto-werte dd { margin: 0; font-weight: 600; text-align: right; }

.konto-feld { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .8rem; }
.konto-feld label { font-size: .85rem; color: var(--gedaempft); }
.konto-feld input { width: 100%; }
.konto-feld input:disabled { color: var(--gedaempft); cursor: not-allowed; }

.konto-knoepfe { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1rem; }

/* Eine Tabelle ist auf dem Telefon schmaler als der Inhalt. Sie schiebt
   sich darum in ihrem eigenen Kasten seitwärts -- die Seite selbst bleibt
   stehen, sonst wandert beim Wischen der ganze Text weg. */
.konto-tabelle { overflow-x: auto; }
.konto-tabelle table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.konto-tabelle th {
  text-align: left; font-size: .75rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--gedaempft);
  padding: 0 .6rem .5rem 0; border-bottom: 1px solid var(--linie); white-space: nowrap;
}
.konto-tabelle td {
  padding: .6rem .6rem .6rem 0; border-bottom: 1px solid var(--linie);
  vertical-align: middle;
}
.konto-tabelle tr:last-child td { border-bottom: 0; }
.konto-tabelle .titel { font-weight: 600; }
/* Der Zusatz gehoert unter den Titel, nicht dahinter: Sonst liest sich
   "Paket Small 25 Inventarlisten" wie ein einziger Satz. */
.konto-tabelle .titel .meta {
  display: block; font-weight: 400; font-size: .82rem;
  color: var(--gedaempft); margin-top: 2px;
}
.konto-tabelle .n { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.stand {
  display: inline-block; padding: .15rem .5rem; border-radius: var(--eck);
  font-size: .78rem; font-weight: 600;
}
.stand-bezahlt { background: rgba(4, 120, 87, .12); color: var(--ok); }
.stand-offen { background: var(--warn-grund); color: var(--warn); }

/* Ein Zugang zur Schnittstelle. Abgesetzt, weil mehrere untereinander
   stehen können und sonst nicht zu sehen ist, wo einer aufhört. */
.zugang {
  border: 1px solid var(--linie); border-radius: var(--radius);
  padding: .9rem; margin-bottom: .8rem;
}
.schluessel-zeile { display: flex; gap: .5rem; align-items: center; }
.schluessel-zeile input {
  flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .82rem;
}
.zAktivZeile { display: flex; align-items: center; gap: .45rem; margin: .2rem 0 .6rem; }
.zAktivZeile input { width: auto; }

.gefahr { color: var(--gefahr); border-color: var(--gefahr); }

@media (max-width: 560px) {
  .konto { padding: .75rem .75rem 3rem; }
  .konto-werte > div { flex-direction: column; gap: .15rem; }
  .konto-werte dd { text-align: left; }
}

/* --- Kacheln im Konto ----------------------------------------------------
 *
 * Drei Zahlen fuer die drei Fragen, mit denen jemand hier ankommt. Sie
 * stehen ueber allem anderen, weil diese Seite ueberflogen und nicht
 * gelesen wird -- die Einzelheiten darunter braucht nur, wer sie sucht.
 *
 * auto-fit statt fester Spalten: Auf dem Telefon stehen sie untereinander,
 * auf dem Bildschirm nebeneinander, ohne dass irgendwo eine Zahl
 * gequetscht wird. */
.kacheln {
  display: grid; gap: .75rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.kachel {
  background: var(--karte); border: 1px solid var(--linie);
  border-radius: var(--radius); box-shadow: var(--schatten);
  padding: 1rem 1.1rem;
  display: flex; flex-direction: column; gap: .25rem;
}
.kachel-marke {
  font-size: .72rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--gedaempft);
}
.kachel-zahl {
  font-size: 2rem; font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.kachel-fuss { font-size: .85rem; color: var(--gedaempft); }
.kachel .balkenspur { margin-top: .5rem; }

/* Die einzige Kachel, bei der eine Zahl allein zu wenig ist: "3 von 25"
   sagt nichts, "3 von 25" in Rot sagt alles. */
.kachel.knapp { border-color: var(--warn); background: var(--warn-grund); }
.kachel.knapp .kachel-zahl, .kachel.knapp .kachel-marke,
.kachel.knapp .kachel-fuss { color: var(--warn); }
.kachel.knapp .balken { background: var(--warn); }
.kachel.leer { border-color: var(--gefahr); }
.kachel.leer .kachel-zahl, .kachel.leer .kachel-marke,
.kachel.leer .kachel-fuss { color: var(--gefahr); }
.kachel.leer .balken { background: var(--gefahr); }

.konto-begruessung { margin: .4rem 0 0; }
.konto-begruessung .konto-titel { margin: 0 0 .15rem; }

/* Die Seite, auf der man gerade ist -- kein Knopf, sondern eine Marke. */
.kopf .hier {
  background: rgba(255, 255, 255, .16); cursor: default;
  font-weight: 700;
}

/* Abmelden traegt sein Symbol immer, die Beschriftung nur, wenn Platz ist.
   Auf einem schmalen Telefon waere sie das erste, was die Reihe sprengt. */
.abmelden { margin-left: .15rem; }
@media (max-width: 700px) {
  .nur-breit { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
}

/* --- Kein Empfang --------------------------------------------------------
 *
 * Eine eigene, schmale Leiste und bewusst keine Stoerung: Es ist kein
 * Fehler der Anwendung, sondern ein Zustand, der von selbst vorbeigeht.
 * Darum warnfarben statt alarmfarben -- und ohne Knopf, weil es nichts zu
 * tun gibt ausser warten.
 *
 * Sie erscheint erst, wenn der Ausfall drei Sekunden angehalten hat. Wer
 * durchs Treppenhaus geht, sieht sie gar nicht.
 */
.ohne-netz {
  display: flex; align-items: flex-start; gap: .6rem;
  background: var(--warn-grund); color: var(--warn);
  border: 1px solid var(--warn); border-radius: var(--radius);
  padding: .8rem 1rem; margin: .75rem 0;
  font-size: .9rem; line-height: 1.5; font-weight: 600;
}
.ohne-netz[hidden] { display: none; }
.ohne-netz svg { flex: none; margin-top: 2px; }

/* Zwei Knoepfe in einer Tabellenzelle: Rechnung und Liste. Sie sollen
   nebeneinander bleiben, aber auf dem Telefon umbrechen duerfen. */
.konto-tabelle .zwei-knoepfe {
  display: flex; gap: .4rem; justify-content: flex-end; flex-wrap: wrap;
}

/* --- Gutscheincode ---
   Unter dem Bezahlknopf und zugeklappt: Wer keinen hat -- das sind fast
   alle -- soll nicht an einem Feld vorbei, das ihn nichts angeht. */
.gutschein { margin-top: 1rem; text-align: left; }
.gutschein summary {
  cursor: pointer; font-size: .88rem; color: var(--gedaempft);
  padding: .3rem 0; list-style-position: inside;
}
.gutschein summary:hover { color: var(--text); }
.gutschein-zeile { display: flex; gap: .5rem; margin-top: .6rem; }
.gutschein-zeile input {
  flex: 1; min-width: 0; text-transform: uppercase; letter-spacing: .06em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.gutschein-hinweis {
  margin: .6rem 0 0; font-size: .85rem; line-height: 1.45; color: var(--warn);
}
.gutschein-hinweis.gut { color: var(--ok); }

/* Der Gutscheincode auf dem Anmeldeschirm. Schlanker als der in der
   Bezahlschranke: Hier steht er zwischen Formularfeldern, nicht in einer
   eigenen Karte. */
.gutschein-anmeldung { margin: .2rem 0 .9rem; }
.gutschein-anmeldung summary {
  cursor: pointer; font-size: .88rem; color: var(--gedaempft);
  padding: .35rem 0; list-style-position: inside;
}
.gutschein-anmeldung summary:hover { color: var(--text); }
.gutschein-anmeldung input {
  text-transform: uppercase; letter-spacing: .06em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.gutschein-anmeldung p { margin: .4rem 0 0; font-size: .82rem; }


/* --- Der Wagen und seine Ladung ---
   Die Zeichnung ist ein Bild, die Fuellung eine Flaeche darunter. In
   dieser Reihenfolge: Das Bild hat einen weissen Grund, also muss die
   Ladung dahinter liegen -- durch die weisse Kofferflaeche scheint sie
   nicht durch. Deshalb ist der Koffer in den Zeichnungen leer, und die
   Farbe kommt von hinten. */
.wagen-rahmen { position: relative; width: 100%; }
.wagen-zeichnung {
  position: relative; z-index: 1; display: block; width: 100%; height: auto;
  /* Die Zeichnung ist schwarz auf weiss. Im dunklen Modus wird sie
     umgekehrt -- weisse Linien auf dunklem Grund --, sonst leuchtet ein
     weisses Rechteck aus der Karte heraus. */
  mix-blend-mode: multiply;
}
.wagen-laderaum {
  position: absolute; z-index: 0;
  /* Dunkel an der Stirnwand, heller zur Rampe: Dort, wo zuerst geladen
     wird, steht es dicht. Die Richtung ist dieselbe wie die des
     Ladens -- das Auge liest sie mit. */
  background: linear-gradient(to left, var(--primaer), #60a5fa);
  transition: width .5s cubic-bezier(.22, 1, .36, 1);
}
@media (prefers-reduced-motion: reduce) {
  .wagen-laderaum { transition: none; }
}
@media (prefers-color-scheme: dark) {
  /* Umgekehrt und aufgehellt: `invert` macht aus schwarzen Linien weisse,
     `multiply` faellt weg -- im Dunkeln wuerde es alles ausloeschen. */
  .wagen-zeichnung { filter: invert(1) brightness(1.6); mix-blend-mode: screen; }
}

/* --- Nochmals von vorn ---
   Ganz unten, zurueckhaltend, mit Abstand zu allem darueber. Er wird selten
   gebraucht; wer ihn sucht, findet ihn, und wer ihn nicht sucht, stolpert
   nicht darueber. */
.neu-beginnen { margin: 2rem 0 .5rem; text-align: center; }
.neu-beginnen .gefahr { color: var(--gefahr); border-color: var(--gefahr); }

/* ===================================================================
   Die Zimmerzeile: eingeklappt eine Zeile, aufgeklappt ein Block.
   =================================================================== */

/* Der Kopf ist ein Knopf plus zwei kleine Griffe daneben. Der grosse
   Bereich klappt auf und zu -- das ist, was man staendig tut. */
/* Kein Umbruch mehr: Frueher standen Nummer, Name, m3 UND kg nebeneinander
   und durften bei grosser Schrift umbrechen. Jetzt traegt der Kopf einen
   Knopf, der sich selber kuemmert -- brechen darf es darin, nicht daneben,
   sonst rutschen Plus und die drei Punkte in eine zweite Zeile. */
.raum-kopf { display: flex; align-items: center; gap: .25rem; flex-wrap: nowrap; }
/* Zwei Zeilen: oben der Name, darunter die Zahlen.
 *
 * Nebeneinander ging es nicht. Der Name muss nachgeben, weil die Zahlen es
 * nicht koennen -- und was nachgibt, wird gequetscht: «Homeoffice» stand
 * als Saeule aus einzelnen Buchstaben da, elf Zeilen hoch. Ein Name, der
 * senkrecht steht, ist kein Name mehr.
 *
 * Ein Raster statt einer Reihe. Nummer und Symbol stehen ueber beide
 * Zeilen, der Name bekommt die ganze Breite, die Zahlen ruecken darunter
 * und stehen buendig unter ihm -- nicht am Rand, sondern dort, wo der
 * Blick nach dem Namen ohnehin hinfaellt. */
.raum-klapp {
  flex: 1 1 auto; min-width: 0;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  grid-template-areas:
    "nr sym name   pfeil"
    "nr sym zahlen pfeil";
  align-items: center; column-gap: .55rem; row-gap: .05rem;
  background: none; border: 0; padding: .5rem .15rem;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.raum-klapp .raum-kopf-nr { grid-area: nr; }
.raum-klapp .raum-sym { grid-area: sym; }
.raum-klapp .raum-kopf-name { grid-area: name; }
.raum-klapp .raum-pfeil { grid-area: pfeil; }
.raum-klapp:disabled { cursor: default; }
.raum-klapp:focus-visible { outline: 2px solid var(--primaer); outline-offset: 2px; border-radius: 8px; }

/* Das Symbol: 24 x 24 gezeichnet, hier so gross wie die Schrift daneben.
   Die Farbe kommt aus der Zeile -- deshalb currentColor und sonst nichts. */
.raum-sym {
  width: 1.15rem; height: 1.15rem; flex: none; opacity: .8;
}

/* Der Pfeil dreht sich, statt ein zweites Zeichen zu sein: Ein Dreieck,
   das mal so und mal so zeigt, ist eine Form weniger zu lernen. */
.raum-pfeil {
  flex: none; width: .7rem; height: .7rem; margin-left: .1rem;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px); opacity: .4;
  transition: transform .16s ease;
}
.raum-kopf.auf .raum-pfeil { transform: rotate(-135deg) translate(-2px, -2px); }

/* Die Zahlen stehen in der geschlossenen Zeile: Man muss entscheiden
   koennen, ob sich das Aufklappen lohnt, ohne aufzuklappen. */
/* Die Zahlen stehen unter dem Namen, nicht neben ihm -- und weiterhin in
   einer Zeile: «12 · 7.05 m³ · 368 kg» umzubrechen hilft niemandem. */
.raum-kopf .raum-kopf-m3 {
  grid-area: zahlen; margin-left: 0; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
/* Und der Name hat jetzt die ganze Breite. Bricht er trotzdem -- «Schlafen
   Eltern» bei grosser Schrift --, dann zwischen Woertern, nicht zwischen
   Buchstaben. */
.raum-klapp .raum-kopf-name { min-width: 0; overflow-wrap: break-word; }

/* Die seltenen Griffe: klein, gleich gross wie das Plus, kein Rahmen. */
.raum-mehr {
  flex: none; background: none; border: 0; cursor: pointer;
  color: var(--gedaempft); font-size: 1rem; line-height: 1;
  padding: 0 .45rem; letter-spacing: .06em;
}
.raum-mehr:focus-visible { outline: 2px solid var(--primaer); outline-offset: 2px; border-radius: 6px; }

/* ===================================================================
   Suche in der Liste
   =================================================================== */
.listen-suche { position: relative; margin-top: .6rem; }
.listen-suche input {
  width: 100%; padding: .6rem 2.2rem .6rem .8rem;
  border: 1px solid var(--linie); border-radius: 10px;
  background: var(--grund); color: var(--text); font: inherit;
  -webkit-appearance: none; appearance: none;
}
.listen-suche input::-webkit-search-cancel-button { display: none; }
/* Die Summe unter der Suche -- klein, gedaempft, eine Zeile. */
.suche-total {
  margin: .4rem 0 0 .2rem; font-size: .82rem; color: var(--gedaempft);
  font-variant-numeric: tabular-nums;
}
.suche-total[hidden] { display: none; }
.such-weg {
  position: absolute; right: .35rem; top: 50%; transform: translateY(-50%);
  background: none; border: 0; cursor: pointer; color: var(--gedaempft);
  font-size: .95rem; padding: .35rem .5rem; line-height: 1;
}

/* ===================================================================
   Rueckgaengig in der Meldung
   =================================================================== */
.toast-weg {
  margin-left: .75rem; background: none; border: 0; cursor: pointer;
  color: inherit; font: inherit; font-weight: 600;
  text-decoration: underline; text-underline-offset: 3px;
  padding: 0; white-space: nowrap;
}

/* ===================================================================
   Das Zimmer-Fenster
   =================================================================== */
.raum-feld { display: block; margin: .2rem 0 1rem; font-size: .85rem; color: var(--gedaempft); }
.raum-feld input {
  display: block; width: 100%; margin-top: .3rem;
  padding: .6rem .7rem; border: 1px solid var(--linie); border-radius: 10px;
  background: var(--grund); color: var(--text); font-size: 1rem;
}
.raum-pack-block {
  border-top: 1px solid var(--linie); border-bottom: 1px solid var(--linie);
  padding: .9rem 0; margin-bottom: 1rem;
}
#raumStufen { margin-top: .6rem; }

/* Der Zaehler im Weg zurueck: 2/4.
   Ruhiger als der Text daneben -- er ist eine Auskunft, keine Aufforderung.
   Ziffern in gleicher Breite, damit der Knopf beim Weiterzaehlen nicht
   zuckt. */
.weiter-zaehler {
  margin-left: .5rem; padding-left: .55rem;
  border-left: 1px solid rgba(255, 255, 255, .35);
  font-variant-numeric: tabular-nums; opacity: .85; font-weight: 600;
}

/* Der Objektivknopf im Sucher: eine Zahl, kein Bild.
   «2/3» sagt in zwei Zeichen, was ein Symbol nicht kann -- wo man steht und
   wie viele es gibt. */
.objektiv-knopf span { font-variant-numeric: tabular-nums; }

/* Der Aufnahmeschirm bekommt den Fokus, wenn man zu ihm springt -- ohne
   Rahmen: Der Fokus ist hier Arbeitsstelle, kein Bedienelement. */
#aufnahme:focus { outline: none; }

/* Die Mannschaft rechts der Wagen -- Strichfiguren, so hoch wie die Reihe.
   Etwas Abstand zur Flotte: Menschen stehen nicht im Laderaum. */
.wagen-bild .mannschaft {
  display: grid; gap: .15rem .1rem; align-content: start;
  /* Waechst im Flex wie ein Wagen: Seitenverhaeltnis und flex-grow setzt
     mannschaftBild() aus Spalten und Reihen. */
  flex-shrink: 1; flex-basis: 0; min-width: 0; margin-left: .6rem;
}
.wagen-bild .mannschaft-bild {
  width: 100%; height: auto; display: block;
  /* Schwarz auf weiss, wie die Wagen -- Weiss faellt auf der Karte weg. */
  mix-blend-mode: multiply;
}
/* Auf dem Telefon zwei Zeilen: oben die Wagen, unten die Maenner.
   Neben zwei Wagen wuerden vier Maenner zu Zwergen.

   Der Umbruch braucht einen Trick: Die Wagen haben `flex-basis: 0`, die
   Zeile wird darum nie «voll» -- ein Block mit 100 % passt rechnerisch
   noch hinein. Ein Pixel Rand darueber hinaus, und er faellt in die
   naechste Zeile. Dort stehen die Maenner in fester Groesse, hoechstens
   vier nebeneinander; das Seitenverhaeltnis aus dem Skript gilt hier
   nicht mehr, die Hoehe kommt aus den Bildern. */
@media (max-width: 480px) {
  .wagen-bild { flex-wrap: wrap; }
  .wagen-bild .mannschaft {
    flex: 0 0 100%; margin: .5rem 0 0 1px;
    aspect-ratio: auto !important;
    /* Klein genug, dass die Wagen darueber die Grossen bleiben. */
    grid-template-columns: repeat(4, 2.2rem) !important;
    gap: .2rem;
  }
}
@media (prefers-color-scheme: dark) {
  .wagen-bild .mannschaft-bild { filter: invert(1) brightness(1.6); mix-blend-mode: screen; }
}

/* --- Die Seitenleiste ---
   Ein Menue fuer Verwaltung, Firmen und Kunden: links am Rand, senkrecht,
   jeder Bereich mit seinem Zeichen. Auf dem Telefon wird sie zur Zeile
   oben -- Zeichen ueber Wort, zum Schieben --, denn dort kostet eine
   Seitenleiste die halbe Breite. Die Zeichen stehen in lib/leiste.php. */
/* Kein Raster auf dem Telefon: Dort ist der Rumpf ein gewoehnlicher Block,
   wie vor der Leiste -- und die Leiste selbst wandert ins Burger-Menue
   (kopf.js). Das Raster gibt es nur am Rechner. */
.rumpf { display: block; }
/* Rasterfelder haben `min-width: auto` -- sie werden so breit wie ihr
   breitester Inhalt, eine Tabelle etwa, und ragen dann ueber den Bildschirm
   hinaus; das Telefon zoomt heraus, der Kopf bleibt schmal. Gesehen auf dem
   Dashboard nach Stand 214. `min-width: 0` laesst den Inhalt in seiner
   eigenen Huelle scrollen, wie vorher. */
.rumpf > * { min-width: 0; }
/* Und was trotzdem breiter ist als der Schirm, wird abgeschnitten statt
   die Seite zu weiten: Auf dem Telefon zoomt der Browser sonst heraus,
   bis alles passt, und der Kopf steht schmal ueber breitem Inhalt. Breite
   Tabellen scrollen in ihrer eigenen Huelle; `clip` macht keinen
   Scrollbereich und laesst die klebende Leiste in Ruhe. */
.rumpf { overflow-x: clip; }
.rumpf > main { overflow-x: clip; }
.seitenleiste { display: flex; margin: 0; padding: 0; }
.seitenleiste > * {
  display: flex; align-items: center; gap: .65rem;
  border: 0; background: transparent; color: var(--gedaempft);
  font: inherit; font-weight: 600; text-decoration: none; cursor: pointer;
  border-radius: .6rem; white-space: nowrap;
}
.seitenleiste > *:hover { color: var(--text); background: var(--grund); }
.seitenleiste > .aktiv {
  color: var(--primaer);
  background: color-mix(in srgb, var(--primaer) 12%, transparent);
}
.seitenleiste .leiste-icon { width: 1.25rem; height: 1.25rem; flex: none; }
.seitenleiste .plakette { margin-left: auto; }
.leiste-trenner { flex: 1; }

@media (min-width: 881px) {
  .rumpf { display: grid; grid-template-columns: 14.5rem minmax(0, 1fr); align-items: start; }
  .seitenleiste {
    flex-direction: column; gap: .15rem;
    position: sticky; top: 3.4rem; overflow-y: auto;
    min-height: calc(100vh - 3.4rem); max-height: calc(100vh - 3.4rem);
    padding: 1rem .7rem; border-right: 1px solid var(--linie);
  }
  .seitenleiste > * { padding: .55rem .8rem; font-size: .93rem; width: 100%; text-align: left; }
}
@media (max-width: 880px) {
  /* Auf dem Telefon steht die Leiste im Burger-Menue -- «die Menuepunkte
     im Mobile besser im Burger integriert». kopf.js schiebt sie beim Laden
     dorthin; bis dahin bleibt sie unsichtbar, damit nichts springt. */
  .rumpf > .seitenleiste { display: none; }
  .kopf .kopf-rechts .seitenleiste {
    display: flex; flex-direction: column; gap: 0; order: -1;
    padding: .2rem 0 .3rem; margin: 0 0 .3rem;
    border-bottom: 1px solid rgba(148, 180, 255, .14);
  }
  .kopf .kopf-rechts .seitenleiste > * {
    flex: none; flex-direction: row; justify-content: flex-start; gap: .75rem;
    width: 100%; padding: .8rem .2rem; border-radius: 0;
    font-size: 1rem; color: #e8eefb; background: none;
    border-bottom: 1px solid rgba(148, 180, 255, .09);
  }
  .kopf .kopf-rechts .seitenleiste > *:last-child { border-bottom: 0; }
  .kopf .kopf-rechts .seitenleiste > *:hover { background: rgba(255, 255, 255, .06); color: #fff; }
  .kopf .kopf-rechts .seitenleiste > .aktiv { color: #9fc0ff; background: rgba(159, 192, 255, .1); }
  .kopf .kopf-rechts .seitenleiste .leiste-icon { width: 1.3rem; height: 1.3rem; }
  .kopf .kopf-rechts .seitenleiste .plakette { margin-left: auto; }
  .leiste-trenner { display: none; }
}

/* --- Das Sheet der Auswertung ---
   Ueber allem, halb durchsichtig, wie ein Sheet: unten auf dem Telefon,
   mittig am Rechner. Ein Zustand, eine Auskunft, ein grosser Knopf. */
.aus-sheet {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: flex-end; justify-content: center;
  padding: .75rem; padding-bottom: max(.75rem, env(safe-area-inset-bottom));
  background: rgba(7, 11, 20, .45);
  backdrop-filter: blur(14px) saturate(1.2); -webkit-backdrop-filter: blur(14px) saturate(1.2);
  margin: 0; text-align: center;
}
.aus-sheet[hidden] { display: none; }
.aus-karte {
  width: min(100%, 30rem); max-height: 92dvh; overflow-y: auto;
  background: var(--karte); color: var(--text);
  border-radius: 1.5rem; padding: 1.4rem 1.3rem 1.2rem;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .35);
  animation: aus-auf .28s cubic-bezier(.22, 1, .36, 1);
}
@keyframes aus-auf { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@media (min-width: 700px) { .aus-sheet { align-items: center; } }
@media (prefers-reduced-motion: reduce) { .aus-karte { animation: none; } }
.aus-karte .spinner.ruht .spinner-ring, .aus-karte .spinner.ruht::before { animation: none; }
.aus-karte #fortschrittText { font-size: 1.05rem; margin: .6rem 0 0; color: var(--text); }
.aus-karte .phasen { margin: .8rem auto .4rem; }
.aus-zustand { margin-top: .9rem; }
.aus-zustand .gross { width: 100%; margin-top: .55rem; }
.aus-hinweis { margin: 0 0 .4rem; font-size: .92rem; color: var(--gedaempft); line-height: 1.45; }
.aus-zaehler {
  font-size: 2.6rem; font-weight: 700; line-height: 1; margin: .4rem 0 .6rem;
  font-variant-numeric: tabular-nums; color: var(--primaer);
}
.aus-haken {
  width: 56px; height: 56px; margin: 0 auto .4rem; display: block;
  fill: none; stroke: #16a34a; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round;
}
#ausFertigText { font-size: 1.05rem; color: var(--text); font-weight: 600; }
#ausFehlerText { color: var(--text); }
/* Die Pille im Sucher: laeuft mit, wird gruen, fuehrt zum Ergebnis. */
.aus-pille {
  position: absolute; z-index: 6; left: 50%; transform: translateX(-50%);
  /* Unter der Zimmerzeile und neben keinem Knopf: Oben ueberdeckte sie
     «Zimmer 5» links und das Vollbild rechts. */
  top: calc(3.5rem + env(safe-area-inset-top));
  display: flex; align-items: center; gap: .5rem; max-width: calc(100% - 6.5rem);
  padding: .45rem .95rem; border: 0; border-radius: var(--eck);
  background: rgba(7, 11, 20, .72); color: #fff; font: inherit; font-size: .85rem; font-weight: 600;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.aus-pille[hidden] { display: none; }
.aus-pille-punkt {
  width: .6rem; height: .6rem; border-radius: 50%; flex: none;
  background: #60a5fa; animation: pille-puls 1.2s ease-in-out infinite;
}
.aus-pille.fertig { background: rgba(22, 163, 74, .92); }
.aus-pille.fertig .aus-pille-punkt { background: #fff; animation: none; }
.aus-pille.fehler { background: rgba(220, 38, 38, .92); }
.aus-pille.fehler .aus-pille-punkt { background: #fff; animation: none; }
@keyframes pille-puls { 0%, 100% { opacity: .4; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .aus-pille-punkt { animation: none; } }

/* --- Der Wink nach dem Foto ---
   Unten in der Mitte, drei Sekunden, leuchtend: der Pfeil nach unten zum
   Speicherknopf. Ueber dem Sucher, auch im Vollbild. */
.speichern-wink {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: max(1.1rem, env(safe-area-inset-bottom)); z-index: 85;
  display: flex; align-items: center; gap: .6rem;
  padding: .65rem 1.15rem .65rem .95rem; border: 0; border-radius: var(--eck);
  background: rgba(29, 78, 216, .94); color: #fff; font: inherit; font-size: .9rem; font-weight: 500;
  white-space: nowrap; max-width: calc(100% - 2rem); overflow: hidden; text-overflow: ellipsis;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 10px 30px rgba(29, 78, 216, .35);
  animation: wink-auf .3s cubic-bezier(.22, 1, .36, 1), wink-glanz 1.6s ease-in-out infinite;
}
.speichern-wink[hidden] { display: none; }
.speichern-wink b { font-weight: 700; }
.speichern-wink svg { width: 1.25rem; height: 1.25rem; flex: none; animation: wink-pfeil 1.2s ease-in-out infinite; }
@keyframes wink-auf { from { transform: translateX(-50%) translateY(16px); opacity: 0; } to { transform: translateX(-50%); opacity: 1; } }
@keyframes wink-glanz {
  0%, 100% { box-shadow: 0 10px 30px rgba(29, 78, 216, .35), 0 0 0 0 rgba(96, 165, 250, .55); }
  50% { box-shadow: 0 10px 30px rgba(29, 78, 216, .45), 0 0 0 10px rgba(96, 165, 250, 0); }
}
@keyframes wink-pfeil { 0%, 100% { transform: translateY(-2px); } 50% { transform: translateY(3px); } }
@media (prefers-reduced-motion: reduce) { .speichern-wink, .speichern-wink svg { animation: none; } }
