/* ============================================================
   Disco-Experience v2 — WebGL auf zwei Ebenen (js/disco-scene.js)
   ------------------------------------------------------------
   Geometrie der O-Aussparungen in logo_text_only.png (1024²):
   linke O:  cx 42.5%  |  rechte O: 57.7%  |  Ø ~24.2%
   Diese Werte sind zentral hier gepflegt; JS liest sie aus.

   Layering:
     .disco-canvas--bg (fixed, z0)   Atmosphäre, God Rays, kleine
                                     Logo-Kugeln, Getränkesäule
     main/header/footer (z1+)        Content
     .disco-canvas--fg (fixed, z2)   RIESIGE Kugeln + Bloom,
                                     VOR dem Content (Logo-Overlap)
     .site-header (z100)             immer bedienbar

   Die O-Aussparungen im Logo-PNG sind transparent — die kleinen
   WebGL-Kugeln liegen HINTER der Typografie und scheinen durch
   die Löcher: echte Maskierung, kein aufgelegtes Bild.

   Default (ohne JS / reduced motion / kein WebGL): statisches
   Logo mit PNG-Kugeln in den Aussparungen. Erst html.js-disco-on
   (Inline-Script im <head>) aktiviert Runway + Choreografie.
   ============================================================ */
:root {
  --o-l-x: 42.5%;   --o-l-y: 39%;    /* linke O  (per Flood-Fill vermessen) */
  --o-r-x: 57.7%;   --o-r-y: 37.3%;  /* rechte O */
  --o-d:   24.2%;   /* Fallback-PNG/Innenschatten: liegen HINTER der Typo,
                       daher bewusst größer als das Loch (füllt es sicher aus) */
  --o-d-gl: 21.5%;  /* WebGL-Kugeln: liegen VOR der Typo und sind selbst die Os.
                       Lochgröße per Flood-Fill: 16.1/16.5%. Bewusst ~20% größer
                       als früher (17.9% -> 21.5%), damit die Kugeln satt und
                       clean auf dem Logo sitzen statt zu klein im O zu wirken. */
  --o-gl-pull: 1.1%; /* Beide GL-Kugeln rücken um diesen Betrag zur Mitte:
                        sie sollen sich ÜBERLAPPEN, nicht nebeneinanderstehen.
                        Der Z-Versatz im JS entscheidet, welche vorne liegt. */
}

/* ---------- WebGL-Canvases: fix, hinter bzw. vor dem Content ---------- */
.disco-canvas {
  position: fixed; inset: 0;
  width: 100vw; height: 100vh; height: 100dvh;
  pointer-events: none;
}
.disco-canvas--bg { z-index: 0; }
.disco-canvas--fg { z-index: 2; }
/* Die Canvas ist bis zum ersten gezeichneten Frame leer — erst dann
   einblenden, sonst überdeckt sie das Ladebild mit einer schwarzen Fläche. */
.disco-canvas { opacity: 0; transition: opacity .45s var(--ease); }
.disco-ready .disco-canvas { opacity: 1; }

/* ============================================================
   LADEZUSTAND
   ------------------------------------------------------------
   Zwischen First Paint und dem ersten WebGL-Frame liegt spürbar
   Zeit: three.js laden und parsen, Env-Map per PMREM backen, vier
   Kugeln mit tausenden Kachel-Instanzen bauen, Shader kompilieren.

   Bis html.disco-ready gesetzt ist, bleibt der Hero bewusst leer
   (nur Hintergrund) — Logo, Tagline, O-Schatten und die statischen
   PNG-Kugeln sind ausgeblendet. Kein Platzhalterbild blitzt vor der
   3D-Szene auf. Sobald die Szene ihren ersten Frame hat, übernimmt
   sie per Crossfade und die Choreografie startet.
   ============================================================ */
.js-disco-on:not(.disco-live) .hero__logo-img,
.js-disco-on:not(.disco-live) .hero__tagline { opacity: 0 !important; }
.js-disco-on:not(.disco-live) .hero__o-shadow { opacity: 0; }
/* Während des WebGL-Ladefensters bleiben die statischen PNG-Kugeln
   unsichtbar (kein "Aufblitzen" eines anderen Kugel-Bilds vor der
   3D-Szene) — der Hero zeigt bis zum ersten Frame nur den Hintergrund.
   Als echter Fallback ohne JS/WebGL/reduced motion bleiben sie aktiv
   (Regel weiter unten, greift nur ohne .js-disco-on). */
.js-disco-on:not(.disco-live) .hero__ball-fallback {
  opacity: 0;
}
.js-disco-on .hero__ball-fallback,
.js-disco-on .hero__o-shadow { transition: opacity .3s var(--ease); }
.js-disco-on.disco-live .hero__ball-fallback,
.js-disco-on.disco-live .hero__o-shadow { opacity: 0; visibility: hidden; transition: opacity .3s var(--ease), visibility 0s .3s; }

/* GSAP ScrollTrigger misst bei CSS-Smooth-Scrolling falsch
   (animierte Scroll-Position während refresh) -> im WebGL-Modus
   übernimmt die Szene selbst das weiche Nachziehen (Damping). */
html.js-disco-on { scroll-behavior: auto; }
.js-disco-on .site-header,
.js-disco-on main,
.js-disco-on .site-footer { position: relative; z-index: 1; }
.js-disco-on .site-header { z-index: 100; }

/* Sektionen mit Hintergrund werden leicht transluzent, damit die
   Ambient-Kugeln, God Rays und Lichtpunkte durchscheinen */
.js-disco-on .section--alt { background: rgba(18, 10, 42, .60); }

/* Ticket-Banner sitzt direkt unter dem Hero — genau dort, wo die
   FG-Canvas (z-index 2) ihre Kugeln durchs Bild fliegen lässt. Ohne
   eigene Ebene verschwindet er dahinter. z-index 3 wie beim
   Wochen-Highlight: der wichtigste Klick der Seite bleibt immer sichtbar. */
.js-disco-on .ticket-section { z-index: 3; }

/* ============================================================
   HEADER-AUFTRITT — erst nach der Hero-Animation
   ------------------------------------------------------------
   Beim Seitenaufruf ist der Header komplett unsichtbar (Logo,
   Navigation, Reservieren). Sichtbar ist nur der BOOGIE!-Button.
   Erst wenn die Kugeln vollständig im Logo angedockt sind und der
   Seiteninhalt beginnt, fährt der Header per Fade + Slide ein.

   Wichtig: der Header bleibt dabei die ganze Zeit im Fluss — nur
   opacity/transform ändern sich. Dadurch springt beim Einblenden
   nichts (kein CLS).
   ============================================================ */
.has-hero-intro .site-header {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-100%);
  pointer-events: none;
}
.has-hero-intro.is-hero-done .site-header {
  opacity: 1;
  visibility: visible;
  transform: none;
  pointer-events: auto;
  transition: opacity .5s var(--ease), transform .65s var(--ease),
              background .3s, border-color .3s;
}
/* Rücksprung an den Seitenanfang: sofort wieder verstecken, ohne
   dass der Header rückwärts herausanimiert wirkt. */
.has-hero-intro:not(.is-hero-done) .site-header { transition: none; }

/* ---------- BOOGIE!-Button (Einstieg) ----------
   Ohne Hero-Intro (kein WebGL, reduced motion, Unterseiten) gibt es
   nichts anzuscrollen -> Button bleibt weg. */
html:not(.has-hero-intro) .boogie-btn { display: none; }
.boogie-btn {
  position: fixed;
  left: 50%; top: clamp(22px, 5vh, 46px);
  transform: translate(-50%, 0);
  z-index: 120;                                   /* über beiden Canvases */
  padding: 1.05em 2.6em;
  border: 0; border-radius: var(--r-btn);
  background: var(--grad-primary);
  color: #fff;
  font-family: var(--font-body);
  font-size: clamp(1rem, 1.7vw, 1.35rem);
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .18) inset,
              0 10px 34px -8px rgba(255, 46, 154, .75),
              0 0 46px rgba(155, 48, 255, .40);
  animation: boogiePulse 2.8s var(--ease) infinite;
  transition: opacity .45s var(--ease), transform .45s var(--ease),
              box-shadow .35s var(--ease), letter-spacing .35s var(--ease);
}
.boogie-btn:hover {
  transform: translate(-50%, -3px) scale(1.04);
  letter-spacing: .21em;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .30) inset,
              0 16px 44px -8px rgba(255, 46, 154, .9),
              0 0 70px rgba(155, 48, 255, .6);
  animation-play-state: paused;
}
.boogie-btn:active { transform: translate(-50%, 0) scale(.98); }
/* Sobald gescrollt wird (oder der Button gedrückt wurde), tritt er ab */
.boogie-btn.is-gone {
  opacity: 0;
  transform: translate(-50%, -14px) scale(.94);
  pointer-events: none;
}
@keyframes boogiePulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255,255,255,.18) inset,
                         0 10px 34px -8px rgba(255,46,154,.75),
                         0 0 46px rgba(155,48,255,.40); }
  50%      { box-shadow: 0 0 0 1px rgba(255,255,255,.26) inset,
                         0 12px 40px -8px rgba(255,46,154,.9),
                         0 0 66px rgba(155,48,255,.62); }
}
@media (prefers-reduced-motion: reduce) {
  .boogie-btn { animation: none; }
}

/* ---------- Hero-Bühne ---------- */
.hero { position: relative; }
.js-disco-on .hero { height: 260vh; }             /* Scroll-Strecke fürs Scrubbing */
.hero__stage {
  position: relative;
  min-height: 100vh; min-height: 100dvh;
  display: grid; place-items: center;
  padding-block: var(--sp-10);
}
.js-disco-on .hero__stage {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  min-height: 0; padding-block: 0;
  overflow: hidden;
}
.hero__logo {
  --logo-w: min(820px, 90vw);
  position: relative;
  width: var(--logo-w);
  aspect-ratio: 1 / 1;                            /* quadratische Logo-Box (1024²) */
}
.hero__logo-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  z-index: 2;                                     /* Typo VOR den kleinen Kugeln */
  filter: drop-shadow(0 0 22px rgba(155, 48, 255, .30));
  will-change: opacity, transform;
}
.js-disco-on .hero__logo-img { opacity: 0; }      /* per JS choreografiert */

/* ---------- Ortszusatz „in Stade" ----------
   Sitzt unten rechts an der Wortmarke, leicht schräg auf der Linie, die
   „Bar" vorgibt. Die Koordinaten sind so gewählt, dass die Schrift nur
   den schwarzen Spritzer-Rand des Logos streift — „Boogie" und „Bar"
   bleiben frei. Größe/Position hängen an --logo-w, damit der Zusatz auf
   jeder Bildschirmbreite exakt gleich am Logo klebt. */
.hero__tagline {
  position: absolute;
  left: 80.5%; top: 64.5%;
  transform: translate(-50%, -50%) rotate(-7deg);
  transform-origin: 50% 50%;
  z-index: 3;                                     /* über der Typo-Ebene */
  white-space: nowrap;
  pointer-events: none;
  font-family: var(--font-display);
  font-size: calc(var(--logo-w) * .048);
  line-height: 1;
  letter-spacing: .04em;
  color: var(--gold);
  text-shadow:
    0 0 .04em rgba(13, 6, 32, .95),               /* trennt sauber vom Spritzer */
    0 .035em .05em rgba(13, 6, 32, .8),
    0 0 .55em rgba(255, 194, 75, .45);            /* warmes Neon, kein Kreis */
}
.js-disco-on .hero__tagline { opacity: 0; }       /* per JS mit dem Logo */

/* Innenschatten der O-Aussparungen: setzt die kleinen Kugeln optisch
   IN die Buchstaben (Kontaktschatten zwischen Typo-Ebene und Kugel).
   Liegt über der BG-Canvas, unter dem Logo -> nur im Loch sichtbar. */
.hero__o-shadow {
  position: absolute;
  width: calc(var(--o-d) * 1.03);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 38%,
      rgba(255, 255, 255, 0) 40%,
      rgba(255, 255, 255, 0) 58%,
      rgba(6, 3, 14, .38) 82%,
      rgba(6, 3, 14, .78) 97%);
  opacity: 0;                                      /* per JS mit dem Logo-Fade */
}
.hero__o-shadow--l { left: var(--o-l-x); top: var(--o-l-y); }
.hero__o-shadow--r { left: var(--o-r-x); top: var(--o-r-y); }
:root:not(.js-disco-on) .hero__o-shadow { opacity: 1; }
/* Im WebGL-Modus liegen die Kugeln AUF dem Logo -> kein Schatten nötig.
   Erst ausblenden, wenn die Szene übernimmt (s. Ladezustand oben). */
.js-disco-on.disco-live .hero__o-shadow { visibility: hidden; }

/* Statischer Fallback: PNG-Kugeln in den Aussparungen (kein JS/WebGL) */
.hero__ball-fallback {
  position: absolute;
  width: var(--o-d);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  object-fit: cover;
  transform: translate(-50%, -50%);
  z-index: 1;                                      /* hinter der Typo-Ebene */
  box-shadow: 0 0 34px rgba(255, 255, 255, .15), 0 0 60px rgba(155, 48, 255, .22);
}
.hero__ball-fallback--l { left: var(--o-l-x); top: var(--o-l-y); }
.hero__ball-fallback--r { left: var(--o-r-x); top: var(--o-r-y); }
/* Nur noch versteckt, sobald die Szene läuft — davor sind sie das
   Ladebild (s. Ladezustand oben). */
.js-disco-on.disco-live .hero__ball-fallback { visibility: hidden; }

/* ---------- Hero-Content ---------- */
.hero__content {
  position: absolute;
  left: 50%; bottom: clamp(6vh, 12vh, 16vh);
  transform: translateX(-50%);
  width: min(720px, 92vw);
  text-align: center;
  z-index: 3;
}
.js-disco-on .hero__content { opacity: 0; }        /* per JS zum Schluss */
:root:not(.js-disco-on) .hero__content {
  position: relative; left: auto; bottom: auto;
  transform: none; margin-top: var(--sp-6);
}
.hero__sub { font-size: clamp(1.05rem, 2.3vw, 1.4rem); color: var(--text); margin-top: var(--sp-2); }
.hero__cta { display: flex; gap: var(--sp-2); justify-content: center; flex-wrap: wrap; margin-top: var(--sp-4); }

/* Dezenter Scroll-Pfeil statt Buttons: der fertige Logo-Zustand soll ruhig
   bleiben (läuft auch mal dauerhaft auf einem Bildschirm). Trotzdem ein
   echtes <button> — anklickbar, fokussierbar, mit Label für Screenreader.
   Die 56px erfüllen nebenbei die Mindestgröße für Touch-Ziele. */
.hero__scroll {
  width: 56px; height: 56px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(13, 6, 32, .35);
  border: 1px solid rgba(255, 255, 255, .22);
  color: var(--turq);
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: border-color .3s, box-shadow .3s, transform .3s var(--ease), background .3s;
}
.hero__scroll svg { width: 24px; height: 24px; animation: hintBob 1.8s var(--ease) infinite; }
.hero__scroll:hover, .hero__scroll:focus-visible {
  border-color: var(--turq);
  background: rgba(13, 6, 32, .6);
  box-shadow: var(--glow-turq);
  transform: translateY(2px);
}
@media (prefers-reduced-motion: reduce) {
  .hero__scroll svg { animation: none; }
  .hero__scroll:hover, .hero__scroll:focus-visible { transform: none; }
}

.hero__hint {
  /* Bühne startet unterm Sticky-Header -> Hint über der Fold-Kante halten */
  position: absolute; left: 50%; bottom: calc(var(--header-h) + 16px); transform: translateX(-50%);
  display: grid; place-items: center; gap: .4rem;
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase; color: var(--text-faint);
  z-index: 3; transition: opacity .3s;
}
:root:not(.js-disco-on) .hero__hint { display: none; }
.hero__hint svg { width: 22px; height: 22px; color: var(--turq); animation: hintBob 1.8s var(--ease) infinite; }
@keyframes hintBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }

/* ============================================================
   GETRÄNKESEKTION — 3D-Cocktail-Tower + Glass-Karte
   ------------------------------------------------------------
   Die Säule wird auf der BG-Canvas gerendert (hinter dem Content).
   Die Karte bekommt einen halbtransparenten Glassmorphism-
   Hintergrund: Text bleibt lesbar, die Säule bleibt sichtbar,
   backdrop-filter blurt die WebGL-Ebene dahinter -> echte Tiefe.
   Mit JS wird die Sektion zur Sticky-Bühne. Die Scroll-Strecke war
   mit 240vh viel zu lang — man musste vier-, fünfmal scrollen, bis es
   weiterging. Jetzt 150vh: der Pin hält 100vh, es bleiben 50vh echter
   Scrollweg. Die Säule fliegt rein, hält kurz, und man ist durch.
   ============================================================ */
.drinks { position: relative; }
.js-disco-on .drinks { height: 150vh; padding-block: 0; }
.drinks__pin { display: grid; align-items: center; }
/* Die Säule ist um ~10° geneigt — ihre Bounding-Box wird dadurch deutlich
   breiter als das Bild selbst und schob auf schmalen Schirmen horizontalen
   Scroll an. Im WebGL-Modus fängt das schon das overflow:hidden der Bühne
   ab, im statischen Fallback bisher nicht. `clip` statt `hidden`, damit
   hier kein zusätzlicher Scroll-Container entsteht. */
.drinks__pin { overflow-x: clip; }
.js-disco-on .drinks__pin {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  overflow: hidden;
}
/* Die Getränkesektion darf breiter laufen als der Standard-Container:
   die Karte wirkte im 1200er-Raster zu klein für ihren Inhalt. */
.drinks .container { max-width: 1340px; }
.drinks__layout {
  display: grid;
  /* Die Karte bekommt die größere Spalte: sie wirkte im alten .82fr-Raster
     zu klein für ihren Inhalt. Ihre rechte Kante läuft dadurch bis unter
     die Säule — genau dort entsteht die gewollte Überlappung. */
  grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  gap: var(--sp-4);
  align-items: center;
}
/* ---------- Schwebende fotorealistische Getränkesäule (Higgsfield) ---------- */
.drinks__stage {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-4);
  min-height: 62vh;
  perspective: 1400px;                             /* echte Tiefe für die Neigung */
}
.drinks__tower {
  position: relative;
  width: 100%;
  max-width: 540px;
  transform-origin: 50% 55%;
  will-change: transform, opacity;                 /* JS setzt Scroll-Parallax/Rotation */
}
/* <picture> ist per Default inline — sonst schrumpft der Wrapper auf
   Shrink-to-fit und das Bild verliert seine 100%-Breite. */
.drinks__tower picture { display: block; }
.drinks__tower-img {
  display: block;
  width: 100%;
  height: auto;
  transform-origin: 50% 58%;
  /* Grundneigung + weicher, dauerhafter Schwebeeffekt (organisch, nie statisch) */
  animation: towerFloat 8s ease-in-out infinite;
  /* Premium-Look: satter Bodenschatten + zarter Neon-Halo der Bar */
  filter:
    drop-shadow(0 34px 46px rgba(0, 0, 0, .55))
    drop-shadow(0 0 70px rgba(120, 90, 255, .22))
    drop-shadow(0 0 26px rgba(46, 230, 214, .12));
}
@keyframes towerFloat {
  0%   { transform: rotate(-10deg) translateY(-12px); }
  50%  { transform: rotate(-12.5deg) translateY(12px); }
  100% { transform: rotate(-10deg) translateY(-12px); }
}
@media (prefers-reduced-motion: reduce) {
  .drinks__tower-img { animation: none; transform: rotate(-9deg); }
}
/* Sobald die 3D-Säule geladen ist, tritt das Standbild ab.
   Bis dahin — und ohne WebGL/GLB — bleibt es die volle Inszenierung.
   Es wird dann auch aus dem Fluss genommen: die WebGL-Säule bringt ihre
   eigene Position mit, und der Bühnenraum gehört danach allein der
   Boogie-Special-Box (sonst schöbe das unsichtbare Bild sie aus dem
   gepinnten 100vh-Ausschnitt heraus).

   visibility ergänzt opacity als Sicherheitsnetz: Transition-Werte stehen in
   der CSS-Kaskade ÜBER !important. Käme der Crossfade je nicht durch, bliebe
   sonst der Startwert 1 stehen und das helle Standbild überdeckte auf
   schmalen Schirmen die 3D-Säule, die dort hinter dem Content liegt. Die
   Verzögerung von .5s schaltet visibility erst NACH dem Ausblenden. */
.js-tower-3d .drinks__tower {
  opacity: 0 !important;
  visibility: hidden !important;
  transition: opacity .5s ease, visibility 0s linear .5s;
  pointer-events: none;
  position: absolute;
  left: 50%; top: 50%;
  translate: -50% -50%;
}

/* ---------- Boogie Special: Wochen-Highlight neben der Karte ----------
   Bewusst schmal und ruhig: ein Ticket/Schild-Anmutung mit Goldkante und
   Glas, damit es neben der großen Getränkekarte als Akzent liest und
   nicht als zweite Karte. */
/* ---- Overlay-Ebene für das Wochen-Highlight ----
   Liegt deckungsgleich über .drinks__pin (gleiche Höhe, negativer
   margin-top) und klebt synchron mit ihm. z-index 3 hebt sie über die
   FG-Canvas (z-index 2): die Säule fliegt dahinter durch, bleibt aber
   vor der Getränkekarte (z-index 1). pointer-events sind nur auf der
   Box selbst wieder aktiv, damit die Ebene nichts blockiert. */
.js-disco-on .drinks__overlay {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  margin-top: -100vh; margin-top: -100dvh;
  z-index: 3;
  display: grid; align-items: center;
  pointer-events: none;
}
.js-disco-on .drinks__overlay .container { width: 100%; }
.drinks__overlay-grid { display: flex; justify-content: center; padding-block: var(--sp-4); }
.js-disco-on .drinks__overlay-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  gap: var(--sp-4);
  padding-block: 0;
}
.js-disco-on .drinks__special { grid-column: 2; justify-self: end; pointer-events: auto; }

.drinks__special {
  position: relative;
  width: min(320px, 100%);
  padding: calc(var(--sp-3) + .2rem) var(--sp-3) var(--sp-3);
  border-radius: 20px;
  text-align: center;
  /* Leicht schräg wie ein aufgeklebter Flyer — zieht den Blick. */
  transform: rotate(-2.5deg);
  /* Deutlich deckender als die Getränkekarte: hinter der Box ziehen jetzt
     Eiswürfel durch, und durch eine zu gläserne Fläche würde der
     Neon-Schriftzug von ihnen zerschnitten. */
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(255, 194, 75, .18), transparent 62%),
    linear-gradient(165deg, rgba(255, 46, 154, .14), rgba(13, 7, 32, .93) 52%);
  border: 2px solid rgba(255, 194, 75, .75);
  box-shadow:
    0 0 0 1px rgba(255, 46, 154, .25),
    0 0 34px -6px rgba(255, 194, 75, .45),
    0 18px 46px -24px rgba(0, 0, 0, .9),
    inset 0 1px 0 rgba(255, 255, 255, .10),
    0 0 26px -8px rgba(255, 194, 75, .35);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
}
/* Feine Innenlinie — der Retro-Schild-Effekt ohne zusätzliches Markup */
.drinks__special::before {
  content: "";
  position: absolute; inset: 6px;
  border-radius: 14px;
  border: 1px dashed rgba(255, 46, 154, .35);
  pointer-events: none;
}
.drinks__special-kicker {
  display: inline-block;
  padding: .25em .8em .3em;
  border-radius: 999px;
  background: var(--pink);
  font-family: var(--font-body);
  font-size: .68rem; font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: #fff;
  box-shadow: 0 0 18px -2px rgba(255, 46, 154, .9);
}
/* Der Titel trägt die Box: Neonröhren-Schrift statt Fließtext-Fett,
   in Gold mit echtem Röhren-Glühen. Monoton hat keine Kleinbuchstaben-
   Varianten und braucht deshalb Luft zwischen den Zeilen. */
.drinks__special-title {
  margin-top: .6rem;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 2.3vw, 2rem);
  line-height: 1.12;
  color: var(--gold);
  text-shadow:
    0 0 6px rgba(255, 255, 255, .55),
    0 0 18px rgba(255, 194, 75, .95),
    0 0 42px rgba(255, 140, 30, .6);
  animation: specialFlicker 5.5s var(--ease) infinite;
}
@keyframes specialFlicker {
  0%, 42%, 46%, 100% { opacity: 1; }
  44% { opacity: .78; }
}
.drinks__special-deal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .1em .35em;
  margin-top: .85rem; padding-top: .85rem;
  border-top: 1px dashed rgba(255, 194, 75, .3);
  font-size: 1.02rem; font-weight: 700;
  color: var(--text);
}
.drinks__special-plus { color: var(--gold); font-size: 1.15em; }
/* Die eigentliche Zugabe — größer, pink, mit Leuchtkante */
.drinks__special-shots {
  font-size: 1.22em; font-weight: 800;
  color: var(--pink);
  text-shadow: 0 0 16px rgba(255, 46, 154, .75);
}
.drinks__special-foot {
  margin-top: .6rem;
  font-size: .7rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim);
}
/* Der Emoji-Glyph bringt selbst kaum Seitenabstand mit */
.drinks__special-emoji { font-size: 1.5em; line-height: 1; }
/* Das Schnapsglas trägt die Aussage und darf deutlich größer sein */
.drinks__special-emoji--shot {
  font-size: 2.1em;
  filter: drop-shadow(0 0 10px rgba(255, 194, 75, .7));
}
@media (prefers-reduced-motion: reduce) {
  .drinks__special-title { animation: none; }
}

.drinks__card {
  position: relative;
  padding: clamp(1.5rem, 3.5vw, 3rem);
  border-radius: 24px;
  background: rgba(16, 9, 38, .42);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 24px 70px -30px rgba(0, 0, 0, .8), inset 0 1px 0 rgba(255, 255, 255, .08);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  backdrop-filter: blur(20px) saturate(140%);
}
.drinks__card .menu-cat { margin-bottom: 0; }
.drinks__card h2 { margin-top: var(--sp-1); }
/* Auf der breiteren Karte müssen Fließtext und Überschrift begrenzt
   bleiben — über ~60 Zeichen pro Zeile leidet die Lesbarkeit. */
.drinks__card h2 { max-width: 18ch; }
.drinks__intro { color: var(--text-dim); margin: var(--sp-2) 0 var(--sp-3); max-width: 52ch; }
.drinks__note { color: var(--text-faint); font-size: var(--fs-small); margin: var(--sp-2) 0 var(--sp-3); }

/* ---------- Mehrseitige Karte ----------
   Alle Seiten teilen sich EINE Grid-Zelle, der Wechsel ist ein weicher
   Crossfade mit leichtem Versatz.

   Die Zelle ist so hoch wie die LÄNGSTE Seite und bleibt konstant — dadurch
   sitzen die Blätter-Punkte darunter immer auf derselben Höhe. Beim Wechsel
   auf eine kürzere Seite muss man sie also nicht neu suchen.

   align-items:end richtet die Seiten an der UNTERKANTE aus: kürzere Seiten
   werden von oben kleiner, ihre letzte Zeile steht immer an derselben
   Stelle. Mit dem Default (stretch) begann jede Seite oben und der Leerraum
   entstand unten — dann wanderten die Punkte bei jedem Wechsel. */
.menu-pages { display: grid; align-items: end; }
.menu-page {
  grid-area: 1 / 1;
  opacity: 0; visibility: hidden;
  transform: translateY(10px);
  /* Abgehende Seite: zügig weg, ohne Verzögerung */
  transition: opacity .22s var(--ease), transform .22s var(--ease), visibility .22s;
}
/* Ankommende Seite wartet, bis die alte verschwunden ist — sonst stehen
   für einen Moment beide Karten übereinander und das wirkt unruhig. */
.menu-page.is-active {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .34s var(--ease) .2s, transform .38s var(--ease) .2s, visibility 0s;
}
.menu-page__title {
  font-family: var(--font-display); font-weight: 400;
  font-size: .82rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold); margin-bottom: var(--sp-2);
}

/* ---------- Blätter-Steuerung ---------- */
.menu-nav {
  display: flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px solid rgba(255, 255, 255, .09);
}
.menu-nav__arrow {
  width: 44px; height: 44px; flex-shrink: 0;
  display: grid; place-items: center;
  border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--line);
  color: var(--text-dim);
  transition: color .25s, border-color .25s, background .25s, box-shadow .25s, transform .25s var(--ease);
}
.menu-nav__arrow svg { width: 20px; height: 20px; }
.menu-nav__arrow:hover {
  color: var(--text); border-color: var(--turq);
  background: rgba(46, 230, 214, .10);
  box-shadow: var(--glow-turq);
  transform: scale(1.06);
}
.menu-nav__arrow:active { transform: scale(.96); }
.menu-nav__dots { display: flex; gap: .5rem; align-items: center; }
.menu-nav__dots button {
  width: 10px; height: 10px; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer;
  background: var(--line);
  transition: width .3s var(--ease), background .3s, box-shadow .3s;
}
.menu-nav__dots button:hover { background: var(--text-faint); }
.menu-nav__dots button[aria-current="true"] {
  width: 28px; border-radius: 6px;
  background: var(--grad-primary); box-shadow: var(--glow-pink);
}
@media (prefers-reduced-motion: reduce) {
  .menu-page { transition: none; }
}
/* Die Punkte bleiben optisch 10px klein, bekommen per Pseudo-Element aber
   eine 44px hohe Trefferfläche. Der größere Abstand verhindert, dass sich
   die Flächen benachbarter Punkte überlappen. */
@media (max-width: 620px) {
  .menu-nav__dots { gap: .85rem; }
  .menu-nav__dots button { position: relative; }
  .menu-nav__dots button::after { content: ""; position: absolute; inset: -17px -6px; }
}

/* Das Säulen-Bild ist ein normales <img> und funktioniert auch ohne
   WebGL/JS — dann entfällt nur die scrollgebundene Parallax. */

/* ---------- Mobile ---------- */
@media (max-width: 820px) {
  /* Säule oben, Karte darunter — beide sichtbar */
  /* Der Schwebe-/Parallax-Transform der Säule ragt seitlich heraus und
     vergrößert die Scrollbreite. clip (nicht hidden) kappt das, ohne einen
     Scroll-Container zu erzeugen — der sticky Header bliebe sonst stehen. */
  .drinks { overflow-x: clip; }
  /* min-width:0 an der ganzen Kette: sonst setzt der min-content der
     Preisliste die Spaltenbreite und die Seite wird breiter als der Schirm. */
  .drinks__layout { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
  .drinks__stage { min-height: 52vh; order: -1; }
  .drinks__tower { max-width: 340px; }
  .drinks__card { max-width: 560px; margin-inline: auto; min-width: 0; }
  .menu-pages, .menu-page { min-width: 0; }
  .drinks__special { width: min(340px, 100%); }

  /* ---- KEIN Pinning auf schmalen Schirmen ----
     Die Karte allein ist bei 375px rund 990px hoch. In einen auf 100vh
     gepinnten Ausschnitt mit overflow:hidden gequetscht wurden oben und
     unten je ~240px abgeschnitten — Sektionsanfang und die letzten
     Einträge fehlten schlicht. Deshalb läuft die Sektion hier im
     normalen Fluss: Bühne mit der Säule, darunter die vollständige
     Karte, darunter das Wochen-Highlight. Die Säule folgt dem
     Bühnen-Element (siehe stageRect() in disco-scene.js), zieht also
     beim Scrollen mit statt in der Bildschirmmitte zu kleben. */
  .js-disco-on .drinks { height: auto; padding-block: var(--sp-5); }
  .js-disco-on .drinks__pin {
    position: static;
    height: auto;
    overflow: visible;
  }
  /* Die Box braucht ihre Overlay-Ebene nur dort, wo die Säule VOR der
     Karte liegt — das ist auf schmalen Schirmen nicht der Fall
     (setTowerLayer). Sie wird hier wieder ein normaler Block. */
  .js-disco-on .drinks__overlay {
    position: static;
    height: auto; margin-top: 0;
    z-index: auto; pointer-events: auto;
    display: block;
    padding-top: var(--sp-4);
  }
  .js-disco-on .drinks__overlay-grid { display: block; padding-block: 0; }
  .js-disco-on .drinks__special { margin-inline: auto; }
  /* Freier Bühnenraum, in dem die Säule wirklich zu sehen ist — hinter
     der weitgehend deckenden Karte verschwände sie sonst fast ganz. */
  .js-tower-3d .drinks__stage { min-height: 58vh; }
}
@media (max-width: 640px) {
  .js-disco-on .hero { height: 200vh; }
  .hero__logo { --logo-w: 94vw; }
}
