/* Neutrale Vorgaben (P0-7). Die Gastseite ueberschreibt --brand und --accent aus dem Betriebsdatensatz (_Branding.cshtml). */
:root { --accent: #9DB7D5; --ink: #F2EDE4; --black: #0B0D10; --brand: #1B2430; }
* { box-sizing: border-box; }
html { background: var(--black); color-scheme: dark; }
body {
  margin: 0; padding: 0 16px calc(24px + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, var(--black), var(--brand));
  background-attachment: fixed; color: var(--ink);
  font: 16px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
.head { text-align: center; padding: 20px 0 12px; border-bottom: 1px solid var(--accent); }
.head p { margin: 0; }
.wordmark { margin: 0; text-transform: uppercase; color: var(--accent); font-size: 1.5rem; letter-spacing: .25em; font-weight: 600; }
.logo { display: block; max-height: 64px; max-width: 80%; margin: 0 auto 8px; }
.operation { margin-top: 4px; font-size: .9rem; opacity: .85; }
.foot { text-align: center; margin: 32px 0 0; font-size: .75rem; opacity: .6; }
.foot a { color: inherit; }
.age { font-size: .85rem; opacity: .85; margin-top: 4px; }
.empty { text-align: center; margin: 40px 0; opacity: .85; }
.table { margin-top: 8px; font-weight: 600; }
main { max-width: 640px; margin: 0 auto; }
h2 { color: var(--accent); font-size: 1.15rem; letter-spacing: .08em; text-transform: uppercase; margin: 28px 0 8px; }
.items { list-style: none; margin: 0; padding: 0; }
.items li {
  display: grid; grid-template-columns: 1fr auto; column-gap: 12px;
  padding: 10px 0; border-bottom: 1px solid rgba(242, 237, 228, .12);
}
.price { color: var(--accent); white-space: nowrap; font-variant-numeric: tabular-nums; }
.desc, .notice, .tag { grid-column: 1 / -1; font-size: .85rem; opacity: .75; }
.soldout .name, .soldout .price { opacity: .45; text-decoration: line-through; }
.offline { margin: 8px 0 0; padding: 6px 10px; border: 1px solid var(--accent); border-radius: 6px; color: var(--accent); font-size: .9rem; }

/* ---- Bausteine: Karte, Feld, Schaltflaeche (02.10.2026) --------------------------------------
   Diese Regeln standen bis heute NUR in admin.css. Das Gast-Layout (_Layout) bindet admin.css aber
   nicht ein - deshalb waren die Gast-Kontoseiten (Register, Pending, Confirm, Resend) ohne jede
   Gestaltung: Beschriftung und Eingabefeld in einer Zeile, keine Abstaende, auf der ersten Seite,
   die ein Gast nach dem QR-Code sieht. Sie gehoeren hierher, weil Gast UND Verwaltung sie brauchen;
   admin.css laedt site.css ohnehin immer mit.
   Keine festen Farben: alles leitet sich aus --ink, --black, --brand und --accent ab, die der
   Betrieb ueber /branding.css setzt (P0-7). Nur "falsch" und "in Ordnung" sind eigene Variablen mit
   neutraler Vorgabe - ein Betrieb mit roter Marke soll seine Fehlermeldung trotzdem lesen koennen. */
:root { --bad: #ff9b8a; --good: #9ed9a0; --line: color-mix(in srgb, var(--ink) 15%, transparent); }
.card { border: 1px solid var(--line); border-radius: 10px; padding: 12px; margin: 10px 0;
  background: color-mix(in srgb, var(--black) 70%, transparent); }
.card h3 { margin: 0 0 8px; font-size: 1rem; }

/* Vom Telefon aus gedacht: ein Feld ist eine Zeile, Beschriftung ueber der Eingabe, Eingabe ueber
   die volle Breite. 48px Mindesthoehe ist die Tippflaeche am Tisch, 1rem Schriftgroesse verhindert
   das Hineinzoomen von iOS, und box-sizing (oben) haelt die Breite in der Spalte - also keine
   waagerechte Rollleiste. */
.field { display: block; margin: 10px 0; }
.field > span { display: block; font-size: .85rem; opacity: .8; margin-bottom: 4px; }
.field input[type=text], .field input[type=email], .field input[type=password],
.field input[type=number], .field select, .field textarea {
  width: 100%; min-height: 48px; padding: 10px 12px; font: inherit; font-size: 1rem; color: var(--ink);
  background: color-mix(in srgb, var(--brand) 55%, var(--black));
  border: 1px solid color-mix(in srgb, var(--ink) 30%, transparent); border-radius: 8px;
}
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible,
.check input:focus-visible, .btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.check { display: flex; align-items: center; gap: 10px; min-height: 48px; }
.check input { flex: 0 0 auto; width: 24px; height: 24px; }
.btn { min-height: 48px; padding: 10px 18px; font: inherit; font-weight: 600; color: var(--black);
  background: var(--accent); border: 0; border-radius: 8px; cursor: pointer; }
.btn.ghost { background: transparent; color: var(--ink);
  border: 1px solid color-mix(in srgb, var(--ink) 40%, transparent); }
.btn.danger { background: color-mix(in srgb, var(--bad) 55%, var(--black)); color: var(--ink); }
/* Link im Schaltflaechen-Look; eigene Klasse statt style-Attribut, weil die Richtlinie
   style-src 'self' (P0-8) Inline-Stile sperrt. */
.btn-link { text-decoration: none; display: inline-block; }
.error, .field-validation-error, .validation-summary-errors { color: var(--bad); display: block; margin: 4px 0; }
.notice-ok { color: var(--good); margin: 8px 0; }
.muted { opacity: .7; font-size: .85rem; }
.hint { opacity: .8; font-size: .9rem; margin: 8px 0; }
.closed { margin: 8px 0; padding: 8px 10px; border: 1px solid var(--accent); border-radius: 8px; }

/* Der leere Aufzaehlungspunkt oben auf der Registrierung: asp-validation-summary schreibt die Liste
   IMMER mit und versteckt ihr Platzhalter-<li> per style-Attribut - genau das verwirft die
   Richtlinie style-src 'self' (P0-8). Also wird hier versteckt, was nichts sagt: die ganze Liste im
   gueltigen Zustand, das leere <li> auch im Fehlerzustand. Gilt fuer alle Formulare, nicht nur fuer
   die Registrierung (Login, Invite, Artikel, Kategorien, Betrieb anlegen, Betrieb). */
.validation-summary-valid, .field-validation-valid { display: none; }
.validation-summary-errors ul { margin: 0; padding-left: 1.1rem; }
.validation-summary-errors li:empty { display: none; }

/* Hinweisleiste des Testzugangs (P-4): ein Etikett, nicht ein Absatz. */
.trialnotice { display: inline-block; margin: 8px 0 0; padding: 2px 10px; border: 1px solid var(--accent);
  border-radius: 999px; color: var(--accent); font-size: .75rem; text-transform: uppercase; letter-spacing: .1em; }

/* Zeilenteile des Gastes: Menge, Summe, Vorname, Nummer, Zustand. Bewusst NUR unter .guest, obwohl
   das Board dieselben Namen benutzt: "die Board-Regeln sind spezifischer" stimmt nur fuer
   Eigenschaften, die sie selbst setzen. .board .tile .state setzt keine Deckkraft - eine freie
   Regel .state { opacity: .75 } haette das Zustandswort auf der roten und der goldenen Kachel
   gedimmt, und fett fuer "bestaetigt" haette es von "neu" nicht mehr zu unterscheiden gemacht
   (B1-3). Das Board bleibt deshalb bei seinen Regeln in admin.css. */
.guest .qty { font-variant-numeric: tabular-nums; opacity: .85; }
.guest .sum { margin: 10px 0 0; font-weight: 600; font-size: 1.05rem; }
.guest .guestname { font-weight: 600; }
.guest .ordernumber { font-weight: 700; font-variant-numeric: tabular-nums; }
.guest .state { font-size: .85rem; opacity: .75; }
.guest .line.new .name, .guest .line.confirmed .name { font-weight: 600; }
.guest .line.delivered { opacity: .6; }
.guest .line.cancelled { opacity: .5; text-decoration: line-through; }

/* ---- Gast: Deckel und Bestellen (Karte) ------------------------------------------------------
   Nur unter .guest: dieselben Namen (tab, lines, cart) bedeuten auf dem Board an der Wand etwas
   anderes, und davon darf die Wand nichts mitbekommen. Die Klasse setzen _Layout und die Karte. */
.guest .tab, .guest .cart { margin: 16px 0; padding: 12px; border: 1px solid var(--line);
  border-radius: 10px; background: color-mix(in srgb, var(--black) 70%, transparent); }
.guest .tab h2, .guest .cart h2 { margin: 0 0 8px; }
.guest .lines { list-style: none; margin: 0; padding: 0; }
.guest .line { display: grid; grid-template-columns: auto 1fr auto; column-gap: 8px;
  align-items: baseline; padding: 8px 0; border-bottom: 1px solid var(--line); }
.guest .line .state, .guest .line .strike-reason { grid-column: 1 / -1; }
.guest .cart label { display: block; font-size: .85rem; opacity: .8; margin-bottom: 4px; }
.guest .cart input[type=text] { width: 100%; min-height: 48px; padding: 10px 12px; font: inherit;
  font-size: 1rem; color: var(--ink); background: color-mix(in srgb, var(--brand) 55%, var(--black));
  border: 1px solid color-mix(in srgb, var(--ink) 30%, transparent); border-radius: 8px; }
/* Die beiden Knoepfe der Karte: "Bestellen" ueber die ganze Breite, "+" eine quadratische
   Tippflaeche rechts in der Artikelzeile. */
.guest .send { width: 100%; min-height: 52px; margin-top: 10px; font: inherit; font-weight: 600;
  color: var(--black); background: var(--accent); border: 0; border-radius: 8px; cursor: pointer; }
.guest .plus { grid-column: 2; justify-self: end; width: 48px; height: 48px; font: inherit;
  font-size: 1.5rem; line-height: 1; color: var(--accent); background: transparent;
  border: 1px solid var(--accent); border-radius: 8px; cursor: pointer; }
.guest .withdraw { color: var(--accent); display: inline-block; padding: 8px 0; min-height: 44px; }

/* ---- Kopf und Fuss der Gastseite (02.10.2026) ------------------------------------------------
   Der Befund des Betreibers: die Gastseite "sieht sehr schwach aus - ohne Logo, ohne Fussbereich".
   Das Logo liess sich nie fuellen, der Fuss trug nur die Marke des Hauses. Keine festen Farben:
   alles aus --accent, --ink und --line, die der Betrieb ueber /branding.css setzt (P0-7). Vom
   Telefon aus gedacht - eine Spalte, und jeder Verweis im Fuss hat 44px Tippflaeche. */
/* Nur unter .guest: class="head" tragen auch Verwaltung, Board und Theke - deren Kopf soll sich
   durch den Auftritt des Kunden nicht verschieben. */
/* Ohne untere Linie: unter dem Kopf steht seit dem Plakat-Zug die Zierlinie (.guest .head::after),
   und beides zusammen waere ein doppelter Abschluss. */
.guest .head { padding: 28px 0 0; border-bottom: 0; }
/* Ein Logo ist der Kopf des Hauses und nicht eine Briefmarke ueber viel Leere: auf dem Rechner
   345px, auf dem Telefon 220px (Stufen am Ende des Blocks). Die Breite bleibt gedeckelt, damit ein
   querformatiges Logo die Spalte nicht sprengt - keine waagerechte Rollleiste.
   Alle Stufen sind am 02.10.2026 um gut 45% gewachsen (Owner: "Das Logo muss noch ein bisschen
   breiter"). Gemessen statt geschaetzt: das Logo des ersten Betriebs ist HOCHFORMATIG (752x1154),
   dort begrenzt die Hoehe und nie die Breite - ein hoeherer Breitendeckel allein haette gar nichts
   bewirkt. Auf 360x640, einem echten Telefon, stand die Claim-Zeile vorher bei 202px und steht
   jetzt bei 272px: der Kopf bleibt also ohne Rollen vollstaendig sichtbar.
   Der Breitendeckel waechst trotzdem mit - fuer den naechsten Betrieb, der einen querformatigen
   Schriftzug hinterlegt. Er bleibt ein Prozentsatz unter 100, deshalb kann er in keiner Breite
   ueber den Rand treten (gemessen: Ueberhang 0 in zehn Breiten, hoch wie quer). */
.guest .logo { max-height: 345px; max-width: min(82%, 520px); margin-bottom: 10px; }
.tagline { margin: 8px auto 0; max-width: 30em; font-size: .9rem; letter-spacing: .04em;
  text-transform: uppercase; opacity: .85; }
/* Ueber die Spezifitaet, nicht mit !important: .head p (0,1,1) ist spezifischer als .tagline
   (0,1,0) und hat deshalb deren `margin: 8px auto 0` ueberschrieben. Mit `margin: 0` fielen die
   auto-Raender weg - der Claim klebte in seinem 30em breiten Kasten am linken Rand, waehrend Logo
   und Name mittig standen. Auf der Produktion sichtbar, und es sah nach einem Layoutfehler aus,
   weil es einer war. Dieselbe Regel hat auch .age, .table und .trialnotice ihr margin-top
   genommen: im Kopf klebte alles aneinander.
   .guest .head .x (0,3,0) gewinnt gegen .head p und bleibt dabei auf die Gastseite begrenzt -
   class="guest" tragen nur _Layout und Menu/Index, also behalten Verwaltung, Board und Theke ihren
   Kopf unveraendert.
   Bewusst NICHT der kuerzere Weg ueber `.head :where(p)`: der zaehlt mit Spezifitaet 0 und haette
   den Abstand auch auf den Personalseiten wiederbelebt (.operation ueberall, .trialnotice im
   Testzugang) - vier Kopfzeilen, die hier niemand angefasst haben wollte. Dass deren margin-top
   dort weiterhin tot ist, ist damit bekannt und absichtlich stehen geblieben. */
.guest .head .tagline { margin: 10px auto 0; }
.guest .head .age { margin-top: 12px; }
.guest .head .trialnotice { margin-top: 12px; }
.guest .head .table { margin-top: 10px; }
/* Schmales Geraet: das Logo nimmt anteilig weniger Hoehe, sonst schiebt es die Karte unter die
   Falz - die erste Seite nach dem QR-Code soll mit Artikeln beginnen, nicht mit Scrollen. Die
   Stufe liegt bei 600px und nicht bei 420px: ein Telefon im Querformat und ein kleines Tablet
   lesen die Karte wie ein Telefon, nicht wie ein Rechner. */
@media (max-width: 900px) {
  .guest .logo { max-height: 290px; }
}
@media (max-width: 600px) {
  .guest .logo { max-height: 220px; }
}
/* Der Fuss war mit .6 fast nicht zu lesen - mit Anschrift und Impressum darin ist er kein
   Kleingedrucktes mehr, sondern eine Angabe, die ein Gast finden soll. */
.foot { margin-top: 36px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: .8rem; opacity: .8; }
.foot p { margin: 0 0 4px; }
.foot .contact { opacity: .9; }
.foot .legal a { display: inline-block; min-height: 44px; padding: 10px 6px; color: var(--accent); }

/* ==== GESTALTUNG-KARTE-2026-10-02 =============================================================
   Der Befund des Betreibers: "Die Seite sieht immer noch sehr schwach aus, kein besonderer Stil.
   Der Flyer sieht besser aus." Er hatte recht - die Karte war eine ununterbrochene Liste aus 81
   Zeilen in 10 Gruppen, alles in derselben Groesse, Gruppe und Artikel kaum zu unterscheiden.

   Was die gedruckte Karte besser macht und hier nachgebaut ist:
     - jede Gruppe steht in einem eigenen Feld mit feiner Linie und dunklerem Grund,
     - die Gruppenueberschrift haengt zwischen zwei Zierlinien und traegt eine Serifenschrift,
     - Name und Preis sind durch eine Punktlinie verbunden, der Preis steht rechts in Akzentfarbe,
     - es gibt eine Groessenstufung (Bereich > Gruppe > Name > Beschreibung) statt einer Groesse.

   Keine festen Farben: alles leitet sich ueber color-mix aus --brand, --accent, --ink, --black und
   --line ab, die der Betrieb ueber /branding.css setzt (P0-7). Die dritte, dunkelrote Farbe des
   Flyers gibt es im Modell nicht und sie wird deshalb NICHT erfunden - wo der Flyer sie benutzt,
   steht hier eine Abstufung von --brand. (Der Name dieser Farbe faellt hier bewusst nicht: er
   gehoert einem Kunden, und BrandingTests prueft genau das.)
   Keine fremde Schrift und kein CDN (style-src 'self', P0-8): die Serifenschrift ist ein Stapel
   aus Schriften, die auf dem Geraet schon liegen, und laedt nichts nach.
   Alles unter .guest - dieselben Namen gelten auf Board und Theke anders.
   Vom Telefon aus gedacht: eine Spalte, nichts rollt waagerecht, jede Tippflaeche misst 44px. */
.guest {
  /* Serifen aus dem Bestand des Geraets, in dieser Reihenfolge: Windows/macOS, Windows, Linux. */
  --display: Georgia, "Times New Roman", "Noto Serif", "Liberation Serif", serif;
  /* Die Zierlinie und der Feldrand: Akzent, aber zurueckgenommen - sonst rahmt die Karte sich
     selbst zu Tode. */
  --rule: color-mix(in srgb, var(--accent) 32%, transparent);
  /* Der Grund eines Feldes: ein dunkler Schleier MIT Hausfarbe darin, nicht fast reines Schwarz.
     Beide Stufen sind durchscheinend, also traegt der Grund der Seite seine Waerme ins Feld hinein
     und das Feld bleibt trotzdem dunkler als der Grund - der Text liegt immer auf der dunkleren
     Flaeche. Das gilt auch fuer eine helle oder blaue Hausfarbe, weil der Schleier aus --black
     kommt und nicht aus --brand. */
  --panel-top: color-mix(in srgb, var(--brand) 30%, color-mix(in srgb, var(--black) 62%, transparent));
  --panel-bottom: color-mix(in srgb, var(--brand) 16%, color-mix(in srgb, var(--black) 74%, transparent));
  /* Die goldene Doppellinie des Plakats: aussen der Rand, innen eine feine zweite Linie. */
  --frame: color-mix(in srgb, var(--accent) 46%, transparent);
  --frame-inner: color-mix(in srgb, var(--accent) 20%, transparent);
  /* Das Mass des Lichtscheins hinter dem Kopf. Als Variable und nicht fest im Verlauf, weil es auf
     einem breiten Schirm mitwachsen muss: ein 900px breiter Schein hinter einem 320px hohen Logo
     sieht aus wie ein Scheinwerfer, der zu kurz greift (Block GROSSE SCHIRME am Ende). */
  --glow-w: 900px;
  --glow-h: 520px;

  /* ---- Die Scorpion-Handschrift (docs\scorpion-handschrift.md, 02.10.2026) --------------------
     Die Karte gehoert dem Wirt: Farbe, Logo, Name und Claim sind seine. Was wir mitbringen, ist
     Handwerk - Tiefe und Licht. Deshalb steht hier KEIN fester Farbwert, sondern nur Abstufungen
     von --brand, --accent, --ink und --black. Dieselben Werte auf einer blauen Cafe-Marke ergeben
     dieselbe Tiefe in Blau.

     Die Flaechenleiter (Regel 1): Grund (der Rumpf) -> Flaeche (ein Gruppenfeld) -> gehobene
     Flaeche (Deckel und Bestellen, die beiden Felder, mit denen der Gast wirklich umgeht). Jede
     Stufe eine Spur heller und eine Spur waermer als die darunter. */
  --panel-raised-top: color-mix(in srgb, var(--brand) 42%, color-mix(in srgb, var(--black) 54%, transparent));
  --panel-raised-bottom: color-mix(in srgb, var(--brand) 26%, color-mix(in srgb, var(--black) 66%, transparent));
  /* Die Lichtkante (Regel 2) - die eine Zeile, die eine Flaeche erst zu einer Flaeche macht: oben
     eine Spur Licht, als laege die Kante naeher an der Lampe. --ink ist auf der Gastseite die
     helle Schrift, also kommt das Licht von dort und nicht aus einem erfundenen Weiss. */
  --edge-light: color-mix(in srgb, var(--ink) 6%, transparent);
  --hairline: color-mix(in srgb, var(--ink) 8%, transparent);
  /* Der Hebeschatten (Regel 4): weit, weich, fast schwarz. Kein kurzer harter Schatten - der sieht
     nach einem aufgeklebten Zettel aus, dieser nach einer Flaeche, die ueber dem Grund schwebt. */
  --lift: 0 30px 70px -40px color-mix(in srgb, var(--black) 90%, transparent);
  /* Der Schein (Regel 3): der Akzent leuchtet, er fuellt nicht. Negativer Radius, damit der Schein
     an der Kante sitzt und nicht als Flaeche darunter steht. */
  --sheen: 0 0 22px -8px color-mix(in srgb, var(--accent) 55%, transparent);
  /* Rundungen (Regel 5): eine Zahl je Rolle - Feld und Bedienteil. Nicht sieben verschiedene. */
  --r-panel: 16px;
  --r-control: 12px;
  /* Eine Bewegungskurve fuer das ganze Produkt (Regel 6). Sie gilt auch fuer die beiden Schleier
     am Ende der Datei. */
  --ease-curve: cubic-bezier(.2, .7, .3, 1);
  --ease: .4s var(--ease-curve);
}

/* ---- Sprungleiste ---------------------------------------------------------------------------
   Umbrechend statt rollend: eine waagerechte Rollleiste ist auf der Gastkarte verboten, und zehn
   haftende Marken fraessen drei Reihen Bildschirm. Deshalb bricht sie um und haftet nicht. */
.guest .jump {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  margin: 16px 0 24px; padding: 0; list-style: none;
}
.guest .jumpitem {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 14px;
  border: 1px solid var(--rule); border-radius: 999px;
  background: color-mix(in srgb, var(--black) 55%, transparent);
  color: var(--accent); text-decoration: none;
  font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
}
.guest .jumpitem:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- Oberbereich: "Getränke & Küche" und "Shisha" --------------------------------------------
   Zwei Linien ueber und unter dem Wort - die ruhigste Art, einen Teil der Karte als eigenen Teil
   zu zeigen, ohne eine dritte Farbe zu erfinden. */
.guest .areahead {
  margin: 40px 0 18px; padding: 10px 0;
  border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
  font-family: var(--display); font-size: 1.5rem; font-weight: 400;
  letter-spacing: .22em; text-transform: uppercase; text-align: center;
  color: var(--accent);
}
.guest .areahead span { display: block; }

/* ---- Gruppe: ein Feld wie auf dem Flyer ------------------------------------------------------ */
.guest .group {
  margin: 0 0 18px; padding: 18px 16px 10px;
  border: 1px solid var(--frame); border-radius: 14px;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bottom));
  /* Die zweite, innere Linie der Doppellinie: ein Umriss mit negativem Abstand liegt INNERHALB des
     Feldes, kostet keinen Platz im Satz und folgt der Rundung. Bewusst kein zweiter Innenschatten -
     der haette ueber dem Verlauf gelegen und ihn an den Raendern aufgehellt. */
  outline: 1px solid var(--frame-inner); outline-offset: -6px;
  box-shadow: 0 14px 28px -22px var(--black);
  /* Damit ein Sprungziel nicht am obersten Bildpunkt klebt. */
  scroll-margin-top: 14px;
}
/* Die Gruppenueberschrift haengt zwischen zwei Zierlinien (::before / ::after) - kein Bild, kein
   Zeichen aus einer fremden Schrift, nur zwei Linien, die den Rest der Zeile fuellen. */
.guest .grouphead {
  display: flex; align-items: center; gap: 12px;
  margin: 0 0 12px; font-family: var(--display); font-size: 1.25rem; font-weight: 400;
  letter-spacing: .08em; color: var(--accent); text-align: center;
}
.guest .grouphead::before, .guest .grouphead::after {
  content: ""; flex: 1 1 auto; height: 0; border-top: 1px solid var(--rule);
}
.guest .groupname { flex: 0 1 auto; }

/* ---- Artikelzeile ---------------------------------------------------------------------------
   Zwei Spalten: links die ganze Angabe, rechts der "+"-Knopf neben der ersten Zeile. Der Abstand
   steckt im Knopf und nicht im column-gap, sonst bliebe ohne Knopf rechts totes Land.
   Der Knopf steht ausdruecklich in `grid-row: 1` und NICHT in `1 / -1`: ohne grid-template-rows
   zeigt die Linie -1 auf dieselbe Linie 1, der Knopf haette also ohnehin nur die erste Zeile
   belegt - sie dabei aber auf seine 48px aufgezogen. Die Punktlinienzeile daneben wird gestreckt,
   und der Name haengt oben in einer 48px hohen Zeile mit einer Luecke zur Beschreibung. Deshalb
   zusaetzlich align-self an der Zeile selbst. */
.guest .items .item {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 0;
  padding: 9px 0; border-bottom: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.guest .items .item:last-child { border-bottom: 0; }
.guest .items .item .plus { grid-row: 1; align-self: center; margin-left: 12px; }

/* Name - Punktlinie - Preis in einer Zeile. Die Punktlinie ist ein leeres Feld, das den Rest der
   Breite nimmt; sie fuehrt das Auge ueber die Luecke wie auf der gedruckten Karte. */
.guest .itemline { display: flex; align-items: baseline; gap: 8px; align-self: center; }
.guest .itemline .name { flex: 0 1 auto; font-size: 1rem; font-weight: 600; letter-spacing: .01em; }
/* min-width ist der harte Boden der Punktlinie: auf einem breiten Schirm steht die Karte in drei
   Spalten, eine Spalte ist dann rund 440px breit statt 549px, und eine Punktlinie, die auf einen
   Strich zusammenschrumpft, verbindet nichts mehr - sie sieht nach einem Fehler aus. Unter 24px
   geht sie deshalb nicht; ab da weicht der Name und nicht die Zier. */
.guest .dots {
  flex: 1 1 24px; min-width: 24px; align-self: center; height: 0;
  border-bottom: 1px dotted color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Der Preis bleibt bewusst bei der Grundschrift: Georgia setzt Mediaevalziffern, bei denen 3, 4, 5
   und 9 unter die Grundlinie reichen - eine Preisspalte wird damit unruhig. Die Zier steckt in den
   Ueberschriften, die Preisspalte soll ruhig sein. */
.guest .itemline .price {
  flex: 0 0 auto; font-size: 1.05rem; font-weight: 600;
  color: var(--accent); font-variant-numeric: tabular-nums;
}

/* Die leisere Stufe: Beschreibung und Hinweis ("hausgemacht") stehen unter dem Namen, nicht
   daneben - und deutlich kleiner, damit der Name die Zeile fuehrt. */
.guest .items .desc, .guest .items .notice, .guest .items .tag {
  grid-column: 1; margin: 3px 0 0; font-size: .82rem; line-height: 1.35; opacity: .72;
}
.guest .items .notice { font-style: italic; color: color-mix(in srgb, var(--accent) 75%, var(--ink)); opacity: .9; }

/* 18+ als kleines Schild - an der Gruppe, wenn jeder Artikel darin 18+ ist, sonst an der Zeile.
   Die Farbe ist eine Abstufung von --accent in Richtung --brand, kein drittes Farbfeld. */
.guest .agemark {
  display: inline-block; margin: 4px 0 0; padding: 1px 8px;
  border: 1px solid color-mix(in srgb, var(--accent) 50%, transparent); border-radius: 999px;
  background: color-mix(in srgb, var(--brand) 55%, transparent);
  color: color-mix(in srgb, var(--accent) 85%, var(--ink));
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: .68rem; font-weight: 600; letter-spacing: .08em; vertical-align: middle;
}
.guest .grouphead .agemark { margin: 0; flex: 0 0 auto; }
/* In der Artikelzeile ausdruecklich in Spalte 1 und auf Inhaltsbreite: ohne grid-column wuerde die
   automatische Platzierung das Schild hinter einer Beschreibung in die Knopfspalte schieben, und
   ohne justify-self zoege es sich als randvolle Pille ueber die ganze Breite. */
.guest .items .agemark { grid-column: 1; justify-self: start; }

/* "aus" statt "gestrichen": der Artikel bleibt lesbar, tritt aber sichtbar zurueck. Durchstrich und
   Deckkraft kommen aus der Grundregel (.soldout .name/.price) und bleiben dort - eine zweite
   Deckkraft an der Zeile haette sich mit ihr multipliziert und Name und Preis auf etwa .25
   heruntergezogen. Hier bleibt nur die Punktlinie, die mitredet. */
.guest .items .soldout .dots { border-bottom-style: dashed; }
.guest .items .tag { text-transform: uppercase; letter-spacing: .08em; font-size: .72rem; }

/* Sanftes Springen nur, wenn niemand darum gebeten hat, es zu lassen. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
/* Schmales Geraet: etwas weniger Rand im Feld, damit die Zeile nicht umbricht, und die Marken der
   Sprungleiste ruecken enger zusammen. Die Tippflaeche von 44px bleibt. */
@media (max-width: 420px) {
  .guest .group { padding: 14px 11px 6px; }
  .guest .areahead { font-size: 1.3rem; letter-spacing: .16em; }
  .guest .grouphead { font-size: 1.12rem; gap: 9px; }
  .guest .jump { gap: 6px; }
  .guest .jumpitem { padding: 0 11px; font-size: .74rem; }
}

/* ==== PLAKAT-2026-10-02 ========================================================================
   Der Befund des Betreibers, zum zweiten Mal: "Die Seite sieht immer noch sehr schwach aus, kein
   besonderer Stil - das Plakat sieht besser aus." Diesmal mit einem Abzug im Browser nachgesehen.
   Was dort zu sehen war und was diese Regeln aendern:
     1. Oben stand reines Schwarz - die Hausfarbe kam erst beim Scrollen. Jetzt steht sie oben, mit
        einem Lichtschein hinter dem Kopf, und laeuft nach unten in die Tiefe aus.
     2. Das Feld war zu drei Vierteln Schwarz, die Hausfarbe also praktisch unsichtbar. Jetzt
        traegt der Schleier des Feldes die Hausfarbe mit (--panel-top / --panel-bottom oben).
     3. Das Logo war eine Briefmarke. Jetzt 240px auf dem Rechner, 150px auf dem Telefon.
     4. Logo und Schriftzug sagten denselben Namen zweimal. Steht ein Logo da, bleibt der Schriftzug
        nur noch fuer die Vorleseeinrichtung stehen; ohne Logo ist er das Plakatelement.
     5. Die Karte war auf dem Rechner eine schmale Saeule in viel Leere. Ab 900px zwei Spalten.
     6. Es gab keinen Rahmen und keine Zier. Jetzt eine goldene Doppellinie um jedes Feld und eine
        Zierlinie unter dem Kopf und ueber dem Fuss - aus Linien und Punkten, kein Bild, kein
        Zeichen aus einer fremden Schrift, nichts nachgeladen.
     7. "Bitte beim Personal melden." war ein linksbuendiger Kasten quer ueber die Seite. Jetzt eine
        ruhige, mittige Pille.
     8. Der Fuss trug nur die Marke des Hauses. Jetzt Name, Claim, Angaben, Rechtsverweise.

   Keine festen Farben und kein Kundenmotiv: alles leitet sich ueber color-mix aus --brand,
   --accent, --ink und --black ab, die der Betrieb ueber /branding.css setzt (P0-7). Jeder Anteil
   von --brand wird gegen --black gemischt, der Grund bleibt also bei jeder Marke dunkler als die
   Marke selbst - mit einer blauen Hausfarbe im Abzug nachgesehen.
   Die Grenze dieser Zusicherung, damit sie niemand weiter spannt als sie traegt: die ganze
   Gastseite rechnet mit einer DUNKLEN BIS MITTLEREN Hausfarbe. Sie setzt color-scheme: dark und
   schreibt in --ink eine helle Schrift - eine sehr helle Marke wird hier zwar abgedunkelt, bleibt
   oben im Lichtschein aber die hellste Flaeche der Seite, und der Abstand zur Schrift wird knapp.
   Das ist eine Eigenschaft des Farbmodells und nicht dieser Regeln; wer eine fast weisse Marke
   zulassen will, braucht eine zweite Schriftfarbe im Modell, nicht einen anderen Verlauf. */

/* ---- Der Grund: Hausfarbe oben, Tiefe unten --------------------------------------------------
   Bewusst OHNE background-attachment: fixed und in px statt in Prozent. Fixed bindet den Verlauf
   an das Fenster: auf einem hohen Fenster zieht sich der Schein dann ueber die halbe Karte, und
   iOS ignoriert fixed ohnehin. In px haengt der Schein am Kopf, wo er hingehoert - auf jedem
   Geraet gleich. Der letzte Halt bleibt eine dunkle Abstufung der Hausfarbe und nicht reines
   Schwarz: Schwarz ist hier Tiefe, nicht Grundfarbe. */
body.guest {
  background:
    radial-gradient(var(--glow-w) var(--glow-h) at 50% 0,
      color-mix(in srgb, var(--brand) 64%, var(--black)) 0%,
      color-mix(in srgb, var(--brand) 38%, var(--black)) 45%,
      transparent 72%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--brand) 42%, var(--black)) 0,
      color-mix(in srgb, var(--brand) 30%, var(--black)) 340px,
      color-mix(in srgb, var(--brand) 16%, var(--black)) 900px,
      color-mix(in srgb, var(--brand) 12%, var(--black)) 100%);
  background-attachment: scroll; background-repeat: no-repeat;
}

/* ---- Die Zierlinie ---------------------------------------------------------------------------
   Zwei auslaufende Linien und drei Punkte, alles aus Verlaeufen: kein Bild, keine fremde Schrift,
   kein Zeichen, das auf einem fremden Geraet fehlen koennte. Sie steht unter dem Kopf und noch
   einmal ueber dem Fuss und klammert damit die Karte wie den Rahmen auf einem Plakat. */
.guest .head::after, .guest .foot::before {
  content: ""; display: block; height: 12px; width: min(460px, 86%);
  background:
    radial-gradient(circle, color-mix(in srgb, var(--accent) 90%, transparent) 0 3.2px, transparent 3.6px)
      left calc(50%) top 50% / 12px 12px no-repeat,
    radial-gradient(circle, color-mix(in srgb, var(--accent) 55%, transparent) 0 2px, transparent 2.4px)
      left calc(50% - 20px) top 50% / 8px 8px no-repeat,
    radial-gradient(circle, color-mix(in srgb, var(--accent) 55%, transparent) 0 2px, transparent 2.4px)
      left calc(50% + 20px) top 50% / 8px 8px no-repeat,
    linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 60%, transparent))
      left center / calc(50% - 34px) 1px no-repeat,
    linear-gradient(90deg, color-mix(in srgb, var(--accent) 60%, transparent), transparent)
      right center / calc(50% - 34px) 1px no-repeat;
}
.guest .head::after { margin: 18px auto 0; }
.guest .foot::before { margin: 0 auto 18px; }

/* ---- Der Kopf als Plakatkopf ----------------------------------------------------------------- */
/* Steht ein Logo da, sagt der Schriftzug denselben Namen ein zweites Mal. Er verschwindet deshalb
   fuer das Auge - aber NICHT aus der Seite: eine Vorleseeinrichtung braucht die Ueberschrift, und
   das Logo traegt bewusst ein leeres alt. Der Nachbarschafts-Waehler erledigt das ohne eine zweite
   Klasse im Markup; ein Klassenausdruck in der .cshtml waere ein neuer Eintrag in
   StyleClassGuardTests.ClassExpressions, und den soll es dafuer nicht geben.
   Ein Betrieb OHNE Logo behaelt den Schriftzug und steht damit nicht kopflos da. */
.guest .head .logo + .wordmark {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.guest .wordmark {
  font-family: var(--display); font-weight: 400; line-height: 1.15;
  font-size: clamp(1.7rem, 5vw, 2.5rem); letter-spacing: .14em;
  color: color-mix(in srgb, var(--accent) 88%, var(--ink));
  text-shadow: 0 2px 12px color-mix(in srgb, var(--black) 70%, transparent);
}
.guest .head .tagline {
  font-size: .95rem; letter-spacing: .14em; opacity: .92;
  color: color-mix(in srgb, var(--ink) 82%, var(--accent));
}
.guest .head .age { font-size: .8rem; letter-spacing: .06em; opacity: .7; }
.guest .head .table { font-size: 1rem; letter-spacing: .08em; }

/* ---- Zwei Spalten ab 900px -------------------------------------------------------------------
   Der Haupteindruck "schwach" am Rechner war eine 640px-Saeule in einer leeren Flaeche. Die Felder
   kommen deshalb ab 900px in ein Raster.
   `:has(> .group)` begrenzt das auf Seiten, die wirklich Gruppenfelder tragen - die Kontoseiten des
   Gastes (Anmelden, Registrieren, Punkte) liegen unter demselben .guest und bleiben unberuehrt.
   Alles, was keine Gruppe ist (Sprungleiste, Deckel, Bestellen, Bereichsueberschrift, Hinweise),
   nimmt beide Spalten; eine Gruppe nimmt eine. Ein Feld kann dabei nicht mitten in der Gruppe
   umbrechen, weil jedes Feld genau eine Rasterzelle ist - der Unterschied zum Mehrspaltensatz.
   align-items: start laesst jedes Feld seine eigene Hoehe behalten: eine Gruppe mit drei Artikeln
   soll neben einer mit zwanzig nicht zu einem halbleeren Kasten aufgezogen werden. */
@media (min-width: 900px) {
  .guest main:has(> .group) {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 22px; align-items: start; max-width: 1120px;
  }
  .guest main:has(> .group) > * { grid-column: 1 / -1; }
  .guest main:has(> .group) > .group { grid-column: auto; }
  .guest .head { padding-top: 40px; }
}

/* ---- Deckel und Bestellen im selben Plakatkleid wie die Felder ------------------------------- */
.guest .tab, .guest .cart {
  border: 1px solid var(--frame); border-radius: 14px; padding: 16px;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bottom));
  outline: 1px solid var(--frame-inner); outline-offset: -6px;
}
.guest .tab h2, .guest .cart h2 {
  font-family: var(--display); font-weight: 400; letter-spacing: .12em;
}

/* ---- Ruhige Pillen statt Kaesten -------------------------------------------------------------
   "Bitte beim Personal melden." stand als volle, linksbuendige Kastenzeile quer unter dem Kopf.
   Als Pille sagt sie dasselbe und stoert das Plakat nicht. Dieselbe Form bekommt die Rueckmeldung
   nach einer Bestellung; `main > .notice` trifft ausdruecklich nur sie und nicht den Hinweis an
   einem Artikel (.items .notice). */
.guest .closed, .guest main > .notice {
  display: block; width: fit-content; max-width: 100%;
  margin: 14px auto; padding: 10px 20px; text-align: center;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); border-radius: 999px;
  background: color-mix(in srgb, var(--black) 45%, transparent);
  color: color-mix(in srgb, var(--accent) 70%, var(--ink));
  font-size: .9rem; letter-spacing: .04em;
  /* Ausdruecklich zurueckgenommen: die Grundregel .desc, .notice, .tag dimmt auf .75, und die
     Rueckmeldung nach einer Bestellung ist keine Nebenbemerkung. */
  opacity: 1;
}

/* ---- Zeile im Deckel: "Zuruecknehmen" --------------------------------------------------------
   Im Abzug sichtbar geworden (der Fehler ist aelter als dieser Zug): das Formular landete durch die
   automatische Platzierung in Spalte 1 des Zeilenrasters `auto 1fr auto`, zog sie auf seine Breite
   auf und schob den Namen des Artikels in die Mitte der Zeile. Es gehoert unter die Zeile, nicht
   neben die Menge.
   Und der Knopf darin war der graue Knopf des Betriebssystems: die 44px standen am Formular, nicht
   an der Tippflaeche. Jetzt im Haus-Stil wie .btn.ghost, aus --accent und --frame abgeleitet. */
.guest .line .withdraw { grid-column: 1 / -1; margin-top: 6px; padding: 0; }
.guest .line .withdraw button {
  min-height: 44px; padding: 8px 18px; font: inherit; font-size: .9rem;
  color: var(--accent); background: transparent;
  border: 1px solid var(--frame); border-radius: 999px; cursor: pointer;
}
.guest .line .withdraw button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Der Weg zum Punktestand stand im Blau des Browsers da - die einzige fremde Farbe der Seite. Und
   als nackter Verweis war er keine 44px hoch. Er steht mittig wie alles andere im Plakatkopf; der
   Hinweis IM Bestellfeld (.cart .hint) ist davon ausgenommen, der gehoert zum Formular. */
.guest main > .hint { text-align: center; margin: 2px 0 0; }
.guest .hint a {
  display: inline-block; min-height: 44px; padding: 10px 4px;
  color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px;
}

/* ---- Der Fussbereich -------------------------------------------------------------------------
   Name, Claim, Angaben, Rechtsverweise - und die Marke des Hauses klein darunter. Die Zierlinie
   oben ersetzt die Trennlinie. Kein neuer Inhalt: alles steht schon im Betriebsdatensatz, und was
   dort leer ist, erzeugt weiterhin keine Zeile. */
.guest .foot {
  margin-top: 46px; padding-top: 24px; border-top: 0; text-align: center;
  font-size: .75rem; opacity: .85;
}
.guest .footname {
  margin: 0; font-family: var(--display); font-weight: 400;
  font-size: 1.15rem; letter-spacing: .16em; text-transform: uppercase;
  color: color-mix(in srgb, var(--accent) 80%, var(--ink));
}
.guest .foot .tagline {
  margin: 4px auto 0; max-width: 34em; font-size: .75rem; letter-spacing: .1em; opacity: .75;
}
.guest .foot .contact { margin-top: 12px; font-size: .85rem; opacity: .9; }
.guest .foot .legal { margin-top: 0; }
.guest .foot .legal a { font-size: .85rem; }

/* ---- Telefon ---------------------------------------------------------------------------------
   Weniger Zier, derselbe Aufbau. Die Zierlinie wird schmaler, damit sie auf 320px nicht an den
   Rand stoesst, und der Kopf ruecht zusammen. */
@media (max-width: 600px) {
  .guest .head { padding-top: 22px; }
  .guest .head::after, .guest .foot::before { width: min(300px, 80%); }
  .guest .wordmark { letter-spacing: .1em; }
  .guest .head .tagline { font-size: .85rem; letter-spacing: .1em; }
}

/* ==== GROSSE SCHIRME 2026-10-02 ================================================================
   Im Browser gemessen, nicht geschaetzt: auf einem 2560px breiten Fenster blieb `main` bei 1120px
   (Raster 549px 549px), das Logo bei 158x240px. Links und rechts standen je 720px leer. Auf dem
   Telefon stimmte alles - der Fehler war, dass die Seite ab etwa 1400px nicht mehr mitwuchs.

   Ein Befund, der hier ausdruecklich NICHT "behoben" wird, weil er keiner ist: der Kopf ist schon
   heute randbreit. `header.head` ist ein Geschwister von `main` und nicht sein Kind, steckt also
   nicht in der 1120px-Spalte. Was ihm fehlte, war Mass - der Lichtschein hinter ihm war 900px
   breit, die Zierlinie 460px, das Logo 240px hoch. Genau diese drei Masse wachsen hier mit, und
   zwar weiter als die Karte darunter: so atmet der Kopf breiter als der Satz, ohne dass eine
   zweite Spaltenbreite erfunden wird.

   Warum ab 2000px KEINE vierte Spalte: eine Artikelzeile ist Name - Punktlinie - Preis. Bei vier
   Spalten bleiben je Spalte rund 340px, davon gehen Feldrand und der "+"-Knopf ab; die Punktlinie
   faellt dann auf ihren Boden von 24px und die Zeile wirkt gequetscht. Ab 2000px wird die Karte
   deshalb nur noch etwas breiter, und der Rest wird Luft und Groesse.

   Was unterhalb von 900px wirkt und was nicht - genau, weil ein zu weit gefasster Satz hier schon
   einmal falsch war: Die Stufen fuer Mass und Spalten stehen alle in Abfragen ab 1400px und sind
   auf dem Telefon ohne Wirkung. Der Abschnitt "Der Fuss als Abbinder" am Ende dieses Blocks steht
   dagegen BEWUSST ohne Abfrage und gilt in jeder Breite: die 44px Tippflaeche unter "laeuft mit
   Scorpion Order" fehlten auf dem Telefon genauso wie auf dem Rechner, und ein Abstand, den man
   nur am grossen Schirm bekommt, waere eine zweite Gestaltung statt einer. */

@media (min-width: 1400px) {
  /* Der Schein greift so weit, wie der Kopf gross ist. */
  .guest { --glow-w: 1500px; --glow-h: 700px; }
  .guest .head { padding-top: 56px; }
  /* Das Logo waechst auf etwa 430px. Der Breitendeckel waechst MIT: ein querformatiges Logo (der
     naechste Betrieb kann einen Schriftzug statt eines Wappens hinterlegt haben) stiesse sonst an
     den Deckel der Grundregel und die zusaetzliche Hoehe waere wirkungslos. */
  .guest .logo { max-height: 430px; max-width: min(72%, 700px); margin-bottom: 14px; }
  /* Der Schriftzug steht nur da, wo kein Logo hinterlegt ist (siehe .logo + .wordmark). Dann ist er
     das Plakatelement und braucht dasselbe Mass wie ein Logo. Eigene clamp-Stufe statt eines
     hoeheren Deckels in der Grundregel, damit zwischen 900 und 1400px nichts springt. */
  .guest .wordmark { font-size: clamp(2.6rem, 3.2vw, 3.4rem); letter-spacing: .16em; }
  .guest .head .tagline { font-size: 1.1rem; letter-spacing: .2em; max-width: 40em; }
  .guest .head .age { font-size: .9rem; }
  .guest .head .table { font-size: 1.1rem; }
  .guest .head::after, .guest .foot::before { width: min(620px, 50%); }
  .guest .areahead { margin: 52px 0 22px; font-size: 1.7rem; }
  .guest .grouphead { font-size: 1.35rem; }
  .guest .foot { margin-top: 64px; padding-top: 30px; font-size: .8rem; }
  .guest .footname { font-size: 1.5rem; letter-spacing: .2em; }
  .guest .foot .tagline { font-size: .85rem; }
  .guest .foot .contact { margin-top: 16px; font-size: .9rem; }
}

/* Drei Spalten erst ab 1500px und nicht ab 1400px: die Stufe des Kopfes und die Stufe des Satzes
   haben verschiedene Gruende. Der Kopf wird gross, weil Platz da ist; der Satz bekommt eine dritte
   Spalte erst, wenn jede Spalte breit genug fuer Name, Punktlinie und Preis bleibt. */
@media (min-width: 1500px) {
  .guest main:has(> .group) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 26px; max-width: 1360px;
  }
}

@media (min-width: 2000px) {
  .guest { --glow-w: 1900px; --glow-h: 820px; }
  .guest main:has(> .group) { column-gap: 32px; max-width: 1480px; }
  .guest .head { padding-top: 68px; }
  .guest .logo { max-height: 490px; max-width: min(66%, 840px); margin-bottom: 18px; }
  .guest .head .tagline { font-size: 1.2rem; }
  .guest .head::after, .guest .foot::before { width: min(760px, 42%); }
  /* Luft statt einer vierten Spalte: mehr Rand im Feld, mehr Abstand zwischen den Feldern, eine
     Stufe groesser in der Zeile. */
  .guest .group { margin-bottom: 24px; padding: 22px 20px 12px; }
  .guest .itemline .name { font-size: 1.06rem; }
  .guest .itemline .price { font-size: 1.12rem; }
  .guest .items .item { padding: 11px 0; }
  .guest .areahead { font-size: 1.9rem; }
  .guest .grouphead { font-size: 1.45rem; }
  .guest .foot { margin-top: 76px; padding-top: 36px; }
  .guest .footname { font-size: 1.7rem; }
}

/* ---- Der Fuss als Abbinder -------------------------------------------------------------------
   Er trug Name, Claim, Angaben, Rechtsverweise und "laeuft mit Scorpion Order" - aber als eine
   duenne Zeile dicht unter der Karte, die Seite franste unten aus. Mehr Luft zwischen Zierlinie
   und Text, mehr Luft unter dem letzten Verweis, und die Marke des Hauses steht abgesetzt.
   Nebenbei eine Tippflaeche, die fehlte: "laeuft mit Scorpion Order" ist ein Verweis ohne eigene
   Klasse (`.foot > a`), die 44px standen bisher nur an den Rechtsverweisen. Kein erfundener
   Inhalt - ein leeres Feld bleibt leer und erzeugt weiterhin keine Zeile. */
.guest .foot { padding-bottom: 10px; }
.guest .foot::before { margin-bottom: 26px; }
/* Der Abstand gehoert an die letzte Zeile darueber und NICHT an den Verweis: ein Betrieb ohne
   Produktadresse bekommt "laeuft mit Scorpion Order" als nackten Text ohne <a> (BrandingTests:
   Without_an_external_product_url...). Haenge der Abstand am Verweis, klebte die Zeile in genau
   diesem Fall 4px unter dem Impressum - ein Zustand, den kein Abzug zeigt, weil die Abzuege alle
   eine Adresse haben. So bekommen beide Faelle denselben Rhythmus. */
.guest .foot p:last-of-type { margin-bottom: 14px; }
.guest .foot > a {
  display: inline-block; margin-top: 0; padding: 12px 10px; min-height: 44px;
  letter-spacing: .08em; opacity: .8;
}

/* ==== DUNST UND GLUT 2026-10-02 ===============================================================
   Der erste Zug zur Atmosphaere: zwei feste Lagen hinter allem, die sich unterschiedlich schnell
   bewegen, dazu der stehende Lichtschein des Kopfes als dritte, unbewegte Tiefe.
   ACHTUNG, STAND 02.10.2026: Aussehen und Bewegung dieser Lagen sind vom Block RAUCH, GLUT UND
   FUNKEN am Ende der Datei UEBERSCHRIEBEN. Der Aufbau hier gilt weiter, und mit ihm die
   Begruendung: nur transform und opacity in den Keyframes (MotionGuardTests); kein Bild, kein
   Skript, kein WebGL und kein Weichzeichner auf einer bildschirmgrossen Flaeche - die weichen
   Kanten kommen aus den Verlaeufen selbst; beide Lagen liegen HINTER allem (position: fixed,
   negativer z-index in dem Stapel, den der Rumpf selbst aufspannt); sie sind per transform groesser
   gezogen als das Fenster, damit keine Kante zu sehen ist und die Rollbreite unberuehrt bleibt;
   und reduzierte Bewegung stellt sie still. Feuer ist --accent, nicht ein festes Orange. */
body.guest { position: relative; z-index: 0; }
body.guest::before, body.guest::after {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  /* Die Lagen sind groesser gezogen als das Fenster: eine wandernde Lage darf an keinem Rand eine
     Kante zeigen. Vergroessern per transform und nicht per inset, damit die feste Lage die
     Rollbreite des Dokuments nicht anfassen kann - waagerecht rollt hier nichts. */
  transform: scale(1.4);
}

/* Lage 1, der Dunst: drei breite, sehr weiche Schwaden aus --ink. Langsam und gross - was sich
   langsam bewegt, liest das Auge als weit entfernt. */
body.guest::before {
  background:
    radial-gradient(58% 40% at 20% 24%, color-mix(in srgb, var(--ink) 26%, transparent) 0, transparent 70%),
    radial-gradient(50% 34% at 80% 56%, color-mix(in srgb, var(--ink) 20%, transparent) 0, transparent 72%),
    radial-gradient(66% 28% at 48% 90%, color-mix(in srgb, var(--ink) 16%, transparent) 0, transparent 74%);
  opacity: .08;
  /* Dieselbe Kurve wie jeder Zustandswechsel des Produkts (Handschrift, Regel 6). */
  animation: dunst 72s var(--ease-curve) infinite alternate;
}

/* Lage 2, die Glut: tief und in den Seitenstreifen, wo auf einem breiten Schirm kein Text steht.
   Schneller als der Dunst - der Unterschied in der Geschwindigkeit IST die Tiefe. */
body.guest::after {
  background:
    radial-gradient(38% 30% at 6% 84%, color-mix(in srgb, var(--accent) 40%, transparent) 0, transparent 70%),
    radial-gradient(34% 26% at 94% 72%, color-mix(in srgb, var(--accent) 30%, transparent) 0, transparent 72%),
    radial-gradient(56% 24% at 50% 104%, color-mix(in srgb, var(--brand) 55%, transparent) 0, transparent 76%);
  opacity: .1;
  animation: glut 52s var(--ease-curve) infinite alternate;
}

@keyframes dunst {
  0%   { transform: scale(1.38) translate3d(-3%, 1.5%, 0); opacity: .055; }
  50%  { transform: scale(1.52) translate3d(1.5%, -2.5%, 0); opacity: .105; }
  100% { transform: scale(1.44) translate3d(3.5%, 2%, 0); opacity: .07; }
}

@keyframes glut {
  0%   { transform: scale(1.3) translate3d(2%, 2.5%, 0); opacity: .07; }
  50%  { transform: scale(1.42) translate3d(-2.5%, -1.5%, 0); opacity: .125; }
  100% { transform: scale(1.34) translate3d(-1%, 3%, 0); opacity: .085; }
}

/* Wer Bewegung am Geraet abgestellt hat, hat dafuer meist einen Grund. Die Tiefe bleibt, die
   Bewegung geht - nicht verhandelbar. */
@media (prefers-reduced-motion: reduce) {
  body.guest::before, body.guest::after { animation: none; }
}

/* Telefon: eine bewegte Lage genuegt. Die Glut faellt ganz weg statt stehen zu bleiben - eine
   zweite bildschirmgrosse Lage kostet auch unbewegt Speicher und einen Anstrich. */
@media (max-width: 600px) {
  body.guest::after { display: none; }
  /* Hier stand einmal ein zweites `opacity` fuer den Dunst. Es war wirkungslos: eine laufende
     Animation setzt die Deckkraft in jedem Bild selbst, die Regel daneben kommt nie zum Zug. Statt
     einer Zeile, die etwas verspricht, was sie nicht haelt, steht hier der wahre Satz: auf dem
     Telefon spart die ENTFALLENE zweite Lage, nicht eine leisere erste. */
}

/* ==== HANDSCHRIFT 2026-10-02 ===================================================================
   Umsetzung von docs\scorpion-handschrift.md, Abschnitt 3. Der Auftrag des Owners war, dass man
   auf einer Kundenseite unsere Handschrift erkennt - ohne dass die Seite dem Wirt weggenommen
   wird. Die Aufloesung steht im Dokument: die Handschrift steckt im Handwerk, nicht in der Farbe.
   Hier kommt also kein Scorpion-Rot und kein Cyan vor, sondern Tiefe und Licht:

     Leiter   - Grund, Flaeche, gehobene Flaeche (die Variablen oben in .guest),
     Kante    - Haarlinie und Lichtkante auf jeder Flaeche,
     Schein   - der Akzent leuchtet an Kanten und Zahlen, statt Flaechen zu fuellen,
     Heben    - ein weiter, weicher, fast schwarzer Schatten unter allem, was obenauf liegt,
     Rundung  - zwei Zahlen (Feld 16px, Bedienteil 12px), nicht sieben,
     Kurve    - eine Bewegungskurve fuer alles, was sich bewegt.

   Zwei Techniken der Werbeseiten kommen bewusst NICHT mit:

   1. KEIN backdrop-filter, auch nicht auf kleinen Flaechen. Das Dokument erlaubt Glas auf Pillen
      und Leisten; hier steht trotzdem keines. Der Grund ist der Gast: er laedt die Karte im
      Halbdunkel auf einem alten Telefon ueber das WLAN einer Bar, und jede durchsichtige Flaeche
      mit Unschaerfe dahinter kostet dort Bilder pro Sekunde - bei zehn Sprungmarken zehnmal. Die
      Wirkung von Glas entsteht hier aus Haarlinie, Lichtkante und Schein, und die kosten nichts.
   2. KEINE Anzeigeschrift. Selbst ausgeliefert waere sie erlaubt, aber sie bleibt ein Download vor
      dem ersten Wort. Es bleibt bei der Serifenschrift aus dem Bestand des Geraets.

   Zur 3D-Regel (Regel 7), weil sie die heikelste ist: perspective steht am Kopf, preserve-3d am
   Logo, die Neigung betraegt 3 Grad. Sie trifft damit ein BILD und keine Textzeile - eine geneigte
   Preisspalte ist unlesbar, und eine Kachel voller Preise ist eine Preisspalte. Die Felder heben
   sich beim Zeigen deshalb nur an und leuchten staerker, sie kippen nicht. Beides nur auf Geraeten
   mit echtem Zeiger und nur, wenn niemand um weniger Bewegung gebeten hat. */

/* ---- Flaechenleiter, Kante, Hebeschatten, Schein --------------------------------------------- */
.guest .group, .guest .tab, .guest .cart {
  border-radius: var(--r-panel);
  /* Reihenfolge: erst heben, dann leuchten, dann die Lichtkante innen. Der kurze Schatten von
     vorher (0 14px 28px -22px) ist damit abgeloest - er sass zu dicht am Feld. */
  box-shadow: var(--lift), var(--sheen), inset 0 1px 0 var(--edge-light);
}
/* Die dritte Stufe der Leiter: die beiden Felder, mit denen der Gast wirklich umgeht, stehen eine
   Spur hoeher und waermer als die Karte selbst. */
.guest .tab, .guest .cart {
  background: linear-gradient(180deg, var(--panel-raised-top), var(--panel-raised-bottom));
}
/* Die Pillen und die Sprungmarken bekommen dieselbe Kante - sie sind kleine Flaechen, keine
   Beschriftungen. */
.guest .jumpitem, .guest .closed, .guest main > .notice, .guest .line .withdraw button {
  box-shadow: inset 0 1px 0 var(--edge-light);
}
.guest .jumpitem { border-color: var(--hairline); }

/* Der Akzent als Schein statt als Flaeche: Preis, Bereich, Gruppe, Name im Kopf und im Fuss. Der
   Schein bleibt schwach - er soll die Zahl heben, nicht sie verwischen. */
.guest .itemline .price { text-shadow: 0 0 18px color-mix(in srgb, var(--accent) 40%, transparent); }
.guest .areahead, .guest .grouphead, .guest .footname {
  text-shadow: 0 0 24px color-mix(in srgb, var(--accent) 28%, transparent);
}
.guest .wordmark {
  text-shadow: 0 2px 12px color-mix(in srgb, var(--black) 70%, transparent),
               0 0 30px color-mix(in srgb, var(--accent) 25%, transparent);
}

/* Rundungen: eine Zahl je Rolle. */
.guest .plus, .guest .send, .guest .field input, .guest .cart input { border-radius: var(--r-control); }

/* ---- Die eine Bewegungskurve ------------------------------------------------------------------
   Alles, was sich bewegt, bewegt sich so. Bewusst nur auf Bedienteilen und nur fuer transform,
   box-shadow und Farbe - nichts davon laeuft von allein los. */
.guest .jumpitem, .guest .plus, .guest .send, .guest .hint a, .guest .line .withdraw button {
  transition: transform var(--ease), box-shadow var(--ease), border-color var(--ease);
}
.guest .plus:active, .guest .send:active, .guest .jumpitem:active { transform: scale(.97); }

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  /* Nur mit einem echten Zeiger: auf einem Telefon bleibt ein :hover nach dem Tippen haengen, und
     der Gast haette ein Feld, das ohne Grund leuchtet. */
  .guest .group, .guest .tab, .guest .cart { transition: transform var(--ease), box-shadow var(--ease); }
  .guest .group:hover {
    transform: translateY(-2px);
    box-shadow: 0 36px 80px -40px color-mix(in srgb, var(--black) 90%, transparent),
                0 0 26px -6px color-mix(in srgb, var(--accent) 65%, transparent),
                inset 0 1px 0 var(--edge-light);
  }
  .guest .jumpitem:hover { border-color: var(--frame); box-shadow: var(--sheen), inset 0 1px 0 var(--edge-light); }
}

/* ---- 3D, sparsam und echt ---------------------------------------------------------------------
   perspective am Behaelter, preserve-3d am Kind, 3 Grad. Es trifft das Logo - ein Bild - und keine
   Textzeile. Wer weniger Bewegung bestellt hat, bekommt auch keine stehende Neigung: eine gekippte
   Flaeche ist fuer manche Augen dasselbe Problem wie eine bewegte. */
@media (prefers-reduced-motion: no-preference) {
  .guest .head { perspective: 1200px; }
  .guest .logo { transform-style: preserve-3d; transform: rotateX(3deg); }
}

/* ==== GRUPPENSEITE 2026-10-02 ==================================================================
   Der zweite Weg durch die Karte (A1): /k/{slug} bzw. /t/{code}/k/{slug}; die lange Karte bleibt
   die Startseite. Drei Entscheidungen: die Daumenleiste unten (zurueck AN DIE STELLE,
   Deckel-Kurzzeile, Bestellen, je 44px) - sie ist die einzige Stelle, die eine Hand am Glas
   sicher trifft; der Kopf mit festem Seitenverhaeltnis, damit Bild (A4) und Szene (A2) spaeter in
   denselben Rahmen passen, ohne die Seite zu verschieben; und die Handschrift
   (docs\scorpion-handschrift.md 3) wie auf der Karte, ohne festen Farbwert.
   KEIN backdrop-filter, auch nicht an der Leiste (HANDSCHRIFT; hier doppelt, sie wuerde bei jedem
   Rollen neu gerechnet). Sie ist deckend, kein Glas. */

/* ---- Die Gruppenueberschrift der Karte wird ein Weg ------------------------------------------
   Hier stand zuerst nur ein „›" hinter dem Namen. Der Betreiber hat damit auf seinem Telefon die
   Gruppenseiten NICHT GEFUNDEN, obwohl sie vor ihm lagen - ein Winkelzeichen in Akzentfarbe ist
   fuer einen Gast im Halbdunkel ein Satzzeichen und kein Knopf. Deshalb jetzt eine Pille mit
   einem Wort: sie hat einen Rand, einen eigenen Grund und sagt, was passiert. Die Tippflaeche ist
   die ganze Ueberschrift (Name UND Pille), 44px hoch, mit sichtbarem Druckzustand. */
.guest .grouphead .grouplink {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px; flex: 0 1 auto;
  min-height: 44px; padding: 0 4px; color: inherit; text-decoration: none;
}
.guest .grouphead .grouplink:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.guest .grouplabel {
  flex: 0 0 auto; display: inline-flex; align-items: center; min-height: 28px; padding: 0 10px;
  border: 1px solid var(--frame); border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  box-shadow: inset 0 1px 0 var(--edge-light);
  color: var(--accent); font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: .68rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  white-space: nowrap; text-shadow: none;
}
/* Der Druckzustand gehoert an die Pille und nicht nur an die Zeile: auf dem Telefon ist er die
   einzige Rueckmeldung, dass getroffen wurde. */
.guest .grouphead .grouplink:active { transform: scale(.98); }
.guest .grouphead .grouplink:active .grouplabel {
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  color: var(--ink);
}
.guest .arrow {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: .9em; opacity: .7;
}
.guest .grouphead .grouplink, .guest .thumbback { transition: transform var(--ease), box-shadow var(--ease); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  /* Nur mit echtem Zeiger: auf dem Telefon bliebe ein :hover nach dem Tippen haengen. */
  .guest .grouphead .grouplink:hover .grouplabel { border-color: var(--accent); }
}

/* ---- Der Rumpf: eine Spalte ueber die ganze Hoehe, damit die Leiste auch bei einer kurzen
   Gruppe unten sitzt und nicht in der Bildmitte haengt. `main` braucht in der Spalten-Flexbox
   eine eigene Breite und zwei automatische Raender - ohne sie zieht die Flexbox es auf die ganze
   Breite und die Karte ist nicht mehr zentriert. */
.guest.grouppage {
  min-height: 100dvh; display: flex; flex-direction: column;
  padding-bottom: calc(26px + env(safe-area-inset-bottom));
}
.guest.grouppage main { flex: 1 1 auto; width: 100%; margin-inline: auto; }

/* ---- Der Kopf der Gruppe: geschichtete Verlaeufe statt eines Bildes, 16:9 wie das Bild von
   morgen. `max-height` ist die Grenze fuer das Telefon im Hochformat - ein Kopf ueber 40% der
   Hoehe laesst keinen Artikel mehr sehen. `overflow: hidden` haelt die driftende Lage drin, sonst
   waere sie waagerechter Ueberhang (auf der Gastkarte verboten). `isolation: isolate` macht einen
   eigenen Stapel: nur so bleibt z-index: -1 ueber dem eigenen Grund statt hinter dem Rumpf. */
.guest .scenehead {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: flex-end; justify-content: center; gap: 10px;
  /* `width: 100%` ist Pflicht: sonst rechnet ein niedriges Fenster die Hoehe aus max-height ueber
     das Seitenverhaeltnis in die BREITE zurueck, und der Kopf steht schmal und links (gemessen:
     298.7 statt 328px). Mit fester Breite klemmt max-height nur die Hoehe. */
  width: 100%; aspect-ratio: 16 / 9; min-height: 170px; max-height: 40dvh;
  margin: 14px 0 20px; padding: 18px 16px;
  border: 1px solid var(--frame); border-radius: var(--r-panel);
  background: linear-gradient(180deg, var(--panel-raised-top), var(--panel-raised-bottom));
  box-shadow: var(--lift), var(--sheen), inset 0 1px 0 var(--edge-light);
  text-align: center;
}
/* Szene „still" (A1, Vorgabe): zwei Lagen, kein animiertes blur, keine dritte Farbe. Tiefe aus
   der Breite der Verlaeufe, Bewegung nur aus transform und opacity - das rechnet auch ein altes
   Telefon im Compositor (MotionGuardTests). */
.guest .scenehead::before, .guest .scenehead::after {
  content: ""; position: absolute; inset: -18%; z-index: -1; pointer-events: none;
}
/* Drei Schichten statt zwei, und deutlicher als auf der Karte: hier steht kein Preis daneben, und
   solange es keine Bilder gibt (A4), muss der Kopf fuer sich allein stehen. */
.guest .scenehead::before {
  background:
    radial-gradient(52% 44% at 26% 20%, color-mix(in srgb, var(--accent) 40%, transparent) 0, transparent 72%),
    radial-gradient(64% 50% at 80% 76%, color-mix(in srgb, var(--brand) 88%, transparent) 0, transparent 74%),
    radial-gradient(38% 30% at 62% 34%, color-mix(in srgb, var(--ink) 12%, transparent) 0, transparent 70%);
  opacity: .66;
  animation: szeneruhe 40s var(--ease-curve) infinite alternate;
}
/* Die zweite Lage steht und bewegt sich nie: sie gibt dem Feld unten Gewicht, damit die Schrift
   auf dem dunkleren Teil steht - und eine unbewegte Flaeche kostet kein Bild pro Sekunde. */
.guest .scenehead::after {
  background: radial-gradient(90% 60% at 50% 112%, color-mix(in srgb, var(--black) 72%, transparent) 0, transparent 70%);
  opacity: .9;
}
@keyframes szeneruhe {
  0%   { transform: translate3d(-2.5%, 1.5%, 0) scale(1.04); opacity: .54; }
  100% { transform: translate3d(2.5%, -1.5%, 0) scale(1.16); opacity: .74; }
}
/* Groesse auf den laengsten echten Gruppennamen gerechnet: „Spezialmischungen" ist EIN Wort ohne
   Trennstelle und stand bei 7vw auf 360px ueber dem Rand (vom overflow abgeschnitten). 5,5vw plus
   `overflow-wrap: anywhere` als letzter Halt - lieber ein getrenntes Wort als ein halbes. */
.guest .scenetitle {
  margin: 0; max-width: 100%; overflow-wrap: anywhere;
  font-family: var(--display); font-weight: 400;
  font-size: clamp(1.25rem, 5.5vw, 2rem); line-height: 1.15;
  letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
  text-shadow: 0 2px 14px color-mix(in srgb, var(--black) 75%, transparent),
               0 0 28px color-mix(in srgb, var(--accent) 30%, transparent);
}
.guest .scenehead .agemark { margin: 0 0 6px; flex: 0 0 auto; }

/* ---- Der Umschlag ist der Grund, warum die Seite ab 900px nicht auseinanderfaellt: dort macht
   `main:has(> .group)` aus der Karte ein Raster mit zwei bis drei Spalten, und eine einzelne
   Gruppe stuende darin auf halber Breite. Mit Umschlag ist sie kein direktes Kind mehr. */
.guest .groupwrap { margin: 0; }
.guest .groupwrap .group { margin-bottom: 0; }

/* ---- Das Bestellformular: dasselbe wie auf der Karte, nur ohne eigenes Feld drumherum - der
   Deckel steht auf der Karte. Der Vorname MUSS sichtbar sein, wenn er gefragt wird: ein
   verstecktes Pflichtfeld laesst den Browser stumm abbrechen. */
.guest .grouporder { margin: 0 0 16px; }
.guest .grouporder label { display: block; font-size: .85rem; opacity: .8; margin-bottom: 4px; }
.guest .grouporder input[type=text] {
  width: 100%; min-height: 48px; padding: 10px 12px; font: inherit; color: var(--ink);
  background: color-mix(in srgb, var(--black) 55%, transparent);
  border: 1px solid var(--rule); border-radius: var(--r-control);
}
.guest .grouporder .hint { margin: 8px 0 0; text-align: center; font-size: .85rem; opacity: .8; }

/* ---- Die Daumenleiste: haftend, deckend, mit Platz fuer den Geraeterand (env). Die seitlichen
   Minusraender heben genau die 16px Innenrand des Rumpfes auf - keinen Pixel mehr, sonst rollt
   die Seite waagerecht. z-index, weil ein Gruppenfeld unter dem Zeiger sich mit transform hebt
   und damit einen eigenen Stapel aufspannt; ohne die Zahl malte es sich ueber die Leiste. */
.guest .thumbbar {
  position: sticky; bottom: 0; z-index: 5;
  display: flex; align-items: center; gap: 10px;
  margin: 12px -16px 0;
  padding: 8px 16px calc(8px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--frame);
  background-color: var(--black);
  background-image: linear-gradient(180deg, var(--panel-raised-top), var(--panel-raised-bottom));
  box-shadow: 0 -24px 50px -30px color-mix(in srgb, var(--black) 95%, transparent),
              inset 0 1px 0 var(--edge-light);
}
.guest .thumbback {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  min-height: 44px; padding: 0 14px;
  border: 1px solid var(--rule); border-radius: var(--r-control);
  box-shadow: inset 0 1px 0 var(--edge-light);
  color: var(--accent); text-decoration: none;
  font-size: .8rem; letter-spacing: .08em; text-transform: uppercase;
}
.guest .thumbback:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.guest .thumbback:active { transform: scale(.97); }
/* Die Kurzzeile des Deckels - nicht die Liste. Sie darf nie umbrechen und nie die Leiste
   aufziehen: lieber abgeschnitten als eine zweireihige Leiste unter dem Daumen. */
.guest .thumbtab {
  flex: 1 1 auto; min-width: 0; text-align: center;
  font-size: .82rem; font-variant-numeric: tabular-nums; opacity: .85;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Der Absende-Knopf der Karte, auf Leistenmass gebracht: Farbe und Rand bleiben seine. */
.guest .thumbbar .send {
  width: auto; flex: 0 0 auto; min-height: 44px; margin: 0; padding: 0 18px;
}
/* Der Satz, der sagt, was noch fehlt (04.10.2026): „Noch ein Vorname, dann geht es los." Er steht
   UEBER der Zeile mit Summe und Knopf (order: -1) und nimmt die ganze Breite - zwischen Summe und
   Knopf gequetscht schoebe er auf 390px den Knopf aus dem Bild. Die Farbe ist die Marke des
   Betriebs (--accent), keine eigene: ein Cafe in Blau bekommt denselben Satz in seinem Blau.
   Er traegt ABSICHTLICH kein `display` - dann wirkt die Regel des Browsers fuer [hidden], und die
   Zeile darunter ist nur die Versicherung dagegen, dass eine spaetere Fassung eine setzt. */
.guest .thumbask {
  flex: 1 1 100%; order: -1; min-width: 0; text-align: center;
  font-size: .82rem; line-height: 1.35; color: var(--accent);
}
.guest .thumbask[hidden] { display: none; }
/* Umbrechen NUR, solange der Satz steht. Dauerhaftes flex-wrap waere ein Rueckschritt fuer die
   Gruppenseite: ihre Kurzzeile (.thumbtab) soll lieber abgeschnitten werden als die Leiste
   zweireihig machen - genau das steht an .thumbtab. */
.guest .thumbbar:has(> .thumbask:not([hidden])) { flex-wrap: wrap; row-gap: 6px; }

/* Die Leiste der langen Karte erscheint erst, wenn etwas im Korb liegt - und ohne Skript nie.
   DIESE ZEILE IST DAFUER NOETIG: `display: flex` oben ist eine Autorenregel und schlaegt die Regel
   des Browsers fuer [hidden]. Ohne sie stuende eine leere Leiste auf jeder Karte, auch ohne Skript,
   und boete „Bestellen" an, ohne je einen Korb gezaehlt zu haben. Die Gruppenseite ist davon nicht
   betroffen - ihre Leiste traegt kein [hidden], sie fuehrt immer zur Karte zurueck. */
.guest .thumbbar[hidden] { display: none; }
/* Platz unter dem Inhalt, solange die Leiste sichtbar ist - und nur dann. Die Leiste steht hinter
   dem Inhalt und damit am Ende der Rolle UNTER dem letzten Artikel; dieser Streifen hebt beim
   Rollen zusaetzlich die Fusszeile aus ihrem Schatten. Ohne Skript gibt es die Leiste nicht, und
   der Platz waere ein leerer Streifen - deshalb haengt er an :not([hidden]). Nicht fuer die
   Gruppenseite: die regelt ihren Abstand ueber .grouppage. */
.guest:not(.grouppage):has(.thumbbar:not([hidden])) main { padding-bottom: 56px; }

/* Wer Bewegung am Geraet abgestellt hat, bekommt den Kopf als stehende Tiefe. */
@media (prefers-reduced-motion: reduce) {
  .guest .scenehead::before { animation: none; opacity: .5; }
}

/* ---- Schmales Geraet ------------------------------------------------------------------------ */
@media (max-width: 420px) {
  .guest .scenehead { margin: 12px 0 16px; padding: 14px 12px; min-height: 150px; }
  .guest .thumbbar { gap: 8px; padding-left: 12px; padding-right: 12px; margin-left: -16px; margin-right: -16px; }
  .guest .thumbback { padding: 0 11px; font-size: .74rem; }
  .guest .thumbbar .send { padding: 0 14px; }
}

/* ==== TELEFON: DIE ATMOSPHAERE DARF MAN SEHEN 2026-10-02 ======================================
   Nachtrag zum Block darueber: der Gast steht MIT DEM TELEFON in der Bar, das Telefon ist der
   Hauptfall und nicht der Sparfall, und derselbe Verlauf wirkt auf kleiner Flaeche schwaecher.
   Also kraeftiger statt sparsamer - ohne teurer zu werden: stehende Lagen statt zweiter bewegter,
   und ein kleinerer, dafuer kraeftigerer Lichtschein (900px Radius sind auf 360px ein flaechiger
   Wischer ohne Mitte, 520px ein Schein).
   Die Deckkraft- und Farbwerte der Lagen sind seit dem Block RAUCH, GLUT UND FUNKEN am Ende der
   Datei ueberschrieben; die Werte der FELDER hier gelten unveraendert. */
@media (max-width: 600px) {
  .guest { --glow-w: 520px; --glow-h: 460px; }
  /* Der zweite Blick des Betreibers auf dem Telefon: „immer noch fast schwarz". Er hatte recht,
     und der Grund lag nicht an den Lagen, sondern an den FELDERN. Sie bedecken auf 360px fast
     die ganze Flaeche, und ihr Schleier war fast reines Schwarz - unter ihnen war von Hausfarbe,
     Dunst und Glut nichts mehr zu sehen. Also traegt auf dem Telefon das Feld selbst die Waerme:
     mehr Hausfarbe, duennerer Schleier. Die Grenze ist der Text, der darauf steht - deshalb
     bleibt der Schleier aus --black und die Hausfarbe darunter; nachgesehen in Weinrot, Blau und
     mit heller Marke, Namen und Preise behalten ihren Kontrast. */
  .guest {
    --panel-top: color-mix(in srgb, var(--brand) 38%, color-mix(in srgb, var(--black) 56%, transparent));
    --panel-bottom: color-mix(in srgb, var(--brand) 25%, color-mix(in srgb, var(--black) 66%, transparent));
    --panel-raised-top: color-mix(in srgb, var(--brand) 48%, color-mix(in srgb, var(--black) 50%, transparent));
    --panel-raised-bottom: color-mix(in srgb, var(--brand) 34%, color-mix(in srgb, var(--black) 60%, transparent));
  }
  /* Die Glut steht still, liegt aber jetzt ueber die ganze Hoehe statt nur in den unteren Ecken:
     hinter einem durchscheinenden Feld kommt nur ein Bruchteil durch, und genau dieser Bruchteil
     ist das, was der Gast mitten in der Karte als Waerme sieht. */
  body.guest::after {
    display: block; animation: none; opacity: .32;
    background:
      radial-gradient(72% 34% at 50% 14%, color-mix(in srgb, var(--brand) 85%, transparent) 0, transparent 74%),
      radial-gradient(64% 30% at 6% 54%, color-mix(in srgb, var(--accent) 30%, transparent) 0, transparent 72%),
      radial-gradient(70% 34% at 94% 88%, color-mix(in srgb, var(--brand) 80%, transparent) 0, transparent 74%);
  }
  body.guest::before { animation-name: dunstnah; }
}

/* Dieselbe Bahn wie `dunst`, nur mit hoeheren Deckkraften. Eine eigene Folge und nicht eine
   zweite opacity-Zeile: eine laufende Animation setzt die Deckkraft in jedem Bild selbst, eine
   Regel daneben kaeme nie zum Zug (der Befund steht im Block DUNST UND GLUT). */
@keyframes dunstnah {
  0%   { transform: scale(1.38) translate3d(-3%, 1.5%, 0); opacity: .10; }
  50%  { transform: scale(1.52) translate3d(1.5%, -2.5%, 0); opacity: .17; }
  100% { transform: scale(1.44) translate3d(3.5%, 2%, 0); opacity: .12; }
}

/* Auf dem Telefon mit abgestellter Bewegung: beide Lagen stehen, und der Dunst bekommt seine
   Deckkraft ausdruecklich - ohne Animation faellt er sonst auf die 8 Prozent des Grundfalls. */
@media (max-width: 600px) and (prefers-reduced-motion: reduce) {
  body.guest::before, body.guest::after { animation: none; }
  body.guest::before { opacity: .15; }
}

/* ==== TIEFE, DIE MAN SIEHT 2026-10-02 ==========================================================
   Der Owner wollte Raeumlichkeit, die man SIEHT, nicht nur spuert. Der staerkste Hebel dafuer
   kostet kein Kilobyte Skript: Bewegung am Rollen (`animation-timeline`). Der Browser rechnet sie
   im Compositor, sie haengt am Rollstand statt an einer Uhr und laeuft deshalb nie im Hintergrund.

   Drei Regeln, die sie vertretbar machen:
     * `@supports` davor: wo es die Zeitachse nicht gibt (Safari heute), passiert schlicht nichts
       und die Karte sieht aus wie bisher. Kein Rueckfall, der nachgebaut werden muesste.
     * KEIN `fill`: ausserhalb des Bereichs gilt wieder die Grundregel. Das ist nicht Kosmetik -
       nur so kann ein Feld, das still steht, auf das Druecken reagieren (eine fuellende Animation
       schlaegt jede Regel daneben, und der Kipp beim Druecken waere wirkungslos).
     * Der Bereich endet bei `entry 65%`: die Bewegung ist vorbei, BEVOR das Feld dort steht, wo
       der Daumen hingreift. Nichts zuckt unter dem Finger.
   Der Endzustand ist der Grundzustand (`opacity: 1`, `transform: none`) - deshalb gibt es beim
   Ende der Animation keinen Sprung. */
@keyframes feldauf {
  from { opacity: .3; transform: translate3d(0, 28px, 0) scale(.94); }
  to   { opacity: 1; transform: none; }
}
/* Die Glut wandert gegen die Rollrichtung - das ist die Parallaxe, die aus zwei Lagen Tiefe macht.
   Sie behaelt die Vergroesserung aus der Grundregel, sonst sprangen ihre Raender ins Bild. */
@keyframes glutzug {
  from { transform: scale(1.42) translate3d(0, -5%, 0); }
  to   { transform: scale(1.52) translate3d(0, 7%, 0); }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .guest .group, .guest .scenehead {
      /* Einzeln und NICHT als Kurzform: die Kurzform setzt die Dauer auf ihren Anfangswert, und
         eine Animation mit der Dauer 0s laeuft an einer Rollachse nicht los. `auto` heisst hier
         „so lang wie der Bereich darunter" - das ist die Zeile, an der es sonst still scheitert. */
      animation-name: feldauf;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-timeline: view();
      animation-range: entry 0% entry 65%;
    }
  }
}
@supports (animation-timeline: scroll()) {
  /* Nur auf dem Telefon: dort steht die Glut (sie spart sich die Dauerbewegung) und bekommt ihre
     Bewegung stattdessen vom Daumen. Auf dem grossen Schirm bleibt ihr langsamer Zug von selbst. */
  @media (max-width: 600px) and (prefers-reduced-motion: no-preference) {
    body.guest::after {
      animation-name: glutzug;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: scroll(root block);
    }
  }
}

/* ---- Perspektive: das Feld ist ein Koerper ---------------------------------------------------
   Die Perspektive sitzt am Behaelter, gekippt wird das FELD und nicht der Text darin - fuer sich
   genommen waere eine geneigte Preisspalte unlesbar. Das Feld kippt nur, solange der Finger darauf
   liegt, und zwar um 2 Grad: genug, dass man es sieht, zu wenig, dass eine Zeile verrutscht. Die
   Drehachse liegt unten, deshalb neigt sich das Feld zum Gast hin wie eine aufgestellte Karte. */
.guest main { perspective: 1100px; }
.guest .group { transform-origin: 50% 90%; }
@media (prefers-reduced-motion: no-preference) {
  .guest .group:active {
    transform: rotateX(2deg) translateY(-2px);
    box-shadow: 0 40px 80px -42px color-mix(in srgb, var(--black) 92%, transparent),
                0 0 28px -6px color-mix(in srgb, var(--accent) 60%, transparent),
                inset 0 1px 0 var(--edge-light);
  }
}

/* Wer Bewegung abgestellt hat, bekommt von alledem nichts - auch nicht die Rollbewegung. */
@media (prefers-reduced-motion: reduce) {
  .guest .group, .guest .scenehead { animation: none; }
  body.guest::after { animation: none; }
}
/* ==== SECHS SZENEN UND EIN PLAKATANFANG 2026-10-02 ==============================================
   Drei Befunde aus dem Browser: der Szenenkopf der Gruppenseite war eine leere Flaeche; alle zehn
   Gruppen sahen gleich aus; die erste Bildschirmfuellung der Karte war ein Inhaltsverzeichnis.
   Jede Gruppe traegt jetzt eine von sechs Szenen, abgeleitet aus ihrem NAMEN (`data-scene`,
   gerechnet in MenuPageState.Scene): kein neues Feld, keine Migration, und kommt das echte Feld
   (A2), schlaegt es die Ableitung ueber einen zweiten Parameter. Die Szene ist ABSTRAKT - aus
   einem Namen wird eine Nummer, nie ein Motiv; alles andere waere kundenspezifisch und ginge beim
   naechsten Betrieb schief (P0-7, BrandingTests).
   Eine Szene setzt NUR Variablen; Lagen, Bewegung und Deckkraft stehen einmal an der Grundregel.
   Ein `animation` in einer Szenenregel haette - hoehere Spezifitaet, spaetere Zeile - jede
   Abstellung weiter oben geschlagen; sie steht deshalb am ENDE des Blocks.
   Bewegt wird nur der Szenenkopf. Das Gruppenfeld der Karte traegt seine Szene STILL und nur im
   oberen Band, nicht unter der Preisspalte: zehn bewegte Felder auf einem alten Telefon waeren der
   Fehler, den die dritte Prueffrage in docs\scorpion-handschrift.md abfaengt. Geprueft in Weinrot,
   Blau und Hell. */

/* ---- Die sechs Szenen: nichts als Variablen --------------------------------------------------
   --sc-mix Akzentanteil der vorderen Lage, --sc-ax/ay/aw/ah Ort und Groesse der Akzentlage,
   --sc-bx/by/bw/bh dasselbe fuer die Hausfarbe, --sc-path die Bahn, --sc-dur ihre Dauer, --frame
   die Doppellinie. Das stille Band der Karte nimmt einen festen, niedrigen Akzentanteil - dort
   unterscheiden die Szenen sich ueber Geometrie und Linie, und ein calc() in color-mix liesse die
   GANZE Verlaufsangabe lautlos fallen, wenn der Browser es nicht versteht. Die Vorgabe steht an
   .guest: ohne data-scene - und bei unbekanntem Wert - bleibt alles wie vorher. */
.guest {
  --sc-mix: 34%; --sc-ax: 26%; --sc-ay: 20%; --sc-aw: 52%; --sc-ah: 44%;
  --sc-bx: 80%; --sc-by: 76%; --sc-bw: 64%; --sc-bh: 50%;
  --sc-path: szeneruhe; --sc-dur: 40s;
}
/* 1 - hoch und schmal, Licht von links oben. */
.guest [data-scene="1"] {
  --sc-mix: 38%; --sc-ax: 18%; --sc-ay: 14%; --sc-aw: 44%; --sc-ah: 58%;
  --sc-bx: 88%; --sc-by: 84%; --sc-bw: 58%; --sc-bh: 44%;
  --sc-path: szenezug; --sc-dur: 38s; --frame: color-mix(in srgb, var(--accent) 52%, transparent);
}
/* 2 - flach und breit, das Licht liegt unten, oben bleibt Raum. */
.guest [data-scene="2"] {
  --sc-mix: 30%; --sc-ax: 50%; --sc-ay: 88%; --sc-aw: 86%; --sc-ah: 30%;
  --sc-bx: 20%; --sc-by: 16%; --sc-bw: 72%; --sc-bh: 38%;
  --sc-path: szenewiege; --sc-dur: 46s; --frame: color-mix(in srgb, var(--accent) 40%, transparent);
}
/* 3 - diagonal von rechts oben nach links unten, die schnellste der sechs. */
.guest [data-scene="3"] {
  --sc-mix: 42%; --sc-ax: 82%; --sc-ay: 18%; --sc-aw: 48%; --sc-ah: 48%;
  --sc-bx: 18%; --sc-by: 78%; --sc-bw: 60%; --sc-bh: 52%;
  --sc-path: szenekreis; --sc-dur: 34s; --frame: color-mix(in srgb, var(--accent) 46%, transparent);
}
/* 4 - zwei Pole an den Seiten, die Mitte bleibt frei. Die ruhigste der sechs. */
.guest [data-scene="4"] {
  --sc-mix: 26%; --sc-ax: 10%; --sc-ay: 50%; --sc-aw: 34%; --sc-ah: 72%;
  --sc-bx: 92%; --sc-by: 46%; --sc-bw: 40%; --sc-bh: 66%;
  --sc-path: szenezug; --sc-dur: 52s; --frame: color-mix(in srgb, var(--accent) 36%, transparent);
}
/* 5 - eine Kuppel ueber der Mitte, Gewicht am unteren Rand. */
.guest [data-scene="5"] {
  --sc-mix: 36%; --sc-ax: 50%; --sc-ay: 8%; --sc-aw: 70%; --sc-ah: 40%;
  --sc-bx: 50%; --sc-by: 96%; --sc-bw: 92%; --sc-bh: 44%;
  --sc-path: szenewiege; --sc-dur: 42s; --frame: color-mix(in srgb, var(--accent) 50%, transparent);
}
/* 6 - die untere linke Ecke glueht, die Hausfarbe steht rechts oben gegenueber. */
.guest [data-scene="6"] {
  --sc-mix: 46%; --sc-ax: 10%; --sc-ay: 88%; --sc-aw: 56%; --sc-ah: 40%;
  --sc-bx: 70%; --sc-by: 24%; --sc-bw: 52%; --sc-bh: 40%;
  --sc-path: szenekreis; --sc-dur: 30s; --frame: color-mix(in srgb, var(--accent) 42%, transparent);
}

/* ---- Die drei Bahnen: ein Zug, eine Wiege, ein Kreis -----------------------------------------
   Nur transform (MotionGuardTests). AUSDRUECKLICH OHNE opacity: eine laufende Bahn setzt die
   Deckkraft in jedem Bild selbst, und eine Regel daneben kaeme nie zum Zug - die drei Lagen des
   Szenenkopfes teilen sich diese Bahnen und brauchen ihre EIGENE Staerke. Derselbe Fehler steht
   im Block DUNST UND GLUT beschrieben. Zwei Lagen auf derselben Bahn mit verschiedener Dauer und
   Richtung ergeben die Parallaxe - und kosten keinen zweiten Anstrich. */
@keyframes szenezug {
  0%   { transform: translate3d(-3%, 1%, 0) scale(1.05); }
  100% { transform: translate3d(3%, -2%, 0) scale(1.18); }
}
@keyframes szenewiege {
  0%   { transform: translate3d(0, 2.5%, 0) scale(1.1) rotate(-1.5deg); }
  50%  { transform: translate3d(1.5%, -1%, 0) scale(1.04) rotate(.5deg); }
  100% { transform: translate3d(-1.5%, 1.5%, 0) scale(1.14) rotate(1.5deg); }
}
@keyframes szenekreis {
  0%   { transform: translate3d(-2%, -2%, 0) scale(1.08); }
  33%  { transform: translate3d(2.5%, -.5%, 0) scale(1.16); }
  66%  { transform: translate3d(1%, 2.5%, 0) scale(1.1); }
  100% { transform: translate3d(-2.5%, .5%, 0) scale(1.2); }
}

/* ---- Der Szenenkopf: vier Lagen, drei Geschwindigkeiten --------------------------------------
   Von hinten nach vorn (alle auf z-index: -1, es entscheidet die Baumfolge): Grund der Flaeche,
   .sceneveil::before (tief, langsam), .scenehead::before (Mitte, heller Kern), .sceneveil::after
   (nah, GEGENLAEUFIG - das IST die Parallaxe), .scenehead::after (dunkler Schleier; steht still,
   liegt VOR allen Lagen, damit die Schrift ihren Grund behaelt). Der Name liegt darueber. */
.guest .scenehead {
  background:
    radial-gradient(var(--sc-bw) var(--sc-bh) at var(--sc-bx) var(--sc-by),
      color-mix(in srgb, var(--brand) 92%, transparent) 0, transparent 74%),
    linear-gradient(180deg, var(--panel-raised-top), var(--panel-raised-bottom));
}
/* Geometrie und Bahn der Szene. Einzelangaben statt der Kurzform `animation`: die haette
   Wiederholung und Richtung aus der Regel weiter oben zurueckgesetzt. */
.guest .scenehead::before {
  background:
    /* Ein kleiner heller Kern IM Schein: ein Verlauf ohne Kern wird als Toenung gelesen, mit Kern
       als Licht. Er sitzt an der Stelle der Szene, der Schleier darueber haelt den Namen frei. */
    radial-gradient(26% 22% at var(--sc-ax) var(--sc-ay),
      color-mix(in srgb, var(--accent) 62%, transparent) 0, transparent 68%),
    radial-gradient(var(--sc-aw) var(--sc-ah) at var(--sc-ax) var(--sc-ay),
      color-mix(in srgb, var(--accent) var(--sc-mix), transparent) 0, transparent 72%),
    radial-gradient(var(--sc-bw) var(--sc-bh) at var(--sc-bx) var(--sc-by),
      color-mix(in srgb, var(--brand) 88%, transparent) 0, transparent 74%),
    radial-gradient(38% 30% at 62% 34%, color-mix(in srgb, var(--ink) 12%, transparent) 0, transparent 70%);
  animation-name: var(--sc-path);
  animation-duration: var(--sc-dur);
  /* Deutlicher als die .66 von vorher: bis es Bilder gibt, ist dieser Kopf das Schaustueck. */
  opacity: .86;
}
/* Der Schleier ist ein leeres, nicht vorgelesenes Element und traegt die beiden aeusseren Lagen. */
.guest .sceneveil {
  display: block; position: absolute; inset: -22%; z-index: -1; pointer-events: none;
}
.guest .sceneveil::before, .guest .sceneveil::after {
  content: ""; position: absolute; inset: 0;
  animation-name: var(--sc-path);
  animation-timing-function: var(--ease-curve);
  animation-iteration-count: infinite;
}
/* Tiefe Lage: gespiegelte Geometrie (100% minus Ort), weit und langsam - also weit entfernt. */
.guest .sceneveil::before {
  background:
    radial-gradient(calc(var(--sc-aw) * 1.4) calc(var(--sc-ah) * 1.2)
      at calc(100% - var(--sc-ax)) calc(100% - var(--sc-ay)),
      color-mix(in srgb, var(--brand) 78%, transparent) 0, transparent 76%);
  opacity: .62;
  animation-duration: calc(var(--sc-dur) * 1.9);
  animation-direction: alternate;
}
/* Nahe Lage: klein, schnell, gegenlaeufig, mit dem Akzent als Schein. */
.guest .sceneveil::after {
  background:
    radial-gradient(calc(var(--sc-aw) * .7) calc(var(--sc-ah) * .6) at var(--sc-ax) var(--sc-ay),
      color-mix(in srgb, var(--accent) var(--sc-mix), transparent) 0, transparent 70%);
  opacity: .46;
  animation-duration: calc(var(--sc-dur) * .55);
  animation-direction: alternate-reverse;
}
/* Die fuenfte Tiefe kommt vom Daumen: der Schleier wandert am Rollstand. Sie liegt am ELEMENT, die
   beiden Lagen daran haben ihre eigene - zwei transform-Bahnen an EINEM Koerper wuerden sich
   ueberschreiben, geschachtelt setzen sie sich zusammen. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .guest .sceneveil {
      animation-name: szenerueck;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: scroll(root block);
    }
  }
}
@keyframes szenerueck {
  from { transform: translate3d(0, -4%, 0) scale(1.02); }
  to   { transform: translate3d(0, 9%, 0) scale(1.08); }
}

/* Mehr Gewicht fuer den Namen auf der Flaeche, die jetzt mehr zu sagen hat. */
.guest .scenetitle {
  text-shadow: 0 2px 16px color-mix(in srgb, var(--black) 82%, transparent),
               0 0 34px color-mix(in srgb, var(--accent) 34%, transparent);
}

/* ---- Das Gruppenfeld der Karte: dieselbe Szene, aber still ----------------------------------
   Ein Band im oberen Drittel - dort steht die Ueberschrift, nicht die Preisspalte. Es liegt VOR
   dem Grund und HINTER jedem Text. `border-radius: inherit` statt `overflow: hidden`: ein
   Beschnitt haette Hebeschatten und Perspektive mit abgeschnitten. */
.guest .group { position: relative; isolation: isolate; }
.guest .group::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 54%; z-index: -1;
  border-radius: inherit; pointer-events: none;
  background:
    radial-gradient(var(--sc-aw) calc(var(--sc-ah) * 1.5) at var(--sc-ax) var(--sc-ay),
      color-mix(in srgb, var(--accent) 18%, transparent) 0, transparent 72%),
    radial-gradient(var(--sc-bw) var(--sc-bh) at var(--sc-bx) 12%,
      color-mix(in srgb, var(--brand) 82%, transparent) 0, transparent 76%);
  /* .34, nicht mehr: bei heller Marke hebt das Band den Grund unter der Ueberschrift an
     (gemessen gegen --ink: bei .46 fiel der schwaechste Punkt auf 3,3:1). Lesbarkeit vor Wirkung. */
  opacity: .34;
}

/* ---- Die Karte beginnt wie ein Plakat -------------------------------------------------------
   Der Kopf haelt die erste Bildschirmfuellung fuer sich; die Sprungleiste schaut am unteren Rand
   herein - das ist die Einladung weiterzurollen. Der Waehler ist eng und POSITIV gefasst, nicht
   mit :not(.grouppage): `:has(.jump)` trifft nur die lange Karte, nicht die Gruppenseite und
   nicht die Kontoseiten des Gastes unter demselben .guest. Und er faellt weg, sobald unter dem
   Kopf etwas Wichtigeres steht (Deckel, Rueckmeldung, geschlossener Tisch) - Wirkung ist
   nachrangig. */
.guest:has(.jump):not(:has(#tab)):not(:has(#order-notice)):not(:has(#closed-notice)) .head {
  min-height: min(72dvh, 620px);
  display: flex; flex-direction: column; justify-content: center;
}

/* Die Ueberschrift der Sprungleiste sagt mit den Worten, die ihre Vorlese-Beschriftung schon immer
   trug, was die Pillen sind. Nichts erfunden - aus der Pillenwolke wird ein Verzeichnis mit Titel.
   Die Pillen treten dafuer eine Spur zurueck; die 44px Tippflaeche bleiben. */
.guest .jumphead {
  margin: 30px 0 10px; font-family: var(--display); font-weight: 400;
  font-size: .95rem; letter-spacing: .26em; text-transform: uppercase; text-align: center;
  color: color-mix(in srgb, var(--accent) 72%, var(--ink)); opacity: .9;
  text-shadow: 0 0 22px color-mix(in srgb, var(--accent) 22%, transparent);
}
.guest .jumphead + .jump { margin-top: 0; }
.guest .jumpitem { background: color-mix(in srgb, var(--black) 62%, transparent); }

/* ---- Feinschliff am grossen Schirm ----------------------------------------------------------
   Die Gruppenseite blieb bei 640px, auch auf 2560px. Jetzt bis 860px; weiter nicht, sonst wird
   die Artikelzeile zur Wueste zwischen Name und Preis. */
@media (min-width: 900px) {
  .guest.grouppage main { max-width: 860px; }
  .guest .scenetitle { font-size: clamp(2rem, 3.4vw, 2.9rem); }
  .guest .scenehead { min-height: 260px; }
}
@media (min-width: 1400px) {
  .guest .scenetitle { font-size: 3.2rem; letter-spacing: .1em; }
  .guest .jumphead { font-size: 1.05rem; margin: 40px 0 14px; }
}
/* Schmales Geraet: das Plakat gibt eine Spur Hoehe ab - auf 360x640 soll die erste Pille noch zu
   sehen sein. */
@media (max-width: 420px) {
  .guest .jumphead { margin: 22px 0 8px; font-size: .88rem; letter-spacing: .2em; }
  .guest:has(.jump):not(:has(#tab)):not(:has(#order-notice)):not(:has(#closed-notice)) .head {
    min-height: min(66dvh, 520px);
  }
}

/* Bewegung abgestellt: die Szenenregeln setzen `animation-name` aus einer Variablen, und bei
   gleicher Spezifitaet gewinnt die spaetere Zeile - eine Abstellung weiter oben waere still
   ausgehebelt worden. Deshalb hier, namentlich. */
@media (prefers-reduced-motion: reduce) {
  .guest .scenehead::before, .guest .sceneveil,
  .guest .sceneveil::before, .guest .sceneveil::after { animation: none; }
  .guest .scenehead::before { opacity: .5; }
}

/* ==== RAUCH, GLUT UND FUNKEN 2026-10-02 ========================================================
   Der Betreiber hat es am 02.10.2026 ZUM DRITTEN MAL gesagt: der Grund soll Rauch und Feuer
   zeigen. Die Zuege davor bauten eine warme Toenung, die sich verschiebt - man spuert sie, man
   sieht sie nicht. Vier Unterschiede: Rauch QUILLT (laengliche Schwaden, jede mit eigener Drift
   und Drehung); KEIN GEMEINSAMER TAKT (die Dauern sind Primzahlen, zwei Lagen treffen sich
   praktisch nie wieder gleich - das unterscheidet Rauch von einem Pendel); Rauch ist DUNKEL, nicht
   hell (eine dunkle Schwade vor der Glut ist sichtbarer Kontrast und nimmt dem Text darueber
   keinen weg - das ist der Hebel, der alles andere erlaubt); und FUNKEN, eine gekachelte Lage
   kleiner Punkte, die steigt und in der Deckkraft pulst. Ein Verlauf kann wabern, nur Funken
   steigen.

   DRITTE FASSUNG, 02.10.2026 ABEND. Der Betreiber hat drei Bildschirmfotos von seinem eigenen
   Telefon geschickt, und sein Urteil war: "keine Aenderung, kein Rauch oder Feuer". Er hat recht
   gehabt, und der Fehler lag nicht in der Staerke, sondern in der LESART:
     - Die Funken lagen als gleichmaessiges Gitter ueber dem GANZEN Schirm, oben am Adressfeld so
       dicht wie unten, und alle gleich gross und gleich hell. Das liest man als Tapete, nicht als
       Glut. Grund: drei Lagen mit DERSELBEN Kachelhoehe (128 px) und EINEM Punkt je Kachel - das
       ergibt waagerechte Reihen, und waagerechte Reihen sind ein Raster.
     - Der Rauch war ein Farbverlauf, also eine Toenung. Jede Schwade hatte einen linearen Abfall
       (Farbe bei 0, transparent bei 72 %) - das ist genau das, was man als gleichmaessigen Nebel
       sieht und nicht als Ballen.
   Die drei Antworten darauf: (1) eine senkrechte MASKE, damit die Funken von unten kommen und nach
   oben praktisch verschwinden - oben steht das Logo, dort gehoert Ruhe hin; (2) MEHRERE Punkte in
   EINER grossen Kachel, in verschiedenen Groessen und Helligkeiten, und zwei Lagen mit teilerfremden
   Kacheln (227x269 und 211x263, alle vier Zahlen Primzahlen), die sich praktisch nie wieder gleich treffen; (3) Schwaden mit
   PLATEAU - dichter Kern, schneller Abfall, langer Saum - statt eines linearen Verlaufs.

   Die vier Lagen, von hinten nach vorn - alle hinter jedem Feld, jeder Pille, jedem Text:
     -3  body.guest::before   Rauchwand: vier Schwaden mit dichtem Kern, langsam (71 s)
     -2  body.guest::after    Glut: unten warm und dicht, nach oben ausduennend (43 s)
     -1  .haze                der STEHENDE Behaelter - er traegt die Maske und sonst nichts
     -1  .haze::before        Funken, grob und langsam (211x263, 37 s, ~14 px/s)
     -1  .haze::after         Funken, fein und schneller (227x269, 23 s, ~23 px/s)
   `.haze` ist ein leeres, nicht vorgelesenes Element am Anfang des Rumpfes: zwei Lagen mehr ohne
   eine Angabe im Inhalt - zwei Pseudo-Elemente gibt es je Element, die des Rumpfes waren vergeben.
   Die helle Rauchfahne von vorher ist weg; ihr heller Saum steckt jetzt als vierte Schwade in der
   Rauchwand. Eine Lage weniger, und die freie ::after traegt die zweite Funkenlage.

   WARUM DIE MASKE AUF DEM BEHAELTER SITZT UND NICHT AUF DEN FUNKEN: mask-image wird im
   Koordinatensystem des Elements gemalt. Auf einer steigenden Lage wuerde die Verlaufskante
   mitsteigen und am Rundenende zurueckspringen - man saehe die Maske statt der Glut. Also steht
   `.haze` still (keine Bewegung, inset 0), und nur seine Kinder steigen. MotionGuardTests haelt
   das fest. Die Kinder reichen um ihren ganzen Weg nach UNTEN aus dem Fenster heraus
   (`inset: 0 0 -526px` bzw. `-538px`), damit beim Aufsteigen kein leerer Streifen mitlaeuft; dass
   das nach unten aus dem Maskenfeld herausreicht, ist gleichgueltig - dort ist der Schirm zu Ende.

   `-webkit-mask-image` steht VOR `mask-image`: Chrome unter 120 und alte Android-WebViews kennen
   nur die prefixte Form, und das alte Telefon ist hier der Hauptfall. Ein `@supports` braucht es
   NICHT - kennt ein Browser beides nicht, fallen beide Angaben weg und die Funken liegen wie
   vorher ueber dem ganzen Schirm. Lieber keine Maske als keine Funken. Im Maskenverlauf stehen
   darum absichtlich keine Variablen und kein color-mix: eine ungueltige Farbe darin wuerde die
   Maske still fallen lassen, und das faellt niemandem auf.

   Grenzen: nur transform und opacity, kein Nachladen, kein Skript, kein Bild (MotionGuardTests).
   Der Funkenweg ist ein GANZES Vielfaches der eigenen Kachelhoehe (2 x 263 bzw. 2 x 269), und
   Anfang und Ende tragen dieselbe Deckkraft - sonst springt die Lage am Rundenende. Reduzierte
   Bewegung stellt jede Lage still, die Tiefe bleibt (am Ende des Blocks). Marken-neutral: Feuer
   ist --accent, Rauch ist --ink und --black - bei blauer Marke kuehler Nebel mit kalten Funken.
   Das Telefon ist der HAUPTFALL: dort bleiben BEIDE Funkenlagen in Bewegung (eine Glut, die nicht
   steigt, ist keine Glut), die Deckkraft hebt der Behaelter fuer beide zugleich, und die Glut
   haengt am Daumen. Die Blocks oben bleiben; dieser ueberschreibt sie.

   WAS GEMESSEN IST, damit es niemand zweimal schaetzen muss. Kontrast am BILD gemessen, nicht aus
   dem Stylesheet gerechnet: dieselbe Ansicht 360x640 zweimal fotografiert, einmal mit unsichtbarer
   Textgruppe - wo sich die Bilder unterscheiden, liegt Text, und das zweite Bild liefert dort den
   Grund. 24 Werte: 3 Marken (Weinrot, Blau, Hell) x 4 Gruppen (Namen, Preise, Fuss, Kopf) x 2
   Bewegungsphasen (Tal und Gipfel der Funkenbahnen). Gegen 88796a5 gewinnen 20, verlieren 4; der
   groesste Verlust ist 0.80. Zwei Werte liegen unter einer Schwelle, und beide lagen es vorher auch:
   Hell/Preise 2.96 gegen 2.90 (Gold auf Creme - das ist die Markenpalette, nicht der Grund) und
   Hell/Kopf 5.51 gegen 5.96, im schlechtesten Fall ueber beide Phasen 3.82 gegen 3.85.
   NICHT gemessen: der Rechner (nur 360 px), ein echtes altes Telefon, und ob die Maske in Chrome
   unter 120, alten WebViews und iOS-Safari wirklich so faellt - das ist begruendet, nicht gesehen. */

/* ---- Lage 1: die Rauchwand. Vier Schwaden, drei dunkel, eine mit hellem Saum; alle stark
   elliptisch, weil Rauch in Schichten zieht und nicht in Kugeln.
   JEDE SCHWADE HAT EIN PLATEAU: die Farbe steht bis etwa ein Drittel des Radius STILL, faellt dann
   schnell und laeuft in einem langen Saum aus. Das ist der Unterschied zwischen einem Ballen und
   einer Toenung - ein linearer Verlauf vom Kern bis zum Rand hat nirgends eine sichtbare Dichte.
   Alle vier sitzen im unteren Drittel und an den Seitenraendern, wo kein Satz steht; HINTER DEM
   KOPF BLEIBT ES RUHIG, und das ist keine Vorsicht, sondern eine Messung: zwei hell gesaeumte
   Schwaden auf halber Hoehe haben am 02.10.2026 den schlechtesten Grund hinter dem 18+-Hinweis der
   HELLEN Marke von 4.72 auf 2.89 gedrueckt. Sie sind daraufhin ganz nach unten gewandert (4 %/88 %)
   und auf eine zusammengeschrumpft. Die eine helle bleibt, weil man auf dunklem Weinrot nur eine
   helle Schwade ueberhaupt als Ballen LIEST.
   Die hohe Deckkraft darf eine dunkle Lage sich nehmen: sie nimmt nur Licht weg, wo keines
   gebraucht wird, und hilft dem hellen Text sogar. */
body.guest::before {
  z-index: -3;
  background:
    radial-gradient(72% 19% at 20% 76%, color-mix(in srgb, var(--black) 92%, transparent) 0 30%,
      color-mix(in srgb, var(--black) 56%, transparent) 56%, transparent 90%),
    radial-gradient(52% 14% at 86% 54%, color-mix(in srgb, var(--black) 86%, transparent) 0 26%,
      color-mix(in srgb, var(--black) 44%, transparent) 52%, transparent 88%),
    radial-gradient(88% 23% at 44% 102%, color-mix(in srgb, var(--black) 90%, transparent) 0 28%,
      color-mix(in srgb, var(--black) 52%, transparent) 58%, transparent 92%),
    radial-gradient(30% 10% at 4% 88%, color-mix(in srgb, var(--ink) 20%, transparent) 0 18%,
      color-mix(in srgb, var(--ink) 8%, transparent) 44%, transparent 84%);
  opacity: .64;
  animation: rauchwand 71s var(--ease-curve) infinite alternate;
}

/* ---- Lage 2: die Glut. UNVERAENDERT gegenueber 88796a5, und zwar nach einem Fehlversuch: dieser
   Zug hatte ihr erst dieselben Plateaus gegeben wie dem Rauch. Auf der HELLEN Marke ist --brand
   aber ein helles Creme, und ein Plateau macht aus einem weichen Schein eine grosse helle Flaeche -
   der schlechteste Grund hinter dem Kopfbereich fiel damit von 4.72 auf 2.89. Plateaus gehoeren zu
   dunklen Schwaden, nicht zu hellem Licht. Zurueckgenommen, gemessen, so geblieben. */
body.guest::after {
  z-index: -2;
  background:
    radial-gradient(84% 34% at 50% 104%, color-mix(in srgb, var(--accent) 62%, transparent) 0, transparent 72%),
    radial-gradient(52% 26% at 12% 88%, color-mix(in srgb, var(--accent) 48%, transparent) 0, transparent 70%),
    radial-gradient(48% 24% at 90% 78%, color-mix(in srgb, var(--brand) 92%, transparent) 0, transparent 72%),
    radial-gradient(70% 18% at 50% 58%, color-mix(in srgb, var(--brand) 72%, transparent) 0, transparent 78%);
  opacity: .44;
  animation: glutatem 43s var(--ease-curve) infinite alternate;
}

/* ---- Lage 3: der Behaelter der Funken. Er BEWEGT SICH NICHT und malt selbst nichts - er traegt
   nur die Maske, die aus zwei Rasterlagen Glut macht: unten voll, oben praktisch nichts. Die
   Deckkraft beider Funkenlagen zugleich haengt auch hier (und nicht an den Kindern), weil die
   laufende Bahn die Deckkraft der Kinder je Bild selbst setzt - eine Regel daneben kaeme nie zum
   Zug. Der Prefix steht zuerst; Begruendung im Kopf des Blocks. */
.guest .haze {
  position: fixed; inset: 0; z-index: -1; pointer-events: none;
  /* Eine dunkle Schwade, die bewusst VOR der Glut liegt (z -1 gegen z -2) und damit als einzige
     Lage unmittelbar hinter den Feldern. Sie ist aus zwei Gruenden hier und nicht in der Rauchwand:
     als Rauch, weil die dichteste Schwade dort gehoert, wo der Rauch aufsteigt - und als
     Lesbarkeitsreserve. Gemessen am 02.10.2026: die Rauchwand (z -3) wird von der Glut so weit
     ueberdeckt, dass eine Erhoehung ihrer Deckkraft am Kontrast hinter den Preisen so gut wie
     nichts aendert (2.74 -> 2.75). Diese Lage VOR der Glut aendert ihn (2.75 -> 2.83). */
  background: radial-gradient(140% 64% at 50% 106%,
    color-mix(in srgb, var(--black) 82%, transparent) 0 32%,
    color-mix(in srgb, var(--black) 36%, transparent) 62%, transparent 94%);
  -webkit-mask-image: linear-gradient(to top, #000 0 9%, rgba(0, 0, 0, .62) 26%,
    rgba(0, 0, 0, .24) 44%, rgba(0, 0, 0, .06) 60%, transparent 72%);
  mask-image: linear-gradient(to top, #000 0 9%, rgba(0, 0, 0, .62) 26%,
    rgba(0, 0, 0, .24) 44%, rgba(0, 0, 0, .06) 60%, transparent 72%);
  opacity: .62;
}
.guest .haze::before, .guest .haze::after {
  content: ""; position: absolute; pointer-events: none;
}
/* Funken, grob: groesser, seltener, langsamer - was langsamer steigt, liegt weiter weg. Sieben
   Punkte in EINER Kachel von 211x263, unregelmaessig verteilt und von 1.6 bis 3.4 px Kern. Jeder
   Punkt hat drei Stufen: heisser Kern, matter Hof, langer Auslauf - ein Punkt ohne Hof bleibt ein
   Punkt und wird nie Glut. Alle Punkte halten ihren Hofradius Abstand vom Kachelrand, sonst waere
   jeder zweite halbiert und das Auge findet die Wiederholung sofort. */
.guest .haze::before {
  inset: 0 0 -526px;
  background-image:
    radial-gradient(circle at 46px 88px, color-mix(in srgb, var(--accent) 80%, transparent) 0 3px,
      color-mix(in srgb, var(--accent) 26%, transparent) 6px, transparent 13px),
    radial-gradient(circle at 158px 196px, color-mix(in srgb, var(--accent) 58%, transparent) 0 2.2px,
      color-mix(in srgb, var(--accent) 18%, transparent) 4.5px, transparent 10px),
    radial-gradient(circle at 104px 36px, color-mix(in srgb, var(--accent) 70%, transparent) 0 2.6px,
      color-mix(in srgb, var(--accent) 22%, transparent) 5.2px, transparent 11px),
    radial-gradient(circle at 190px 130px, color-mix(in srgb, var(--ink) 44%, transparent) 0 1.8px,
      color-mix(in srgb, var(--ink) 14%, transparent) 3.6px, transparent 8px),
    radial-gradient(circle at 28px 228px, color-mix(in srgb, var(--accent) 88%, transparent) 0 3.4px,
      color-mix(in srgb, var(--accent) 30%, transparent) 6.8px, transparent 14px),
    radial-gradient(circle at 122px 146px, color-mix(in srgb, var(--accent) 52%, transparent) 0 2px,
      color-mix(in srgb, var(--accent) 17%, transparent) 4px, transparent 9px),
    radial-gradient(circle at 70px 190px, color-mix(in srgb, var(--accent) 66%, transparent) 0 1.6px,
      color-mix(in srgb, var(--accent) 20%, transparent) 3.4px, transparent 8px);
  background-size: 211px 263px;
  animation: funkengrob 37s linear infinite;
}
/* Funken, fein: acht Punkte in 227x269. Alle vier Zahlen - 211, 263, 227, 269 - sind Primzahlen,
   die beiden Lagen legen sich also erst nach 211*227 px in der Breite und 263*269 px in der Hoehe
   wieder gleich uebereinander; das sieht kein Gast. Ein Punkt ist Asche (--ink) statt Funke. */
.guest .haze::after {
  inset: 0 0 -538px;
  background-image:
    radial-gradient(circle at 34px 52px, color-mix(in srgb, var(--accent) 95%, transparent) 0 1.7px,
      color-mix(in srgb, var(--accent) 32%, transparent) 3.6px, transparent 8px),
    radial-gradient(circle at 148px 96px, color-mix(in srgb, var(--accent) 62%, transparent) 0 1.1px,
      color-mix(in srgb, var(--accent) 20%, transparent) 2.4px, transparent 6px),
    radial-gradient(circle at 196px 34px, color-mix(in srgb, var(--accent) 88%, transparent) 0 2.3px,
      color-mix(in srgb, var(--accent) 28%, transparent) 4.6px, transparent 10px),
    radial-gradient(circle at 84px 196px, color-mix(in srgb, var(--accent) 50%, transparent) 0 1.3px,
      color-mix(in srgb, var(--accent) 16%, transparent) 2.8px, transparent 7px),
    radial-gradient(circle at 172px 238px, color-mix(in srgb, var(--accent) 76%, transparent) 0 2px,
      color-mix(in srgb, var(--accent) 24%, transparent) 4.2px, transparent 9px),
    radial-gradient(circle at 22px 142px, color-mix(in srgb, var(--ink) 40%, transparent) 0 1px,
      color-mix(in srgb, var(--ink) 13%, transparent) 2.2px, transparent 5px),
    radial-gradient(circle at 112px 148px, color-mix(in srgb, var(--accent) 68%, transparent) 0 1.5px,
      color-mix(in srgb, var(--accent) 21%, transparent) 3.2px, transparent 7px),
    radial-gradient(circle at 62px 108px, color-mix(in srgb, var(--accent) 56%, transparent) 0 1.25px,
      color-mix(in srgb, var(--accent) 18%, transparent) 2.6px, transparent 6px);
  background-size: 227px 269px;
  animation: funkenfein 23s linear infinite;
  animation-delay: -7s;   /* die Seite oeffnet mitten im Puls, nicht im Tal */
}

/* ---- Die Bahnen: Drift, Drehung und Atmen in EINER transform-Angabe. Die Drehung bleibt unter
   drei Grad - eine Schwade, die sichtbar kreist, ist ein Rad und kein Rauch. */
/* Die Rauchwand QUILLT: der Maszstab atmet zwischen 1.3 und 1.74, und weil scale und rotate um die
   MITTE rechnen, laeuft jede Schwade je nach Abstand von der Mitte anders weit - aus einer
   transform-Angabe werden so vier verschieden schnelle Drifts.
   Die Deckkraft steht HIER und nicht in einer Regel daneben (siehe Telefon-Block weiter unten).
   Sie liegt hoeher als in der Fassung davor, und zwar fuer das Aussehen - nicht fuer die
   Lesbarkeit: gemessen wurde, dass eine dunklere Rauchwand am Kontrast hinter den Preisen so gut
   wie nichts aendert (2.74 -> 2.75), weil die Glut davor liegt. Der Hebel, der dort wirkt, ist die
   dunkle Schwade auf .haze (2.75 -> 2.83). */
@keyframes rauchwand {
  0%   { transform: scale(1.3) rotate(-2.2deg) translate3d(-5%, 3%, 0); opacity: .64; }
  34%  { transform: scale(1.62) rotate(.6deg) translate3d(2%, -2%, 0); opacity: .86; }
  68%  { transform: scale(1.4) rotate(2.4deg) translate3d(5%, 1.5%, 0); opacity: .72; }
  100% { transform: scale(1.74) rotate(-.8deg) translate3d(-2%, -3.5%, 0); opacity: .9; }
}
@keyframes glutatem {
  0%   { transform: scale(1.22) translate3d(1.5%, 2%, 0); opacity: .34; }
  50%  { transform: scale(1.34) translate3d(-1%, -1%, 0); opacity: .52; }
  100% { transform: scale(1.26) translate3d(-2%, 2.5%, 0); opacity: .4; }
}
/* Die Funken steigen und pulsen. Der Weg ist ein ganzes Vielfaches der EIGENEN Kachelhoehe
   (2 x 269px bzw. 2 x 263px) und Anfang und Ende tragen dieselbe Deckkraft - deshalb kein Sprung,
   obwohl die Runde NICHT hin- und herlaeuft. Und das Tempo ist jetzt sichtbar: 538px in 23s sind
   23 px/s, 526px in 37s sind 14 px/s. Vorher waren es 6 px/s - unter der Schwelle, ab der das Auge
   ueberhaupt Bewegung bemerkt, und damit ein Raster statt Funkenflug. */
@keyframes funkenfein {
  0%   { transform: translate3d(0, 0, 0); opacity: .52; }
  50%  { transform: translate3d(0, -269px, 0); opacity: .82; }
  100% { transform: translate3d(0, -538px, 0); opacity: .52; }
}
@keyframes funkengrob {
  0%   { transform: translate3d(0, 0, 0); opacity: .42; }
  50%  { transform: translate3d(0, -263px, 0); opacity: .68; }
  100% { transform: translate3d(0, -526px, 0); opacity: .42; }
}

/* ---- Telefon: nicht sparen, sondern tauschen. BEIDE Funkenlagen bleiben jetzt in Bewegung - eine
   Glut, die nicht steigt, ist keine Glut, und genau das war der Befund vom Telefon des Betreibers.
   Bezahlt wird es damit, dass die Rauchwand hier die einzige weitere laufende Lage ist (die Glut
   haengt am Daumen). Alles darf kraeftiger sein als am Rechner: auf 360px decken die Felder fast
   alles ab, und sichtbar bleibt der Grund nur in den Zwischenraeumen und am Rand. */
@media (max-width: 600px) {
  /* HIER STAND BIS ZUM 02.10.2026 `body.guest::before { opacity: .7 }` UND `.guest .haze
     { opacity: .5 }` - und BEIDES WAR TOTER CODE. Eine laufende Bahn setzt die Deckkraft je Bild
     selbst; `rauchwand` und die alten Funkenbahnen taten das, also kam die Regel daneben nie zum
     Zug. Das ist ein Teil der Antwort auf die Frage des Betreibers, warum das Telefon aussah wie
     der Rechner: die telefon-eigene Staerke hat es nie gegeben. GEMESSEN ist das fuer
     body.guest::before - der Wert wurde am 02.10.2026 von .74 auf .82 gezogen, und alle neun
     Kontrastmesswerte blieben auf die vierte Stelle GLEICH. Fuer .haze ist es GESCHLOSSEN und
     nicht gemessen: dort lief dieselbe Mechanik, die Lage trug eine Bahn mit Deckkraft im Keyframe. Die Staerke der Rauchwand steht deshalb jetzt in `@keyframes rauchwand`.
     `.guest .haze` traegt keine Bahn mehr, nur noch die Maske - DIESE Zeile wirkt also wirklich,
     und sie hebt beide Funkenlagen zugleich. */
  .guest .haze { opacity: .8; }
  /* Mehr Luft zwischen den Feldern: der Zwischenraum ist auf 360px die einzige Stelle, an der
     Rauch und Funken ungedaempft zu sehen sind. */
  .guest .group { margin-bottom: 26px; }
  /* Die Glut steht hier still (Rollachse unten) und reicht dafuer hoeher hinauf - was der Gast
     mitten in der Karte als Waerme sieht, kommt von hier. Die Stufen sind die von 88796a5; der
     Versuch mit Plateaus steht als Fehlversuch im Kommentar der Lage 2. */
  body.guest::after {
    animation: none; opacity: .5;
    background:
      radial-gradient(90% 30% at 50% 100%, color-mix(in srgb, var(--accent) 60%, transparent) 0, transparent 72%),
      radial-gradient(74% 26% at 8% 66%, color-mix(in srgb, var(--accent) 42%, transparent) 0, transparent 72%),
      radial-gradient(78% 30% at 92% 40%, color-mix(in srgb, var(--brand) 92%, transparent) 0, transparent 74%),
      radial-gradient(84% 24% at 50% 12%, color-mix(in srgb, var(--brand) 80%, transparent) 0, transparent 76%);
  }
}

/* Die Glut am Daumen (wie im Block TIEFE, DIE MAN SIEHT): ihre Bewegung kommt vom Rollstand. Sie
   steht hier NOCH EINMAL, weil die Regel oben ihr `animation: none` gesetzt hat und die
   Quellreihenfolge entscheidet. `glutzug` bewegt nur transform. */
@supports (animation-timeline: scroll()) {
  @media (max-width: 600px) and (prefers-reduced-motion: no-preference) {
    body.guest::after {
      animation-name: glutzug;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: scroll(root block);
    }
  }
}

/* Bewegung abgestellt: alles steht, nichts verschwindet. Am Ende der Datei, damit keine spaetere
   Zeile es aushebelt; die Deckkraft ausdruecklich, weil eine laufende Bahn sie je Bild selbst
   setzt. */
@media (prefers-reduced-motion: reduce) {
  body.guest::before, body.guest::after,
  .guest .haze::before, .guest .haze::after { animation: none; }
  body.guest::before { opacity: .5; }
  body.guest::after { opacity: .32; }
  /* `.haze` selbst bekommt hier KEIN `animation: none` - es hat gar keine Bewegung, und der
     Waechter soll bei dem Selektor nie eine finden muessen. Die Maske bleibt: stillstehende Funken
     nur im unteren Drittel sind auch im Stand Glut und nicht Tapete. */
  .guest .haze { opacity: .46; }
  .guest .haze::before { opacity: .5; }
  .guest .haze::after { opacity: .62; }
}

/* ==== DIE BILDER DES WIRTS 2026-10-02 ==========================================================
   A3 hat die Ablage, den Endpunkt und die beiden Spalten gebaut; gezeigt hat die Karte bis hierher
   nichts davon. Hier wird aus den gespeicherten Pfaden Bild.

   DER NORMALFALL IST: ES GIBT KEIN BILD. Jede Regel in diesem Block haengt deshalb an der
   Anwesenheit des Bildes - entweder weil sie nur die Klasse des Bildes selbst trifft, oder ueber
   `:has(> ...)`. Ein Betrieb ohne Bilder bekommt kein Element, keine zusaetzliche Regel und damit
   genau die Seite von vorher. Bytegleich nachgewiesen in einer Hausfarbe, 360 bis 2560px, Bewegung
   abgestellt; die beiden anderen Hausfarben wurden nur fotografiert, nicht verglichen.

   `:has()` steht in `@supports selector(:has(*))`, weil die Lage des Daumenbildes absolut ist: ein
   Browser ohne `:has()` wuerde den Rand der Zeile nicht freiraeumen und das Bild lege sich auf die
   Schrift. Ohne `:has()` bleibt das Bild deshalb im Fluss - es steht dann unter der Zeile statt
   links daneben. Das ist haesslicher, aber nichts ueberdeckt etwas, und der waagerechte Ueberhang
   bleibt 0. `main:has(> .group)` weiter oben steht bewusst OHNE Pruefung: dort faellt ohne `:has()`
   nur eine Spaltenaufteilung weg, hier wuerde Text unleserlich.

   Kein url() im Stil (MotionGuardTests) und kein style-Attribut im Markup (style-src 'self'): die
   Bilder sind <img> mit einer Adresse, die unveraendert aus den Daten kommt. */

/* ---- Das Kopfbild der Gruppe -----------------------------------------------------------------
   z-index: -2 ist der Platz hinter allem, was der Kopf schon hat: die vier Lagen aus Rauch, Glut
   und Schleier liegen auf -1 und bleiben damit DARUEBER - der Gruppenname steht also weiter auf
   einem dunklen Grund und nicht auf dem hellsten Fleck eines Fotos. Ueber dem eigenen Grund der
   Flaeche liegt es trotzdem: ein Stapel streicht erst seinen Grund, dann die negativen Kinder.
   `inset: 0` plus `object-fit: cover` heisst: der Ausschnitt fuellt die 16:9-Flaeche, ein hohes
   Bild wird beschnitten statt verzerrt. Das Seitenverhaeltnis steht am Kopf selbst schon fest,
   deshalb springt beim Nachladen nichts. */
.guest .scenepic {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2; pointer-events: none;
}
/* Mit Bild braucht der Schleier mehr Gewicht als ueber einem Verlauf: ein Foto hat helle Stellen,
   ein Verlauf nicht. Nur mit Bild - ohne bleibt die Szene unveraendert. */
@supports selector(:has(*)) {
  /* Gemessen an einem absichtlich hellen Platzhalter: ueber einem Verlauf reicht der bisherige
     Schleier, ueber einem FOTO nicht - der Gruppenname stand auf einer hellen Flaeche und war kaum
     zu lesen. Deshalb mit Bild eine durchgehende dunkle Bahn statt nur des Lichthofs unten: oben
     etwas, in der Mitte wenig (dort soll man das Bild sehen), unten viel - und unten steht der
     Name. Die Lagen bleiben, es aendert sich nur ihre Staerke, und nur wenn ein Bild da ist. */
  .guest .scenehead:has(> .scenepic)::after {
    background:
      linear-gradient(180deg,
        color-mix(in srgb, var(--black) 52%, transparent) 0,
        color-mix(in srgb, var(--black) 18%, transparent) 38%,
        color-mix(in srgb, var(--black) 86%, transparent) 100%),
      radial-gradient(90% 60% at 50% 112%, color-mix(in srgb, var(--black) 82%, transparent) 0, transparent 70%);
    opacity: 1;
  }
  .guest .scenehead:has(> .scenepic)::before { opacity: .5; }
  .guest .scenehead:has(> .scenepic) .scenetitle {
    text-shadow: 0 2px 16px var(--black), 0 0 34px color-mix(in srgb, var(--black) 85%, transparent);
  }
}

/* ---- Das Daumenbild am Artikel ---------------------------------------------------------------
   Die Zeile Name - Punktlinie - Preis ist das Herz der Karte und darf nicht aufbrechen. Deshalb
   liegt das Bild NICHT in dieser Zeile: in `.itemline` ist `align-items: baseline`, ein hoeheres
   Bild daneben haengte die drei Teile an den oberen Rand einer zu hohen Zeile. Und es ist auch
   keine dritte Rasterspalte: `.items .item` hat keine festen Zeilen, eine Spalte ueber mehrere
   Zeilen zoege Zeile 1 auf die Hoehe des Bildes - dieselbe Falle, die der Kommentar an
   `.items .item .plus` schon beschreibt.
   Stattdessen: die Zeile raeumt links Platz (padding-left), das Bild liegt absolut darin. Damit
   ruehrt dieses Stueck weder an `.itemline` noch an `.plus`, weder an cart.js noch am Raster. */
.guest .items .itempic {
  grid-column: 1; justify-self: start;
  width: var(--pic, 44px); aspect-ratio: 1; object-fit: cover;
  border-radius: 7px; border: 1px solid var(--frame);
  background: color-mix(in srgb, var(--black) 40%, transparent);
}
@supports selector(:has(*)) {
  /* min-height, weil ein Artikel ohne Beschreibung niedriger waere als sein Bild - ohne sie legte
     sich das Bild ueber die naechste Zeile. 12px Luft zwischen Bild und Name; der Abstand nach
     oben ist derselbe wie das padding der Zeile. */
  .guest .items .item:has(> .itempic) {
    --pic: 44px; position: relative;
    padding-left: calc(var(--pic) + 12px); min-height: calc(var(--pic) + 18px);
  }
  /* `grid-column: auto` ist hier keine Kosmetik, sondern der Kern: ein absolut gestelltes Kind
     eines Rasters, das eine FESTE Spalte nennt, bekommt diese Rasterflaeche als Bezugsrahmen - und
     die beginnt hinter dem freigeraeumten Rand. `left: 0` landete damit genau auf dem Namen
     (gemessen: Bild und Name beide bei x=89 statt 33 und 89). Ohne feste Spalte ist der Bezug
     wieder der Innenrand der Zeile, und links steht der freigeraeumte Platz. */
  .guest .items .item > .itempic { position: absolute; grid-column: auto; left: 0; top: 9px; }
}