/* ==================================================================
   ALWAYSSAME — style.css
   Minimalistisch / brutalistisch. Keine Frameworks.

   ANPASSEN OHNE PROGRAMMIERKENNTNISSE:
   Fast alles Wichtige steht im Block ":root" direkt hier drunter.
   Zahlen ändern, Datei speichern, Browser neu laden. Fertig.
   ================================================================== */

:root {
  /* ---------- FARBEN ------------------------------------------------
     Standard: schwarzer Hintergrund, weiße Schrift.
     Der Finger-Abdruck ist WEISS gemalt -> braucht dunklen Grund.
     Wer einen SCHWARZ gemalten Abdruck hochlädt, tauscht einfach
     die beiden Werte --bg und --fg gegeneinander.               */
  --bg:   #0A0A0A;
  --fg:   #FFFFFF;
  --line: rgba(255,255,255,.28);   /* dünne technische Linien       */
  --dim:  rgba(255,255,255,.55);   /* zurückgenommener Text         */

  /* ---------- MANDALA: GRÖSSE & GEOMETRIE ---------------------------
     --mandala      = Kantenlänge des quadratischen Menü-Bereichs
     --hand-size    = Größe EINER Hand (in % vom Mandala)
     --hand-radius  = Abstand der Hand vom Mittelpunkt (in %)
     --label-radius = Abstand der Schrift vom Mittelpunkt (in %)

     Die Werte sind AUSGEMESSEN an finger-original.png. In dieser Datei
     liegt die Fingerspitze 0,433 Bildhöhen über der Bildmitte und der
     Handballen 0,434 darunter. Daraus folgt:

        Abstand Fingerspitze zur Mitte = --hand-radius - 0,433 x --hand-size
        äußerer Rand der Hand          = --hand-radius + 0,434 x --hand-size

     Mit 22,5% und 42% bleibt die Mitte also um rund 4% des Mandalas frei —
     die vier Finger zeigen zur Mitte, berühren sich dort aber nicht.
     Größere freie Mitte gewünscht?  --hand-radius erhöhen.
     Danach --label-radius mindestens auf den "äußeren Rand" + 2% setzen,
     sonst überlappt die Schrift die Hände. */
  --mandala:      min(72vh, 84vw);
  --hand-size:    42%;
  --hand-radius:  22.5%;
  --label-radius: 44%;

  /* ---------- AUSRICHTUNG DER FINGERSPITZE --------------------------
     In finger-original.png sitzt die Spitze des Mittelfingers nicht auf
     der Bildmitte, sondern bei 52,9% der Bildbreite — also 2,9% zu weit
     rechts. Ohne Korrektur dreht dieser Versatz mit und die vier Finger
     zielen an der Mitte vorbei (Windrad statt Kreuz).
     Deshalb wird die Hand um  2,9% x --hand-size  nach links geschoben:
         0,029 x 42% = 1,22%                                          */
  --tip-off: 1.22%;

  /* ---------- KLICKFLÄCHE PRO HAND ----------------------------------
     Das Handbild ist quadratisch, der gemalte Abdruck darin aber
     schmal und hoch. Wären die Klickflächen ebenfalls quadratisch,
     würden sie sich in der Mitte überlappen und die zuletzt gezeichnete
     Hand würde alle Klicks der anderen drei schlucken.
     Deshalb ist die Klickfläche ein schmales Rechteck entlang des
     Fingers, leicht nach außen versetzt.
     Die Werte entsprechen der ausgemessenen Tinte in
     finger-original.png (48,3% breit, 86,8% hoch vom Bild). */
  --hit-w:   20%;   /* Breite  der Klickfläche (% vom Mandala) */
  --hit-h:   36%;   /* Höhe    der Klickfläche                 */
  --hit-off:  0%;   /* Versatz nach außen (0 = mittig auf der Hand) */

  /* ---------- MANDALA: ANGEDOCKTER ZUSTAND (nach Klick, oben) ------
     Im angedockten Zustand liegt das Mandala wie ein WASSERZEICHEN
     über dem Kategorie-Banner. --dock-scale steuert, wie groß es
     dabei ist.

     WO es sitzt, wird NICHT mehr als Abstand von oben angegeben,
     sondern IMMER mittig in die Bildfläche des Banners gerechnet —
     auf jedem Gerät und in jeder Lage (siehe .mandala.docked).
     Früher stand hier ein fester --dock-top; dadurch klebte das Menü
     am Rechner und im Handy-Querformat oben statt in der Bannermitte.

     --dock-gap ist nur noch die MINDESTLUFT über und unter dem
     angedockten Mandala. Sie legt fest, wie flach der Kopfbereich
     höchstens werden darf (--head-min weiter unten), und hält das
     Menü vom Schriftzug oben frei. */
  --dock-scale: .30;
  --dock-gap:   46px;

  /* Wie stark das Menü im angedockten Zustand zurücktritt. Über dem
     Banner soll es wie ein Wasserzeichen wirken — erst beim Überfahren
     oder bei der aktiven Kategorie kommt es wieder voll heraus.
     0 = unsichtbar, 1 = wie im Startmenü. */
  --dock-hand-op:  .28;
  --dock-label-op: .45;

  /* ---------- TIMING ------------------------------------------------ */
  --t-spread: 1500ms;   /* Dauer der Vervielfältigungs-Animation      */
  --t-dock:    700ms;   /* Dauer der Fahrt nach oben                  */
  /* Banner-Wechsel: eine Hälfte schiebt sich hoch oder runter,
     die andere zeitversetzt hinterher (siehe .b-half weiter unten) */
  --t-slide:       1100ms;   /* Dauer EINER Hälfte                   */
  --slide-stagger:  700ms;   /* Versatz bis zur zweiten Hälfte       */
  --ease-slide: cubic-bezier(.45,.05,.2,1);   /* ruhig, ohne Ruckeln */
  --ease: cubic-bezier(.16,.84,.30,1);

  /* ---------- BANNER ------------------------------------------------
     --banner-ar  Seitenverhältnis des aktuellen Bannerbildes
                  (Breite / Höhe). Wird von script.js aus dem echten
                  Bild ausgelesen und hier überschrieben. Der Wert hier
                  ist nur der Startwert für den ersten Wimpernschlag:
                  2560 / 610 = 4,197.
                  Auf Hochformat-Geräten ergibt sich die Höhe des
                  Kopfbereichs GENAU daraus — deshalb dort keine
                  schwarzen Ränder mehr.
     --motto-h    Höhe der Motto-Zeile im Banner (0, wenn keine da ist,
                  gesetzt über die Klasse "has-motto" am body).       */
  --banner-ar: 4.197;
  --motto-h:   0px;

  /* ---------- PRODUKTFOTOS ------------------------------------------
     --hero-ar     Seitenverhältnis des Produktfotos (Breite / Höhe).
                   Wird von script.js aus der echten Datei gelesen,
                   der Wert hier ist nur der Startwert: 1000/1250 = 0,8.
                   DIE FLÄCHE RICHTET SICH NACH DEM FOTO: aus diesem
                   Verhältnis rechnet sich die Breite der Fotospalte
                   (Produktseite) bzw. die Höhe der Kachel (Übersicht).
                   Dadurch sitzt das Foto randlos UND unbeschnitten.
     --thumbs-h    Höhe der Thumbnail-Zeile unter dem großen Foto.
     --has-thumbs  1, wenn es Thumbnails gibt, sonst 0 (setzt script.js
                   am Produkt-Element). Damit weiß die Rechnung oben,
                   ob sie die Zeile abziehen muss.                    */
  --hero-ar:     .8;
  --thumbs-h:    73px;
  --has-thumbs:  0;

  /* ---------- TYPO --------------------------------------------------- */
  --label-size: 13px;   /* Schriftgröße der 4 Kategorie-Labels        */

  /* Platz, den Produktseite und Kachelzeile unten freihalten MÜSSEN.
     Der Streifen unten ist ein geschlossener schwarzer Block aus:
        .legal-bar::before (Bereich des CART-Buttons)  32px
        .legal-bar         (die vier Links)            24px
                                                    = 56px
     --footer-h ist dieser Wert PLUS 6px Luft. Er muss immer GRÖSSER
     sein als der Streifen — sonst schneidet der Streifen die Zeile
     darüber ab (genau das passierte mit der "ENDPREIS"-Zeile unter
     den Kachelpreisen). */
  --footer-h: 62px;

  /* ---------- LOGO (Bilddatei images/logo-alwayssame.png) -----------
     Die Bilddatei kommt fertig ausgerichtet und bereits flach (7,65:1)
     aus Downloads/logoAlwaysSame.png. Sie wird deshalb NICHT gedreht und
     NICHT gestaucht, sondern in ihren eigenen Proportionen angezeigt:
     nur die Breite wird vorgegeben, die Höhe ergibt sich von selbst.
     Größer/kleiner? Nur --logo-w ändern.
     --logo-intro-scale = wie groß der Schriftzug in der Intro-Animation
     mittig auf der Seite steht, bevor er nach oben wandert. */
  --logo-w: 196px;
  --logo-intro-scale: 1.5;

  /* Der Schriftzug wird IMMER GESTAUCHT gezeigt: die Breite bleibt
     (--logo-w), die Höhe wird zusammengedrückt. Grundlage ist das
     eigene Verhältnis der Datei (1400 / 183 = 7,65) — davon werden
     nur noch --logo-squash der Höhe genommen.
       1    = unverzerrt
       .7   = Standard, deutlich gestaucht
       .5   = extrem flach
     Nur diesen einen Wert ändern, alles andere folgt.             */
  --logo-ar:     7.65;
  --logo-squash: .7;
}

/* ---------- HÖHE DES BANNERS -------------------------------------
   DER KOPFBEREICH RICHTET SICH NACH DEM BILD, nicht umgekehrt:

       Höhe = Bildschirmbreite / Seitenverhältnis des Banners

   Deine Banner sind exakt zugeschnitten (2560 x 610). Genau so werden
   sie gezeigt: über die volle Breite, in ihrem eigenen Verhältnis.
   Nichts wird beschnitten, nichts verzerrt, und es bleiben keine
   schwarzen Ränder übrig. Das gilt auf JEDEM Format — Monitor,
   Laptop, Tablet, Handy.

   Zwei Sicherheitsleinen bleiben:
     --head-min   Untergrenze: das angedockte Mandala muss hineinpassen.
     --head-cap   Obergrenze für extrem breite, flache Fenster, damit
                  der Produktbereich nicht verschwindet.
   Im Normalfall greift keine von beiden.

   Die Motto-Zeile kommt oben drauf, sie knabbert nichts vom Bild ab. */
:root {
  /* Untergrenze: das angedockte Mandala plus Mindestluft oben UND unten.
     Wichtig: hier darf NICHTS stehen, was selbst von --head-h abhängt —
     sonst rechnet CSS im Kreis und die ganze Kopfhöhe fällt aus. Genau
     deshalb ist --dock-top hier verschwunden: die Mitten-Position wird
     aus --head-h abgeleitet, nicht umgekehrt. */
  --head-min: calc(var(--mandala) * var(--dock-scale) + var(--dock-gap) * 2);
  --head-cap: 65dvh;
  --head-h: clamp(
              var(--head-min),
              calc(100vw / var(--banner-ar) + var(--motto-h)),
              max(var(--head-min), var(--head-cap))
            );
}

/* Hat die Kategorie ein Motto, wird der Kopfbereich um genau diese
   Zeile höher — die Zeile knabbert also nichts vom Bild ab.
   Die Klasse setzt script.js am <html>-Element (nicht am body):
   --head-h wird hier oben ausgerechnet und kann deshalb nur Werte
   sehen, die ebenfalls hier oben stehen. */
:root.has-motto { --motto-h: 34px; }

/* ==================================================================
   BASIS
   ================================================================== */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Die gesamte Seite passt auf einen Bildschirm — kein Scrollen.
   (Auf schmalen Geräten wird das weiter unten wieder gelockert.) */
html, body {
  height: 100dvh;
  overflow: hidden;
}

img { display: block; max-width: 100%; }
button { font: inherit; color: inherit; }

::selection { background: var(--fg); color: var(--bg); }

/* Hilfsklasse: schaltet ALLE Übergänge kurzzeitig ab
   (für Wiederkehrer, die die Intro-Animation nicht mehr sehen sollen) */
.no-anim, .no-anim * { transition: none !important; animation: none !important; }

/* ==================================================================
   LOGO (oben mittig) + WARENKORB-BUTTON (unten mittig)
   ================================================================== */
.logo, .cart-btn {
  position: fixed;
  left: 50%;
  /* Ohne max-content stünde dem Element nur die rechte Bildschirmhälfte
     als Layoutbreite zur Verfügung (Folge von left:50%) — das Logo würde
     auf schmalen Schirmen zusammengequetscht. */
  width: max-content;
  max-width: 96vw;
  z-index: 70;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .26em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--fg);
  background: none;
  border: 0;
  padding: 6px 10px;
  cursor: pointer;
  opacity: 0;
  transform: translateX(-50%);
  transition: opacity 600ms var(--ease);
}
.logo     { top: 14px; padding: 4px 10px; transition: opacity 600ms var(--ease), transform 900ms var(--ease); }
/* Der CART-Button sitzt ÜBER der Rechts-Leiste (siehe .legal-bar).
   Wird die Leiste höher, muss dieser Wert mitwachsen. Bewusst knapp
   gehalten: jeder Pixel hier fehlt der Produktspalte darüber. */
.cart-btn { bottom: 30px; letter-spacing: .22em; }

/* INTRO Phase 0: der Schriftzug steht zuerst mitten auf der Seite und
   wandert danach an seinen Platz oben. 50vh minus eigener halber Höhe
   minus der 14px, die "top" bereits vorgibt. */
body.intro-logo .logo {
  transform: translate(-50%, calc(50vh - 14px - 50%)) scale(var(--logo-intro-scale));
}

/* Der Schriftzug als Bild — Breite vorgegeben, Höhe GESTAUCHT.
   object-fit: fill heißt hier ausdrücklich "verzerren erlaubt":
   das Bild wird in die flachere Fläche gedrückt. */
.logo img {
  display: block;
  width:  var(--logo-w);
  height: calc(var(--logo-w) / var(--logo-ar) * var(--logo-squash));
  object-fit: fill;
  transition: opacity 200ms var(--ease);
}
.logo:hover img { opacity: .7; }

/* SNEAKER-SEITE: der Schriftzug oben ist dort SCHWARZ.
   Die Datei selbst ist weiß, invert(1) dreht sie um und lässt die
   Freistellung unangetastet. Gilt nur, solange SNEAKER offen ist —
   script.js setzt dafür data-cat am body. Andere Kategorie soll auch
   schwarz? Einfach in die Auswahlliste aufnehmen, z.B.
   body[data-cat="sneaker"] .logo img, body[data-cat="women"] .logo img */
body[data-cat="sneaker"] .logo img { filter: invert(1); }

/* Der Schriftzug erscheint als ERSTES (eigene Klasse), der CART-Button
   erst ganz am Ende zusammen mit den Kategorie-Labels. */
body.logo-in   .logo     { opacity: 1; }
body.chrome-in .logo,
body.chrome-in .cart-btn { opacity: 1; }

.cart-btn:hover { text-decoration: underline; text-underline-offset: 5px; }

/* ==================================================================
   RECHTS-LEISTE (unten links) — Impressum / Datenschutz / AGB / Widerruf

   Warum fest am Bildschirmrand?
   Für einen deutschen Shop müssen diese vier Seiten von JEDER Ansicht
   aus mit einem Klick erreichbar sein ("ständig verfügbar"). Im
   Startmenü gibt es aber keinen Inhaltsbereich, in den eine Fußzeile
   passen würde — deshalb liegt die Zeile fest unten links.

   Sie ist ABSICHTLICH auch ohne JavaScript sichtbar: nur WÄHREND der
   Intro-Animation wird sie ausgeblendet (Klasse "intro-run" am body).
   Bliebe sie von JavaScript abhängig, wären die Pflichtseiten bei einem
   Skriptfehler unerreichbar.

   Die Leiste liegt MITTIG GANZ UNTEN über die volle Breite, der
   CART-Button sitzt darüber. Reihenfolge von unten nach oben:

        IMPRESSUM · DATENSCHUTZ · AGB · WIDERRUF   <- Leiste
        CART (0)                                   <- Button

   Sie hat einen EIGENEN schwarzen Grund. Grund: auf der Produktseite
   liegt unten die Thumbnail-Zeile des Fotos, und Bannerbilder sind
   unterschiedlich hell. Ohne eigenen Grund würde die Schrift auf
   manchen Seiten im Bild verschwinden.

   WICHTIG: Wer die Höhe hier ändert, muss --footer-h mitändern. Diese
   Variable ist der Platz, den Produktseite und Kachelzeile unten
   freihalten — sonst verdeckt die Leiste den Text darüber.
   ================================================================== */
.legal-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;              /* unter Logo (70) und Warenkorb (100) */
  display: flex;
  flex-wrap: wrap;          /* notfalls umbrechen statt überlaufen */
  justify-content: center;
  gap: 4px 18px;
  padding: 6px 14px 7px;
  background: var(--bg);
  opacity: 1;
  transition: opacity 600ms var(--ease);
}

/* Der schwarze Grund reicht bis ÜBER den CART-Button hinauf, damit
   unten ein einziger geschlossener Streifen entsteht:

        ------------------------------  <- Trennlinie
                 CART (0)
        IMPRESSUM DATENSCHUTZ AGB ...

   Ohne das stand der CART-Button auf hellen Produktfotos (Sneaker!)
   und war unlesbar. Die Höhe muss den Button einschließen — Button
   ab 30px Höhe, rund 28px hoch, also mindestens 32px. Zusammen mit
   der Leiste ergibt das --footer-h. */
.legal-bar::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 32px;
  background: var(--bg);
  border-top: 1px solid var(--line);
}
.legal-bar a {
  color: var(--dim);
  text-decoration: none;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  white-space: nowrap;
}
.legal-bar a:hover { color: var(--fg); }

/* Während der Intro-Animation zurückhalten */
body.intro-run .legal-bar { opacity: 0; pointer-events: none; }

/* ==================================================================
   MANDALA — das Herzstück
   Zustand 1 (Start)  = exakt in der Bildschirmmitte
   Zustand 2 (docked) = verkleinert oben, als Wasserzeichen über dem Banner
   ================================================================== */
.mandala {
  position: fixed;
  left: 50%;
  top: 0;
  width:  var(--mandala);
  height: var(--mandala);
  z-index: 50;
  /* Mitte des Viewports: 50vh minus halbe eigene Höhe */
  transform: translate(-50%, calc(50vh - 50%));

  /* MITSCROLLEN.
     Das Menü liegt "fixed", der Banner darunter scrollt aber mit der
     Seite weg (auf dem Handy und in niedrigen Fenstern). Ohne
     Ausgleich bliebe das Menü stehen und rutschte aus dem Banner
     heraus. --scroll-y setzt script.js bei jedem Scrollen.

     Bewusst die EIGENE Eigenschaft "translate" statt eines zweiten
     Wertes in "transform": transform hat einen 700ms-Übergang für die
     Fahrt nach oben. Läge der Scroll-Ausgleich darin, würde das Menü
     dem Finger hinterherschleifen. So wirkt er sofort. */
  translate: 0 calc(-1 * var(--scroll-y, 0px));

  transition: transform var(--t-dock) var(--ease);
  will-change: transform;
  /* WICHTIG: der Container selbst fängt keine Klicks ab, sonst würde
     die oberste der vier Ebenen alle Klicks der anderen schlucken.
     Klickbar sind nur die Hände (.hand-btn) und die Labels. */
  pointer-events: none;
}

/* Phase C: nach oben gefahren und verkleinert.

   DIE FINGER SITZEN IMMER IN DER MITTE DER BANNERFLÄCHE — Rechner,
   Tablet, Handy hoch, Handy quer. Rechnung: das Element ist so groß wie
   --mandala und hängt mit top:0 an der Oberkante. "translateY(-50%)"
   legt seine MITTE auf y=0, der Zuschlag schiebt sie auf die Mitte der
   Bildfläche. Die Motto-Zeile sitzt unter dem Bild, sie wird deshalb
   abgezogen — sonst rutschte das Menü bei SNEAKER um die halbe
   Motto-Höhe nach unten.

   Kein --dock-top mehr: der Abstand von oben ergibt sich von selbst und
   passt sich jeder Bannerhöhe an. */
.mandala.docked {
  transform:
    translate(-50%, calc((var(--head-h) - var(--motto-h)) / 2 - 50%))
    scale(var(--dock-scale));
}

/* ------------------------------------------------------------------
   DIE VIER HÄNDE
   Jeder Slot ist so groß wie das ganze Mandala und dreht sich damit um
   den gemeinsamen Mittelpunkt. Danach wird er nach außen geschoben:
       rotate(--a)  ->  translate(0, --hand-radius)
   0°=UNTEN, 90°=LINKS, 180°=OBEN, 270°=RECHTS
   So zeigt der Mittelfinger jeder Hand zur Mitte (anatomisch korrekt,
   deshalb Drehung statt Spiegelung).
   ------------------------------------------------------------------ */
.hand-slot {
  position: absolute;
  inset: 0;
  /* STARTZUSTAND der Intro: ALLE VIER exakt übereinander in der Mitte und
     ALLE UNGEDREHT (0°) — man sieht also genau EINE Hand.
     Wichtig: hier darf NICHT rotate(var(--a) - 360deg) stehen. Das sieht
     optisch identisch zu rotate(var(--a)) aus, die vier Hände lägen dann
     schon in ihren Endwinkeln übereinander und würden ineinander
     verschwimmen statt wie eine einzelne Hand zu wirken. */
  transform: rotate(0deg) translate(0, 0);
  transition: transform var(--t-spread) var(--ease);
  will-change: transform;
  pointer-events: none;   /* nur der Button darin ist klickbar */
}

/* ENDZUSTAND: auseinandergefahren = fertiges Mandala.
   Das "+360deg" ist der Trick für die Animation: rechnerisch dreht jede
   Hand eine volle Umdrehung im Uhrzeigersinn PLUS ihren Zielwinkel,
   optisch landet sie exakt auf var(--a). So vervielfältigt sich die eine
   Hand sichtbar WÄHREND der Drehung. */
.mandala.spread .hand-slot {
  transform: rotate(calc(var(--a) + 360deg)) translate(0, var(--hand-radius));
}

/* Das sichtbare Handbild — nimmt selbst keine Klicks entgegen */
.hand-img {
  position: absolute;
  /* seitlich versetzt, damit die Fingerspitze auf der Drehachse liegt */
  left: calc(50% - var(--tip-off));
  top: 50%;
  width: var(--hand-size);
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  object-fit: contain;
  opacity: .82;
  pointer-events: none;
  transition: opacity 300ms var(--ease), transform 300ms var(--ease);
}

/* Die unsichtbare Klickfläche — schmal, damit sich die vier nicht
   gegenseitig überdecken. "top" ist hier nach AUSSEN gerichtet, weil
   der Slot mitgedreht wird. */
.hand-btn {
  position: absolute;
  left: calc(50% - var(--tip-off));   /* folgt dem Versatz des Bildes */
  top: calc(50% + var(--hit-off));
  width:  var(--hit-w);
  height: var(--hit-h);
  transform: translate(-50%, -50%);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  pointer-events: auto;   /* <- macht JEDE der vier Hände klickbar */
  -webkit-tap-highlight-color: transparent;
  /* Zur Fingerspitze hin verjüngt (oben = Richtung Mandala-Mitte).
     Das folgt der Handform und verhindert, dass sich die Ecken zweier
     benachbarter Klickflächen im toten Raum neben der Mitte treffen. */
  clip-path: polygon(30% 0, 70% 0, 100% 45%, 100% 100%, 0 100%, 0 45%);
}

/* Hover (Hand ODER Label) und aktive Kategorie: Hand größer und heller.
   Die Klasse setzt script.js, damit auch das Label die Hand aufhellt. */
.hand-slot.hl     .hand-img { opacity: 1; transform: translate(-50%, -50%) scale(1.10); }
.hand-slot.active .hand-img { opacity: 1; transform: translate(-50%, -50%) scale(1.06); }

/* WASSERZEICHEN: sobald das Menü oben über dem Banner klebt, tritt es
   deutlich zurück. Die überfahrene und die aktive Kategorie bleiben
   voll sichtbar — sonst wüsste man nicht mehr, wo man ist. */
.mandala.docked .hand-img { opacity: var(--dock-hand-op); }
/* Reihenfolge wichtig: .hl muss NACH .active stehen, sonst gewinnt bei
   gleicher Spezifität die aktive Kategorie und die berührte Hand würde
   nicht ganz aufhellen. */
.mandala.docked .hand-slot.active .hand-img { opacity: .92; }
.mandala.docked .hand-slot.hl     .hand-img { opacity: 1; }

/* Solange der Cursor auf IRGENDEINER Hand steht ("hovering"), tritt die
   aktive Kategorie zurück — sonst wären zwei Hände gleichzeitig hell und
   man wüsste nicht, welche gemeint ist. Hervorgehoben ist immer genau
   eine: die berührte. */
.mandala.docked.hovering .hand-slot.active:not(.hl) .hand-img {
  opacity: var(--dock-hand-op);
}
.mandala.docked.hovering .m-label.active:not(.hl) {
  color: rgba(255,255,255,var(--dock-label-op));
  font-weight: 400;
}

.hand-btn:focus-visible { outline: 1px solid var(--line); outline-offset: 2px; }

/* Beim allerersten Erscheinen sanft einblenden */
.mandala { opacity: 0; }
.mandala.visible { opacity: 1; transition: opacity 700ms var(--ease), transform var(--t-dock) var(--ease); }

/* ------------------------------------------------------------------
   DIE VIER LABELS
   Bleiben immer aufrecht (nicht mitgedreht) und sitzen außerhalb der
   Handflächen. Die dünne Linie zur Hand ist ein ::after-Element —
   Optik einer technischen Zeichnung.
   ------------------------------------------------------------------ */
.m-label {
  position: absolute;
  z-index: 2;
  font-size: var(--label-size);
  font-weight: 400;
  letter-spacing: .3em;
  text-transform: uppercase;
  white-space: nowrap;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  pointer-events: auto;
  color: var(--dim);
  opacity: 0;
  transition: opacity 500ms var(--ease), color 250ms var(--ease), font-weight 150ms linear;
  -webkit-tap-highlight-color: transparent;
}

/* Phase B: Labels morphen ein */
.mandala.labelled .m-label { opacity: 1; }

/* .hl setzt script.js — dadurch leuchtet die Schrift auch dann auf,
   wenn der Cursor auf der HAND steht (und umgekehrt). */
.m-label.hl, .m-label:focus-visible, .m-label.active { color: var(--fg); font-weight: 700; }
.m-label:focus-visible { outline: 1px solid var(--line); outline-offset: 6px; }

/* --- Positionen + Verbindungslinien ------------------------------- */
.m-label::after {
  content: "";
  position: absolute;
  background: var(--line);
}

/* OBEN */
.m-label[data-pos="top"] {
  bottom: calc(50% + var(--label-radius));
  left: 50%;
  transform: translateX(-50%);
}
.m-label[data-pos="top"]::after {
  left: 50%; top: 100%; width: 1px; height: 14px;
}

/* UNTEN */
.m-label[data-pos="bottom"] {
  top: calc(50% + var(--label-radius));
  left: 50%;
  transform: translateX(-50%);
}
.m-label[data-pos="bottom"]::after {
  left: 50%; bottom: 100%; width: 1px; height: 14px;
}

/* LINKS */
.m-label[data-pos="left"] {
  right: calc(50% + var(--label-radius));
  top: 50%;
  transform: translateY(-50%);
}
.m-label[data-pos="left"]::after {
  top: 50%; left: 100%; height: 1px; width: 14px;
}

/* RECHTS */
.m-label[data-pos="right"] {
  left: calc(50% + var(--label-radius));
  top: 50%;
  transform: translateY(-50%);
}
.m-label[data-pos="right"]::after {
  top: 50%; right: 100%; height: 1px; width: 14px;
}

/* Im angedockten Zustand wird alles auf --dock-scale geschrumpft.
   Damit die Labels lesbar bleiben, wird die Schrift gegengerechnet. */
.mandala.docked .m-label {
  font-size: calc(var(--label-size) / var(--dock-scale) * .8);
  letter-spacing: .18em;
  /* zurückgenommen wie die Hände — Wasserzeichen-Wirkung */
  color: rgba(255,255,255,var(--dock-label-op));
}
.mandala.docked .m-label.active,
.mandala.docked .m-label.hl { color: var(--fg); }
.mandala.docked .m-label::after { height: 40px; }
.mandala.docked .m-label[data-pos="left"]::after,
.mandala.docked .m-label[data-pos="right"]::after { height: 1px; width: 40px; }

/* ==================================================================
   INHALT — füllt exakt den Bildschirm, kein Scrollen
   Aufbau:  [Kopf: Banner + Mandala als Wasserzeichen]
            [Bühne: links Produktfoto, rechts Beschreibung/Bestellung]
   ================================================================== */
.content { display: none; height: 100dvh; }
body.docked .content { display: flex; flex-direction: column; }

/* ---------- Kopfbereich: Banner LIEGT HINTER dem Mandala ----------
   Aufbau:  .head-band
              .banner-stack   <- alle Bilder liegen ÜBEREINANDER
                .b-slide (.on = das sichtbare)
                  .b-half.l   <- linke Bildhälfte
                  .b-half.r   <- rechte Bildhälfte
              .band-motto     <- optionale Motto-Zeile               */
.head-band {
  position: relative;
  flex: 0 0 var(--head-h);
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  display: flex;
  flex-direction: column;
}
.banner-stack { position: relative; flex: 1 1 auto; min-height: 0; }

/* ---------- RANDABDUNKLUNG ---------------------------------------
   Die Models stehen mittig, links und rechts liegt gespiegelte
   Umgebung. Der Verlauf zieht die Ränder ins Schwarz und führt das
   Auge in die Mitte.

   BEWUSST ALS CSS-VERLAUF, nicht als banneroverlay.png:
     - keine zusätzliche Bilddatei bei jedem Seitenaufruf
     - passt sich jeder Breite an; eine feste PNG-Datei müsste
       mitskaliert und -beschnitten werden und würde bei den flachen
       Handy-Ausschnitten nicht mehr passen
     - Stärke und Breite hier in einer Zeile änderbar

   Liegt ÜBER dem Bild und über den Gesichtsmasken, aber unter dem
   Menü (z-index 50) und unter der Motto-Zeile, die ausserhalb dieses
   Kastens sitzt.

   --vig      Deckkraft am äussersten Rand (0 = aus, 1 = ganz schwarz)
   --vig-in   ab wo die Mitte völlig frei bleibt (in % der Breite)   */
:root {
  --vig:    .92;
  --vig-in: 34%;
}
.banner-stack::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(10,10,10, var(--vig)) 0%,
    rgba(10,10,10, 0)          var(--vig-in),
    rgba(10,10,10, 0)          calc(100% - var(--vig-in)),
    rgba(10,10,10, var(--vig)) 100%);
}

/* Ein Bild der Diashow. Alle Bilder liegen deckungsgleich
   uebereinander; jedes ist in eine LINKE und eine RECHTE HAELFTE
   geteilt, damit sich beide Seiten getrennt bewegen koennen. */
.b-slide {
  position: absolute;
  inset: 0;
  visibility: hidden;
}
.b-slide.on,
.b-slide.leaving { visibility: visible; }
/* Die abtretende Folie liegt OBEN — sie schiebt sich weg und
   darunter kommt die neue zum Vorschein. */
.b-slide.leaving { z-index: 2; }

/* ---------- DER ÜBERGANG: ZWEI HÄLFTEN, VERSETZT ------------------
   Beim Bildwechsel passiert Folgendes:

     1. Eine Haelfte (links ODER rechts, das wechselt jedes Mal)
        schiebt sich nach oben oder unten aus dem Bild — Richtung
        zufaellig. Von der anderen Seite kommt gleichzeitig die
        gleiche Haelfte des NEUEN Bildes nachgerutscht.
     2. Nach --slide-stagger macht die zweite Haelfte dasselbe,
        wieder mit zufaelliger Richtung.

   Welche Seite anfaengt, wechselt immer ab (und startet beim ersten
   Wechsel zufaellig links oder rechts).

   Dauer einer Haelfte  --t-slide
   Versatz dazwischen   --slide-stagger
   Standzeit            BANNER_INTERVAL in script.js               */
.b-half {
  position: absolute;
  top: 0;
  height: 100%;
  width: 50%;
  overflow: hidden;
  transition: transform var(--t-slide) var(--ease-slide);
  will-change: transform;
}
.b-half.l { left: 0; }
.b-half.r { left: 50%; }

/* Jede Haelfte zeigt ihren Teil des Bildes: das Bild ist doppelt so
   breit wie die Haelfte (= genau die Bannerbreite) und wird nach
   links geschoben, damit rechts auch die rechte Bildhaelfte steht. */
.b-half > img,
.b-half > picture {
  position: absolute;
  top: 0;
  height: 100%;
  width: 200%;
  /* muss die 100%-Grenze aus dem BASIS-Block ausdrücklich aufheben,
     sonst bleibt das Bild bei halber Breite stehen */
  max-width: none;
}
.b-half.l > img, .b-half.l > picture { left: 0; }
.b-half.r > img, .b-half.r > picture { left: -100%; }
.b-half picture > img { width: 100%; height: 100%; }

.b-half img {
  /* NIE BESCHNITTEN. Die Bannerflaeche ist ohnehin genau so hoch wie
     das Bild (siehe --head-h), deshalb fuellt "contain" sie exakt aus:
     kein Beschnitt, keine Raender, kein Verzerren. */
  object-fit: contain;
  /* IN FARBE, aber abgedunkelt — die Abdunklung MUSS bleiben, damit das
     weisse Mandala und die Kategorie-Namen als Wasserzeichen darueber
     lesbar sind. Vorher stand hier zusaetzlich grayscale(1).
     Zu bunt? brightness kleiner (z.B. .32) oder saturate ergaenzen,
     z.B.  brightness(.40) contrast(1.05) saturate(.7). */
  filter: brightness(.40) contrast(1.05);
}

/* ==================================================================
   GESICHTSMASKEN IM BANNER
   ------------------------------------------------------------------
   Kein starrer schwarzer Balken, sondern ein bewegtes Pixelfeld:
   backdrop-filter verwischt das, was DAHINTER liegt, darüber liegt ein
   Raster aus 7px-Blöcken, das ruckweise seine Position wechselt. Das
   wirkt wie eine laufende Verpixelung.

   Die Position der Felder rechnet script.js aus (platziereMasken) —
   hier steht nur das Aussehen.

   Stärker verpixeln?  blur() erhöhen.
   Ruhiger?            animation-duration erhöhen oder animation: none.
   Blockgröße?         background-size ändern (beide Werte gleich).
   ================================================================== */
.b-faces {
  position: absolute;
  inset: 0;
  pointer-events: none;   /* darf keine Klicks abfangen */
  z-index: 2;
}
.b-face {
  position: absolute;
  /* verwischt den Bildinhalt darunter */
  -webkit-backdrop-filter: blur(9px) contrast(1.3);
          backdrop-filter: blur(9px) contrast(1.3);
  /* zwei versetzte Raster ergeben die Blockstruktur */
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,.13) 0 50%, rgba(0,0,0,.16) 50% 100%),
    repeating-linear-gradient(0deg,  rgba(255,255,255,.10) 0 50%, rgba(0,0,0,.13) 50% 100%);
  background-size: 7px 7px, 7px 7px;
  animation: face-shift 1.4s steps(1, end) infinite;
}
/* Ruckweise verschieben — steps(1) sorgt dafür, dass es springt statt
   weich zu gleiten. Das ist der "Pixel"-Eindruck. */
@keyframes face-shift {
  0%   { background-position:  0px  0px,  0px  0px; }
  25%  { background-position:  3px -2px, -2px  3px; }
  50%  { background-position: -2px  3px,  3px  2px; }
  75%  { background-position:  2px  2px, -3px -2px; }
  100% { background-position:  0px  0px,  0px  0px; }
}

/* Safari auf älteren Geräten kann kein backdrop-filter. Dort bleibt
   das Raster allein zu durchsichtig — deshalb dann ein deckender
   Block, damit das Gesicht in JEDEM Fall zu ist. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .b-face { background-color: #0A0A0A; }
}

/* ---------- MOTTO DER KOLLEKTION IM BANNER ------------------------
   Eigene Zeile am unteren Rand des Banners. Sie ist Teil des
   Kopfbereichs, deshalb schiebt sie den Produktbereich nicht weg. */
.band-motto {
  flex: 0 0 var(--motto-h);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .34em;
  text-transform: uppercase;
  text-align: center;
  padding: 0 12px;
  white-space: nowrap;
  overflow: hidden;
  color: var(--fg);
}

/* Hinweis zu "-hoch"-Zuschnitten: der Kopfbereich ist immer genau so
   hoch wie das gerade gezeigte Bild (siehe --banner-ar), egal ob
   Quer- oder Hochformat-Datei. Deshalb braucht es hier keine
   Sonderregel mehr — "contain" oben gilt für beide Fälle. */

/* ---------- Bühne: nimmt die komplette Resthöhe -------------------
   overflow-y: auto ist die Notbremse für die Übersicht: dort füllen
   die Fotos die ganze Spaltenbreite (damit neben ihnen NICHTS
   schwarz bleibt) und werden dadurch höher als der Bildschirm.
   Die Produktseite passt weiterhin genau, dort wird nicht gescrollt. */
.stage { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* ---------- Produkt-Grid ------------------------------------------
   Zeigt ALLE Produkte einer Kategorie. Bis zu drei stehen
   nebeneinander, danach wird in die nächste Reihe umgebrochen und die
   Bühne scrollt.

   Früher lag hier "grid-auto-flow: column": alle Produkte kamen in EINE
   Reihe, egal wie viele. Bei fünf Artikeln wurde jede Kachel 20% breit
   und auf dem Handy unlesbar.

   --cols  Anzahl der Spalten. Kommt aus DIESER Datei, nicht aus dem
           Skript — sonst könnte die Handy-Regel nicht dagegenhalten.
           Das Skript liefert nur data-count (Anzahl der Produkte).
   --meta-h  Höhe der Textzeile unter dem Foto. Wird von script.js
             gemessen (Name kann in schmalen Spalten umbrechen).      */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: 1px;
  background: var(--line);
  align-content: start;
  --cols:   3;
  --meta-h: 80px;
}
/* Bei ein oder zwei Produkten keine leeren Spalten aufmachen */
.grid[data-count="1"] { --cols: 1; }
.grid[data-count="2"] { --cols: 2; }
.card {
  background: var(--bg);
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;   /* Foto mittig in seiner Spalte */
  min-height: 0;
  overflow: hidden;
}

/* DIE FLÄCHE IST GENAU DAS FOTO — nie beschnitten, nie mit Rand.
   Die Höhe ist der KLEINERE dieser zwei Werte:
     1. was die Spaltenbreite zulässt  (Spaltenbreite / Verhältnis)
     2. was die Bildschirmhöhe zulässt (Resthöhe minus Textzeile)
   Die Breite ergibt sich aus der Höhe (width: auto). Ist die Spalte
   der engere Fall, füllt das Foto sie randlos aus. Ist die Höhe der
   engere Fall, wird das Foto kleiner und der freie Platz liegt als
   Abstand ZWISCHEN den Produkten — nicht als Rand um ein Foto. */
.card-img {
  flex: 0 0 auto;
  height: min(
            calc((100vw / var(--cols) - 1px) / var(--hero-ar)),
            calc(100dvh - var(--head-h) - var(--footer-h) - var(--meta-h))
          );
  width: auto;
  max-width: 100%;
  object-fit: contain;
  /* PRODUKTFOTOS IN FARBE.
     Hier stand  filter: grayscale(1)  und dazu eine Regel, die das Foto
     erst beim Überfahren mit der Maus einfärbte. Auf dem Handy gibt es
     kein "Überfahren" — dort waren die Fotos also immer schwarzweiß.
     Farbe ist jetzt der Normalzustand, an allen vier Stellen:
     Übersicht (hier), Produktseite (.p-hero), Thumbnails und
     Warenkorb. Beim Überfahren wird die Kachel nur leicht heller.
     Zurück zu schwarzweiß? An diesen vier Stellen
     "filter: grayscale(1);" wieder eintragen. */
  transition: filter 350ms var(--ease);
}
.card:hover .card-img { filter: brightness(1.08); }
.card-meta {
  flex: 0 0 auto;
  align-self: stretch;
  /* Bodenabstand = voller --footer-h. Hier stand früher "- 8px"; das
     passte zum kleinen CART-Button, nicht zum heutigen Streifen. */
  padding: 14px 20px var(--footer-h);
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 13px;
  letter-spacing: .14em;
  text-transform: uppercase;
}
.card-meta .name  { font-weight: 700; }
.card-meta .price { color: var(--dim); white-space: nowrap; }
/* Preis + Pflichtangabe rechtsbündig untereinander.
   flex: 0 0 auto + nowrap: der Hinweis bleibt EINZEILIG. Sonst bricht
   er in der schmalen Spalte auf drei Zeilen um, die Textzeile wird
   dadurch dreimal so hoch und drückt die Fotos zusammen. Wird es eng,
   bricht stattdessen der Produktname um — dafür ist die Messung in
   messeKachelzeile() gebaut. */
.card-price { flex: 0 0 auto; text-align: right; }
.card-price .tax-note { margin-top: 4px; white-space: nowrap; }

/* ==================================================================
   PRODUKTSEITE — links Foto, rechts Beschreibung + Bestellung
   ================================================================== */
/* DIE FOTOSPALTE IST GENAU SO BREIT WIE DAS FOTO.
   Rechnung: das Foto bekommt die volle Resthöhe des Bildschirms
   (abzüglich der Thumbnail-Zeile UND des Streifens unten), seine Breite
   ergibt sich aus dem Seitenverhältnis der Datei. Ergebnis: das Foto
   ist komplett zu sehen (kein Beschnitt) und daneben bleibt NICHTS
   schwarz. Foto links, Bestellung rechts.

   --footer-h MUSS hier abgezogen werden (und in .p-media unten als
   padding stehen). Sonst reicht die Fotospalte bis zur Unterkante des
   Fensters und der Streifen (CART-Button + Rechts-Leiste) legt sich
   über die THUMBNAIL-ZEILE — die zweite Produktansicht war dadurch
   unsichtbar. Beide Werte gehören zusammen: hier abziehen, dort
   freihalten, sonst wird die Spalte breiter als das Foto. */
.product {
  display: grid;
  grid-template-columns:
    calc((100dvh - var(--head-h) - var(--footer-h)
          - var(--thumbs-h) * var(--has-thumbs))
         * var(--hero-ar))
    minmax(0, 1fr);
  gap: 1px;
  background: var(--line);
  /* ENDET ÜBER DEM STREIFEN, nicht an der Fensterunterkante.
     Ein blosses padding-bottom in den Spalten genügt nicht: .p-info ist
     ein eigener Scrollbereich, dessen Unterkante lag dann weiter hinter
     dem Streifen — die Größen-Buttons wurden angeschnitten. Wird die
     ganze Zeile kürzer, endet beides sauber darüber: die
     Thumbnail-Zeile links und der Scrollbereich rechts. */
  height: calc(100% - var(--footer-h));
}
.p-media, .p-info { background: var(--bg); min-height: 0; }

.p-media { display: flex; flex-direction: column; overflow: hidden; }
.p-hero {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  /* Die Fläche ist auf das Foto zugeschnitten, "contain" füllt sie
     deshalb randlos aus — und beschneidet nie. */
  object-fit: contain;
  /* in Farbe, siehe Hinweis bei .card-img */
}
.p-thumbs {
  flex: 0 0 var(--thumbs-h);
  display: flex;
  /* Hintergrund SCHWARZ: die Zeile ist so breit wie das Foto, die
     Thumbnails füllen sie aber nicht aus — der Rest soll schwarz
     bleiben und nicht als grauer Balken auffallen. Getrennt werden
     die Thumbnails durch eine dünne Linie. */
  background: var(--bg);
  border-top: 1px solid var(--line);
}
.p-thumbs button {
  flex: 0 0 72px;
  padding: 0;
  border: 0;
  background: var(--bg);
  cursor: pointer;
  opacity: .45;
  transition: opacity 250ms var(--ease);
}
.p-thumbs button + button { border-left: 1px solid var(--line); }
.p-thumbs button.active, .p-thumbs button:hover { opacity: 1; }
.p-thumbs img { width: 100%; aspect-ratio: 1/1; object-fit: contain; }

.p-info {
  /* kein --footer-h mehr nötig: die ganze .product-Zeile endet bereits
     über dem Streifen */
  padding: 24px 30px;
  display: flex;
  flex-direction: column;
  /* 14 statt 18: auf 720px Fensterhöhe passen Beschreibung, Größen und
     Kaufen-Knopf sonst nicht mehr gemeinsam in die Spalte und die
     Größenreihe wird angeschnitten. Die Spalte kann zwar scrollen, das
     sieht aber nach Fehler aus. */
  gap: 14px;
  overflow-y: auto;    /* Notfall-Scroll nur INNERHALB der Spalte */
}

/* Die Fotospalte ist jetzt genau so breit wie das Foto — dadurch
   bleibt rechts mehr Platz. Damit Text und Knopf nicht über die ganze
   Restbreite auseinandergezogen werden und die Aufteilung so wirkt wie
   vorher, sind die Zeilen auf eine Spaltenbreite begrenzt.
   Breiter/schmaler? Nur diesen Wert ändern. */
.p-info > * { max-width: 640px; }

.p-back {
  align-self: flex-start;
  background: none;
  border: 0;
  padding: 0;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  color: var(--dim);
  transition: color 200ms var(--ease);
}
.p-back:hover { color: var(--fg); }

.p-name {
  margin: 0;
  font-size: clamp(24px, 3.2vw, 42px);
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  line-height: 1.02;
}
.p-price { font-size: 15px; letter-spacing: .18em; color: var(--dim); }

/* ---------- PREISANGABE (Pflicht) ---------------------------------
   Die Preisangabenverordnung verlangt beim Preis den Hinweis, dass es
   ein Endpreis ist und ob Versandkosten anfallen. Bei Kleinunternehmern
   darf dort NICHT "inkl. MwSt." stehen — der Text kommt aus
   PREIS_HINWEIS in script.js. Steht unter dem Preis bzw. unter der
   Produktübersicht. */
.tax-note {
  margin: 6px 0 0;
  font-size: 9px;
  letter-spacing: .12em;
  line-height: 1.6;
  text-transform: uppercase;
  color: var(--dim);
}
.tax-note.center { text-align: center; margin: 14px 0 0; }
/* Im Warenkorb sitzt der Hinweis zwischen Summe und CHECKOUT-Knopf —
   dort enger, damit kein Loch entsteht. */
.cart-foot .tax-note.center { margin: -6px 0 13px; }

/* ---------- VORBESTELL-MARKIERUNG --------------------------------
   Sitzt an Produkten mit  preorder: true  (siehe script.js). */
.p-tag {
  align-self: flex-start;
  border: 1px solid var(--fg);
  padding: 5px 9px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
}
.card-tag {
  font-size: 10px;
  letter-spacing: .16em;
  color: var(--dim);
  margin-top: 4px;
}

/* Fehlt eine Bilddatei, bleibt die Fläche einfach schwarz —
   kein kaputtes Bild-Symbol. Die Klasse setzt script.js. */
.img-missing { visibility: hidden; }

.p-desc {
  margin: 0;
  font-size: 12px;
  line-height: 1.85;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dim);
  white-space: pre-line;   /* respektiert den Zeilenumbruch im Text */
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 14px 0;
}

/* ---------- Größenauswahl (Buttons, kein Dropdown) ---------------- */
.p-sizes-label {
  font-size: 11px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 10px;
}
.p-sizes { display: flex; flex-wrap: wrap; gap: 8px; }
.size-btn {
  min-width: 50px;
  padding: 11px 13px;
  background: none;
  border: 1px solid var(--line);
  font-size: 12px;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 180ms var(--ease), color 180ms var(--ease), border-color 180ms var(--ease);
}
.size-btn:hover  { border-color: var(--fg); }
.size-btn.active { background: var(--fg); color: var(--bg); border-color: var(--fg); }

/* ---------- Haupt-Button ------------------------------------------ */
.btn-block {
  display: block;
  width: 100%;
  padding: 18px;
  background: var(--fg);
  color: var(--bg);
  border: 1px solid var(--fg);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .28em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 180ms var(--ease), color 180ms var(--ease);
}
.btn-block:hover    { background: var(--bg); color: var(--fg); }
.btn-block:disabled { opacity: .35; cursor: not-allowed; }

.hint {
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--dim);
  min-height: 14px;
}

/* ==================================================================
   WARENKORB — Slide-in von rechts, ohne Overlay
   ================================================================== */
.cart {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 100;
  width: min(400px, 100vw);
  height: 100dvh;
  background: var(--bg);
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(0,0,0,.55);  /* nur subtile Tiefe */
  transform: translateX(101%);
  transition: transform 420ms var(--ease);
  display: flex;
  flex-direction: column;
}
.cart.open { transform: translateX(0); }

.cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px;
  border-bottom: 1px solid var(--line);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .28em;
}
.icon-btn {
  background: none;
  border: 0;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
  color: var(--dim);
  transition: color 200ms var(--ease);
}
.icon-btn:hover { color: var(--fg); }

.cart-items { flex: 1; overflow-y: auto; }
.cart-empty {
  padding: 40px 20px;
  font-size: 11px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--dim);
}

.cart-row {
  display: grid;
  grid-template-columns: 62px 1fr auto;
  gap: 14px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
  align-items: start;
}
.cart-row img { width: 62px; aspect-ratio: 4/5; object-fit: contain; }
.cart-row .r-name {
  font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
}
.cart-row .r-sub {
  font-size: 11px; letter-spacing: .16em; color: var(--dim); margin-top: 5px;
}
.cart-row .r-price { font-size: 12px; letter-spacing: .1em; white-space: nowrap; }

.qty { display: flex; align-items: center; gap: 0; margin-top: 9px; }
.qty button {
  width: 26px; height: 26px;
  background: none;
  border: 1px solid var(--line);
  cursor: pointer;
  font-size: 13px;
  line-height: 1;
  transition: background 160ms var(--ease), color 160ms var(--ease);
}
.qty button:hover { background: var(--fg); color: var(--bg); }
.qty span { min-width: 34px; text-align: center; font-size: 12px; }

/* ---------- KASSE (klappt im Warenkorb auf) ----------------------- */
.checkout {
  display: none;
  border-top: 1px solid var(--line);
  padding: 18px 20px 4px;
  overflow-y: auto;
  flex: 0 1 auto;
}
.checkout.open { display: block; }

/* Kasse offen: die Artikelliste wird kleiner, verschwindet aber nicht —
   der Kunde soll sehen, was er bestellt, während er tippt. */
.cart.kasse .cart-items { flex: 0 1 auto; max-height: 28vh; }

.co-head {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 14px;
}
.co-field { display: block; margin-bottom: 12px; }
.co-label {
  display: block;
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--dim);
  margin-bottom: 5px;
}
.checkout input,
.checkout select {
  width: 100%;
  padding: 11px 12px;
  background: none;
  border: 1px solid var(--line);
  color: var(--fg);
  font: inherit;
  font-size: 13px;
  letter-spacing: .06em;
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
}
.checkout input:focus,
.checkout select:focus { outline: none; border-color: var(--fg); }
.checkout select { text-transform: uppercase; }
/* Auswahlliste: die Einträge zeichnet das System, deshalb hier
   ausdrücklich dunkel setzen — sonst weiß auf weiß. */
.checkout select option { background: var(--bg); color: var(--fg); }

/* ---------- Bestellübersicht direkt über dem Bestell-Button --------
   § 312j Abs. 2 BGB: unmittelbar vor dem Absenden müssen Ware, Menge,
   Gesamtpreis und Versandkosten noch einmal klar zusammengefasst
   stehen. Genau das ist dieser Block. */
.co-sum {
  border: 1px solid var(--line);
  padding: 12px 14px;
  margin: 4px 0 14px;
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.co-sum-row {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 3px 0;
  color: var(--dim);
}
.co-sum-row span:last-child { white-space: nowrap; }
.co-sum-row.total {
  color: var(--fg);
  font-weight: 700;
  letter-spacing: .14em;
  border-top: 1px solid var(--line);
  margin-top: 8px;
  padding-top: 8px;
}
.co-sum-tax {
  margin: 8px 0 0;
  font-size: 9px;
  letter-spacing: .1em;
  line-height: 1.6;
  color: var(--dim);
  text-transform: none;
}

/* ---------- Pflicht-Checkbox --------------------------------------
   Ohne Häkchen bleibt der Bestell-Button gesperrt. */
.co-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 0 14px;
  cursor: pointer;
  font-size: 10px;
  line-height: 1.65;
  letter-spacing: .06em;
  color: var(--dim);
}
.co-check input[type="checkbox"] {
  flex: 0 0 15px;
  width: 15px;
  height: 15px;
  margin: 2px 0 0;
  padding: 0;
  border: 1px solid var(--fg);
  background: none;
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  position: relative;
}
.co-check input[type="checkbox"]:checked { background: var(--fg); }
/* Das Häkchen selbst: zwei Striche, gedreht — kein Bild, keine Schrift */
.co-check input[type="checkbox"]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 1px;
  width: 5px;
  height: 9px;
  border: solid var(--bg);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.co-check input[type="checkbox"]:focus-visible { outline: 1px solid var(--fg); outline-offset: 2px; }
.co-check a { color: var(--fg); text-decoration: underline; text-underline-offset: 2px; }
/* Fehlt das Häkchen und es wird trotzdem geklickt: rot ist im Design
   nicht vorgesehen, deshalb wird der Kasten kurz voll umrandet. */
.co-check.missing { color: var(--fg); }
.co-check.missing input[type="checkbox"] { outline: 1px solid var(--fg); outline-offset: 2px; }

/* Der Bestell-Button trägt einen längeren Text ("ZAHLUNGSPFLICHTIG
   BESTELLEN") — kleinere Sperrung, damit er in einer Zeile bleibt. */
.checkout .btn-block {
  margin-top: 6px;
  font-size: 11px;
  letter-spacing: .14em;
  padding: 17px 10px;
}

.co-hint {
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dim);
  min-height: 14px;
  padding: 8px 0 4px;
  line-height: 1.7;
}
.co-hint a { color: var(--fg); display: block; margin-top: 4px; }

.cart-foot { border-top: 1px solid var(--line); padding: 20px; }
.cart-total {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  margin-bottom: 16px;
}
.cart-note {
  margin: 12px 0 0;
  font-size: 10px;
  letter-spacing: .2em;
  color: var(--dim);
  text-align: center;
}

/* ==================================================================
   RESPONSIVE
   Auf schmalen Geräten passen auf der PRODUKTSEITE Foto und
   Beschreibung nicht mehr nebeneinander -> untereinander, und
   Scrollen wird erlaubt.
   Die ÜBERSICHT bleibt dagegen IMMER nebeneinander — die Breite wird
   geteilt (halbiert/gedrittelt), damit man alles auf einen Blick hat.
   Das zentrierte Startmenü bleibt immer scrollfrei.
   ================================================================== */
@media (max-width: 700px) {
  html, body { height: auto; overflow-y: auto; }
  body:not(.docked) { height: 100dvh; overflow: hidden; }

  .content  { height: auto; }
  .stage    { min-height: 0; }

  /* Untereinander: das Foto nimmt die volle Breite, die Höhe folgt
     seinem Seitenverhältnis — randlos und unbeschnitten. */
  .product  { grid-template-columns: 1fr; height: auto; }
  .p-hero   { aspect-ratio: var(--hero-ar); flex: 0 0 auto; }
  /* Hier stehen Foto und Text untereinander und die SEITE scrollt.
     .product ist deshalb "height: auto" (siehe unten) — die Verkürzung
     um --footer-h greift hier nicht. Den Streifen hält darum wieder das
     Padding von .p-info frei, es ist das letzte Element der Seite. */
  .p-info   { padding: 22px 18px var(--footer-h); overflow: visible; }

  /* Die Bühne behält mindestens die Resthöhe des Bildschirms, damit die
     Produktreihe darin MITTIG sitzt statt oben zu kleben. Bei längeren
     Inhalten (Produktseite) wächst sie einfach weiter.
     margin: auto statt justify-content: center — so wird bei Überlänge
     oben nichts abgeschnitten. */
  .stage {
    overflow-y: visible;
    display: flex;
    flex-direction: column;
    min-height: calc(100dvh - var(--head-h));
  }
  /* ZWEI Spalten auf dem Handy, nicht drei. Bei drei Spalten auf 375px
     Breite ist eine Kachel nur 125px breit — darauf ist ein Shirt nicht
     mehr zu erkennen. Ab dem dritten Produkt wird umgebrochen und die
     Seite scrollt. */
  .grid { margin: 0; --cols: 2; }
  .grid[data-count="1"] { --cols: 1; }
}

@media (max-width: 700px) {
  :root {
    /* Mandala bleibt komplett sichtbar, nur kleiner skaliert.
       Hände etwas enger, damit die Labels daneben Platz haben. */
    /* Hand etwas kleiner, damit die Labels neben dem Mandala noch
       auf den Schirm passen. Gleiche Rechnung wie oben:
       21,5% - 0,433 x 36% = 6% freie Mitte, äußerer Rand bei 37,1%. */
    --mandala:      min(60vh, 84vw);
    --hand-size:    36%;
    --hand-radius:  21.5%;
    --tip-off:      1.04%;   /* 0,029 x 36% */
    --label-size:   9px;
    --label-radius: 39%;
    --hit-w:        17%;
    --hit-h:        31%;
    --dock-scale:   .42;
    /* Weniger Mindestluft: auf kleinen Schirmen darf der Kopfbereich
       flacher werden. Die Mitten-Position rechnet sich selbst. */
    --dock-gap:     22px;
    --logo-w:      145px;

    /* Schrift und Button sind hier kleiner, der Streifen ist rund 50px
       hoch (28 + 22). Plus Luft. */
    --footer-h:     58px;
  }

  /* Auf 375px passen die vier Wörter nur mit engerer Sperrung in eine
     Zeile. Bricht es doch um, fängt flex-wrap es ab — dann aber
     --footer-h erhöhen, sonst verdeckt die zweite Zeile Inhalt. */
  .legal-bar   { gap: 4px 14px; padding: 7px 10px 8px; }
  .legal-bar a { font-size: 8px; letter-spacing: .14em; }
  /* Kleinerer Button -> flacherer Grund darüber */
  .legal-bar::before { height: 30px; }

  .cart-btn { font-size: 10px; bottom: 28px; }
  .m-label   { letter-spacing: .16em; }
  /* Die Spalten sind auf dem Handy schmal (halbiert/gedrittelt),
     deshalb Name und Preis untereinander statt nebeneinander. */
  .card-meta {
    padding: 10px 10px 20px;
    font-size: 10px;
    letter-spacing: .1em;
    flex-direction: column;
    gap: 4px;
  }
  .card-meta .price { color: var(--dim); }
  /* Auf dem Handy stehen Name und Preis untereinander, die Spalte ist
     nur ein Drittel breit — der Hinweis wird deshalb kleiner und darf
     umbrechen. Linksbündig, damit er unter dem Namen sitzt. */
  .card-price { text-align: left; }
  .card-price .tax-note {
    font-size: 8px;
    letter-spacing: .04em;
    white-space: normal;
    margin-top: 2px;
  }
}

/* ==================================================================
   HOCHFORMAT (Smartphone, Tablet senkrecht)
   ------------------------------------------------------------------
   Hier gilt eine ANDERE Regel als im Querformat:

     Kopfhoehe = --head-share der Fensterhoehe   (Standard 38%)

   Damit ist das Verhaeltnis Banner zu Shop auf dem Handy GENAUSO wie
   am Rechner (dort ergeben sich aus 2560x610 ueber die Fensterbreite
   ebenfalls rund 38%). Die Aufteilung wirkt auf beiden Geraeten gleich.

   Der Preis dafuer: das Querformat-Banner ist auf dem Handy viel
   breiter als die Flaeche. Es wird deshalb an den SEITEN beschnitten
   (object-fit: cover) und mittig gezeigt — die Mitte des Bildes bleibt
   also stehen. Schwarze Raender gibt es nicht.

   Willst du weniger Beschnitt: --head-share kleiner (z.B. 28dvh) —
   dann wird der Banner flacher und es ist mehr Bildbreite zu sehen.
   Willst du gar keinen Beschnitt: einen "-hoch"-Zuschnitt neben das
   Banner legen (siehe README), der fuellt die Flaeche dann passend.

   Das angedockte Mandala sitzt mittig in der Bannerflaeche und ist
   hier grosszuegiger als vorher (--dock-scale .42), weil der Kopf
   jetzt hoch genug ist. Die Klickflaechen sind extra breit gerechnet,
   damit man mit dem Finger sicher trifft.
   ================================================================== */
@media (max-aspect-ratio: 1/1) {
  :root {
    --head-share: 38dvh;
    --head-h:     calc(var(--head-share) + var(--motto-h));
  }
  :root.has-motto { --motto-h: 30px; }

  /* An den Seiten beschneiden statt Raender lassen */
  .b-half img { object-fit: cover; }

  body.docked {
    /* Im Hochformat darf das Menue groesser sein, der Kopf ist hoch
       genug. Mittig sitzt es automatisch (siehe .mandala.docked). */
    --dock-scale: .42;
    /* Grosszuegige Trefferflaechen fuer den Finger */
    --hit-w: 46%;
    --hit-h: 55%;
  }

  /* Labels gegen die Verkleinerung lesbar halten */
  .mandala.docked .m-label {
    font-size: calc(9.5px / var(--dock-scale));
    letter-spacing: .1em;
  }
  .mandala.docked .m-label::after { height: 26px; }
  .mandala.docked .m-label[data-pos="left"]::after,
  .mandala.docked .m-label[data-pos="right"]::after { height: 1px; width: 26px; }

  .band-motto { font-size: 9px; letter-spacing: .26em; }
}

/* Sehr niedrige Fenster — gilt hoch UND quer.
   --footer-h steht hier ABSICHTLICH nicht mehr: es käme sonst kleiner
   heraus als die Rechts-Leiste plus CART-Button hoch sind, und die
   beiden würden den Inhalt verdecken. Der Wert kommt aus :root (74px)
   bzw. aus dem Handy-Block (70px). */
@media (max-height: 520px) {
  :root { --mandala: min(84vh, 70vw); --label-size: 9px; }
}

/* ==================================================================
   NIEDRIGE FENSTER AM RECHNER (breit, aber flach)
   ------------------------------------------------------------------
   Beispiel 1280 x 720: der Banner nimmt seine natürliche Höhe von
   305px ein, für die Bestellspalte bleiben 341px. Hinein müssen aber
   Name, Preis, Preisangabe, Beschreibung, Größen, Kaufen-Knopf und
   Hinweis — gemessen 457px. Es fehlten 116px.

   Vorher fiel das kaum auf, weil .p-info einen EIGENEN Scrollbereich
   hat. Genau das ist die Falle: der Kaufen-Knopf lag unsichtbar darin,
   und ein Scrollbalken mitten in der Spalte findet niemand.

   Deshalb darf hier die SEITE scrollen. Zwei Spalten bleiben — nur die
   feste Höhe fällt weg. Ab 821px Fensterhöhe (normaler Laptop) greift
   das nicht mehr: dort passt alles ohne Scrollen auf einen Schirm.
   ================================================================== */
@media (min-aspect-ratio: 1/1) and (max-height: 820px) {
  html, body { height: auto; overflow-y: auto; }
  body:not(.docked) { height: 100dvh; overflow: hidden; }

  .content { height: auto; }
  .stage   { overflow-y: visible; min-height: 0; }

  .product {
    height: auto;
    /* mindestens der freie Rest des Bildschirms, damit bei kurzen
       Produkttexten unten kein Loch entsteht */
    min-height: calc(100dvh - var(--head-h) - var(--footer-h));
  }
  /* Kein Spalten-Scroll mehr — die Seite übernimmt das. */
  .p-info { overflow: visible; padding-bottom: var(--footer-h); }

  /* DIE FARBAUSWAHL MUSS OHNE SCROLLEN SICHTBAR SEIN.
     Die zwei Thumbnails unter dem Foto sind die Farbwahl des Produkts
     (schwarzes bzw. weisses Teil). Sie sitzen an der Unterkante der
     Fotospalte — und die wurde vorher auf die Höhe der TEXTSPALTE
     gestreckt. Bei 1000x553 landeten sie dadurch auf y 581, also
     unterhalb des Bildschirms: die Farbwahl war unsichtbar, solange
     man nicht scrollte.

     align-self: start + feste Höhe = die Fotospalte endet genau über
     dem Streifen. Das Foto nimmt den Rest, die Thumbnails sitzen
     darunter und sind immer sofort zu sehen. Die Textspalte darf
     weiterhin länger sein, dafür scrollt die Seite. */
  .p-media {
    align-self: start;
    height: calc(100dvh - var(--head-h) - var(--footer-h));
  }
}

/* ==================================================================
   HANDY IM QUERFORMAT (flach UND breit)
   ------------------------------------------------------------------
   Der Problemfall, den es vorher gab: Bei 844 x 390 greift weder der
   Handy-Block (der geht nach BREITE, und 844px ist nicht schmal) noch
   der Hochformat-Block. Es galt also die Rechner-Regel:

     - der Banner nahm über die Bildbreite gerechnet 231 von 390 px,
       also 59% der Höhe ein
     - html/body waren auf 100dvh mit overflow:hidden festgenagelt

   Ergebnis: unter dem Banner blieb ein 159px hoher Streifen, in dem
   Beschreibung, Größen und Kaufen-Knopf steckten, und die Seite ließ
   sich nicht scrollen. Genau das ist mit diesem Block behoben:

     1. Der Kopfbereich wird auf höchstens 44% der Höhe begrenzt.
     2. Die SEITE darf scrollen (nicht mehr nur die rechte Spalte).
     3. Foto und Text stehen untereinander, das Foto wird über seine
        HÖHE begrenzt — die Breite folgt dem Seitenverhältnis, deshalb
        entstehen keine schwarzen Ränder.

   Das Startmenü bleibt wie überall auf genau einem Bildschirm
   (body:not(.docked)).
   ================================================================== */
/* max-width: 950px gehört dazu! Ohne diese Grenze fiel auch ein
   kleines RECHNER-Fenster (z.B. 1000 x 553) in diesen Block und wurde
   einspaltig wie ein Handy dargestellt — die Farbauswahl rutschte
   dadurch unter den Bildschirmrand. Ein Handy im Querformat ist nie
   breiter als etwa 950px. */
@media (max-height: 560px) and (min-aspect-ratio: 1/1) and (max-width: 950px) {
  :root {
    /* Kleineres Wasserzeichen, weniger Mindestluft -> flacher Kopf.
       Bei --dock-scale .22 sitzt das angedockte Menü unterhalb des
       Schriftzugs, ohne ihn zu berühren. */
    --dock-scale: .22;
    --dock-gap:   16px;
    /* 46% statt 44%: bei 44% berührte die Oberkante des angedockten
       Menüs den Schriftzug auf den Pixel genau. */
    --head-cap:   46dvh;
    --logo-w:    130px;
    /* Streifen 56px (32 + 24) plus Luft — hier gilt der Rechner-Button */
    --footer-h:   62px;
  }

  /* Die SEITE scrollt. Ohne das ist der Shop unter dem Banner
     gefangen. Das Startmenü bleibt auf einem Bildschirm. */
  html, body { height: auto; overflow-y: auto; }
  body:not(.docked) { height: 100dvh; overflow: hidden; }

  .content { height: auto; }
  .stage   { overflow-y: visible; min-height: 0; }

  /* An den SEITEN beschneiden statt Ränder lassen. Der Kopf ist hier
     durch --head-cap flacher als das Bild von sich aus wäre; mit
     "contain" blieben links und rechts schwarze Balken stehen. */
  .b-half img { object-fit: cover; }

  /* Untereinander statt nebeneinander: bei 390px Höhe wäre die
     Fotospalte sonst nur rund 135px breit. */
  .product { grid-template-columns: 1fr; height: auto; }
  .p-media { align-items: center; }
  /* Höhe vorgeben, Breite automatisch: das Bild behält sein
     Seitenverhältnis und wird mittig gesetzt — keine Balken. */
  .p-hero {
    flex: 0 0 auto;
    height: 62dvh;
    width: auto;
    max-width: 100%;
  }
  .p-info { overflow: visible; padding: 18px 20px var(--footer-h); }

  /* Trefferflächen fürs Tippen und lesbare Labels trotz .22 */
  body.docked { --hit-w: 44%; --hit-h: 52%; }
  .mandala.docked .m-label {
    font-size: calc(9px / var(--dock-scale));
    letter-spacing: .1em;
  }
  .mandala.docked .m-label::after { height: 22px; }
  .mandala.docked .m-label[data-pos="left"]::after,
  .mandala.docked .m-label[data-pos="right"]::after { height: 1px; width: 22px; }
}

/* Nutzer, die Animationen abgeschaltet haben */
@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}
