/* =========================================================
   EXPERIENCE.CSS — SCROLL JOURNEY (SCENE 01 .. 05)
   ---------------------------------------------------------
   Mobilfunk · Internet · Zubehoer · Reparatur · Termin

   Prinzip:
   - Jede Szene ist eine sticky Fullscreen-Buehne (.story-stage).
   - Der Fortschritt kommt ausschliesslich aus dem Scrollstand.
   - Animiert werden nur transform, opacity und clip-path.
   - Uebergaenge entstehen aus den Polygon-Hotspots des Heros.
   ========================================================= */

:root{
  /* Freihalte-Spalte fuer die beschriftete Fortschrittsleiste (>=1101px) */
  --rail-gutter:clamp(102px,7.6vw,142px);
  /* GEGENSTUECK LINKS: die Kachelleiste (.scene-banner.is-left). Ihre
     rechte Kante ist Abstand + Breite; die 22 px sind die Luft dahinter.
     Beide Zahlen stehen bei .scene-banner — wer sie dort aendert, aendert
     sie HIER mit, sonst laufen Leiste und Text wieder ineinander.
     Unter 1100 px (und bei sehr flachen Schirmen) verschwindet die Leiste,
     dann ist der Streifen 0 — siehe die Media-Query bei .scene-banner. */
  --banner-gutter:calc(clamp(14px,1.8vw,30px) + clamp(56px,8.4vh,124px) + 22px);

  --ink:#06141a;
  --ink-mid:#33474f;
  --ink-soft:#6b7f88;
  --hair:rgba(8,32,42,.10);

  --accent:#12c7e0;
  --accent-deep:#0a8ea5;
  --accent-ink:#05323b;

  /* Basisflaeche aller Szenen.
     Bewusst ueberall identisch: dadurch ist der Uebergang
     zwischen zwei sticky Stages absolut nahtlos. */
  --scene-base:#f8fbfc;

  /* 1 → .8 → .64 (Zuruf Erguen 15.08.: "scrollen bis der naechste bereich
     kommt dauert zulange", danach "Scrollwege noch ein Fünftel kürzer
     machen"). Der Faktor verkuerzt JEDE Szene gleichmaessig — alle
     Animationsfenster und Landepunkte rechnen in ANTEILEN des Fortschritts
     und wandern von selbst mit; nur der Mausradweg wird kuerzer.
     DIE SCHMALEN FENSTER WANDERN MIT (responsive.css .86 → .69, .7 → .56):
     stuenden sie still, waere der Weg auf dem Telefon plötzlich LAENGER
     als am Schreibtisch — die Werte dort sind Abschlaege auf diesen, keine
     eigenen Groessen.
     .64 -> .5 (Zuruf 19.08.: "man muss zuviel scrollen"): GEMESSEN war die
     Seite mit .64 noch 21,4 Bildschirme hoch (Mobilfunk und Internet je
     4,1) - mit .5 sind es rund 17. Die toten Strecken je Szene lagen bei
     hoechstens 10% und nie ueber einem halben Bildschirm; das Problem war
     die LAENGE selbst, nicht Leerlauf an einer Stelle. */
  --space-scale:.5;

  --edge:clamp(26px,4.6vw,96px);
}

/* =========================================================
   1 — GRUNDGERUEST
   ========================================================= */
.story{
  position:relative;
  z-index:1;
  display:block;
}

/* SZENEN-EINRASTEN (Zuruf 19.08.: "ist ein sticky scroll moeglich?"):
   proximity, NICHT mandatory - die Erzaehlung haengt am ScrollFORTSCHRITT,
   ein Zwangs-Einrasten machte jede Zwischenposition (und damit jede
   Animation) unerreichbar. proximity zieht nur, wer NAHE einer
   Szenengrenze stehen bleibt, auf den frischen Szenenanfang - dort steht
   das Bereichs-Intro mit dem grossen Namen, und der Besucher weiss, wo er
   ist. goTo() bleibt unberuehrt: seine Landepunkte liegen MITTEN in den
   Szenen, weit weg von jedem Rastpunkt. Im Tab-Modus (#angebote) rollt
   das Overlay in einem eigenen Kasten - das html-Einrasten greift dort
   nicht. */
html:not(.ang-tab){ scroll-snap-type:y proximity; }
.story-section{ scroll-snap-align:start; }

.story-section{
  position:relative;
  display:block;
  width:100%;
  height:calc(var(--space,240) * var(--space-scale) * var(--app-height) / 100);
}

/* Jede Szene startet genau dort, wo das Pinning der vorherigen endet.
   Ohne diese Ueberlappung entsteht zwischen zwei sticky Buehnen eine
   volle Bildschirmhoehe, in der die alte Buehne heraus- und die neue
   hereinrutscht — also genau die sichtbare Schnittkante, die es hier
   nicht geben darf. Der Uebergang laeuft stattdessen komplett im
   Portal der abgehenden Szene ab. */
.story-section + .story-section{
  margin-top:calc(var(--app-height) * -1);
}

/* ================= ACHT VOLLBILD-SEITEN (html.kurz) =====================
   Zuruf Erguen 19.08.: die Seite auf acht Seiten kuerzen, die lange Fassung
   hinter einen Knopf. In diesem Modus ist JEDE Szene genau ZWEI Bildschirme
   hoch: einer davon ist der Raum, in dem ihre Buehne gepinnt steht, der
   andere wird von der naechsten Szene ueberlappt (die Regel darueber). Damit
   ruecken die Rastpunkte auf genau einen Bildschirm Abstand — acht Szenen,
   acht Seiten, acht Mausrad-Wege.
   GEMESSEN vorher: 15,2 Bildschirme; danach 8.
   Die Szenen behalten ihr `--space` — es entscheidet nur in der langen
   Fassung. Nichts wird geloescht, der Knopf in der Fusszeile schaltet zurueck.

   EINRASTEN HIER MANDATORY, in der langen Fassung proximity: dort haengt die
   Erzaehlung am ScrollFORTSCHRITT und ein Zwangsrasten machte jede
   Zwischenposition unerreichbar. Hier IST die Zwischenposition der Uebergang
   zwischen zwei Seiten — ein Rastpunkt je Seite ist genau das Gewollte. */
html.kurz .story-section{
  height:calc(var(--app-height) * 2);
}
html.kurz:not(.ang-tab){ scroll-snap-type:y mandatory; }

/* DIE LETZTE SEITE BRAUCHT KEINEN WEG ZUR NAECHSTEN.
   Die zweite Bildschirmhoehe jeder Szene ist der Raum, den die FOLGENDE
   ueberlappt — nach der Termin-Szene folgt keine mehr. Mit voller Hoehe
   bliebe hinter ihrem Rastpunkt ein ganzer Bildschirm ohne eigenen
   Rastpunkt stehen: gemessen stand die Seite dort LEER (Fortschritt 1,
   alle Einblendungen vorbei) — und die Fusszeile mit Impressum,
   Datenschutz und dem Weg zur Vollversion war nur in diesem Niemandsland
   zu sehen. Mit einer Bildschirmhoehe faellt Rastpunkt und Scrollende
   zusammen, und der Fortschritt steht dort auf 1: Termin-Knopf UND
   Fusszeile stehen vollstaendig da (gemessen). */
html.kurz .story-section:last-of-type{
  height:var(--app-height);
}

.story-scroll-space{
  position:relative;
  width:100%;
  height:100%;
}

.story-stage{
  position:sticky;
  top:0;
  z-index:var(--stage-z,1);
  width:100%;
  height:var(--app-height);
  overflow:hidden;
  background:var(--scene-base);
  transform:translateZ(0);
}

/* Durch die Ueberlappung der Sections liegt die naechste Buehne
   bereits im Viewport, bevor sie an der Reihe ist. Sichtbar wird
   sie erst, wenn ihre Section den oberen Rand erreicht — also
   genau dann, wenn das Portal der vorherigen Szene fertig
   aufgezogen ist. Beide Frames sind in diesem Moment identisch,
   der Wechsel ist dadurch nicht wahrnehmbar.
   Die Klasse setzt scroll-story.js — als Positivliste, damit die
   Seite ohne JavaScript nicht komplett unsichtbar ist. */
.story-stage.is-dormant{
  visibility:hidden;
}

/* WAEHREND DER FAHRT RUHT DER SCHMUCK (Zuruf Erguen 27.08.2026: "die uebergaenge
   der webseite ruckeln ... der seitenwechsel muss ganz leicht ohne ruckeln gehen").
   Die Seite traegt im Seitenflug laengst die Klasse `blaettert` (scroll-story.js,
   seit 1.649.0) — aber bis jetzt las KEINE CSS-Regel sie. Die Endlos-Animationen
   (Goldglanz, Energiefluss, Pulse, Aurora — 23 Stueck) malten deshalb waehrend der
   Fahrt jeden einzelnen Frame mit, zusaetzlich zum fahrenden Vorhang. Fuer die
   1,15 s des Flugs stehen sie jetzt still: das Auge haengt am Vorhang und sieht
   davon nichts, und jeder gesparte Anstrich kommt dem Seitenwechsel zugute.
   TRANSITIONS bleiben unberuehrt — der Seitenwechsel selbst ist keine
   Keyframe-Animation, sondern der native Scroll der Buehne. Das !important ist
   hier der Riegel-Zweck (dieselbe Bauart wie der transition-Riegel 1.656.0):
   keine der 23 Einzelregeln soll sich vordraengeln koennen. */
html.blaettert *,
html.blaettert *::before,
html.blaettert *::after{
  animation-play-state:paused !important;
}

/* SICHTBARER SEITEN-SLIDE IN DER KURZFASSUNG (Zuruf Erguen 20.08.:
   "bitte einen slide effekt beim übergang der seiten"). Der Slide
   EXISTIERT laengst: in der Kurzfassung bleibt die hereinfahrende
   Buehne sichtbar (der Schlaf-Governor in scroll-story.js weckt sie
   als Flugziel ausdruecklich, kurzZielKey — seit 1.676.0 schlafen
   die uebrigen Buehnen auch in der Kurzfassung) und sie
   zieht wie ein Vorhang von unten ueber die stehende alte Seite.
   Was fehlte, war die sichtbare KANTE — beide Seiten sind hell, und
   eine helle Flaeche, die ueber eine helle Flaeche faehrt, liest sich
   als Ueberblendung statt als Blatt. Der weiche Schatten OBERHALB der
   Buehne macht die Vorderkante des hereinfahrenden Blatts sichtbar;
   im Ruhezustand liegt die Buehnen-Oberkante am Viewport-Rand und der
   Schatten damit AUSSERHALB des Bilds — er kostet in Ruhe nichts und
   erscheint genau waehrend der Fahrt. Nur html.kurz: in der langen
   Fassung baut sich die Szene aus dem Scrollfortschritt auf, dort
   gibt es keine Blattkante. Der Schatten liegt ausserhalb der Box und
   wird vom overflow:hidden der Buehne selbst NICHT geclippt; die
   Section clippt nicht. */
html.kurz .story-stage{
  box-shadow:0 -22px 48px rgba(8,14,24,.35);
}

/* Der Hero bekommt keine eigene Grundfarbe untergeschoben. */
#stage-hero{
  background:#fff;
}

/* =========================================================
   2 — ANIMATIONSSYSTEM
   ---------------------------------------------------------
   Die Engine schreibt pro Element drei Zahlen:
     --ri  Eintritt   0 .. 1
     --ro  Austritt   0 .. 1
     --r   sichtbar   ri * (1 - ro)
   CSS entscheidet, was daraus wird.
   ========================================================= */
.anim{
  --ri:0;
  --ro:0;
  --r:0;
  --d:56px;
  opacity:var(--r);
}

.anim-rise{
  transform:translate3d(0,calc((1 - var(--ri)) * var(--d) + var(--ro) * var(--d) * -.7),0);
}
/* Die Varianten anim-fall/-in-left/-in-right/-depth/-plain baute nie
   eine Zeile JS (ueberall "anim anim-rise" bzw. "anim-line") — ENTFERNT.
   Weg zurueck: Git vor dem Aufraeumen (1.655.0). */

/* Zeichenweises Aufziehen fuer Headline-Blocks */
.anim-line{
  display:block;
  overflow:hidden;
  /* KOPFRAUM FUER UMLAUTE (Zuruf Erguen 20.08.: "das Ö bei Zubehör ist
     oben abgeschnitten"): die Zeilenhoehe der Headline (~.94) ist knapper
     als die Punkte ueber dem Versal-Ö — overflow:hidden schnitt sie ab.
     Das Polster oeffnet das Sichtfenster nach oben (geclippt wird an der
     PADDING-Box), der negative Rand nimmt den Layoutversatz zurueck. */
  padding-top:.14em;
  margin-top:-.14em;
}
.anim-line > span{
  display:block;
  /* 120% statt 105%: die versteckte Zeile faehrt tief genug, dass ihre
     Umlautpunkte nicht oben ins geoeffnete Sichtfenster ragen. */
  transform:translate3d(0,calc((1 - var(--ri)) * 120% + var(--ro) * -60%),0);
}

/* =========================================================
   3 — TYPOGRAFIE DER SZENEN
   ========================================================= */
.scene-content{
  position:absolute;
  inset:0;
  z-index:20;
  pointer-events:none;
}
.scene-content a,
.scene-content button{
  pointer-events:auto;
}

.scene-eyebrow{
  margin:0 0 clamp(14px,1.5vw,22px);
  color:var(--accent-deep);
  font-size:clamp(10px,.78vw,13px);
  font-weight:900;
  letter-spacing:.34em;
  text-transform:uppercase;
}
.scene-eyebrow::before{
  content:"";
  display:inline-block;
  width:clamp(22px,2.4vw,44px);
  height:1px;
  margin-right:12px;
  vertical-align:middle;
  background:currentColor;
  opacity:.55;
}

.scene-headline{
  margin:0;
  color:var(--ink);
  font-size:clamp(32px,4.6vw,84px);
  line-height:.95;
  font-weight:900;
  letter-spacing:-.045em;
  text-transform:uppercase;
  /* Kein Zeilen-/Wortumbruch in Display-Typo: fitHeadlines()
     in experience.js skaliert die Schrift stattdessen so,
     dass jede Zeile exakt in den Container passt. */
  white-space:nowrap;
}
.scene-headline em{
  font-style:normal;
  color:var(--accent-deep);
}

.scene-sub{
  margin:clamp(18px,2vw,30px) 0 0;
  max-width:34ch;
  color:var(--ink-mid);
  font-size:clamp(14px,1.05vw,19px);
  line-height:1.5;
  font-weight:500;
}

/* Sehr grosse Einzelaussagen */
.scene-statement{
  position:absolute;
  margin:0;
  color:var(--ink);
  font-size:clamp(30px,4.6vw,82px);
  line-height:.9;
  font-weight:900;
  letter-spacing:-.05em;
  text-transform:uppercase;
  white-space:nowrap;
}
.scene-statement{
  text-shadow:
    0 0 12px rgba(255,255,255,.85),
    0 0 32px rgba(255,255,255,.55);
}
.scene-statement small{
  display:block;
  margin-top:.55em;
  color:var(--ink-soft);
  font-size:clamp(11px,.8vw,14px);
  font-weight:700;
  letter-spacing:.22em;
  text-transform:uppercase;
}

/* =========================================================
   4 — CTAs
   ========================================================= */
.scene-actions{
  display:flex;
  flex-wrap:wrap;
  gap:clamp(10px,1vw,16px);
}

.scene-cta{
  position:relative;
  isolation:isolate;
  display:inline-flex;
  align-items:center;
  gap:12px;
  height:clamp(48px,3.3vw,58px);
  padding:0 clamp(22px,1.9vw,34px);
  border:1px solid transparent;
  border-radius:999px;
  background:var(--ink);
  color:#fff;
  font:900 clamp(11px,.82vw,13px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
  text-decoration:none;
  cursor:pointer;
  transition:transform .3s cubic-bezier(.2,.8,.2,1),
             background .3s ease,
             color .3s ease,
             border-color .3s ease,
             box-shadow .3s ease;
}
.scene-cta::after{
  content:"";
  width:16px;
  height:1px;
  background:currentColor;
  opacity:.55;
  transition:width .3s cubic-bezier(.2,.8,.2,1);
}
.scene-cta:hover,
.scene-cta:focus-visible{
  outline:none;
  transform:translateY(-2px);
  background:var(--accent-ink);
  box-shadow:0 14px 34px rgba(9,60,72,.18);
}
.scene-cta:hover::after,
.scene-cta:focus-visible::after{
  width:26px;
}
.scene-cta:focus-visible{
  border-color:var(--accent);
  box-shadow:0 0 0 3px rgba(18,199,224,.28);
}

/* ---------------------------------------------------------
   Ruhiger CTA-Puls in den Story-Szenen (nicht im Abschluss —
   dort ist der andockende Gold-Button der Star).
   Primaerbutton: weicher, auslaufender Ring.
   Ghost-Button: atmender Rand, versetzt getaktet.
   Hover pausiert beides.
   --------------------------------------------------------- */
@keyframes ctaRing{
  0%{opacity:.75;transform:scale(.97)}
  70%,100%{opacity:0;transform:scale(1.34)}
}
@keyframes ctaShadowPulse{
  0%,100%{box-shadow:0 0 0 0 rgba(18,199,224,0)}
  45%{box-shadow:0 0 0 8px rgba(18,199,224,.16)}
}
@keyframes ctaBreathe{
  0%,100%{border-color:var(--hair);box-shadow:none}
  50%{border-color:rgba(18,199,224,.7);
      box-shadow:0 0 0 5px rgba(18,199,224,.12)}
}

/* Primaerbutton: pulsierender Schatten + auslaufender Ring */
.scene-actions .scene-cta:not(.is-ghost){
  animation:ctaShadowPulse 2.6s ease-in-out infinite;
}
.scene-actions .scene-cta:not(.is-ghost)::before{
  content:"";
  position:absolute;
  z-index:-1;
  inset:-3px;
  border-radius:999px;
  border:2px solid rgba(18,199,224,.75);
  opacity:0;
  pointer-events:none;
  animation:ctaRing 2.6s ease-out infinite;
}
.scene-actions .scene-cta.is-ghost{
  animation:ctaBreathe 2.6s ease-in-out 1.3s infinite;
}
.scene-actions .scene-cta:not(.is-ghost):hover,
.scene-actions .scene-cta:not(.is-ghost):focus-visible{
  animation:none;
}
.scene-actions .scene-cta:hover::before,
.scene-actions .scene-cta:focus-visible::before{
  animation:none;
  opacity:0;
}
.scene-actions .scene-cta.is-ghost:hover,
.scene-actions .scene-cta.is-ghost:focus-visible{
  animation:none;
}
@media (prefers-reduced-motion:reduce){
  .scene-actions .scene-cta::before,
  .scene-actions .scene-cta.is-ghost{
    animation:none !important;
  }
}

.scene-cta.is-ghost{
  background:transparent;
  color:var(--ink);
  border-color:var(--hair);
}
.scene-cta.is-ghost:hover,
.scene-cta.is-ghost:focus-visible{
  background:rgba(18,199,224,.08);
  border-color:rgba(18,199,224,.5);
  color:var(--accent-ink);
  box-shadow:0 12px 28px rgba(12,110,130,.10);
}

/* =========================================================
   5 — ATMOSPHAERE
   ---------------------------------------------------------
   Die Grundflaeche ist in allen Szenen exakt gleich.
   Die Stimmung entsteht ueber weiche, scrollgesteuerte
   Farbfelder darueber — die an den Szenengrenzen bei 0 sind.
   ========================================================= */
.scene-atmos{
  position:absolute;
  inset:0;
  z-index:1;
  pointer-events:none;
  background:var(--scene-base);
}

.atmos-glow{
  position:absolute;
  border-radius:50%;
  opacity:var(--r,0);
  filter:blur(var(--blur,60px));
}

.atmos-grid{
  position:absolute;
  inset:-10%;
  opacity:calc(var(--r,0) * .5);
  background-image:
    linear-gradient(to right,rgba(9,60,72,.05) 1px,transparent 1px),
    linear-gradient(to bottom,rgba(9,60,72,.05) 1px,transparent 1px);
  background-size:clamp(56px,5vw,92px) clamp(56px,5vw,92px);
  mask-image:radial-gradient(ellipse at 50% 50%,#000 15%,transparent 68%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 50%,#000 15%,transparent 68%);
}

/* =========================================================
   6 — PORTAL / POLYGON-UEBERGANG
   ---------------------------------------------------------
   Liegt am Ende der abgehenden Szene, oeffnet die naechste.
   Die Startpolygone sind exakt die Hero-Hotspots.
   ========================================================= */
.scene-portal{
  position:absolute;
  inset:0;
  z-index:60;
  pointer-events:none;
  opacity:var(--portal-alpha,0);
  clip-path:polygon(var(--portal-poly,0% 0%,100% 0%,100% 100%,0% 100%));
  -webkit-clip-path:polygon(var(--portal-poly,0% 0%,100% 0%,100% 100%,0% 100%));
  will-change:clip-path,opacity;
}

/* Bei Scrollposition 0 darf das Portal nichts kosten und nichts
   verdecken — der Hero bleibt inklusive Hotspot-Hover unberuehrt. */
.scene-portal.is-idle{
  visibility:hidden;
}

/* Der Ausschnitt des Shops — exakt die Geometrie von .hero-visual */
.portal-shot{
  position:absolute;
  left:0;
  right:0;
  top:0;
  bottom:var(--benefit-h);
  overflow:hidden;
  background:#fff;
  opacity:var(--shot-alpha,1);
}

.portal-image{
  position:absolute;
  left:0;
  top:0;
  width:100%;
  height:117.2%;
  max-width:none;
  display:block;
  object-fit:fill;
  object-position:center top;
  user-select:none;
  -webkit-user-drag:none;
  /* Faktor 1.003 = Basis-Skalierung des Hero-Bilds (Parallax-
     Reserve). Ohne ihn saesse der Portal-Inhalt beim Einblenden
     minimal neben dem Hero. */
  transform:translate3d(var(--p-img-x,0px),var(--p-img-y,0px),0)
            scale(calc(var(--portal-dolly,1) * 1.003));
  transform-origin:var(--portal-origin,50% 50%);
}

/* Streifen unter dem Shopbild: entspricht der Vorteilsleiste */
.portal-skirt{
  position:absolute;
  left:0;
  right:0;
  bottom:0;
  height:var(--benefit-h);
  background:#fff;
  border-top:1px solid rgba(8,32,42,.08);
  opacity:var(--shot-alpha,1);
}

/* Die neue Welt blendet innerhalb des Portals auf */
.portal-world{
  position:absolute;
  inset:0;
  background:var(--scene-base);
  opacity:var(--world-alpha,0);
}

/* Tuerkise Kontur der aktiven Zone */
.portal-edge{
  position:absolute;
  inset:0;
  opacity:var(--edge-alpha,0);
  box-shadow:
    inset 0 0 0 2px rgba(var(--zone-rgb,18,203,226),.85),
    inset 0 0 42px rgba(var(--zone-rgb,18,203,226),.20);
  background:linear-gradient(135deg,
    rgba(var(--zone-rgb,18,203,226),.10),
    rgba(var(--zone-rgb,18,203,226),.02));
}

/* Die Umgebung tritt zurueck, waehrend sich die Zone oeffnet.
   Sie geht fast vollstaendig in die Grundflaeche der naechsten
   Szene ueber — dadurch bleibt die Polygonkante des Portals eine
   weiche Formkante und wird nicht zur harten Bildkante. */
.scene-recede{
  position:absolute;
  inset:0;
  z-index:55;
  pointer-events:none;
  opacity:var(--recede,0);
  background:var(--scene-base);
}

/* =========================================================
   7 — VERBINDUNGSLINIE ZWISCHEN DEN SZENEN
   ========================================================= */
.scene-link{
  position:absolute;
  inset:0;
  z-index:58;
  width:100%;
  height:100%;
  pointer-events:none;
  overflow:visible;
  opacity:var(--link-alpha,0);
}
.scene-link .link-soft{
  fill:none;
  stroke:rgba(23,205,229,.16);
  stroke-width:7;
  stroke-linecap:round;
  stroke-linejoin:round;
  vector-effect:non-scaling-stroke;
  filter:blur(3px);
}
.scene-link .link-base{
  fill:none;
  stroke:rgba(31,213,236,.42);
  stroke-width:2;
  stroke-linecap:round;
  stroke-linejoin:round;
  vector-effect:non-scaling-stroke;
  filter:drop-shadow(0 0 4px rgba(31,213,236,.4));
}
.scene-link .link-flow{
  fill:none;
  stroke:rgba(231,254,255,.98);
  stroke-width:2.6;
  stroke-linecap:round;
  stroke-linejoin:round;
  vector-effect:non-scaling-stroke;
  filter:
    drop-shadow(0 0 4px rgba(73,236,252,.95))
    drop-shadow(0 0 10px rgba(31,213,236,.45));
}
.scene-link .link-node{
  fill:#efffff;
  stroke:#3ee2f5;
  stroke-width:1.7;
  vector-effect:non-scaling-stroke;
  filter:drop-shadow(0 0 5px rgba(62,226,245,.8));
  opacity:calc(var(--draw,0) * var(--draw,0));
}

/* Die Pfade tragen pathLength="1" — dadurch laesst sich der
   Linienverlauf direkt aus dem Scrollfortschritt zeichnen. */
.scene-link .link-soft,
.scene-link .link-base,
.scene-link .link-flow{
  stroke-dasharray:1 1;
  stroke-dashoffset:calc(1 - var(--draw,0));
}

/* =========================================================
   8 — SZENE 01 · MOBILFUNK
   ========================================================= */
.mob-copy{
  position:absolute;
  left:var(--edge);
  top:50%;
  transform:translateY(-50%);
  /* DIE SPALTE ENDET VOR DEM GERAET (1.700.0, Befund aus dem Bild:
     "DEIN SMARTPHONE." war als "DEIN SMARTPHON" zu lesen, das E lag
     hinter dem Telefon). GEMESSEN bei 1600x900: die Spalte war 700 px
     breit und endete bei x 774, die Geraetebuehne beginnt bei x 648 —
     126 px Ueberlappung; bei 1280x800 waren es 38 px. Die Schrift folgt
     der Spalte von selbst (fitHeadlines skaliert jede Zeile auf die
     Containerbreite), es braucht also keine zweite Schriftregel.
     34vw laesst bei 1600 rund 30 px Luft zum Geraet, bei 1280 rund 47.
     Die Anbieter-Chips darunter sind mitgewandert (siehe dort) — sie
     rechneten mit den alten 700 px und lagen sonst selbst unter dem
     Telefon. */
  max-width:min(34vw,560px);
}
.mob-copy > *{
  pointer-events:auto;
}

/* ANBIETERLOGOS AUF DER MOBILFUNK-LANDESEITE (Zuruf Erguen 20.08.: "hier
   fehlen die anbieter logos"). Die Reihe baut experience.js NUR in der
   Kurzfassung (kurzModus) — hier steht allein die Gestalt: kleine weisse
   Chips unter der Unterzeile, Logos eingepasst statt beschnitten.
   Die 1.458.0-Regel gilt: ohne diese Regeln truegen die Chips nur ihren
   NAMEN, der Browser malte nackte Bilder in Originalgroesse. */
.mob-anbieter{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin-top:clamp(14px,2vh,22px);
}
.mob-anbieter-chip{
  display:grid;
  place-items:center;
  /* GROESSER (Zuruf Erguen 20.08.: "logos und kacheln grösser") — rund ein
     Viertel mehr in beiden Richtungen. NACHGEZOGEN 1.700.0: die Spalte ist
     jetzt 560 statt 700 px breit (sie endet vor dem Geraet) — sechs Chips
     brauchen mit diesen Massen 6x84 + 5x8 = 544 px und passen weiter in
     EINE Reihe; wird es enger, bricht sie um wie bisher. */
  width:clamp(66px,5.6vw,84px);
  /* Die Kachelhoehe steht als eigene Groesse da, weil das Logo darunter
     mit ihr rechnet — siehe die Regel .mob-anbieter-chip img. */
  --anb-h:clamp(42px,3.7vw,55px);
  height:var(--anb-h);
  border-radius:14px;
  background:#fff;
  border:1px solid rgba(9,44,56,.10);
  box-shadow:0 6px 16px rgba(9,30,44,.08);
}
.mob-anbieter-chip img{
  /* PASSEND IN DIE KACHEL (Zuruf Erguen 20.08.: "die logos passen nicht
     ganz in die kacheln"): 78/64 liess breite Wortmarken bis an den Rand
     laufen — mehr Luft rundum. Mit der groesseren Kachel (Zuruf desselben
     Tages: "logos und kacheln grösser") waechst das Logo ohnehin um ein
     Viertel mit; 70/58 gibt ihm zusaetzlich etwas mehr Flaeche, ohne die
     Luft aufzubrauchen — gemessen bleiben an der breitesten Wortmarke
     (congstar) je Seite noch rund 15 px frei.

     DIE HOEHE RECHNET IN PIXELN, NICHT IN PROZENT (gemessener Befund zum
     Zuruf Erguen 20.08. "o2 und 1&1 etwas kleiner und etwas hoeher in der
     kachel"): `max-height:58%` blieb bei den drei nahezu QUADRATISCHEN
     Zeichen (Vodafone, o2, 1&1) wirkungslos — der Browser loest eine
     Prozenthoehe an einem mittig gesetzten Rasterkind nicht auf, wenn die
     Zeilenhoehe fuer ihn unbestimmt ist. Gemessen war o2 dadurch 39,2 px
     hoch statt 30,7 und sass zudem 7 px zu TIEF (die Kachel richtete es
     nicht mehr mittig aus: oben 15, unten 1). Die flachen Wortmarken hing
     ohnehin an der Breite und blieben richtig — deshalb fiel es nur an
     diesen dreien auf. `calc(var(--anb-h) * .56)` ist eine feste Laenge und
     loest immer auf; .56 der Aussenhoehe entspricht den bisherigen 58 % der
     Innenhoehe (55 - 2 px Rand), die fuenf uebrigen Zeichen bleiben damit
     auf den Bildpunkt, wo sie waren. */
  max-width:70%;
  max-height:calc(var(--anb-h) * .56);
  object-fit:contain;
}
/* EIN QUADRATISCHES ZEICHEN WIRKT BEI GLEICHER HOEHE GROESSER als eine
   flache Wortmarke: o2 und 1&1 fuellen ihre Bilddatei fast bis an den Rand,
   Telekom und congstar tragen einen breiten, flachen Schriftzug. Bei
   gleicher Kastenhoehe stand die o2-Tinte 28 px hoch neben 24 px Telekom.
   Beide bekommen deshalb etwas weniger Hoehe — gemessen liegt ihre Tinte
   danach auf demselben Mass wie die der Nachbarn. */
.mob-anbieter-chip.anb-o2 img,
.mob-anbieter-chip.anb-eins-und-eins img{
  max-height:calc(var(--anb-h) * .50);
}
.mob-anbieter-chip span{
  font-weight:800;
  font-size:11px;
  color:#0d1b2a;
}

.mob-actions{
  position:absolute;
  left:var(--edge);
  bottom:clamp(96px,11vh,150px);
}
/* MITTIG UNTER DEM ROUTER (Zuruf Erguen 15.08.: "das beratung starten
   button mittig unter den router"). Der Router steht mittig in der Buehne;
   in der linken Ecke stand der Knopf weit weg von dem, worauf er sich
   bezieht. Die Mitte kommt aus der Buehne selbst (50 % + Ruecknahme der
   eigenen Breite), nicht aus einer geratenen Zahl. */
/* ZURUECK IN DIE LINKE ECKE (19.08.): die Mitte gehoert seither dem
   zentrierten "Unsere aktuellen Angebote"-Knopf, und seit dem Umbau der
   Szene (1.639.0, Angebot mittig) lag der mittige Geist-Knopf zudem auf
   der ANGEBOTSKARTE (gemessen: Karte bis ~742, Knopf ab 712). Die
   1.632er-Zentrierung galt dem Router, der dort nicht mehr steht —
   .net-actions erbt jetzt schlicht die .mob-actions-Ecke; die Klasse
   bleibt als Anker fuer die flache Media-Query in responsive.css. */
.net-actions{}
/* REPARATUR: dieselbe Mitte und derselbe Abstand zum Scroll-Hinweis wie
   .net-actions (Zuruf Erguen 19.08.: "die beiden button sollten mittig
   sofort erscheinen wenn man oben auf reparatur klickt"). Eine eigene
   Klasse statt einer zweiten .mob-actions-Regel: die linke Ecke bleibt
   fuer die Mobilfunk-Szene die richtige. */
.rep-actions{
  left:50%;
  transform:translateX(-50%);
  bottom:clamp(112px,15vh,182px);
}
.rep-actions .scene-actions{ justify-content:center }

/* --- 2.5D Geraet ------------------------------------------------ */
.device-stage{
  position:absolute;
  left:50%;
  top:50%;
  width:clamp(210px,19vw,330px);
  aspect-ratio:1 / 2.06;
  transform:translate(-50%,-50%);
  perspective:1400px;
  pointer-events:none;
}

.device{
  position:relative;
  width:100%;
  height:100%;
  transform-style:preserve-3d;
  opacity:var(--r,0);
  transform:
    translate3d(
      calc((1 - var(--ri,0)) * 16vw + var(--mx,0) * 10px),
      calc((1 - var(--ri,0)) * 30vh + var(--my,0) * 8px),
      0)
    rotateY(calc(-9deg + var(--ri,0) * 5deg + var(--mx,0) * 3.2deg))
    rotateX(calc(var(--my,0) * -2.4deg))
    scale(calc(.84 + .16 * var(--ri,0) - .2 * var(--ro,0)));
  will-change:transform,opacity;
}

.device-body{
  position:absolute;
  inset:0;
  border-radius:15%/7.3%;
  background:
    linear-gradient(148deg,#2b343c 0%,#0e1519 26%,#050809 62%,#1d252b 100%);
  box-shadow:
    0 0 0 1px rgba(255,255,255,.10),
    0 2px 1px rgba(255,255,255,.14) inset,
    0 42px 70px rgba(8,38,48,.24),
    0 12px 26px rgba(8,38,48,.16);
}

.device-screen{
  position:absolute;
  inset:2.4% 2.2%;
  border-radius:13.4%/6.4%;
  overflow:hidden;
  background:
    radial-gradient(circle at 50% 22%,rgba(24,215,240,.34),transparent 46%),
    linear-gradient(168deg,#04222b 0%,#06333f 46%,#031820 100%);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.07);
}

.device-notch{
  position:absolute;
  z-index:3;
  left:50%;
  top:1.6%;
  width:30%;
  height:2.4%;
  transform:translateX(-50%);
  border-radius:999px;
  background:#04080a;
}

.device-ui{
  position:absolute;
  inset:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:6%;
  color:#eafeff;
  text-align:center;
}
.device-ui strong{
  font-size:clamp(26px,2.6vw,46px);
  font-weight:900;
  letter-spacing:-.05em;
  line-height:1;
  text-shadow:0 0 26px rgba(30,214,240,.5);
}
.device-ui span{
  font-size:clamp(8px,.62vw,11px);
  font-weight:800;
  letter-spacing:.26em;
  text-transform:uppercase;
  opacity:.72;
}

.device-bars{
  display:flex;
  align-items:flex-end;
  gap:14%;
  width:38%;
  height:9%;
}
.device-bars i{
  flex:1;
  border-radius:2px;
  background:linear-gradient(180deg,#7ff0ff,#17c2df);
  box-shadow:0 0 10px rgba(35,208,235,.55);
}
.device-bars i:nth-child(1){height:38%}
.device-bars i:nth-child(2){height:58%}
.device-bars i:nth-child(3){height:78%}
.device-bars i:nth-child(4){height:100%}

.device-glare{
  position:absolute;
  z-index:4;
  left:-28%;
  top:-32%;
  width:78%;
  height:170%;
  pointer-events:none;
  transform:rotate(19deg) translateX(calc(var(--mx,0) * 12px));
  background:linear-gradient(
    90deg,
    transparent,
    rgba(255,255,255,.05),
    rgba(255,255,255,.13),
    rgba(255,255,255,.03),
    transparent);
  mix-blend-mode:screen;
}

.device-shadow{
  position:absolute;
  left:50%;
  bottom:-9%;
  width:74%;
  height:5%;
  transform:translateX(-50%);
  border-radius:50%;
  background:radial-gradient(ellipse,rgba(8,42,54,.30),transparent 68%);
  filter:blur(9px);
  opacity:calc(var(--r,0) * .9);
}

/* --- Angebot des Monats (rechts, vor der Providerreihe) ----------
   Zuruf Erguen 14.08.: "leerer platz rechts ein super angebot des
   monats". Die Karte steht an DERSELBEN rechten Kante wie die
   Providerreihe und weicht wie sie dem --rail-gutter aus, damit sie
   nicht unter den Bereichsnamen der Fortschrittsleiste liegt.
   Sie erscheint frueh und geht wieder, bevor die Providerreihe
   einschwenkt — beide teilen sich denselben Platz. */
.mob-angebot{
  position:absolute;
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:50%;
  width:clamp(272px,23vw,368px);
  /* DER HOVER-ZOOM IST ENTFALLEN (Zuruf Erguen 20.08.: "kein vergrössern
     der kachel bei mouse over mehr") — das transform traegt nur noch die
     LAGE. Rueckmeldung beim Ueberfahren geben Schatten und Randfarbe. */
  transform:translateY(-50%);
  transform-origin:right center;
  display:flex;
  flex-direction:column;
  gap:10px;
  padding:clamp(18px,1.6vw,26px);
  border:1px solid rgba(11,58,72,.14);
  border-radius:20px;
  background:rgba(255,255,255,.94);
  box-shadow:0 18px 48px rgba(8,38,48,.14);
  opacity:var(--r,0);
  pointer-events:auto;
  backdrop-filter:blur(6px);
  transition:box-shadow .28s ease, border-color .28s ease,
             transform .3s cubic-bezier(.2,.8,.2,1);
}
/* KEIN VERGROESSERN MEHR BEIM UEBERFAHREN (Zuruf Erguen 20.08.: "kein
   vergrössern der kachel bei mouse over mehr" — die Kacheln wachsen an
   KEINEM Ort mehr, auch nicht auf der Shop-Seite; die 15.08.-Regel
   "die ganze Kachel waechst" und die 19.08.-Ausnahme "im shop können die
   kachel aber so bleiben" sind damit beide ueberholt). Rueckmeldung
   geben Schatten und Randfarbe — die veraendern keine Flaeche und
   koennen nichts verdecken.
   `:focus-visible` STATT `:focus-within` (Zuruf Erguen 15.08.: ein
   MAUSKLICK auf den Warenkorb-Knopf setzte den Fokus, und die Kachel
   klebte hervorgehoben fest); `:has(:focus-visible)` gehoert dazu, weil
   der Fokus auf einem KIND liegen kann. */
.mob-angebot:hover,
.mob-angebot:focus-visible,
.mob-angebot:has(:focus-visible){
  box-shadow:0 26px 60px rgba(8,38,48,.22);
  border-color:rgba(18,199,224,.5);
}
.mang-badge{
  align-self:flex-start;
  padding:5px 12px;
  border-radius:999px;
  background:linear-gradient(140deg,#e6bc50,#c99a2e);
  color:#231903;
  font:900 clamp(9px,.62vw,10.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
}
.mang-bild{
  width:100%;
  height:auto;
  border-radius:12px;
  position:relative;
  z-index:1;
  transform-origin:top right;
  transition:transform .38s cubic-bezier(.2,.8,.2,1), box-shadow .38s ease;
}
/* DAS BILD WIRD NIE BESCHNITTEN — UND DIE KNOEPFE SIND OHNE SCROLLEN DA
   (zwei Zurufe Erguen 23.08.: "das bild in der kachel darf nicht
   schrumpfen und abgeschnitten werden", direkt danach am Live-Stand:
   "so sind die button ohne scrollen nicht sichtbar" — beides zusammen
   passt bei einem 2:3-Plakat in voller Kartenbreite nicht auf einen
   1080er-Schirm). Die Aufloesung: das Bild bleibt IMMER vollstaendig
   (object-fit:contain, nie mehr cover wie bis 1.690.0), gibt aber in der
   GROESSE nach — es weicht im Massstab, nie im Ausschnitt. width:auto +
   align-self:center lassen es beim Stauchen sein Seitenverhaeltnis
   halten und mittig stehen. Der Innen-Scroll der Karte (.mang-roll,
   Lehre 1.643.0: Knoepfe muessen erreichbar bleiben) bleibt NUR als
   Sicherheitsnetz fuer Extremfaelle — im Normalfall rollt nichts, weil
   das Bild vorher nachgibt. */
.mob-angebot{
  max-height:calc(var(--app-height, 100vh) - 170px);
}
.mang-roll{
  display:flex;
  flex-direction:column;
  gap:10px;
  min-height:0;
  overflow-y:auto;
  scrollbar-width:thin;
}
.mob-angebot .mang-bild{
  flex:0 1 auto;
  min-height:0;
  width:auto;
  max-width:100%;
  align-self:center;
  object-fit:contain;
}
/* Der Aufklapp-Weg zu den uebrigen Leistungen: ein stiller Textknopf in
   Petrol — er oeffnet DASSELBE Leistungs-Fenster wie der Klick auf die
   Karte. Kein Rahmenknopf: er ist Teil der Liste, keine Handlung der
   Karte (die Hausform-Knoepfe darunter bleiben die Handlungen). */
.mang-listemehr{
  align-self:flex-start;
  margin:-2px 0 0;
  padding:2px 0 2px 18px;
  border:0;
  background:none;
  color:#0e7c8f;
  font:800 clamp(11.5px,.82vw,13px)/1.2 Inter,system-ui,sans-serif;
  cursor:pointer;
  text-align:left;
}
.mang-listemehr:hover{ text-decoration:underline }
/* DER BILDZOOM IST ENTFALLEN (15.08.). Er kam aus dem Zuruf "bei den
   monatsangeboten soll bei maus over auch das volle bild nach vorne
   kommen" und wuchs auf das Anderthalbfache ueber die eigene Kachel
   hinaus — genau darueber kam der naechste Befund: "da das bild den rest
   überlappt also die button im menü". Seit 20.08. waechst auch die Kachel
   selbst nicht mehr (Zuruf "kein vergrössern der kachel bei mouse over
   mehr"); das Bild bleibt in ihrem Rahmen. */
/* Der z-index-Vorrang beim Ueberfahren bleibt: der staerkere Schatten
   soll ueber den Szenen-Nachbarn liegen, nicht unter ihnen. */
.mob-angebot:hover{ z-index:30 }
/* DIE z-index-NOTLOESUNG IST MIT DEM BILDZOOM ENTFALLEN (15.08.). Sie
   rettete Preis und Knoepfe vor dem gewachsenen Bild (Zuruf "durch den
   maus over effekt ... kann ich in den warenkorb nicht anklicken") — der
   TITEL blieb dabei darunter und verschwand. Seit die ganze Kachel
   waechst, gibt es nichts mehr zu retten: alles darin behaelt seine Lage
   zueinander. Kein toter Codeweg. */
@media (prefers-reduced-motion:reduce){
  .mang-bild{ transition:none }
}
.mang-title{
  margin:2px 0 0;
  color:#0b2f3a;
  font:900 clamp(21px,1.7vw,27px)/1.05 Inter,system-ui,sans-serif;
  letter-spacing:-.01em;
}
.mang-sub{
  margin:0;
  color:#5a6f78;
  font:600 clamp(12px,.85vw,13.5px)/1.4 Inter,system-ui,sans-serif;
}
.mang-preis{
  display:flex;
  align-items:baseline;
  gap:4px;
  margin:4px 0 0;
  color:#0b2f3a;
}
.mang-preis strong{
  font:900 clamp(34px,3vw,46px)/1 Inter,system-ui,sans-serif;
  letter-spacing:-.02em;
}
.mang-wa{
  font:900 clamp(18px,1.4vw,23px)/1 Inter,system-ui,sans-serif;
}
.mang-note{
  margin-left:4px;
  color:#5a6f78;
  font:700 clamp(11px,.8vw,12.5px)/1 Inter,system-ui,sans-serif;
}
.mang-tarif{
  margin:0;
  color:#0e7c8f;
  font:800 clamp(11px,.8vw,12.5px)/1.3 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
}
.mang-liste{
  margin:6px 0 0;
  padding:0;
  list-style:none;
  display:grid;
  gap:6px;
}
.mang-liste li{
  position:relative;
  padding-left:18px;
  color:#31454d;
  font:600 clamp(11.5px,.82vw,13px)/1.35 Inter,system-ui,sans-serif;
}
/* Haken als CSS-Zeichen — kein Emoji (Hausregel). */
.mang-liste li::before{
  content:"";
  position:absolute;
  left:2px;
  top:.34em;
  width:8px;
  height:4px;
  border-left:2px solid #12c7e0;
  border-bottom:2px solid #12c7e0;
  transform:rotate(-45deg);
}
/* Knopfzeile am Angebot des Monats: Warenkorb ueber der Beratung.
   In der schmalen Karte untereinander — nebeneinander blieben von zwei
   Knoepfen je rund 130 px, und beide Beschriftungen brechen dort um. */
.mang-akt{
  margin-top:8px;
  display:flex;
  flex-direction:column;
  gap:8px;
}
.mang-akt .mang-cta{ margin-top:0 }
.mang-cta{
  margin-top:8px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  height:clamp(40px,2.9vw,46px);
  border-radius:999px;
  border:1px solid #a8801f;
  background:linear-gradient(140deg,#e6bc50,#c99a2e);
  color:#231903;
  font:900 clamp(10px,.74vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em;
  text-transform:uppercase;
  text-decoration:none;
  box-shadow:0 12px 28px rgba(120,86,16,.26);
  transition:transform .3s cubic-bezier(.2,.8,.2,1), box-shadow .3s ease;
}
.mang-cta:hover{
  transform:translateY(-2px);
  box-shadow:0 16px 36px rgba(120,86,16,.34);
}
/* Zubehoer: die rechte Kante ist dort zu keiner Zeit frei (gemessen) —
   diese Karte steht unten mittig und quer, damit sie flach bleibt. */
.mob-angebot.ist-unten{
  right:auto;
  left:50%;
  top:auto;
  /* ueber dem Scroll-Hinweis, der mittig unten steht */
  bottom:clamp(150px,19vh,230px);
  width:min(78vw,760px);
  transform:translateX(-50%);
  transform-origin:center bottom;
}
/* Die Zeilen-Auslegung wohnt seit 1.691.0 am ROLL-Container — die Karte
   selbst traegt nur noch Lage und Rahmen (ihr einziges Flusskind ist
   .mang-roll). */
.mob-angebot.ist-unten .mang-roll{
  flex-direction:row;
  flex-wrap:wrap;
  align-items:center;
  gap:8px 18px;
}
.mob-angebot.ist-unten .mang-badge{ order:1; flex:0 0 auto }
.mob-angebot.ist-unten .mang-title{ order:2; margin:0; flex:0 1 auto }
/* Die Knopfzeile haelt die rechte Kante der ersten Zeile — ohne
   margin-left:auto rutschte sie in die zweite und stuende dort
   unter dem Etikett statt am Zeilenende. Quer liegend stehen die
   beiden Knoepfe NEBENeinander: hier ist Breite da, in der schmalen
   Karte nicht. */
.mob-angebot.ist-unten .mang-akt{
  order:3; margin:0 0 0 auto; flex:0 0 auto;
  flex-direction:row; align-items:center;
}
.mob-angebot.ist-unten .mang-hinweis{ order:4; flex:1 1 100% }

/* Platzhalter: der Platz ist da, das Angebot noch nicht. Zurueckhaltend
   gezeichnet, damit er nicht wie ein fertiges Angebot wirkt — und mit
   einem Satz, der sagt, WO es gepflegt wird. Kein Preis, keine Null. */
.mob-angebot.ist-platzhalter{
  border-style:dashed;
  border-color:rgba(11,58,72,.24);
  background:rgba(255,255,255,.82);
  box-shadow:0 10px 28px rgba(8,38,48,.08);
}
.mob-angebot.ist-platzhalter .mang-badge{
  background:rgba(11,58,72,.08);
  color:#41616d;
}
.mang-hinweis{
  margin:0;
  color:#5a6f78;
  font:600 clamp(11.5px,.82vw,13px)/1.45 Inter,system-ui,sans-serif;
}

/* --- Provider: grosse seitliche Logo-Banner (nur Logos) ---------- */
.provider-rail{
  position:absolute;
  /* Platz fuer die beschriftete Fortschrittsleiste (Befund 13.08.,
     Reparatur-Spalte lag unter den Bereichsnamen) — unter 1100px ist
     der Streifen 0, dort stehen nur die Striche. */
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:50%;
  display:flex;
  flex-direction:column;
  gap:clamp(10px,1.1vw,16px);
  transform:translateY(-50%);
}

.provider{
  position:relative;
  display:grid;
  place-items:center;
  width:clamp(215px,17.5vw,280px);
  height:clamp(64px,5.4vw,86px);
  border:1px solid var(--hair);
  border-radius:18px;
  background:rgba(255,255,255,.92);
  box-shadow:0 10px 30px rgba(12,58,72,.06);
  opacity:var(--r,0);
  transform:translate3d(calc((1 - var(--ri,0)) * 46px + var(--ro,0) * 30px),0,0)
            scale(calc(.94 + .06 * var(--ri,0)));
  transition:border-color .3s ease,box-shadow .3s ease,background .3s ease;
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
}
.provider:hover{
  border-color:rgba(18,199,224,.42);
  background:#fff;
  box-shadow:0 14px 34px rgba(12,58,72,.10);
}
.provider-mark{
  position:absolute;
  inset:14% 13%;
  display:grid;
  place-items:center;
  color:var(--accent-ink);
  font-size:clamp(16px,1.4vw,22px);
  font-weight:900;
  letter-spacing:-.02em;
}
.provider-mark img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:contain;
}
/* Nur Logos — Namen sitzen in alt/title, nicht im Layout */
.provider-name,
.provider-note{
  display:none;
}

/* Fehlendes Original-Logo klar markieren (nur im Debug sichtbar) */
.provider[data-asset-missing="true"]::after{
  content:"Logo-Asset fehlt";
  position:absolute;
  right:10px;
  top:6px;
  color:#c2410c;
  font-size:8px;
  font-weight:800;
  letter-spacing:.1em;
  text-transform:uppercase;
  opacity:0;
}
html.is-debug .provider[data-asset-missing="true"]::after{
  opacity:1;
}

/* =========================================================
   9 — SZENE 02 · INTERNET
   ========================================================= */
.net-screen{
  position:absolute;
  left:50%;
  top:calc(50% - clamp(10px,3vh,40px));
  width:clamp(300px,52vw,880px);
  aspect-ratio:16 / 9.6;
  transform:
    translate(-50%,-50%)
    scale(calc(.34 + .66 * var(--ri,0) - .16 * var(--ro,0)))
    translate3d(calc(var(--mx,0) * 9px),calc(var(--my,0) * 6px),0);
  opacity:var(--r,0);
  border-radius:clamp(6px,.7vw,12px);
  border:clamp(5px,.55vw,10px) solid #111820;
  background:#05080b;
  box-shadow:
    0 0 0 1px rgba(0,0,0,.9),
    0 0 0 2px rgba(95,112,122,.34),
    0 46px 90px rgba(6,42,54,.24),
    0 0 34px rgba(32,204,229,.12);
  overflow:hidden;
  will-change:transform,opacity;
}

.net-screen .tv-slide{
  transition:opacity 1.1s ease;
  transform:none !important;
}

/* ANGEBOT IN DIE MITTE, BILDSCHIRM NACH RECHTS UND KLEINER (Zuruf Erguen
   19.08. an der Internet-Szene: "hier angebot in die mitte und den
   fernseher nach rechts und kleiner mit animationen und texten auf dem
   bildschirm"). Vorher stand der Bildschirm formatfuellend in der Mitte
   (52vw) und die Karte rechts — jetzt tauschen beide die Rollen.
   NUR AB 1101px: darunter stapelt die Szene, und die Quer-Lage der Karte
   aus responsive.css muss unangetastet bleiben.
   Die Karte zentriert ueber die EIGENSTAENDIGE translate-Eigenschaft —
   ihr transform traegt die Lage (translateY(-50%)); eine zweite
   transform-Deklaration ERSETZTE sie (Lehre 1.633.0).
   Masse gegen die Nachbarn GEMESSEN: Karte mittig 616..984px (1600er
   Fenster) bzw. 493..787px (1280er); der Bildschirm beginnt bei 24vw und
   left:76% erst bei 1024 bzw. 819px und endet vor dem --rail-gutter der
   Fortschrittsleiste. */
@media (min-width:1101px){
  [data-scene-content="internet"] .mob-angebot{
    left:50%;
    right:auto;
    translate:-50% 0;
    transform-origin:center;
  }
  /* NACH LINKS (Zuruf Erguen 19.08.: "da es beim scrollen überlappungen
     gibt den fernseher nach links"): rechts wohnt ab Fortschritt ~0.52
     die Tempo-Liste (.net-speeds) — der Bildschirm lief mitten hinein
     (am Bildschirmfoto gesehen). 24% ist die Spiegellage zu 76%; links
     ist frei, weil die Kopfzeile (.net-copy) bis 0.4 ausgeblendet ist,
     BEVOR der Bildschirm einfaehrt (Fenster in experience.js). */
  [data-scene-content="internet"] .net-screen{
    left:24%;
    width:clamp(220px,24vw,420px);
  }
  [data-scene-content="internet"] .net-screen-stand{
    left:24%;
    top:calc(50% + clamp(56px,9.5vh,132px));
  }
  /* DER SALE-ANHAENGER RUECKT NEBEN DIE KARTE (Zuruf Erguen 19.08. mit
     Bildschirmfoto: er deckte die Plakette „ANGEBOT DES MONATS" ab).
     URSACHE: in DIESER Szene steht die Karte mittig (Regel oben), und der
     Anhaenger haengt ebenfalls mittig — beide teilen sich also dieselbe
     Spalte. Solange die Karte flach ist, trennt sie die Hoehe; ein
     ECHTES MOS-Angebot mit 4:5-Bild ist aber rund 570 px hoch und waechst
     wegen `top:50%` + `translateY(-50%)` nach OBEN in den Anhaenger hinein.
     GEMESSEN mit einem gepflegten Angebot samt Bild: Karte 166..734,
     Plakette 192..212, Anhaenger 79..212 — Ueberdeckung der Plakette bis
     1560 px² (1600x900) bzw. 1938 px² (1280x720).
     NACH RECHTS, nicht nach links: links liegt die Kopfzeile (.net-copy,
     74..626 / 135..475) — dort saesse er auf der Ueberschrift. Rechts der
     Karte ist sein ganzes Hoehenband frei; die Tempo-Liste beginnt erst
     bei y 273 (1600) bzw. 206 (1280), der Anhaenger endet bei 212 bzw. 172.
     GERECHNET, nicht geraten: halbe Kartenbreite + halbe Anhaengerbreite
     + 24 px Luft ab der Mitte. Damit wandert er mit, wenn eine der beiden
     Breiten sich aendert — eine feste Zahl waere beim naechsten
     Feinschliff wieder falsch. */
  [data-scene-content="internet"] .sale-rund-szene{
    left:calc(50% + clamp(272px,23vw,368px) / 2
                  + clamp(84px,7.6vw,122px) / 2 + 24px);
  }
}

.net-screen-stand{
  position:absolute;
  left:50%;
  top:calc(50% + clamp(80px,15vh,230px));
  width:clamp(90px,9vw,150px);
  height:clamp(6px,.7vh,10px);
  transform:translate(-50%,-50%) scaleX(calc(.3 + .7 * var(--ri,0)));
  border-radius:999px;
  background:linear-gradient(90deg,#0a0d10,#2b333b 48%,#0a0d10);
  opacity:calc(var(--r,0) * .8);
}

.net-copy{
  position:absolute;
  /* Zurueck an den linken Rand (20.08.): die 1.649er-Logosaeule, der die
     Kopfzeile ausweichen musste, ist entfallen — die grossen Logos wohnen
     seither rechts neben der Karte (.net-logos-gross). */
  left:var(--edge);
  top:clamp(88px,13vh,150px);
  /* KLEINER (Zuruf: "überschrift kleiner"): die schmalere Spalte laesst
     fitHeadlines() die nowrap-Zeilen ohnehin herunterrechnen; das
     kleinere clamp nimmt zusaetzlich die Obergrenze zurueck. */
  max-width:min(34vw,470px);
}
[data-scene-content="internet"] .scene-headline{
  font-size:clamp(26px,3.2vw,58px);
}

/* GROSSE ANBIETERLOGOS RECHTS NEBEN DER KARTE (20.08., "rechts neben der
   kachel grosses telekom und o2 logo"). Die Lage ist GERECHNET, nicht
   geraten: halbe Kartenbreite (die Karte steht in dieser Szene mittig,
   clamp(272px,23vw,368px)) plus Luft ab der Bildmitte — dieselbe Rechnung
   wie beim SALE-Anhaenger darueber; eine feste Zahl waere beim naechsten
   Kartenmass wieder falsch. Senkrecht mittig wie die Karte selbst.
   NUR AB 1101px: darunter stapelt die Szene, und fuer zwei grosse Kacheln
   neben der Karte ist kein Platz. Die Deckkraft faehrt die Engine ueber
   das anim-Fenster der Karte. */
.net-logos-gross{
  position:absolute;
  display:none;
  z-index:6;
}
@media (min-width:1101px){
  .net-logos-gross{
    display:flex;
    flex-direction:column;
    gap:clamp(14px,1.8vh,24px);
    /* WEITER RECHTS (Zuruf Erguen 20.08.: "die kacheln weiter rechts"):
       an der rechten Inhaltskante verankert (edge+gutter) statt an der
       Kartenmitte gerechnet — dieselbe Kante wie die Angebotsspalten. */
    right:calc(var(--edge) + var(--rail-gutter,0px));
    top:50%;
    translate:0 -50%;
  }
}
.net-logo-gross{
  display:grid;
  place-items:center;
  width:clamp(170px,15vw,240px);
  height:clamp(88px,8.2vw,128px);
  border-radius:18px;
  background:#fff;
  border:1px solid rgba(9,44,56,.10);
  box-shadow:0 14px 34px rgba(6,20,26,.12);
}
.net-logo-gross img{
  /* Logos EINGEPASST (Zuruf Erguen 20.08.: "logos ausbessern paasend in
     die kacheln"): mehr Luft rundum statt randnaher Wortmarken. */
  max-width:60%;
  max-height:50%;
  object-fit:contain;
}
.net-logo-wort{
  font:800 clamp(18px,1.6vw,26px)/1 Inter,system-ui,sans-serif;
  color:#0d1b2a;
}


/* Durchlaufende Technologie-Typografie */
.net-marquee{
  position:absolute;
  left:0;
  right:0;
  display:flex;
  justify-content:center;
  color:var(--ink);
  font-size:clamp(42px,9vw,168px);
  line-height:.86;
  font-weight:900;
  letter-spacing:-.06em;
  text-transform:uppercase;
  white-space:nowrap;
  opacity:var(--r,0);
  /* Kontinuierliche Kamerabewegung: das Wort steht genau dann mittig,
     wenn der Szenenfortschritt seinen Anker --wa erreicht. */
  transform:translate3d(calc((var(--wa,.5) - var(--p,0)) * var(--travel,300vw)),0,0);
  pointer-events:none;
}
/* Alle Laufworte solide mit weichem Lichthof — bleibt auch beim
   Kreuzen des dunklen Displays lesbar */
.net-marquee{
  text-shadow:
    0 0 14px rgba(255,255,255,.9),
    0 0 38px rgba(255,255,255,.65),
    0 4px 60px rgba(233,251,253,.5);
}
.net-marquee.is-outline{
  color:var(--accent-deep);
}

/* Geschwindigkeitsstufen */
.net-speeds{
  position:absolute;
  /* Platz fuer die beschriftete Fortschrittsleiste (Befund 13.08.,
     Reparatur-Spalte lag unter den Bereichsnamen) — unter 1100px ist
     der Streifen 0, dort stehen nur die Striche. */
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:50%;
  width:clamp(240px,26vw,380px);
  transform:translateY(-50%);
}
.net-speed{
  padding:clamp(10px,1vw,15px) 0;
  border-bottom:1px solid var(--hair);
  opacity:var(--r,0);
  transform:translate3d(calc((1 - var(--ri,0)) * 40px + var(--ro,0) * 24px),0,0);
}
.net-speed-head{
  display:flex;
  align-items:baseline;
  justify-content:space-between;
  gap:12px;
}
.net-speed-value{
  color:var(--ink);
  font-size:clamp(21px,2.1vw,38px);
  font-weight:900;
  letter-spacing:-.045em;
  line-height:1;
}
.net-speed-value i{
  font-style:normal;
  font-size:.42em;
  font-weight:800;
  letter-spacing:.02em;
  color:var(--ink-soft);
  margin-left:.4em;
}
.net-speed-label{
  color:var(--ink-soft);
  font-size:clamp(9px,.68vw,11px);
  font-weight:800;
  letter-spacing:.18em;
  text-transform:uppercase;
}
.net-speed-bar{
  position:relative;
  margin-top:9px;
  height:3px;
  border-radius:999px;
  background:rgba(9,60,72,.09);
  overflow:hidden;
}
.net-speed-bar::after{
  content:"";
  position:absolute;
  inset:0;
  border-radius:inherit;
  background:linear-gradient(90deg,var(--accent-deep),var(--accent));
  transform:scaleX(calc(var(--ri,0) * var(--fill,1)));
  transform-origin:left center;
}

/* Router / WLAN */
.net-home{
  position:absolute;
  /* UNTER DER UEBERSCHRIFT statt mittig (Zuruf Erguen 19.08.: "den 3d
     router in schwarz unter der überschrift abblden"): er uebernimmt die
     Spalte der Kopfzeile (links neben der Logo-Saeule) und sitzt in der
     unteren Haelfte — die Kopfzeile endet dort laengst. GEAENDERT statt
     eine zweite Regel danebenzustellen (1.562.0-Falle: bei gleicher
     Spezifitaet gewinnt die spaetere). */
  left:calc(var(--edge) + clamp(150px,11.5vw,188px) + clamp(18px,1.6vw,28px) + clamp(24px,2.4vw,48px));
  top:auto;
  /* HOEHER als bis 1.659.0 (Zuruf Erguen 20.08.: "der router ist zu weit
     unten", mit Bild der abgeschnittenen Unterkante). GEMESSEN am
     gerenderten Bild, nicht geschaetzt: die Canvas ist 230 % des Blocks
     und haengt damit rund zwei Drittel einer Blockhoehe darunter hinaus —
     bei 1920x925 stand die schwarze Router-Tinte bei y=662..913, also
     11 px ueber der Fensterkante (1600x900: 15 px). Nach oben ist reichlich
     Platz: die Kopfzeile endet bei 438 bzw. 405. clamp(104px,17vh,190px)
     hebt ihn um rund 65 px an; der Abstand zur Kopfzeile bleibt ueber
     150 px. Weg zurueck: Git (1.659.0). */
  bottom:clamp(104px,17vh,190px);
  /* GROESSER (1.699.0, Befund Erguen: "Router der Internet-Szene
     sichtbarer"). GEMESSEN bei 1600x900 war der schwarze Kasten rund
     170 px breit und stand ohne Umfeld in der unteren linken Ecke — das
     einzige dunkle Ding auf hellem Grund, und trotzdem uebersah man ihn.
     13vw -> 16vw, Deckel 220 -> 268 px. Die Canvas ist 230 % davon; nach
     oben bleibt der Abstand zur Kopfzeile ueber 100 px (gerechnet mit der
     Messung von 1.659.0). */
  width:clamp(168px,16vw,268px);
  transform:scale(calc(.8 + .2 * var(--ri,0)));
  opacity:var(--r,0);
  text-align:center;
}
.net-router{
  position:relative;
  width:100%;
  aspect-ratio:1 / .62;
  margin:0 auto;
  border-radius:14px;
  background:linear-gradient(160deg,#f4fafb,#dcecf0 60%,#c9e2e8);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.9),
    0 20px 44px rgba(10,62,76,.14);
}
.net-router::before{
  content:"";
  position:absolute;
  left:14%;
  bottom:22%;
  width:12%;
  aspect-ratio:1;
  border-radius:50%;
  background:var(--accent);
  box-shadow:0 0 12px rgba(18,199,224,.7);
}
.net-wave{
  position:absolute;
  left:50%;
  bottom:64%;
  width:var(--w);
  aspect-ratio:1;
  transform:translateX(-50%);
  border:2px solid rgba(18,199,224,.5);
  border-bottom-color:transparent;
  border-left-color:transparent;
  border-right-color:transparent;
  border-radius:50%;
  /* NUR NOCH --o (1.699.0): das Blenden erledigt `.net-home` fuer die
     ganze Gruppe. Der Faktor --r stand hier an Elementen, deren --r nie
     gesetzt wurde — gemessen 0, und damit waren die Wellen immer
     unsichtbar. */
  opacity:var(--o,1);
}

/* =========================================================
   10 — SZENE 03 · ZUBEHOER
   ========================================================= */
.acc-object{
  position:absolute;
  left:var(--ox,22%);
  top:50%;
  /* Breit statt quadratisch: hier stehen jetzt Sets aus 2-3
     Objekten. Das Verhaeltnis kommt je Set aus der Konfiguration
     (--oar), weil das Power-Set deutlich breiter ist. */
  width:clamp(320px,52vw,860px);
  aspect-ratio:var(--oar,16/9);
  transform:
    translate(-50%,-50%)
    translate3d(
      calc(var(--ro,0) * -16vw + var(--mx,0) * 12px),
      calc((1 - var(--ri,0)) * 8vh + var(--my,0) * 9px),
      0)
    scale(calc(.72 + .28 * var(--ri,0) - .18 * var(--ro,0)))
    rotate(calc((1 - var(--ri,0)) * -6deg));
  opacity:var(--r,0);
  will-change:transform,opacity;
}

/* DIE KOPFHOERER OBEN LINKS (Zuruf Erguen 20.08.: "bei zubehör links oben
   in den leeren platz die 3d audio kopfhörer die wir zuletzt verwenden
   hatten"). Die Lage ist GEMESSEN, nicht gewaehlt: der Motivstreifen mit
   den Kategoriesymbolen endet bei rund 190 px, der SALE-Anhaenger beginnt
   bei etwa 47 % der Breite, die Ueberschrift erst auf halber Hoehe — die
   Flaeche dazwischen ist frei.
   Ohne `has-3d` (Modell nicht geladen, schmales Geraet) bleibt der Wirt
   leer und damit unsichtbar — es gibt hier keine CSS-Ersatzdarstellung,
   und ein leerer Kasten waere schlechter als nichts. */
.acc-kopf3d{
  position:absolute;
  left:clamp(200px,15vw,280px);
  top:clamp(96px,15vh,190px);
  width:clamp(180px,17vw,300px);
  aspect-ratio:4/3;
  opacity:var(--r,0);
  transform:translate3d(0, calc((1 - var(--ri,0)) * 5vh), 0);
  pointer-events:auto;
  will-change:transform,opacity;
}
.acc-kopf3d .device-3d-canvas{
  width:150%;
  height:150%;
}
@media (max-width:1100px){
  /* Unter 1100 px steigt die 3D-Datei ohnehin aus (device-3d.js) und der
     Platz oben links gehoert der Ueberschrift. */
  .acc-kopf3d{ display:none }
}

.acc-shape{
  position:absolute;
  inset:0;
  border-radius:var(--shape-r,30%);
  background:var(--shape-bg,linear-gradient(150deg,#ffffff,#e6f2f5 58%,#cfe6ec));
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.9),
    inset 0 -18px 40px rgba(10,62,76,.07),
    0 46px 80px rgba(10,62,76,.16);
}
.acc-shape::after{
  content:"";
  position:absolute;
  left:8%;
  top:6%;
  width:44%;
  height:34%;
  border-radius:50%;
  background:radial-gradient(circle at 35% 35%,rgba(255,255,255,.85),transparent 68%);
  filter:blur(6px);
}
.acc-ring{
  position:absolute;
  inset:14%;
  border:1px solid rgba(18,199,224,.35);
  border-radius:50%;
  opacity:.7;
}
.acc-core{
  position:absolute;
  inset:32%;
  border-radius:50%;
  background:linear-gradient(150deg,#0e1519,#04090b);
  box-shadow:inset 0 2px 6px rgba(255,255,255,.16),0 18px 34px rgba(6,32,40,.24);
}
.acc-bar{
  position:absolute;
  left:22%;
  right:22%;
  top:46%;
  height:8%;
  border-radius:999px;
  background:linear-gradient(90deg,var(--accent-deep),var(--accent));
  box-shadow:0 0 18px rgba(18,199,224,.4);
  opacity:.85;
}
.acc-photo{
  position:absolute;
  inset:8%;
  width:84%;
  height:84%;
  object-fit:contain;
}

/* Fehlendes Produktfoto klar markieren (nur im Debug sichtbar) */
html.is-debug .acc-object[data-asset-missing="true"]::after{
  content:"Produktfoto fehlt";
  position:absolute;
  left:50%;
  bottom:-26px;
  transform:translateX(-50%);
  color:#c2410c;
  font:800 9px/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  white-space:nowrap;
}

.acc-copy{
  position:absolute;
  /* LINKS UND KLEINER (Zuruf Erguen 14.08.: "zubehör links und kleiner
     damit rechts platz für das angebot des monats entstehen kann") —
     die rechte Kante gehoert jetzt der Monatsangebot-Karte. Damit
     entfaellt hier auch der Freihalte-Streifen fuer die Fortschritts-
     leiste: er wird nur rechts gebraucht.
     DAFUER WEICHT ER JETZT DER KACHELLEISTE AUS (Befund Erguen 14.08. mit
     drei Bildschirmfotos: "SCHUTZ", "AUDIO" und "POWER" lagen samt Text
     unter den Zubehoer-Kacheln). GEMESSEN bei 1866x900: die Leiste endet
     bei x=106, --edge liegt bei 86 — 20 px Ueberlappung, und der
     Zeilenanfang verschwand unter den Kacheln. max() nimmt den groesseren
     der beiden Werte: auf schmalen Schirmen gibt es die Leiste nicht,
     dort gilt weiter --edge. */
  left:max(var(--edge), var(--banner-gutter,0px));
  top:50%;
  max-width:min(30vw,420px);
  text-align:left;
  opacity:var(--r,0);
  /* DER EINFLUG KOMMT VON UNTEN, NICHT VON LINKS. Seitlich waren es
     64 px — und die legten den Text waehrend des Einblendens noch einmal
     unter die Kachelleiste (gemessen 2550 px² bei 27 % Deckkraft), obwohl
     seine Ruhelage laengst daneben liegt. Nach oben gibt es dort nichts,
     womit er zusammenstossen koennte; die Bewegung bleibt gleich lang.
     Der AUSflug nach rechts bleibt: er fuehrt von der Leiste WEG. */
  transform:translateY(-50%)
            translate3d(calc(var(--ro,0) * 90px),calc((1 - var(--ri,0)) * 26px),0);
}
.acc-index{
  display:block;
  margin-bottom:12px;
  color:var(--accent-deep);
  font-size:clamp(11px,.82vw,14px);
  font-weight:900;
  letter-spacing:.28em;
}
.acc-name{
  margin:0;
  color:var(--ink);
  /* Kleiner als bisher (4.4vw/78px) — die Spalte ist schmaler geworden,
     ein 78-px-Wort brach dort in drei Zeilen um. */
  font-size:clamp(26px,3.2vw,56px);
  line-height:.94;
  font-weight:900;
  letter-spacing:-.05em;
  text-transform:uppercase;
}
.acc-note{
  margin:clamp(12px,1.4vw,20px) 0 0;
  margin-right:auto;
  max-width:28ch;
  color:var(--ink-mid);
  font-size:clamp(13px,.98vw,17px);
  line-height:1.5;
}

.acc-categories{
  position:absolute;
  left:50%;
  top:50%;
  width:min(84vw,1080px);
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:clamp(8px,.9vw,15px);
  transform:translate(-50%,-50%);
}
.acc-chip{
  padding:clamp(9px,.85vw,14px) clamp(15px,1.4vw,25px);
  border:1px solid var(--hair);
  border-radius:999px;
  background:rgba(255,255,255,.8);
  color:var(--ink);
  font-size:clamp(11px,.86vw,15px);
  font-weight:800;
  letter-spacing:.02em;
  opacity:var(--r,0);
  transform:translate3d(0,calc((1 - var(--ri,0)) * 22px),0)
            scale(calc(.94 + .06 * var(--ri,0)));
  transition:border-color .3s ease,color .3s ease,box-shadow .3s ease,background .3s ease;
}
.acc-chip:hover{
  border-color:rgba(18,199,224,.5);
  color:var(--accent-ink);
  background:rgba(18,199,224,.07);
  box-shadow:0 10px 24px rgba(12,88,104,.08);
}

/* =========================================================
   11 — SZENE 04 · REPARATUR
   ========================================================= */
.rep-device{
  position:absolute;
  left:50%;
  top:50%;
  width:clamp(190px,17vw,300px);
  aspect-ratio:1 / 2.06;
  transform:translate(-50%,-50%) scale(calc(.9 + .1 * var(--ri,0)));
  perspective:1500px;
  opacity:var(--r,0);
}
.rep-layers{
  position:relative;
  width:100%;
  height:100%;
  transform-style:preserve-3d;
  transform:
    rotateX(calc(6deg + var(--my,0) * -2deg))
    rotateY(calc(-13deg + var(--mx,0) * 3deg));
}
/* --r der .rep-layers steuert die Explosionsansicht:
   auseinander bei "Fix.", wieder zusammen bei "Ready." */
.rep-layer{
  position:absolute;
  inset:0;
  border-radius:15%/7.3%;
  transform:translate3d(
      calc(var(--r,0) * var(--lx,0) * 1px),
      calc(var(--r,0) * var(--ly,0) * 1px),
      0);
}
.rep-layer.is-glass{
  background:linear-gradient(150deg,rgba(226,248,252,.5),rgba(184,229,238,.18));
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.6),0 20px 40px rgba(8,52,64,.12);
}
.rep-layer.is-screen{
  background:linear-gradient(168deg,#04222b,#052c37 52%,#03151c);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08);
}
.rep-layer.is-board{
  background:
    repeating-linear-gradient(90deg,rgba(18,199,224,.16) 0 1px,transparent 1px 13px),
    repeating-linear-gradient(0deg,rgba(18,199,224,.12) 0 1px,transparent 1px 17px),
    linear-gradient(160deg,#123039,#0a2028);
}
.rep-layer.is-battery{
  background:linear-gradient(160deg,#1d2a30,#0d181d);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.07);
}
.rep-layer.is-shell{
  background:linear-gradient(148deg,#2b343c,#0b1114 62%,#1d252b);
  box-shadow:0 0 0 1px rgba(255,255,255,.1),0 42px 70px rgba(8,38,48,.22);
}

.rep-marker{
  position:absolute;
  z-index:5;
  left:var(--px,50%);
  top:var(--py,40%);
  width:clamp(46px,4vw,72px);
  aspect-ratio:1;
  transform:translate(-50%,-50%) scale(calc(.6 + .4 * var(--ri,0)));
  border:1px solid rgba(18,199,224,.75);
  border-radius:50%;
  opacity:var(--r,0);
}
.rep-marker::before{
  content:"";
  position:absolute;
  inset:32%;
  border-radius:50%;
  background:rgba(18,199,224,.85);
  box-shadow:0 0 14px rgba(18,199,224,.7);
}

.rep-word{
  position:absolute;
  left:calc(50% + var(--wx,0px));
  top:calc(50% + var(--wy,0px));
  transform:translate(-50%,-50%)
            translate3d(0,calc((1 - var(--ri,0)) * 34px),0);
  margin:0;
  color:transparent;
  -webkit-text-stroke:clamp(1px,.13vw,2.2px) rgba(6,20,26,.30);
  font-size:clamp(46px,10vw,190px);
  line-height:.84;
  font-weight:900;
  letter-spacing:-.07em;
  text-transform:uppercase;
  opacity:var(--r,0);
  pointer-events:none;
}

.rep-copy{
  position:absolute;
  left:var(--edge);
  top:clamp(96px,15vh,170px);
  max-width:min(46vw,640px);
  /* UEBER der seitenbreiten 3D-Canvas ("texte sollen aber noch lesbar
     sein"): die fliegenden Teile ziehen HINTER dem Titel vorbei.
     pointer-events:none, damit der Textkasten den Drag nicht schluckt —
     er traegt keine Links. */
  z-index:6;
  pointer-events:none;
}
.rep-copy .scene-headline{
  font-size:clamp(32px,4.6vw,80px);
}

.rep-services{
  position:absolute;
  /* Platz fuer die beschriftete Fortschrittsleiste (Befund 13.08.,
     Reparatur-Spalte lag unter den Bereichsnamen) — unter 1100px ist
     der Streifen 0, dort stehen nur die Striche. */
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:50%;
  width:clamp(230px,24vw,340px);
  transform:translateY(-50%);
}
.rep-service{
  display:flex;
  align-items:center;
  gap:14px;
  padding:clamp(9px,.9vw,14px) 0;
  border-bottom:1px solid var(--hair);
  opacity:var(--r,0);
  transform:translate3d(calc((1 - var(--ri,0)) * 32px),0,0);
}
.rep-service span{
  color:var(--ink);
  font-size:clamp(12px,.95vw,16px);
  font-weight:800;
  letter-spacing:-.01em;
}
.rep-service i{
  width:6px;
  height:6px;
  flex:0 0 6px;
  border-radius:50%;
  background:var(--accent);
  box-shadow:0 0 0 4px rgba(18,199,224,.14);
}

/* =========================================================
   12 — SZENE 05 · SHOP / TERMIN
   ========================================================= */
.fin-wrap{
  position:absolute;
  inset:0;
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  text-align:center;
  /* Platz fuer den Footer am Buehnenrand. Seitlich kommt der Platz der
     benannten Fortschrittsleiste dazu (--rail-gutter, unter 1100px = 0):
     .fin-word ist display:block und damit so breit wie dieser Kasten —
     ohne den Gutter ragte die ELEMENTBOX unter die Leistennamen, auch
     wenn der zentrierte Text selbst frei war. Symmetrisch auf beiden
     Seiten, damit die Mitte die Mitte bleibt. */
  padding:clamp(64px,9vh,96px) calc(var(--edge) + var(--rail-gutter,0px)) clamp(76px,11vh,116px);
  /* `safe` IST DER RIEGEL, NICHT ZIERDE (1.700.0). GEMESSEN bei 1366x740:
     die Termin-Ueberschrift stand 44 px UNTER der Kopfleiste — nicht weil
     das Polster zu klein war, sondern weil `center` bei Ueberlauf nach
     BEIDEN Seiten hinausschiebt, auch nach oben aus dem Bild. `safe`
     faellt genau dann auf `start` zurueck: passt der Inhalt, bleibt er
     mittig wie bisher; passt er nicht, beginnt er am oberen Polster und
     der Ueberschuss geht nach unten, wo die Seite ohnehin weitergeht. */
  justify-content:safe center;
}

/* DAS ZUBEHOER-INTRO WEICHT DER MONATSKARTE AUS (Zuruf Erguen 19.08.:
   "überschrift etwas weiter nach links damit die angebotskachel nicht
   überdeckt wird", mit Bildschirmfoto: "DIE DEN UNTERSCHIED" lief unter
   die Karte rechts). Die Karte steht rechts mit Breite
   clamp(272px,23vw,368px) — genau diese Breite plus Luft kommt hier als
   ZUSAETZLICHES rechtes Polster dazu. Polster begrenzt die Inhaltsbox:
   die zentrierte Ueberschrift KANN die Kartenspur damit gar nicht mehr
   betreten, egal in welchem Ein-/Ausblende-Moment beide gerade stehen.
   Nur im Zubehoer — die Termin-Schlussworte (derselbe .fin-wrap) haben
   rechts keine Karte und bleiben mittig. */
.acc-intro{
  padding-right:calc(var(--edge) + var(--rail-gutter,0px) + clamp(272px,23vw,368px) + 24px);
}
/* FLEX-KIND-FALLE (dieselbe Klasse wie 1.592.0): ein Flex-Kind hat die
   Mindestbreite `auto` — die nowrap-Zeilen der Ueberschrift machten das h2
   BREITER als die Inhaltsbox (gemessen 934px in 807px), es lief mittig
   ueber beide Polster hinaus und beruehrte die Karte doch (7186 px²).
   Die Falle geht ZWEI Ebenen tief (Wrapper-Lehre 1.641.0): auch der
   namenlose Zwischen-Wrapper ist ein Flex-Kind und wuchs mit — deshalb
   beide Ebenen. Erst damit greift auch fitHeadlines: es misst h.clientWidth,
   und das war vorher die eigene Ueberbreite — geschrumpft wurde nie. */
.acc-intro > *{ max-width:100%; }
.acc-intro .scene-headline{ max-width:100%; }

.fin-words{
  position:relative;
  display:block;
}
.fin-word{
  display:block;
  color:var(--ink);
  font-size:clamp(32px,5.5vw,102px);
  line-height:.94;
  font-weight:900;
  letter-spacing:-.055em;
  text-transform:uppercase;
  opacity:var(--r,0);
  transform:translate3d(0,calc((1 - var(--ri,0)) * 42px),0);
}
/* DIE TERMIN-SCHLUSSWORTE SIND KLEINER ALS DIE DES ZUBEHOER-INTROS
   (1.700.0, Befund aus dem Bild: die Ueberschrift klebte oben an der
   Kopfleiste). GEMESSEN bei 1600x900: der dreizeilige Titel war 248 px
   hoch und begann bei y 56 — genau an der Unterkante der 56 px hohen
   Leiste, Abstand 0. Ursache ist nicht zu wenig Polster, sondern zu viel
   Inhalt fuer die Buehnenhoehe: Titel, Unterzeile, zwei Knoepfe und drei
   Filialkarten stehen untereinander, und bei Ueberlauf schiebt
   `justify-content:center` oben wie unten hinaus. 5,5vw -> 4,6vw nimmt
   dem Titel rund 40 px Hoehe.
   NACHGEMESSEN, nicht angenommen: `.fin-word` baut HEUTE nur die
   Termin-Szene (buildAppointment). Das Zubehoer-Intro teilt sich mit ihr
   den `.fin-wrap`, seine Ueberschrift ist aber ein `headlineBlock`
   (`.scene-headline`) und bleibt von dieser Zahl unberuehrt. Der Selektor
   nennt die Szene trotzdem ausdruecklich — er sagt damit, wofuer die Zahl
   gerechnet ist. */
[data-scene-content="appointment"] .fin-word{
  font-size:clamp(30px,4.6vw,84px);
}
.fin-word em{
  font-style:normal;
  color:var(--accent-deep);
}

.fin-sub{
  margin:clamp(20px,2.4vw,34px) 0 0;
  color:var(--ink-mid);
  font-size:clamp(14px,1.15vw,21px);
  font-weight:500;
  opacity:var(--r,0);
  transform:translate3d(0,calc((1 - var(--ri,0)) * 22px),0);
}

.fin-actions{
  margin-top:clamp(28px,3.4vw,50px);
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:clamp(10px,1vw,16px);
  opacity:var(--r,0);
  transform:translate3d(0,calc((1 - var(--ri,0)) * 20px),0);
}

.fin-locations{
  margin-top:clamp(26px,3vw,44px);
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:clamp(10px,1.2vw,20px);
  opacity:var(--r,0);
}
.fin-location{
  min-width:clamp(220px,18vw,290px);
  padding:clamp(14px,1.3vw,22px) clamp(18px,1.6vw,28px);
  border:1px solid var(--hair);
  border-radius:18px;
  background:rgba(255,255,255,.82);
  box-shadow:0 12px 34px rgba(12,58,72,.06);
  text-align:left;
  font-style:normal;
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
  transition:border-color .3s ease,box-shadow .3s ease;
}
.fin-location:hover{
  border-color:rgba(18,199,224,.4);
  box-shadow:0 16px 40px rgba(12,58,72,.1);
}
.fin-location strong{
  display:block;
  color:var(--ink);
  font-size:clamp(13px,1vw,17px);
  font-weight:800;
  letter-spacing:-.01em;
}
.fin-location span{
  display:block;
  margin-top:4px;
  color:var(--ink-soft);
  font-size:clamp(10px,.74vw,12.5px);
}
.fin-location-address{
  color:var(--ink-mid) !important;
  font-weight:600;
}
.fin-location-links{
  display:flex;
  flex-wrap:wrap;
  gap:4px 14px;
  margin:10px 0 8px;
  padding:9px 0 8px;
  border-top:1px solid var(--hair);
  border-bottom:1px solid var(--hair);
}
.fin-location-link{
  color:var(--accent-deep);
  font-size:clamp(10px,.74vw,12.5px);
  font-weight:800;
  text-decoration:none;
  transition:color .25s ease;
}
.fin-location-link:hover{
  color:var(--accent-ink);
  text-decoration:underline;
  text-underline-offset:3px;
}
.fin-location-link:focus-visible{
  outline:none;
  color:var(--accent-ink);
  text-decoration:underline;
  text-underline-offset:3px;
  box-shadow:0 0 0 3px rgba(18,199,224,.25);
  border-radius:4px;
}
.fin-location-hours{
  font-variant-numeric:tabular-nums;
}
.fin-location[data-placeholder="true"]{
  border-style:dashed;
  border-color:rgba(194,65,12,.35);
}

.fin-converge{
  position:absolute;
  inset:0;
  z-index:2;
  width:100%;
  height:100%;
  pointer-events:none;
  overflow:visible;
}

/* =========================================================
   12b — 3D-VIEWER (GLB)
   ---------------------------------------------------------
   js/device-3d.js haengt eine Canvas in die jeweilige
   Buehne und setzt .has-3d. Die CSS-Objekte bleiben im DOM
   und uebernehmen wieder, wenn kein Modell geladen ist.
   ========================================================= */
.device-3d-canvas{
  position:absolute;
  z-index:5;
  left:50%;
  top:50%;
  width:190%;
  height:125%;
  transform:translate(-50%,-50%);
  pointer-events:none;
  opacity:0;
  transition:opacity .8s ease;
}
.has-3d > .device-3d-canvas,
.has-3d .device-3d-canvas{
  opacity:1;
  /* Modelle sind vom Nutzer drehbar (Drag) */
  pointer-events:auto;
  cursor:grab;
  touch-action:pan-y;
}
.device-3d-canvas.is-grabbing{
  cursor:grabbing;
}

/* Mobilfunk: CSS-Geraet weicht dem Modell, weicher Bodenschatten bleibt */
.device-stage.has-3d .device{
  visibility:hidden;
}
.device-stage.has-3d::after{
  content:"";
  position:absolute;
  left:50%;
  bottom:-7%;
  width:78%;
  height:6%;
  transform:translateX(-50%);
  border-radius:50%;
  background:radial-gradient(ellipse,rgba(8,42,54,.28),transparent 68%);
  filter:blur(9px);
}

/* Internet: Router-Attrappe weicht dem Modell */
.net-router.has-3d{
  background:transparent;
  box-shadow:none;
}
/* Lichtsockel und Funkwellen des Modells stehen weiter unten in EINER
   Regel, gemeinsam mit der Vorab-Marke html.hat-3d (1.699.0) — sie gelten
   nur oberhalb 1101 px, wo es das Modell ueberhaupt gibt. */
.net-router.has-3d::before{
  display:none;
}

.net-router.has-3d .device-3d-canvas{
  width:230%;
  height:230%;
}
.net-router.has-3d::after{
  content:"";
  position:absolute;
  left:50%;
  bottom:-46%;
  width:110%;
  height:14%;
  transform:translateX(-50%);
  border-radius:50%;
  background:radial-gradient(ellipse,rgba(8,42,54,.22),transparent 68%);
  filter:blur(8px);
}
/* Die Bildunterschrift des Routers ist mit 1.659.0 entfallen (Zuruf
   Erguen 20.08.). Weg zurueck: Git (1.658.0). */

/* Zubehoer: abstrakte Formen weichen dem Modell,
   Ein-/Austritts-Transform der .acc-object bleibt erhalten */
.acc-object.has-3d .acc-shape,
.acc-object.has-3d .acc-ring,
.acc-object.has-3d .acc-core,
.acc-object.has-3d .acc-bar{
  visibility:hidden;
}
.acc-object.has-3d .device-3d-canvas{
  width:150%;
  height:150%;
}

/* Reparatur: die CSS-Explosionsansicht weicht dem Modell. Sie bleibt im DOM
   und uebernimmt wieder, wenn das Modell nicht laedt — auf schmalen Geraeten
   laedt es nie, dort steigt die ganze 3D-Datei aus.
   Der Rahmen ist mit 1:2.06 hochkant fuer eine Handy-Silhouette gebaut; der
   Betrachter braucht rundherum Luft, sonst schneidet ein leicht gedrehtes
   Geraet an den Kanten ab. */
.rep-device.has-3d .rep-layers{
  visibility:hidden;
}
/* Die Explosionsansicht braucht die GANZE Seitenbreite (Zuruf Erguen 14.08.:
   "verkleinern und auf die voll breite der seite anpassen"): der Mount steht
   in der Seitenmitte, die Canvas dehnt sich symmetrisch fast ueber das
   Fenster. Prozentmasse vom 300-px-Mount truegen hier — deshalb vw/vh. */
.rep-device.has-3d .device-3d-canvas{
  width:min(96vw,1860px);
  height:min(94vh,900px);
}
.rep-device.has-3d::after{
  content:"";
  position:absolute;
  left:50%;
  bottom:2%;
  width:62%;
  height:3.4%;
  transform:translateX(-50%);
  border-radius:50%;
  background:radial-gradient(ellipse,rgba(8,42,54,.26),transparent 70%);
  filter:blur(8px);
}

/* PLATZHALTER RUHEN SCHON BEIM SEITENSTART (1.676.0, Freigabe Erguen:
   "Platzhalter auf dem Schreibtisch weglassen — Handy behaelt sie").
   html.hat-3d setzt js/device-3d.js in dem Moment, in dem ALLE
   3D-Bedingungen stehen (Breite >1100, feiner Zeiger, WebGL, keine
   reduzierte Bewegung) — bis dahin stand auf dem Schreibtisch erst die
   flache Attrappe und Sekunden spaeter das echte Modell. Ohne die Marke
   (Handy, reduced motion, kein WebGL) aendert sich NICHTS: dort sind
   die Platzhalter der einzige Inhalt. kein-3d am einzelnen Wirt holt
   den Platzhalter zurueck, wenn genau diese eine Buehne ihr Modell
   nicht bekommt (Datei fehlt, Vendor fehlt, Aufbau wirft) — die Zusage
   "die Seite verliert nie Funktionalitaet" bleibt wahr. Der
   Media-Riegel deckt zusaetzlich den Fall, dass jemand das Fenster NACH
   dem Laden schmal zieht: die Marke bleibt dann stehen, aber unter
   1101 px gehoeren die Platzhalter wieder ins Bild.
   Die Deklarationen SPIEGELN die has-3d-Regeln dieses Abschnitts (und
   die TV-Regel weiter unten) — nur das Verstecken, nicht die Zugaben
   (Bodenschatten, Canvas-Masse): die entstehen weiter erst mit dem
   Modell. */
@media (min-width:1101px){
  html.hat-3d .device-stage:not(.kein-3d) .device{
    visibility:hidden;
  }
  html.hat-3d .net-router:not(.kein-3d){
    background:transparent;
    box-shadow:none;
  }
  /* LICHTSOCKEL UND FUNKWELLEN DES MODELLS (1.699.0, Befund Erguen:
     "Router der Internet-Szene sichtbarer"). Bis 1.698.0 stand hier
     `display:none` bzw. `opacity:0 !important` — der Router war ein
     schwarzer Kasten ohne Aussage auf hellem Grund. BEIDE Selektoren in
     EINER Regel: `.has-3d` am Wirt und die Vorab-Marke `html.hat-3d`
     beschreiben denselben Zustand, und zwei gespiegelte Bloecke sind die
     Stelle, an der eines Tages nur einer gepflegt wird. Sie stehen in
     dieser Media-Query, weil es das Modell erst ab 1101 px gibt; darunter
     gilt weiter die Attrappe mit ihrer Leuchtdiode.
     Der Sockel ist Deko: pointer-events:none, z-index 0 haelt ihn hinter
     der Canvas. Die Wellen sitzen an der Geometrie des MODELLS, das in
     der 230-%-Canvas deutlich hoeher steht als die alte Attrappe. */
  .net-router.has-3d::before,
  html.hat-3d .net-router:not(.kein-3d)::before{
    display:block;
    left:50%;
    bottom:-6%;
    width:190%;
    aspect-ratio:1 / .78;
    translate:-50% 0;
    border-radius:50%;
    background:radial-gradient(ellipse at 50% 50%,
                rgba(18,199,224,.20), rgba(18,199,224,.07) 46%, rgba(18,199,224,0) 72%);
    box-shadow:none;
    filter:blur(10px);
    z-index:0;
    pointer-events:none;
  }
  .net-router.has-3d .net-wave,
  html.hat-3d .net-router:not(.kein-3d) .net-wave{
    /* GERECHNET, nicht geschaetzt (1600x900): die Router-Box ist 157 px
       hoch und endet bei y 746, die Antennenspitzen des Modells stehen bei
       rund y 550. 118 % der Boxhoehe setzen die Boegen bei y 561 an —
       direkt ueber den Antennen. Mit den alten 96 % sassen sie bei y 595
       und wirkten losgeloest vom Geraet. */
    bottom:118%;
    border-color:rgba(18,199,224,.42);
    border-bottom-color:transparent;
    border-left-color:transparent;
    border-right-color:transparent;
  }
  html.hat-3d .acc-object:not(.kein-3d) .acc-shape,
  html.hat-3d .acc-object:not(.kein-3d) .acc-ring,
  html.hat-3d .acc-object:not(.kein-3d) .acc-core,
  html.hat-3d .acc-object:not(.kein-3d) .acc-bar{
    visibility:hidden;
  }
  html.hat-3d .rep-device:not(.kein-3d) .rep-layers{
    visibility:hidden;
  }
  html.hat-3d .tv-stage:not(.kein-3d) .tv-screen-fallback{
    display:none;
  }
}

/* Bedienfeld der 3D-Animation (Zurufe Erguen 14.08.: "ein kleines info
   fenster zum bedienen", "und pause taste", "alles passen zum style der
   seite"). Weisse Karte wie Banner/Footer, Pillen-Knoepfe wie die CTAs.
   Es haengt am Stage (nicht am 300-px-Mount) und sitzt unten links —
   ueber der Scooter-Fahrbahn, unter dem Titeltext; opacity folgt --r,
   damit es mit der Szene ein- und ausblendet.

   ES STEHT UEBER DEN AKTIONSKNOEPFEN, NICHT AUF IHNEN (Befund Erguen
   14.08.: „links unten überlappung"). Beide sassen in derselben Ecke:
   `.mob-actions` bei bottom clamp(96px,11vh,150px), das Bedienfeld bei
   13vh — GEMESSEN lagen sie an jeder Fensterhoehe uebereinander
   (1866x900: 12000 px2), und `elementFromPoint` traf in der Ueberlappung
   den Knopf „Von vorn": der Hauptweg „Reparatur anfragen" war dort gar
   nicht anklickbar. Deshalb DIESELBE Grundlage wie die Knopfzeile plus
   ihre gemessene Hoehe: sie ist 48–58 px hoch (720p bis 1050p), 80 px
   lassen ueberall mindestens 22 px Luft. Eine eigene vh-Rechnung waere
   die Stelle, an der beide bei der naechsten Fensterhoehe wieder
   auseinanderlaufen. */
.dv-steuer{
  position:absolute;
  z-index:7;
  left:var(--edge);
  bottom:calc(clamp(96px,11vh,150px) + 80px);
  max-width:300px;
  padding:14px 16px 13px;
  border-radius:16px;
  border:1px solid rgba(6,20,26,.08);
  background:rgba(255,255,255,.92);
  box-shadow:0 18px 40px rgba(6,20,26,.12);
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
  opacity:var(--r,1);
  pointer-events:auto;
}
.dv-tipp{
  margin:0 0 10px;
  color:var(--ink-mid);
  font:500 12.5px/1.5 Inter,system-ui,sans-serif;
}
.dv-tipp strong{
  display:block;
  margin-bottom:3px;
  color:var(--accent-deep);
  font:900 10px/1 Inter,system-ui,sans-serif;
  letter-spacing:.26em;
  text-transform:uppercase;
}
.dv-reihe{
  display:flex;
  gap:8px;
}
.dv-knopf{
  display:inline-flex;
  align-items:center;
  gap:8px;
  height:34px;
  padding:0 14px;
  border:1px solid rgba(6,20,26,.16);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  font:900 10.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em;
  text-transform:uppercase;
  cursor:pointer;
  transition:border-color .25s ease,background .25s ease,
             color .25s ease,transform .25s ease;
}
.dv-knopf:hover,
.dv-knopf:focus-visible{
  outline:none;
  border-color:var(--accent);
  transform:translateY(-1px);
}
.dv-knopf:focus-visible{
  box-shadow:0 0 0 3px rgba(18,199,224,.28);
}
.dv-knopf .dv-ic{
  width:11px;
  height:11px;
  fill:currentColor;
  flex:0 0 auto;
}

/* Ladeanzeige des 3D-Modells (Zuruf Erguen 14.08.: "keinen dummy sondern
   einen ladebalken bis animation voll geladen wurde"). Dieselbe Karte wie
   das Bedienfeld, aber MITTIG im Einbauort — dort, wo gleich das Geraet
   steht. Sie erbt ueber .rep-device die Szenen-Deckkraft (--r), erscheint
   also nicht, waehrend die Szene noch weit weg ist. */
.dv-laden{
  position:absolute;
  z-index:6;
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
  width:min(280px,78vw);
  padding:14px 16px 13px;
  border-radius:16px;
  border:1px solid rgba(6,20,26,.08);
  background:rgba(255,255,255,.92);
  box-shadow:0 18px 40px rgba(6,20,26,.12);
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
}
.dv-lt{
  margin:0 0 10px;
  color:var(--ink-mid);
  font:500 12.5px/1.5 Inter,system-ui,sans-serif;
}
.dv-lt strong{
  display:block;
  margin-bottom:3px;
  color:var(--accent-deep);
  font:900 10px/1 Inter,system-ui,sans-serif;
  letter-spacing:.26em;
  text-transform:uppercase;
}
.dv-lbahn{
  position:relative;
  height:4px;
  border-radius:999px;
  background:rgba(6,20,26,.10);
  overflow:hidden;
}
.dv-lfuell{
  display:block;
  width:0;
  height:100%;
  border-radius:999px;
  background:linear-gradient(90deg,var(--accent),var(--accent-deep));
  transition:width .3s ease;
}
/* Ohne gemeldete Gesamtgroesse gibt es KEINE Prozentzahl — eine ruhige
   Bewegung sagt "es passiert etwas", ohne einen Stand zu behaupten. */
.dv-lbahn.ist-unbestimmt .dv-lfuell{
  width:40%;
  animation:dvLade 1.3s ease-in-out infinite;
}
@keyframes dvLade{
  0%{ transform:translateX(-110%); }
  100%{ transform:translateX(260%); }
}
@media (prefers-reduced-motion:reduce){
  .dv-lbahn.ist-unbestimmt .dv-lfuell{ animation:none; width:100%; opacity:.5; }
}

/* Solange geladen wird, bleibt die Platzhalter-Grafik weg (genau der
   "dummy", den der Zuruf meint). Scheitert das Laden, nimmt die
   Ladeanzeige die Klasse mit — und der Platzhalter uebernimmt wieder. */
.rep-device.is-laedt .rep-layers{
  visibility:hidden;
}

/* =========================================================
   13 — FOOTER (lebt in der letzten Buehne)
   ---------------------------------------------------------
   Die Seite endet exakt mit der Termin-Szene — dadurch wird
   beim Scrollen ans Ende nichts mehr abgeschnitten.
   ========================================================= */
.site-footer{
  position:absolute;
  z-index:8;
  left:0;
  right:0;
  bottom:0;
  padding:clamp(14px,1.6vh,22px) var(--edge);
  background:rgba(255,255,255,.92);
  border-top:1px solid var(--hair);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
}
.footer-inner{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  justify-content:space-between;
  gap:clamp(14px,2vw,34px);
  max-width:1440px;
  margin:0 auto;
}
.footer-brand img{
  width:clamp(130px,9vw,170px);
  height:auto;
  display:block;
}
.footer-nav{
  display:flex;
  flex-wrap:wrap;
  gap:clamp(14px,2vw,34px);
}
.footer-nav a{
  color:var(--ink-mid);
  font-size:12px;
  font-weight:800;
  letter-spacing:.1em;
  text-transform:uppercase;
  text-decoration:none;
  transition:color .25s ease;
}
.footer-nav a:hover,
.footer-nav a:focus-visible{
  color:var(--accent-deep);
  outline:none;
}
.footer-nav a:focus-visible{
  text-decoration:underline;
  text-underline-offset:4px;
}
.footer-meta{
  display:flex;
  align-items:center;
  gap:clamp(12px,1.4vw,22px);
  color:var(--ink-soft);
  font-size:11px;
  letter-spacing:.04em;
}
/* Impressum / Datenschutz — Buttons, weil sie ein Overlay
   oeffnen; optisch bleiben es schlichte Links. */
.footer-legal{
  padding:0;
  border:0;
  background:none;
  color:var(--ink-mid);
  font:800 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  transition:color .25s ease;
}
.footer-legal:hover,
.footer-legal:focus-visible{
  outline:none;
  color:var(--accent-deep);
  text-decoration:underline;
  text-underline-offset:4px;
}

/* =========================================================
   14 — HEADER IM STORY-MODUS
   ---------------------------------------------------------
   Kein neuer Header. Nur etwas kompakter.
   ========================================================= */
.site-header{
  transition:height .4s cubic-bezier(.2,.8,.2,1),
             background .4s ease,
             box-shadow .4s ease,
             border-color .4s ease;
}
.site-header.is-compact{
  height:clamp(56px,3.3vw,64px);
  background:transparent;
  box-shadow:0 4px 24px rgba(13,40,50,.07);
}
/* DIE MILCHGLAS-FLAECHE LIEGT AUF EINEM EIGENEN ELEMENT, nicht auf dem
   Kopf selbst (Befund Erguen 14.08.: "bei hover sollte der button nicht
   abgeschnitten werden"). Chromium legt fuer `backdrop-filter` eine
   eigene Zeichenflaeche an und SCHNEIDET alles Darinliegende an der
   Kante ab — der weiche Schatten des goldenen Knopfes endete deshalb
   exakt an der Kopfunterkante (am Bild gesehen). Auf einem Pseudo-
   Element wirkt derselbe Effekt, ohne den Knopf zu beschneiden. */
.site-header.is-compact::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:-1;
  background:rgba(255,255,255,.9);
  backdrop-filter:blur(16px) saturate(1.15);
  -webkit-backdrop-filter:blur(16px) saturate(1.15);
}
.site-header.is-compact .site-logo img{
  max-height:34px;
  transition:max-height .4s cubic-bezier(.2,.8,.2,1);
}
.site-logo img{
  transition:max-height .4s cubic-bezier(.2,.8,.2,1);
}

/* ---------------------------------------------------------
   Bereichs-Navigation im Header (identisch mit dem Footer)
   Absolut zentriert, damit sie unabhaengig von Logo- und
   Buttonbreite exakt in der Mitte sitzt.
   --------------------------------------------------------- */
.header-nav{
  position:absolute;
  left:50%;
  top:50%;
  transform:translate(-50%,-50%);
  display:flex;
  align-items:center;
  gap:clamp(18px,2vw,34px);
}
.header-nav a{
  position:relative;
  padding:6px 0;
  color:var(--ink-mid);
  font:800 clamp(10px,.76vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
  text-decoration:none;
  white-space:nowrap;
  transition:color .25s ease;
}
/* Unterstrich waechst aus der Mitte */
.header-nav a::after{
  content:"";
  position:absolute;
  left:0;
  right:0;
  bottom:0;
  height:2px;
  border-radius:2px;
  background:var(--accent-deep);
  transform:scaleX(0);
  transform-origin:center;
  transition:transform .32s cubic-bezier(.2,.8,.2,1);
}
.header-nav a:hover,
.header-nav a:focus-visible{
  outline:none;
  color:var(--ink);
}
/* Haus-Symbol: Strichstaerke und Farben der Nachbarlinks, kein Text.
   17 px wirkten neben den fetten Versalien zu zart (Zuruf Erguen 14.08.:
   "home icon grösser passend zum rest") — 21 px mit etwas mehr Strich
   traegt das Gewicht der 800er-Schrift. */
.header-nav .nav-home{
  display:inline-flex;
  align-items:center;
}
.header-nav .nav-home svg{
  width:21px;
  height:21px;
  fill:none;
  stroke:currentColor;
  stroke-width:2.2;
  stroke-linecap:round;
  stroke-linejoin:round;
}
.header-nav a:hover::after,
.header-nav a:focus-visible::after{
  transform:scaleX(1);
}

/* Aktive Szene markieren — ohne eigenen Listener, allein
   ueber data-scene, das die Engine am <html> setzt. */
html[data-scene="mobile"]       .header-nav a[data-nav="mobile"],
html[data-scene="internet"]     .header-nav a[data-nav="internet"],
html[data-scene="accessories"]  .header-nav a[data-nav="accessories"],
html[data-scene="repair"]       .header-nav a[data-nav="repair"],
html[data-scene="appointment"]  .header-nav a[data-nav="appointment"]{
  color:var(--accent-ink);
}
html[data-scene="mobile"]       .header-nav a[data-nav="mobile"]::after,
html[data-scene="internet"]     .header-nav a[data-nav="internet"]::after,
html[data-scene="accessories"]  .header-nav a[data-nav="accessories"]::after,
html[data-scene="repair"]       .header-nav a[data-nav="repair"]::after,
html[data-scene="appointment"]  .header-nav a[data-nav="appointment"]::after{
  transform:scaleX(1);
}

/* Logo + Navigation + Goldbutton brauchen Platz. Darunter
   uebernimmt die Fortschrittsleiste rechts die Navigation. */
@media (max-width:1180px){
  .header-nav{ display:none }
}
@media (prefers-reduced-motion:reduce){
  .header-nav a,
  .header-nav a::after{ transition:none }
}

/* =========================================================
   15 — SCROLL-FORTSCHRITT
   ========================================================= */
/* Die Goldlinie an der Oberkante: wie weit bin ich auf der Seite. Liegt
   UEBER der Kopfleiste (z 140), damit sie auf deren weissem Grund liegt
   statt dahinter zu verschwinden. pointer-events:none - reine Anzeige. */
.seiten-balken{
  position:fixed;
  top:0; left:0;
  width:100%;
  height:3px;
  z-index:210;
  pointer-events:none;
  background:linear-gradient(90deg,#e6bc50,#c99a2e);
  transform:scaleX(0);
  transform-origin:left center;
}

.story-progress{
  position:fixed;
  z-index:120;
  right:clamp(12px,1.5vw,26px);
  top:50%;
  display:flex;
  flex-direction:column;
  /* Die Namen sind verschieden lang — rechtsbuendig enden alle
     Striche auf derselben Kante (Vorgabe 13.08.: Namen statt Zahlen). */
  align-items:flex-end;
  gap:clamp(10px,1.1vw,16px);
  transform:translateY(-50%);
  opacity:0;
  pointer-events:none;
  transition:opacity .45s ease;
}
.story-progress.is-visible{
  opacity:1;
  pointer-events:auto;
}

.progress-step{
  display:flex;
  align-items:center;
  gap:9px;
  padding:0;
  border:0;
  background:transparent;
  color:var(--ink-soft);
  font:800 10px/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em;
  cursor:pointer;
  transition:color .3s ease;
}
.progress-step span{
  opacity:.55;
  text-transform:uppercase;
  /* Ziehende Elemente (Laufworte) koennen unter der Leiste durchfahren —
     der helle Schein haelt den Namen in dem Moment lesbar. */
  text-shadow:0 1px 8px rgba(244,251,253,.9);
  transition:opacity .3s ease;
}
.progress-step i{
  display:block;
  width:clamp(18px,1.9vw,30px);
  height:1px;
  background:currentColor;
  opacity:.28;
  transform-origin:right center;
  transition:opacity .3s ease,transform .3s ease,background .3s ease;
}
.progress-step:hover,
.progress-step:focus-visible{
  outline:none;
  color:var(--ink);
}
.progress-step:focus-visible i{
  opacity:1;
  transform:scaleX(1.25);
}
.progress-step.is-active{
  color:var(--accent-deep);
}
.progress-step.is-active span{
  opacity:1;
}
.progress-step.is-active i{
  opacity:1;
  background:var(--accent);
  transform:scaleX(1.5);
  box-shadow:0 0 10px rgba(18,199,224,.5);
}

/* =========================================================
   16 — SCROLL-FAB AUF DEM HERO
   ---------------------------------------------------------
   Dezenter, animierter Hinweis, dass gescrollt werden kann.
   Klick startet die Journey.
   ========================================================= */
.scroll-cue{
  position:absolute;
  z-index:120;
  left:50%;
  bottom:calc(var(--benefit-h) + clamp(14px,2.2vh,28px));
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:9px;
  padding:0;
  border:0;
  background:transparent;
  transform:translateX(-50%);
  color:var(--accent-ink);
  font:800 clamp(10px,.8vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.3em;
  text-transform:uppercase;
  cursor:pointer;
  /* Bewusst ohne Opacity-Transition: der Hinweis haengt direkt
     am Scrollstand und darf ihm nicht hinterherlaufen. */
  opacity:var(--cue-alpha,1);
}
.scroll-cue.is-gone{
  pointer-events:none;
}
/* .scroll-cue-text ist WEG (Zuruf Erguen 19.08.: "scrollen als text
   ueberalle entfernen") — Markup und Regel zusammen entfernt; eine Regel
   ohne Element waere die naechste Attrappe. */
/* HALB SO GROSS (Zuruf Erguen 15.08.: „scrollen button um die haelfte
   kleiner"). Die Kugel war mit bis zu 66 px der groesste runde Koerper der
   Hero-Szene und zog den Blick vom Motiv weg — sie soll fuehren, nicht
   dominieren. Halbiert wird die GANZE Spanne (54–66 -> 27–33), damit sie
   auf jedem Schirm im selben Verhaeltnis schrumpft; das Zeichen darin
   wandert mit (27 -> 14 px), sonst spraengte es die Kugel. */
.scroll-cue-orb{
  display:grid;
  place-items:center;
  width:clamp(27px,2.1vw,33px);
  height:clamp(27px,2.1vw,33px);
  border-radius:50%;
  border:1px solid rgba(18,199,224,.4);
  background:rgba(255,255,255,.85);
  box-shadow:
    0 6px 20px rgba(12,88,104,.16),
    inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
  animation:cueFloat 2.6s ease-in-out infinite;
  transition:border-color .25s ease, box-shadow .25s ease;
}
.scroll-cue-orb svg{
  width:14px;
  height:14px;
  fill:none;
  stroke:var(--accent-deep);
  stroke-width:2.2;
  stroke-linecap:round;
  stroke-linejoin:round;
  animation:cueChevron 2.6s ease-in-out infinite;
}
/* Nach kurzer Stille wird der Hinweis aufdringlicher: groesser, goldener
   Puls-Ring. Der Ring faellt bei reduzierter Bewegung weg — die goldene
   Kante und die Groesse bleiben als stiller Hinweis. */
.scroll-cue{
  transition:transform .35s ease;
}
.scroll-cue.is-insist{
  transform:translateX(-50%) scale(1.14);
}
.scroll-cue.is-insist .scroll-cue-orb{
  border-color:rgba(201,154,46,.85);
  animation:cueFloat 2.6s ease-in-out infinite, cueRing 1.7s ease-out infinite;
}
@keyframes cueRing{
  from{ box-shadow:0 0 0 0 rgba(224,180,72,.5), 0 6px 20px rgba(12,88,104,.16), inset 0 1px 0 rgba(255,255,255,.9); }
  /* 24 -> 12 px: der Ring waechst um die halbe Kugelgroesse. Mit der
     alten Zahl waere er nach dem Verkleinern breiter als die Kugel
     selbst und saehe aus wie ein Fehler statt wie ein Puls. */
  to{   box-shadow:0 0 0 12px rgba(224,180,72,0), 0 6px 20px rgba(12,88,104,.16), inset 0 1px 0 rgba(255,255,255,.9); }
}
@media (prefers-reduced-motion:reduce){
  .scroll-cue.is-insist .scroll-cue-orb{ animation:none; }
}

/* DER SCHWEBENDE HINWEIS DER FOLGE-SZENEN IST ENTFALLEN (Zuruf Erguen
   20.08.: "das scroll fab unten auf den seiten entfernen") — mit Markup
   und Steuerung zusammen; eine Regel ohne Element waere die naechste
   Attrappe. Der Hinweis IM HERO (.scroll-cue) bleibt.
   Weg zurueck: Git (1.655.0). */

.scroll-cue:hover .scroll-cue-orb,
.scroll-cue:focus-visible .scroll-cue-orb{
  border-color:rgba(18,199,224,.75);
  box-shadow:
    0 10px 26px rgba(12,88,104,.22),
    0 0 0 3px rgba(18,199,224,.18),
    inset 0 1px 0 rgba(255,255,255,.9);
}
.scroll-cue:focus-visible{
  outline:none;
}
@keyframes cueFloat{
  0%,100%{transform:translateY(0)}
  50%{transform:translateY(5px)}
}
@keyframes cueChevron{
  0%,100%{transform:translateY(-1px);opacity:.75}
  50%{transform:translateY(2px);opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .scroll-cue-orb,
  .scroll-cue-orb svg{
    animation:none;
  }
}

/* =========================================================
   16b — GOLDENER SHOP-BUTTON (im Header, oben rechts)
   ========================================================= */
/* Form und Anmutung vom Chat-Knopf (Zuruf Erguen 14.08.: "online shop
   button im style vom chat aber gold farbe behalten"): Pille, weicher
   Schatten, leichter Hub beim Ueberfahren — das Gold bleibt.
   Bis 1.698.0 trugen BEIDE Shop-Knoepfe dieselbe Form; der schwebende
   Zubehoer-Knopf war schon so gebaut, der Kopf-Knopf war der Ausreisser
   (3-px-Kasten, kein Schatten). Seit 1.699.0 gibt es nur noch diesen.
   Die HOEHE bleibt die des Kopfes — der Chat-Knopf ist mit bis zu 58 px
   deutlich hoeher und wuerde die Kopfzeile sprengen. */
.shop-fab{
  display:inline-flex;
  align-items:center;
  gap:12px;
  height:clamp(38px,2.6vw,44px);
  padding:0 clamp(20px,1.7vw,28px);
  border:1px solid #a8801f;
  border-radius:999px;
  background:linear-gradient(140deg,#e6bc50,#c99a2e);
  color:#231903;
  font:900 clamp(10px,.78vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em;
  text-transform:uppercase;
  white-space:nowrap;
  cursor:pointer;
  box-shadow:0 14px 34px rgba(120,86,16,.3);
  transition:background .22s ease,
             border-color .22s ease,
             color .22s ease,
             transform .3s cubic-bezier(.2,.8,.2,1),
             box-shadow .3s ease;
}
.shop-fab::after{
  content:"";
  width:16px;
  height:1.5px;
  background:currentColor;
  opacity:.75;
  transition:width .28s cubic-bezier(.2,.8,.2,1);
}
.shop-fab:hover{
  background:linear-gradient(140deg,#f0c85c,#d4a437);
  border-color:#8f6c17;
  transform:translateY(-2px);
  box-shadow:0 18px 42px rgba(120,86,16,.38);
}
.shop-fab:hover::after{
  width:24px;
}
.shop-fab:active{
  background:#c1922a;
  transform:translateY(0);
}
/* Fokusring wie am Chat-Knopf: ein Ring statt der harten Kontur —
   auf der Pille sass die 2-px-Kontur als Rechteck um die Rundung. */
.shop-fab:focus-visible{
  outline:none;
  box-shadow:0 14px 34px rgba(120,86,16,.3),
             0 0 0 3px rgba(224,180,72,.6);
}
@media (prefers-reduced-motion:reduce){
  .shop-fab,
  .shop-fab::after{ transition:none }
}

/* 16c (Telefon-Panel im Header) ist ENTFERNT — der Kopf traegt seit
   ec4c203 keinen Telefon-Knopf mehr, das Panel entstand nie.
   Weg zurueck: Git vor dem Aufraeumen (1.655.0). */

/* =========================================================
   16d — EINMALIGES ZONEN-INTRO AUF DEM HERO
   ---------------------------------------------------------
   Nutzt exakt die (freigegebene) Hover-Optik der Zonen —
   kein Flash, kein Sweep, laeuft einmal nach dem Laden.
   ========================================================= */
.hero-zone.is-intro{
  background-color:rgba(var(--zone-hover-rgb), .105) !important;
  box-shadow:
    inset 0 0 0 1.5px rgba(var(--zone-hover-rgb), .62),
    inset 0 0 42px rgba(var(--zone-hover-rgb), .055),
    0 0 15px rgba(var(--zone-hover-rgb), .08) !important;
}
.hero-zone.is-intro::before{
  opacity:1 !important;
  background:
    linear-gradient(
      135deg,
      rgba(var(--zone-hover-rgb), .095),
      rgba(var(--zone-hover-rgb), .025)
    ) !important;
  box-shadow:
    inset 0 0 0 1px rgba(var(--zone-hover-rgb), .45),
    inset 0 0 28px rgba(var(--zone-hover-rgb), .055) !important;
}

/* =========================================================
   16e — INTERNET-HEADLINE UEBER DEM DISPLAY LESBAR
   ========================================================= */
.net-copy{
  z-index:6;
}
.net-copy .scene-headline{
  text-shadow:
    0 0 16px rgba(255,255,255,.8),
    0 0 40px rgba(255,255,255,.5);
}

/* =========================================================
   16f — ONLINE-SHOP-AUSWAHL (Overlay)
   ---------------------------------------------------------
   Zwei externe Partner-Shops plus eigene Angebote. Oeffnet
   ueber dem laufenden Scrollstand, damit die Journey beim
   Abbrechen erhalten bleibt.
   ========================================================= */
/* GESCHLOSSEN HEISST UNSICHTBAR — mit visibility, nicht nur mit
   pointer-events (Live-Befund Erguen 15.08.: "fast auf allen seiten
   funktioniert die maus nicht richtig ... ich kann bereiche nicht
   anklicken"). `pointer-events:none` am Overlay schuetzt NICHT vor
   Kindern, die selbst `pointer-events:auto` tragen (.ang-karte u. a. —
   fuer die Offers-SZENE gebaut, aber dieselbe Klasse steckt in der
   Angebotsseite): nach einmal Oeffnen und Schliessen der Seite fingen
   ihre unsichtbaren Kacheln quer ueber den Bildschirm jeden Klick ab —
   gemessen 15 von 54 Rasterpunkten tot. `visibility:hidden` gilt fuer
   JEDEN Nachfahren, egal was er an pointer-events traegt; die
   Verzoegerung im transition laesst das Ausblenden weich zu Ende laufen. */
.shop-overlay{
  position:fixed;
  inset:0;
  z-index:200;
  display:grid;
  place-items:center;
  /* SCHMALER RAND OBEN UND UNTEN (Zuruf Erguen 15.08.: "bitte auch die
     anderen overlay die höhe des browsers voll nutzen lassen"). Der
     Kasten darf bis 100% der Hoehe wachsen — die 4vh Polster oben und
     unten nahmen ihm bei 900 px rund 72 px weg, und der Inhalt musste
     rollen, obwohl daneben Platz war. Seitlich bleibt es, wie es war. */
  padding:clamp(10px,1.6vh,20px) clamp(16px,4vw,48px);
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transition:opacity .32s ease, visibility 0s linear .32s;
}
.shop-overlay.is-open{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transition:opacity .32s ease, visibility 0s;
}
.shop-overlay-scrim{
  position:absolute;
  inset:0;
  background:rgba(6,20,26,.42);
  backdrop-filter:blur(10px) saturate(1.05);
  -webkit-backdrop-filter:blur(10px) saturate(1.05);
}

/* OHNE BINNEN-SCROLL (Zuruf Erguen 23.08.: "dieses overlay sollte ohne
   scrollen komplett sichtbar sein" — Bild: Scrollbalken im Panel, letzte
   Zeile angeschnitten). GEMESSEN war der Inhalt 43-216 px hoeher als das
   Panel (FullHD bis 1366x768), weil ALLE senkrechten Masse nur an der
   FensterBREITE hingen (vw): ein breites, flaches Fenster bekam grosse
   Schrift und grosse Polster in ein niedriges Panel. Deshalb traegt jedes
   senkrechte Mass hier zusaetzlich eine vh-Schranke (min(vw,vh) in der
   clamp-Mitte): auf hohen Fenstern aendert sich nichts, auf flachen
   schrumpfen Polster und Schrift, bis alles steht. overflow-y:auto
   BLEIBT als letzte Sicherung fuer extrem niedrige Fenster — die
   Untergrenzen der Schrift sind nicht verhandelbar. */
.shop-panel{
  position:relative;
  width:min(920px,100%);
  max-height:100%;
  overflow-y:auto;
  padding:clamp(18px,min(3.4vw,3vh),52px) clamp(22px,3.2vw,52px)
          clamp(16px,min(2.8vw,2.4vh),42px);
  border:1px solid rgba(255,255,255,.9);
  border-radius:clamp(20px,2vw,30px);
  background:rgba(252,254,255,.97);
  box-shadow:0 40px 110px rgba(6,38,48,.3);
  transform:translateY(18px) scale(.985);
  transition:transform .38s cubic-bezier(.16,.8,.24,1);
}
.shop-overlay.is-open .shop-panel{
  transform:none;
}

.shop-close{
  position:absolute;
  top:clamp(12px,1.2vw,18px);
  right:clamp(12px,1.2vw,18px);
  width:40px;
  height:40px;
  border:0;
  border-radius:50%;
  background:rgba(10,32,41,.07);
  color:#13262d;
  font-size:24px;
  line-height:1;
  cursor:pointer;
  transition:background .2s ease;
}
.shop-close:hover,
.shop-close:focus-visible{
  outline:none;
  background:rgba(18,199,224,.18);
}

.shop-eyebrow{
  margin:0 0 10px;
  color:var(--accent-deep);
  font-size:clamp(10px,.76vw,12px);
  font-weight:900;
  letter-spacing:.3em;
  text-transform:uppercase;
}
.shop-title{
  margin:0;
  color:var(--ink);
  font-size:clamp(24px,min(2.9vw,4.4vh),46px);
  line-height:1.02;
  font-weight:900;
  letter-spacing:-.04em;
}
.shop-sub{
  margin:clamp(8px,min(1.2vw,1.2vh),16px) 0 clamp(14px,min(2.4vw,2.6vh),34px);
  max-width:56ch;
  color:var(--ink-mid);
  font-size:clamp(12px,min(1vw,1.7vh),16px);
  line-height:1.55;
}

/* --- Partner-Karten --- */
.shop-cards{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:clamp(12px,1.4vw,20px);
}
.shop-card{
  position:relative;
  display:flex;
  flex-direction:column;
  gap:6px;
  padding:clamp(13px,min(1.8vw,1.9vh),26px);
  border:1px solid var(--hair);
  border-radius:20px;
  background:#fff;
  text-decoration:none;
  box-shadow:0 12px 32px rgba(12,58,72,.07);
  transition:transform .28s cubic-bezier(.2,.8,.2,1),
             border-color .28s ease,
             box-shadow .28s ease;
}
.shop-card:hover,
.shop-card:focus-visible{
  outline:none;
  transform:translateY(-3px);
  border-color:rgba(18,199,224,.5);
  box-shadow:0 20px 46px rgba(12,58,72,.13);
}
.shop-card:focus-visible{
  box-shadow:0 20px 46px rgba(12,58,72,.13),
             0 0 0 3px rgba(18,199,224,.3);
}
.shop-card-mark{
  position:relative;
  width:100%;
  height:clamp(38px,min(4vw,5vh),62px);
  margin-bottom:clamp(8px,min(1.2vw,1.2vh),16px);
}
/* Absolut in die Box gespannt: Prozent-Hoehen loesen sich in
   Grid-/Flex-Tracks sonst nicht auf und hohe Logos (o2)
   sprengen die Karte. */
.shop-card-mark img{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:contain;
  object-position:left center;
}
.shop-card-name{
  color:var(--ink);
  font-size:clamp(15px,1.15vw,19px);
  font-weight:800;
  letter-spacing:-.015em;
}
.shop-card-note{
  color:var(--ink-mid);
  font-size:clamp(12px,.88vw,14px);
  line-height:1.5;
}
.shop-card-go{
  display:inline-flex;
  align-items:center;
  gap:8px;
  margin-top:clamp(6px,min(1vw,1vh),14px);
  color:var(--accent-deep);
  font-size:clamp(11px,.82vw,13px);
  font-weight:900;
  letter-spacing:.12em;
  text-transform:uppercase;
}
.shop-card-ext{
  width:11px;
  height:11px;
  border:1.6px solid currentColor;
  border-left-width:0;
  border-bottom-width:0;
  transform:rotate(45deg);
  transition:transform .28s cubic-bezier(.2,.8,.2,1);
}
.shop-card:hover .shop-card-ext{
  transform:rotate(45deg) translate(2px,-2px);
}
.shop-card-hint{
  color:var(--ink-soft);
  font-size:clamp(9.5px,.68vw,11px);
  letter-spacing:.04em;
}

/* --- Eigene Angebote --- */
.shop-own{
  margin-top:clamp(14px,min(2.4vw,2.2vh),34px);
  padding-top:clamp(12px,min(2vw,1.9vh),26px);
  border-top:1px solid var(--hair);
}
/* --- DER LADEN-BEREICH (Entwurf Erguen 23.08., „baue den banner nach … als css")
   Zwei Spalten: links Ansprache und die beiden Wege, rechts drei Karten. Unter
   900 px untereinander — das Shop-Fenster ist auf dem Handy schmal.
   ALS CSS statt als Bild: scharf auf jedem Bildschirm, anklickbar, in jeder
   Fensterbreite richtig gesetzt, und der Text bleibt Text. */
.shop-laden{
  display:grid;
  grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  gap:clamp(18px,2.2vw,34px);
  align-items:start;
}
@media (max-width:900px){
  .shop-laden{grid-template-columns:minmax(0,1fr)}
}
.shop-laden-l{min-width:0}
.shop-laden-eyebrow{
  margin:0 0 8px;
  color:var(--accent-deep);
  font-size:clamp(10px,.72vw,12px);
  font-weight:900;
  letter-spacing:.18em;
  text-transform:uppercase;
}
.shop-laden-titel{
  margin:0 0 clamp(6px,min(1vw,1vh),14px);
  color:var(--ink);
  font-size:clamp(20px,min(2.6vw,3.8vh),40px);
  font-weight:900;
  line-height:1.08;
  letter-spacing:-.03em;
}
.shop-laden-sub{
  margin:0;
  max-width:34ch;
  color:var(--ink-mid);
  font-size:clamp(12px,min(1vw,1.7vh),16px);
  line-height:1.55;
}
.shop-laden-linie{
  height:1px;
  margin:clamp(10px,min(1.7vw,1.5vh),22px) 0;
  background:var(--hair);
}
.shop-laden-btns{
  display:flex;
  flex-wrap:wrap;
  gap:clamp(10px,1.1vw,14px);
}
/* Der zweite Knopf entsteht erst, wenn MOS Angebote gemeldet hat — ohne Inhalt
   darf sein Platzhalter die Zeile nicht auseinanderziehen. */
.shop-laden-zweit:empty{display:none}
.shop-laden-cta,
.shop-laden-zum{
  display:inline-flex;
  align-items:center;
  gap:9px;
  padding:clamp(10px,min(1.15vw,1.3vh),16px) clamp(18px,1.7vw,26px);
  border:1px solid transparent;
  border-radius:12px;
  font:inherit;
  font-size:clamp(11px,.8vw,13px);
  font-weight:900;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  transition:background-color .25s ease,border-color .25s ease,
             box-shadow .25s ease,transform .25s cubic-bezier(.2,.8,.2,1);
}
/* GENAU EINE gefuellte Flaeche im Bild: der Termin ist die Handlung, „Zum Shop"
   ist der Nebenweg und bleibt hell. */
.shop-laden-cta{
  background:var(--accent-deep);
  color:#fff;
  box-shadow:0 12px 28px rgba(10,142,165,.28);
}
.shop-laden-cta:hover,
.shop-laden-cta:focus-visible{
  outline:none;
  transform:translateY(-2px);
  box-shadow:0 18px 38px rgba(10,142,165,.34);
}
.shop-laden-cta-ic{display:inline-flex}
.shop-laden-zum{
  background:#fff;
  border-color:var(--hair);
  color:var(--accent-deep);
}
.shop-laden-zum:hover,
.shop-laden-zum:focus-visible{
  outline:none;
  border-color:rgba(18,199,224,.55);
  transform:translateY(-2px);
  box-shadow:0 14px 30px rgba(12,58,72,.1);
}
/* Derselbe Pfeil-Baustein wie an den Partner-Karten. */
.shop-laden-pfeil{
  width:9px;
  height:9px;
  border:1.8px solid currentColor;
  border-left-width:0;
  border-bottom-width:0;
  transform:rotate(45deg);
  transition:transform .25s cubic-bezier(.2,.8,.2,1);
}
.shop-laden-zum:hover .shop-laden-pfeil{transform:rotate(45deg) translate(2px,-2px)}
/* DREI NEBENEINANDER, nicht umgebrochen: die linke Spalte ist rund 440 px breit,
   und mit einem Flex-Umbruch rutschte „Alle Top-Marken" allein in eine zweite Zeile
   (am Bild gemessen). Als Raster teilen sich die drei den Platz gleichmaessig; die
   Beischrift bricht dann eher zweizeilig um, als dass eine Spalte wegfaellt. */
.shop-laden-merk{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(118px,1fr));
  gap:clamp(10px,1.1vw,18px);
  margin-top:clamp(12px,min(1.9vw,1.7vh),26px);
}
.shop-laden-m{
  display:flex;
  align-items:flex-start;
  gap:8px;
  min-width:0;
}
.shop-laden-m-ic{
  display:inline-flex;
  flex:0 0 auto;
  margin-top:1px;
  color:var(--accent-deep);
}
.shop-laden-m-t{
  display:flex;
  flex-direction:column;
  gap:2px;
  min-width:0;
}
.shop-laden-m-t b{
  color:var(--ink);
  font-size:clamp(11.5px,.8vw,13px);
  font-weight:800;
}
.shop-laden-m-t small{
  color:var(--ink-soft);
  font-size:clamp(10.5px,.72vw,12px);
  line-height:1.45;
}
.shop-laden-r{
  display:flex;
  flex-direction:column;
  gap:clamp(8px,min(1.1vw,1.1vh),14px);
  min-width:0;
}
.shop-laden-k{
  display:flex;
  align-items:flex-start;
  gap:clamp(11px,1.1vw,15px);
  padding:clamp(9px,min(1.3vw,1.4vh),18px);
  border:1px solid var(--hair);
  border-radius:16px;
  background:#fff;
  box-shadow:0 8px 22px rgba(12,58,72,.05);
  transition:border-color .25s ease,box-shadow .25s ease;
}
.shop-laden-k:hover{
  border-color:rgba(18,199,224,.45);
  box-shadow:0 14px 32px rgba(12,58,72,.1);
}
.shop-laden-k-ic{
  display:grid;
  place-items:center;
  flex:0 0 auto;
  width:clamp(30px,min(3vw,4vh),44px);
  height:clamp(30px,min(3vw,4vh),44px);
  border-radius:50%;
  background:rgba(18,199,224,.12);
  color:var(--accent-deep);
}
.shop-laden-k-t{
  display:flex;
  flex-direction:column;
  gap:4px;
  min-width:0;
}
.shop-laden-k-t b{
  color:var(--ink);
  font-size:clamp(13px,.98vw,15.5px);
  font-weight:800;
  letter-spacing:-.01em;
}
.shop-laden-k-t span{
  color:var(--ink-mid);
  font-size:clamp(11px,min(.82vw,1.35vh),13.5px);
  line-height:1.5;
}

/* Seite hinter dem Overlay nicht mitscrollen */
html.shop-open body{
  overflow:hidden;
}

@media (prefers-reduced-motion:reduce){
  .shop-panel{
    transform:none;
    transition:none;
  }
  .shop-card{
    transition:border-color .2s ease;
  }
  .shop-card:hover{
    transform:none;
  }
}

/* =========================================================
   16g — SCHWEBENDE AKTIONEN: SALE-BANNER + VERFUEGBARKEIT
   ---------------------------------------------------------
   Beide blenden szenenabhaengig ein (data-scene am <html>,
   gesetzt von scroll-story.js). Sale links, Check rechts —
   sie kollidieren dadurch nie.
   ========================================================= */
.sale-banner,
.check-fab{
  position:fixed;
  z-index:124;
  bottom:clamp(18px,3vh,34px);
  opacity:0;
  pointer-events:none;
  transform:translateY(16px);
  transition:opacity .45s ease,
             transform .45s cubic-bezier(.2,.8,.2,1);
}
html.shop-open .sale-banner,
html.shop-open .check-fab{
  opacity:0 !important;
  pointer-events:none !important;
}

/* --- RUNDER SALE-ANHAENGER (Zurufe Erguen 19.08.) ------------------
   Wie ein Aufkleber im Schaufenster eines Einkaufszentrums: rund, in der
   SALE-Palette des Aktionsbands (#ff3d6e→#ff7a3d — Gold bleibt dem
   Online-Shop-Knopf, Regel 1.376.0), und er PENDELT leicht, als hinge er
   an einem Faden. GESCHWUNGEN WIRD UEBER DIE `rotate`-EIGENSCHAFT, nicht
   ueber transform: die Szenen-Fassung braucht transform-freies Zentrieren
   (`translate:-50% 0`), und eine transform-Animation ERSETZTE jede
   Deklaration daneben (Lehre 1.633.0 — die Lage steht in Variablen bzw.
   eigenen Eigenschaften, nie in einer zweiten transform-Regel). */
.sale-rund{
  position:absolute;
  display:grid;
  place-content:center;
  gap:1px;
  aspect-ratio:1/1;
  padding:0;
  border:0;
  border-radius:50%;
  background:
    radial-gradient(120% 120% at 30% 22%, rgba(255,255,255,.34), rgba(255,255,255,0) 44%),
    linear-gradient(135deg,#ff3d6e,#ff7a3d);
  color:#fff;
  text-align:center;
  cursor:pointer;
  box-shadow:
    0 18px 44px rgba(214,42,84,.36),
    inset 0 0 0 2px rgba(255,255,255,.55);
  transform-origin:50% -46%;            /* der gedachte Faden ueber dem Kreis */
  animation:saleRundSchwingen 3.8s ease-in-out infinite;
  /* Damit er nach einer Blaetterfahrt zurueck ins Bild GLEITET statt
     hineinzuspringen — die Ausblendung waehrend der Fahrt steht weiter
     unten bei html.blaettert. */
  transition:opacity .28s ease;
}
/* Der Faden, an dem er haengt — nur Zierde, faengt keine Klicks. */
.sale-rund::before{
  content:"";
  position:absolute;
  left:50%;
  bottom:100%;
  width:2px;
  height:26px;
  margin-left:-1px;
  background:linear-gradient(180deg,rgba(12,26,32,0),rgba(12,26,32,.4));
  pointer-events:none;
}
/* DIE SCHRIFT WANDERT MIT DER BALLGROESSE (1.699.0). GEMESSEN im Bild
   direkt nach dem Verkleinern: mit den alten 36 px stand "SALE" links und
   rechts UEBER den 100-px-Kreis hinaus und "JETZT IM SHOP" brach auf zwei
   Zeilen — die Zahlen der Schrift waren gegen die alte Ballbreite (122 px)
   gerechnet. Rund ein Viertel der Ballbreite traegt das Wort, `nowrap`
   haelt die Unterzeile einzeilig. */
.sale-rund-wort{
  font:900 clamp(17px,1.72vw,27px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
}
.sale-rund-sub{
  font:800 clamp(7.5px,.58vw,9.5px)/1.2 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  white-space:nowrap;
  opacity:.92;
}
.sale-rund:hover,
.sale-rund:focus-visible{
  outline:none;
  box-shadow:
    0 22px 54px rgba(214,42,84,.46),
    inset 0 0 0 2px rgba(255,255,255,.75),
    0 0 0 6px rgba(255,61,110,.18);
}
/* RUHIGER (1.699.0, Zuruf Erguen: "SALE-Ball baendigen"). GEMESSEN in der
   TV-Szene bei 1600x900: der Ball stand mit 134 px Bildbreite (rotiert) nur
   12 px ueber der Eyebrow-Zeile "05 — TV & Entertainment", sein 44-px-Schein
   lag darauf. Der Ausschlag halbiert sich (6 -> 3.2 Grad) und der Takt wird
   laenger (3.8 -> 5.6 s): er haengt weiter wie im Schaufenster, zieht aber
   den Blick nicht mehr staendig von der Ueberschrift weg. */
@keyframes saleRundSchwingen{
  0%,100%{ rotate:-3.2deg }
  50%{ rotate:3.2deg }
}
/* Im Hero haengt er ueber der Mobilfunk-Wand — Prozentmasse gegen dasselbe
   Motiv wie die Zonen (object-fit:fill streckt das Bild immer auf die
   volle Flaeche, Prozent traegt deshalb, Lehre Haendlerseiten-Stand
   e3083f3). Ueber den Zonen (z 20), damit der Klick IHN trifft; der Rest
   der Wand oeffnet weiter Mobilfunk. */
/* OBEN ANGEHEFTET (Zuruf Erguen 19.08.: "sale im shop oben anheften so
   das man mobilfunk lesen kann"): bei top:21% deckte der Anhaenger die
   MOBILFUNK-Wandtafel des Shop-Motivs (GEMESSEN: Badge 181..339, Tafel ab
   y 221 = 27,8 % der Hero-Hoehe). Jetzt haengt er direkt unter der
   Kopfleiste (68 px hoch, gemessen) — der Faden verschwindet hinter ihr
   (z 140 > 24) und liest sich als Aufhaengung an der Kante. Und er steht
   LINKS NEBEN der Tafel (left:35 %): die Tafel beginnt bei 45,8 % der
   Bildbreite; in voller Groesse passt der Anhaenger nicht in die 150 px
   zwischen Kopfleiste und Tafelkante — kleiner wuerde sein Text unlesbar
   (sale-rund-wort min. 22 px). Prozent traegt, weil object-fit:fill das
   Motiv immer auf die volle Flaeche streckt. */
.sale-rund-hero{
  left:35%;
  top:74px;
  /* KLEINER (1.699.0): 148 -> 120 px Deckel. Er deckte die obere Kante der
     Mobilfunk-Nische; das Wort SALE bleibt bei 120 px lesbar (sale-rund-wort
     rechnet mit 2.3vw und faellt nie unter 22 px). */
  width:clamp(82px,7.4vw,120px);
  z-index:24;
}
/* In den Szenen (Mobilfunk, TV) haengt er mittig ueber dem Produkt — unter
   der klebenden Kopfzeile, ueber dem Geraet. Er blendet mit der Szene
   (data-anim → --r), sonst stuende er in der Ueberlappung zweier Szenen
   doppelt im Bild. */
.sale-rund-szene{
  left:50%;
  top:clamp(70px,9.5vh,116px);
  /* KLEINER (1.699.0, GEMESSEN): mit 122 px endete der Ball in der TV-Szene
     bei y 213 und die Eyebrow begann bei 225 — 12 px Luft, in die sein
     Schein hineinreichte. 100 px ergeben rund 34 px Abstand. */
  width:clamp(72px,6.2vw,100px);
  translate:-50% 0;
  z-index:8;
  opacity:var(--r,1);
}
/* IN DER TV-SZENE HAENGT ER LINKS NEBEN DEM FERNSEHER (19.08.). Der
   Fernseher ist gewachsen und steht hoeher (siehe .tv-stage); mittig
   ueber der Buehne saesse der Anhaenger damit AUF dem Bildschirm statt
   darueber — an den Bildpunkten gemessen fehlte oben genau ein Pixel.
   Er behaelt seine Hoehe unter der Kopfleiste und rueckt nur waagerecht:
   26 % = Mitte 416, also 355..477 (1600) bzw. 284..381 (1280) — die
   linke Kante des Fernsehers (breiteste Pose, an den Bildpunkten
   gemessen) liegt bei 528 (1600) bzw. 416 (1280); mit 28 % blieben am
   1280er nur 2 px Luft zum Geraet. Die Kopfzeile beginnt erst bei y 262
   (1600) bzw. 204 (1280), er deckt sie nicht. In Mobilfunk bleibt er
   mittig ueber dem Telefon (unveraendert). */
[data-scene-content="tv"] .sale-rund-szene{ left:26% }
/* Die 1.649er-Kurzmodus-Ausnahme (Anhaenger auf 26 % in Mobilfunk und
   Zubehoer) ist mit 1.650.0 GEFALLEN: ihr Anlass war der MITTIG sitzende
   Unterseiten-Pager — der wohnt seither oben rechts, die Mitte ist wieder
   frei, und der Anhaenger haengt in beiden Fassungen am selben Platz. */
@media (prefers-reduced-motion: reduce){
  .sale-rund{ animation:none; rotate:none }
}
/* Unter 900px wird die Buehne eng — dieselbe Grenze, ab der auch der
   Scooter nie fuhr: lieber kein Anhaenger als einer auf der Ueberschrift. */
@media (max-width:900px){
  .sale-rund{ display:none }
}

/* --- SALE-Banner (links) --- */
/* DIE HIDDEN-FALLE, wieder zugeschnappt: `display:inline-flex` schlaegt
   das `hidden`-Attribut. Mit `sale.active:false` stand der Banner zwar
   auf hidden — und war trotzdem im Bild (von der Sonde gemessen: Flaeche
   grosser als 0). Jede eigene display-Regel an einem Element mit hidden
   braucht ihre Gegenregel. */
.sale-banner[hidden]{ display:none }
.sale-banner{
  left:clamp(16px,2vw,34px);
  display:inline-flex;
  align-items:center;
  gap:12px;
  padding:0 clamp(18px,1.6vw,26px) 0 0;
  height:clamp(46px,3.4vw,56px);
  border:0;
  border-radius:999px;
  background:#0c1a20;
  color:#fff;
  font:900 clamp(11px,.84vw,13px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  box-shadow:0 14px 34px rgba(8,38,48,.3);
  overflow:hidden;
}
html[data-scene="mobile"] .sale-banner,
html[data-scene="accessories"] .sale-banner{
  opacity:1;
  transform:none;
  pointer-events:auto;
}
.sale-banner-flag{
  display:grid;
  place-items:center;
  align-self:stretch;
  padding:0 clamp(14px,1.3vw,20px);
  background:linear-gradient(135deg,#ff3d6e,#ff7a3d);
  color:#fff;
  font-weight:900;
  letter-spacing:.14em;
  position:relative;
  overflow:hidden;
}
/* Wanderndes Licht im Flag — auffaellig, aber nicht blinkend */
.sale-banner-flag::after{
  content:"";
  position:absolute;
  inset:-40% -60%;
  background:linear-gradient(110deg,transparent 38%,
             rgba(255,255,255,.45) 50%,transparent 62%);
  transform:translateX(-60%);
  animation:saleSheen 3.4s ease-in-out infinite;
}
@keyframes saleSheen{
  0%,55%{transform:translateX(-70%)}
  90%,100%{transform:translateX(70%)}
}
.sale-banner:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 42px rgba(8,38,48,.36);
}
.sale-banner:focus-visible{
  outline:none;
  box-shadow:0 14px 34px rgba(8,38,48,.3),
             0 0 0 3px rgba(255,61,110,.5);
}

/* --- „Unsere aktuellen Angebote" (fest, unten links) ---
   Zuruf Erguen 15.08.: "ab mobilfunk unten links einen Button mit Unsere
   Aktuellen Angebote ... so dass es nirgends überlappt und zu den
   angeboten führt". Sichtbar auf JEDER Szene ausser dem Hero — die
   aktive Szene steht als html[data-scene] am Wurzelelement (von
   scroll-story gesetzt), ein eigener Scroll-Rechner waere eine zweite
   Wahrheit. Unten links wohnt sonst nur der (abgeschaltete) Sale-Banner;
   laeuft der eines Tages wieder, rueckt dieser Knopf per :has() ueber
   ihn, statt ihn zu verdecken. Der Scooter faehrt eine Ebene tiefer
   vorbei (z 108 < 124). Unter 760px bleibt der Knopf weg: dort saesse er
   auf dem mittigen Scroll-Hinweis, und die Kopfnavigation traegt den Weg. */
.ang-aktuell{
  position:fixed;
  z-index:124;
  /* Der Einkaufswagen steht VOR der Beschriftung (Zuruf Erguen 15.08.:
     „ein passenden einkaufswagen symbol") — dafuer braucht der Knopf ein
     Flex-Layout; vorher trug er nur Text. */
  display:inline-flex;
  align-items:center;
  gap:9px;
  left:clamp(16px,2vw,34px);
  bottom:clamp(18px,3vh,34px);
  height:clamp(42px,3.2vw,52px);
  padding:0 clamp(16px,1.5vw,24px);
  border:0;
  border-radius:999px;
  background:#0c1a20;
  color:#fff;
  font:900 clamp(10px,.78vw,12.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  /* Schatten, Ring und Puls tragen ihre FARBEN als Variablen mit
     tuerkisen Vorgabewerten: die Mobilfunk-Szene faerbt den Knopf gold
     (Zuruf 20.08.) und wechselt dafuer nur die --fab-*-Werte — Form,
     Puls und Hover bleiben EINE Regel statt je Szene eine Kopie. */
  --fab-schatten:rgba(6,20,26,.28);
  --fab-schatten2:rgba(6,20,26,.36);
  --fab-rand:rgba(18,199,224,.35);
  --fab-rand2:rgba(18,199,224,.55);
  --fab-rand-voll:rgba(18,199,224,.7);
  --fab-puls:rgba(18,199,224,.34);
  --fab-puls-aus:rgba(18,199,224,0);
  --fab-fokus:rgba(18,199,224,.45);
  box-shadow:0 14px 30px var(--fab-schatten), inset 0 0 0 1px var(--fab-rand);
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  transform:translateY(16px);
  transition:opacity .45s ease, transform .45s cubic-bezier(.2,.8,.2,1),
             visibility 0s linear .45s;
}
/* SICHTBAR AB DER MOBILFUNK-SZENE — UND NICHT AUF DER LETZTEN (Zuruf
   Erguen 15.08.: "unsere aktuellen angebote button auf der letzten seite
   ausblenden"). Auf der Termin-Szene stehen Kontaktkarten und Fusszeile;
   dort ist der Besucher am Ziel und braucht keinen Ruecksprung mehr.
   AUCH NICHT AUF DER ANGEBOTE-SZENE (Zuruf Erguen 19.08.: "auf dieser
   seite unten links den button ausblenden dafür den alle angebote kachel
   viel höher"): dort steht das Sortiment selbst vor dem Besucher, und die
   goldene breite Kachel ist der Weg — ein zweiter Knopf in der Ecke
   fuehrte auf dieselbe Seite.
   AUCH NICHT AUF DER REPARATUR-SZENE (Zuruf Erguen 19.08.: "auf der
   reparatur seite den unsere aktuellen abgebote button entfernen"):
   dort geht es um den Service, nicht um den Verkauf — die Wege der
   Szene sind die beiden mittigen Reparatur-Knoepfe.
   AUCH NICHT AUF DER INTERNET-SZENE (Zuruf Erguen 20.08.: "auf dieser
   seite unsere aktuellen abgebote button entfernen"): die Monatsangebot-
   Karte traegt dort selbst "Weitere Angebote im Shop" — der FAB daneben
   war derselbe Weg ein zweites Mal. Die 1.643er-Versatzregel (FAB rechts
   neben der Karte) ist MIT entfallen (kein toter Codeweg; Weg zurueck:
   Git 1.652.0/1.653.0). */
html[data-scene]:not([data-scene="hero"]):not([data-scene="appointment"]):not([data-scene="offers"]):not([data-scene="repair"]):not([data-scene="internet"]):not([data-scene="accessories"]) .ang-aktuell{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transform:none;
  /* LEICHT PULSIEREND (Zuruf Erguen 15.08.). Ein ruhiger Atem im
     Akzent-Ring, KEIN Gold — das gehoert der Handlung (Shop-Knopf), und
     zwei goldene Flaechen in einem Bild heben sich gegenseitig auf.
     Beim Ueberfahren haelt er an, bei ruhiger Bewegung bleibt der Ring
     stehen statt zu atmen. */
  animation:angAktuellAtem 3.2s ease-in-out infinite;
  transition:opacity .45s ease, transform .45s cubic-bezier(.2,.8,.2,1),
             visibility 0s;
}
@keyframes angAktuellAtem{
  0%,100%{ box-shadow:0 14px 30px var(--fab-schatten), inset 0 0 0 1px var(--fab-rand), 0 0 0 0 var(--fab-puls) }
  55%{ box-shadow:0 14px 30px var(--fab-schatten), inset 0 0 0 1px var(--fab-rand-voll), 0 0 0 8px var(--fab-puls-aus) }
}
/* Der Wagen faerbt sich ueber `currentColor` mit und nimmt keinen Zeiger —
   sonst waere `e.target` bei einem Klick darauf ein SVG-Pfad. */
.ang-aktuell-sym{
  width:17px; height:17px; flex:0 0 auto;
  pointer-events:none;
}
.ang-aktuell:hover{ animation:none }
@media (prefers-reduced-motion: reduce){
  html[data-scene] .ang-aktuell{ animation:none }
}
html.shop-open .ang-aktuell{
  opacity:0 !important;
  pointer-events:none !important;
}
/* KEINE KNOEPFE DER VORIGEN SEITE WAEHREND DER FAHRT (Zuruf Erguen 20.08.:
   "es dürfen waehrend des scrollens keine buttons aus der vorherigen seite
   beim blaettern übernommen werden" — sein Bildschirmfoto zeigte den
   goldenen Mobilfunk-FAB und den SALE-Anhaenger ueber der einfahrenden
   Internet-Szene, den Anhaenger sogar doppelt).
   Waehrend der 1,15 s stehen ZWEI Szenen im Bild; ihr INHALT gehoert dazu,
   ihre schwebenden Knoepfe nicht — die gelten immer nur fuer die Seite,
   auf der man ANKOMMT. `blaettert` setzt js/scroll-story.js fuer die Dauer
   der Fahrt.
   `!important` wie an der Zeile darueber: die Sichtbarkeitsregel des FAB
   traegt fuenf :not()-Bedingungen und waere sonst staerker.
   DIE LISTE IST DIE VOLLSTAENDIGE LISTE der szenengebundenen schwebenden
   Knoepfe — sie ist an `position:fixed` im ganzen Stylesheet abgelesen,
   nicht aus dem Kopf geschrieben. Draussen bleiben mit Absicht die
   DAUERHAFTEN Bedienelemente: Kopfleiste, Fortschrittsleiste, Goldbalken
   und der Chat-Knopf gehoeren keiner Seite, sie gelten ueberall. */
html.blaettert .ang-aktuell,
html.blaettert .sale-rund,
html.blaettert .check-fab,
html.blaettert .sale-banner,
/* `rollt` setzt js/scroll-story.js bei JEDEM Rollen (Zuruf Erguen 20.08.:
   "beim scrollen kommt der unsere aktuelle angebote button mit auf die
   neue seite was es aber nicht soll"). `blaettert` deckt nur die eigene
   Blaettermaschine ab — Rollbalken, Tastatur, ein Sprung aus der
   Kopfleiste und das Nachrasten erzeugen dieselben Zwischenstaende. */
html.rollt .ang-aktuell,
html.rollt .sale-rund,
html.rollt .check-fab,
html.rollt .sale-banner,
/* Der Scooter faehrt ebenfalls schwebend und gehoert einem Szenenband
   (Mobilfunk bis Reparatur). Sein Skript ist seit 1.639.0 stillgelegt —
   Markup und Modell stehen als "Weg zurueck" weiter da; wird er je wieder
   angeschaltet, wandert er nicht mit. */
html.blaettert .scooter-fahrt,
html.rollt .scooter-fahrt{
  opacity:0 !important;
  pointer-events:none !important;
  /* `transition:none` IST DER EIGENTLICHE RIEGEL, nicht Zierde.
     GEMESSEN (20.08.): mit einem weichen Uebergang blieb der SALE-Anhaenger
     bei voller Deckkraft stehen, obwohl die Regel hier `!important` traegt
     und der Anhaenger sie nachweislich trifft. Der Grund steht in der
     Rangfolge der Kaskade: eine LAUFENDE Ueberblendung steht GANZ OBEN —
     ueber jedem `!important` des Autors. Der Anhaenger traegt seit 1.653.0
     `transition:opacity .28s`, die Fahrt startete also eine Ueberblendung,
     und solange die laeuft, gewinnt sie gegen diese Regel.
     `transition:none` bricht eine laufende Ueberblendung ab (die
     Eigenschaft steht danach nicht mehr in `transition-property`) und die
     Null greift sofort. Weich bleibt es trotzdem: der Schleier darunter
     traegt den Uebergang, und beim ZURUECKKOMMEN gilt wieder die eigene
     Ueberblendung des Knopfes — er gleitet ins Bild, statt zu springen. */
  transition:none !important;
}

/* DER UEBERGANG SOLL VERSCHMELZEN, NICHT ANEINANDERSTOSSEN (Zuruf Erguen
   20.08.: "… und nicht überlappt und mit der neuen seite verschmelzt").
   Waehrend der Fahrt legt sich ein heller Schleier ueber die Buehne und
   nimmt sich danach wieder zurueck — die alte Seite geht damit weich in
   die neue ueber, statt an einer harten Kante stehenzubleiben.
   z-index 130 ist bewusst gewaehlt: UEBER dem Szeneninhalt, der
   Fortschrittsleiste (120) und den schwebenden Knoepfen (124), aber UNTER
   der Kopfleiste (140) und dem Goldbalken (210) — das dauerhafte Geruest
   der Seite blinkt nicht mit.
   Die Dauer entspricht der Flugzeit in js/scroll-story.js (1150 ms). Wer
   sie dort aendert, aendert sie hier mit. */
html.blaettert::after{
  content:"";
  position:fixed;
  inset:0;
  z-index:130;
  pointer-events:none;
  /* Der Grund der Seite selbst (body in css/hero.css) — der Schleier ist
     eine Aufhellung, keine fremde Farbe. */
  background:#f8fbfc;
  animation:blaetterSchleier 1.15s ease both;
}
@keyframes blaetterSchleier{
  0%   { opacity:0 }
  42%  { opacity:.26 }
  100% { opacity:0 }
}
@media (prefers-reduced-motion:reduce){
  html.blaettert::after{ animation:none; opacity:0 }
}

/* KEIN EINRASTEN WAEHREND DER FAHRT (Zuruf Erguen 20.08.: "ich will auf
   jedenfall diesen übergangseffekt funktionierend auf allen browsern
   haben"). `scroll-snap-type:y mandatory` und ein programmgesteuertes
   Rollen sind zwei Kraefte auf derselben Achse: Chromium laesst das JS
   gewaehren, andere Maschinen rasten mitten im Flug zurueck — dort bricht
   der Uebergang ab. Fuer die Dauer der Fahrt ist das Rasten deshalb aus;
   am Flugende steht die Seite exakt auf einem Rastpunkt, das
   Wiedereinschalten bewegt also nichts. */
html.blaettert:not(.ang-tab){ scroll-snap-type:none; }
html:has(.sale-banner:not([hidden])) .ang-aktuell{
  bottom:calc(clamp(18px,3vh,34px) + 68px);
}
/* MITTIG UNTER DEM OBJEKT (Zurufe Erguen 19.08.: "unsere aktuellen
   angebote button unter dem telefon" / "auch hier den button mittig"
   (Zubehoer) / "unter dem tv"). In diesen Szenen steht das Beworbene
   mittig — der Knopf rueckt darunter. INTERNET steht seit dem Zuruf vom
   20.08. nicht mehr in der Liste: dort gibt es den FAB gar nicht mehr
   (Ausnahme in der Sichtbarkeitsregel oben).
   Zentriert wird ueber die `translate`-EIGENSCHAFT, nicht ueber
   transform: dort wohnen Einblendung (translateY(16px)) und Hover
   (translateY(-2px)), und eine zweite transform-Deklaration ERSETZTE sie
   (Lehre 1.633.0). Der Abstand nach unten haengt am SCROLL-HINWEIS
   (bottom:clamp(18px,3.4vh,34px) + rund 54 px Hoehe): +62 px setzen den
   Knopf knapp UEBER ihn, an jeder Fensterhoehe (gemessen 900: Knopf
   756..807, Hinweis ab 827; 720: Knopf 592..634, Hinweis ab 646).
   REPARATUR bleibt links: die Mitte gehoert dort .rep-actions. */
html[data-scene="mobile"] .ang-aktuell,
html[data-scene="tv"] .ang-aktuell{
  left:50%;
  translate:-50% 0;
  bottom:calc(clamp(18px,3.4vh,34px) + 62px);
}
/* IM ZUBEHOER GIBT ES DEN FAB NICHT MEHR (Zuruf Erguen 20.08.: "auf dieser
   seite unsere aktuellen ambegote button entfernen"). Der Weg in die
   Angebote steht dort schon als tuerkiser CTA "Finde das passende Zubehoer
   in unserem Shop" mitten unter der Ueberschrift — der FAB doppelte ihn.
   Mit ihm ist auch die Textachsen-Versatzregel ERSATZLOS entfallen: sie
   versetzte einen Knopf, den es in der Szene nicht mehr gibt (kein toter
   Codeweg; Weg zurueck: Git 1.657.0). Dieselbe Entscheidung wie bei der
   Internet-Szene in 1.654.0. */
/* Die 1.643er-Internet-Versatzregel (FAB rechts neben der Karte) ist mit
   dem Entfernen des FAB aus der Internet-Szene (Zuruf 20.08.) ERSATZLOS
   raus — kein toter Codeweg; Weg zurueck: Git 1.652.0/1.653.0. */
.ang-aktuell:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 40px var(--fab-schatten2), inset 0 0 0 1px var(--fab-rand2);
}
.ang-aktuell:focus-visible{
  outline:none;
  box-shadow:0 14px 30px var(--fab-schatten), 0 0 0 3px var(--fab-fokus);
}
/* AUF DER MOBILFUNK-SZENE IST DER FAB GOLD (Zuruf Erguen 20.08.: "auf
   dieser seite unsere aktuellen angebote button in gold", Bildschirmfoto
   der Mobilfunk-Szene mit dem dunklen Knopf unter dem Telefon).
   DIESELBEN Goldwerte wie Shop-Knopf und "Alle Angebote"-Kachel — EIN
   Gold im Haus, nicht drei. KEIN var(--gold): MOS-Token, auf der
   Haendlerseite nicht definiert — eine unbekannte Variable macht die
   ganze Deklaration ungueltig (Regel 1.632.0). Ring, Atem-Puls, Hover
   und Fokusring kommen ueber die --fab-*-Variablen aus DENSELBEN Regeln
   und Keyframes wie ueberall; hier wechseln nur die Farbwerte auf die
   Goldfamilie. NUR diese eine Szene — die uebrigen behalten das dunkle
   Navy mit tuerkisem Ring. */
html[data-scene="mobile"] .ang-aktuell{
  background:linear-gradient(140deg,#e6bc50,#c99a2e);
  color:#231903;
  --fab-schatten:rgba(120,86,14,.30);
  --fab-schatten2:rgba(120,86,14,.40);
  --fab-rand:#a8801f;
  --fab-rand2:#8a6717;
  --fab-rand-voll:#7a5c10;
  --fab-puls:rgba(201,154,46,.45);
  --fab-puls-aus:rgba(201,154,46,0);
  --fab-fokus:rgba(201,154,46,.55);
}
@media (max-width:760px){
  .ang-aktuell{ display:none }
}

/* --- Zubehoer-Szene: Weg zu den Angeboten unter der Ueberschrift ---
   (Zuruf Erguen 15.08.: "hier ein button mit Finde das passende Zubehör
   in unserem Shop - öffnet dann unsere Angebote"). Er faehrt mit der
   Ueberschrift ein und aus (anim-Fenster in buildAccessories). */
.acc-angebote{
  /* UNTER DAS 3D-OBJEKT (Zuruf Erguen 15.08.: "button unter das 3d objekt")
     — mittig im Intro lag er MITTEN AUF Huelle, Kopfhoerer und Powerbank.
     Die Objekte stehen bei top:50% und sind so hoch wie ihre Breite durch
     das Seitenverhaeltnis (16/9): halbe Hoehe = Breite x 9/32. Genau darum
     rutscht der Knopf nach unten — er WANDERT damit mit der Objektgroesse
     mit, statt an einer geratenen Zahl zu haengen. Der Bezugsrahmen ist
     die Buehne (.fin-wrap ist absolut ueber sie gespannt). */
  position:absolute;
  /* AUF DER TEXTACHSE, NICHT DER FENSTERMITTE (Zuruf Erguen 20.08.:
     "die beiden button und zentriert nach links unter dem text"): die
     Ueberschrift steht mittig in der Inhaltsbox von .acc-intro
     (links Polster edge+gutter, rechts dasselbe PLUS Kartenspur+24) —
     die beiden edge+gutter kuerzen sich heraus, uebrig bleibt
     (100% − Kartenspur − 24) / 2. GEMESSEN: Textmitte 604 bei 1600. */
  left:calc((100% - clamp(272px,23vw,368px) - 24px) / 2);
  /* Der Deckel haelt ihn auch auf flachen Fenstern in der Buehne: sonst
     rutschte er bei 600 px Hoehe unter die Kante. */
  /* Der Abstand zum Objekt ist seit 19.08. knapper (16..34 -> 8..16 px):
     darunter steht jetzt der zentrierte "Unsere aktuellen Angebote"-Knopf
     (gemessen 900: CTA endete bei 759, der Knopf beginnt bei 756 — ohne
     die Anhebung laegen beide uebereinander). */
  /* Der Deckel rechnet gegen die LAGE DES ANGEBOTE-KNOPFS darunter
     (Hinweis-Abstand + 70 px Luft/Knopfabstand + Knopf- und CTA-Hoehe) —
     eine feste Zahl hielt bei 1280x720 nicht: dort endete der CTA bei
     600, der Knopf begann bei 592 (gemessen, 8 px uebereinander). */
  top:min(calc(50% + (clamp(320px,52vw,860px) * 9 / 32) + clamp(8px,1.2vh,16px)),
          calc(100% - (clamp(18px,3.4vh,34px) + clamp(42px,3.2vw,52px)
                       + clamp(44px,3.2vw,54px) + 70px)));
  transform:translateX(-50%);
  margin-top:0;
  height:clamp(44px,3.2vw,54px);
  padding:0 clamp(20px,2vw,30px);
  border:0;
  border-radius:999px;
  background:linear-gradient(135deg,#0f8ea3,#12b3c9);
  color:#fff;
  font:900 clamp(11px,.84vw,13.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  cursor:pointer;
  pointer-events:auto;
  box-shadow:0 16px 36px rgba(15,142,163,.32);
  transition:transform .2s ease, filter .2s ease;
}
.acc-angebote:hover,
.acc-angebote:focus-visible{ transform:translateX(-50%) translateY(-2px); filter:brightness(1.06) }
.acc-angebote:focus-visible{ outline:none; box-shadow:0 16px 36px rgba(15,142,163,.32), 0 0 0 3px rgba(18,199,224,.4) }
/* Der Pfeil auf den Knopf (Zuruf 19.08.) — haengt oben links AUS dem Knopf
   heraus und nickt in seine Zeigerichtung (unten rechts). Navy wie die
   Hausschrift, damit er auf dem hellen Grund steht, ohne mit dem petrolnen
   Knopf zu verschwimmen. */
.acc-pfeil{
  position:absolute;
  bottom:calc(100% + 4px);
  left:-52px;
  width:clamp(44px,4vw,64px);
  aspect-ratio:1/1;
  color:#0c1a20;
  pointer-events:none;
  animation:accPfeilNicken 1.15s ease-in-out infinite alternate;
}
.acc-pfeil svg{ width:100%; height:100% }
@keyframes accPfeilNicken{
  from{ translate:0 0 }
  to{ translate:7px 6px }
}
@media (prefers-reduced-motion: reduce){
  .acc-pfeil{ animation:none }
}

.sale-badge{
  display:inline-block;
  margin-bottom:12px;
  padding:7px 14px;
  border-radius:999px;
  background:linear-gradient(135deg,#ff3d6e,#ff7a3d);
  color:#fff;
  font:900 clamp(12px,1vw,16px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
}
.sale-price{
  display:flex;
  align-items:baseline;
  gap:10px;
  margin:clamp(14px,1.6vw,20px) 0;
}
.sale-price b{
  color:var(--ink);
  font-size:clamp(26px,2.6vw,40px);
  font-weight:900;
  letter-spacing:-.04em;
  font-variant-numeric:tabular-nums;
}
.sale-price span{
  color:var(--ink-soft);
  font-size:clamp(12px,.9vw,14px);
}
.sale-points{
  margin:0 0 clamp(18px,2vw,26px);
  padding:0;
  list-style:none;
  display:grid;
  gap:9px;
}
.sale-points li{
  position:relative;
  padding-left:26px;
  color:var(--ink-mid);
  font-size:clamp(13px,.95vw,15px);
  line-height:1.5;
}
.sale-points li::before{
  content:"";
  position:absolute;
  left:2px;
  top:.45em;
  width:9px;
  height:5px;
  border:2px solid var(--accent-deep);
  border-top:0;
  border-right:0;
  transform:rotate(-45deg);
}
/* Bundle-Karte im Aktions-Overlay: zeigt die Bestandteile des Sets
   typografisch — bewusst ohne fremde Marken-Grafiken. */
.sale-bundle{
  display:flex;
  align-items:stretch;
  gap:clamp(8px,.8vw,12px);
  margin:clamp(16px,1.8vw,24px) 0 clamp(18px,2vw,26px);
}
.sale-bundle-item{
  flex:1 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  justify-content:center;
  gap:4px;
  padding:clamp(12px,1.2vw,18px) clamp(12px,1.2vw,18px);
  border:1px solid rgba(9,58,72,.12);
  border-radius:16px;
  background:linear-gradient(150deg,rgba(255,255,255,.9),rgba(233,250,253,.7));
}
.sale-bundle-kind{
  color:var(--accent-deep);
  font:800 clamp(10px,.72vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
}
.sale-bundle-item b{
  color:var(--ink);
  font-size:clamp(14px,1.05vw,18px);
  font-weight:800;
  letter-spacing:-.02em;
  line-height:1.25;
}
.sale-bundle-plus{
  align-self:center;
  color:var(--ink-soft);
  font:300 clamp(18px,1.5vw,24px)/1 Inter,system-ui,sans-serif;
}

.sale-actions{
  margin-top:clamp(4px,.6vw,8px);
}

/* --- Verfuegbarkeits-Check (rechts) --- */
/* HALBE GROESSE (Zuruf Erguen 14.08.: „die button um die haelfte kleiner
   machen"). Halbiert sind Hoehe, Polster und Abstand; die SCHRIFT geht nur
   auf rund drei Viertel — 6 px Versalien mit Sperrung liest niemand mehr,
   und ein Knopf, den man nicht lesen kann, ist kein kleinerer Knopf. */
/* ETWAS GROESSER, WIEDER GUT ZU TREFFEN (Zuruf Erguen 14.08.: "button
   etwas grösser wieder unten rechts"). In 1.622.0 waren die drei
   Schwebeknoepfe halbiert worden, damit sie dem Bild nicht die Ecke
   nehmen — das war zu weit: 30 px hoch mit 10-px-Schrift ist am Telefon
   kaum zu treffen. Jetzt rund ein Drittel groesser (40 statt 30 px), aber
   deutlich unter der vollen Pille des Kopf-Knopfs (44 px). Die drei
   Knoepfe teilen sich diese Masse — wer einen aendert, aendert alle. */
.check-fab{
  right:clamp(16px,2vw,34px);
  display:inline-flex;
  align-items:center;
  gap:8px;
  height:clamp(34px,2.5vw,40px);
  padding:0 clamp(13px,1.1vw,18px) 0 clamp(8px,.65vw,10px);
  border:1px solid rgba(255,255,255,.7);
  border-radius:999px;
  background:linear-gradient(140deg,#13cbe4,#0a90a8);
  color:#03242b;
  font:900 clamp(10px,.74vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  box-shadow:0 8px 20px rgba(10,110,130,.32);
}
html[data-scene="internet"] .check-fab{
  opacity:1;
  transform:none;
  pointer-events:auto;
}

/* DER SCHWEBENDE ZUBEHOER-KNOPF IST MIT 1.699.0 ERSATZLOS AUSGEBAUT
   (Befund Erguen: "CTA-Wiederholungen der Zubehoer-Szene reduzieren").
   GEZAEHLT im Bild der Szene fuehrten FUENF sichtbare Wege in denselben
   Shop: der breite Knopf "Finde das passende Zubehoer in unserem Shop",
   der Karten-Knopf "Im Shop bestellen", die sechs Kategorie-Kacheln
   links, "Online Shop" im Kopf — und dieser schwebende. Er sagte
   woertlich dasselbe wie der breite Knopf mitten im Bild und war die
   DRITTE goldene Flaeche darin. Der Weg bleibt vollstaendig erhalten;
   Weg zurueck: Git (1.698.0). */
.check-fab:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 42px rgba(10,110,130,.4);
}
.check-fab:focus-visible{
  outline:none;
  box-shadow:0 14px 34px rgba(10,110,130,.34),
             0 0 0 3px rgba(18,199,224,.55);
}
.check-fab-icon{
  position:relative;
  display:grid;
  place-items:center;
  width:clamp(18px,1.35vw,21px);
  height:clamp(18px,1.35vw,21px);
  border-radius:50%;
  background:rgba(255,255,255,.9);
}
.check-fab-icon svg{
  position:relative;
  z-index:2;
  width:12px;
  height:12px;
  fill:none;
  stroke:#0a8ea5;
  stroke-width:2.2;
  stroke-linecap:round;
}
.check-fab-icon circle{
  fill:#0a8ea5;
  stroke:none;
}
/* Radar-Wellen: signalisieren "wir prüfen" */
.check-fab-wave{
  position:absolute;
  inset:0;
  border-radius:50%;
  border:2px solid rgba(255,255,255,.85);
  opacity:0;
  animation:checkPing 2.6s ease-out infinite;
}
.check-fab-wave:nth-child(2){
  animation-delay:1.3s;
}
@keyframes checkPing{
  0%{opacity:.75;transform:scale(1)}
  70%,100%{opacity:0;transform:scale(2.1)}
}

/* --- Hauptweg: echter Anbieter-Check --- */
.check-primary{
  padding:clamp(18px,1.9vw,26px);
  border:1px solid rgba(18,199,224,.35);
  border-radius:20px;
  background:linear-gradient(140deg,rgba(18,199,224,.09),rgba(18,199,224,.02));
}
.check-primary-cta{
  border:0;
}
.check-primary-note{
  margin:clamp(10px,1.1vw,15px) 0 0;
  max-width:58ch;
  color:var(--ink-mid);
  font-size:clamp(12px,.88vw,14px);
  line-height:1.55;
}

/* --- Zweitweg: persoenliche Pruefung --- */
.check-alt{
  margin-top:clamp(20px,2.2vw,30px);
  padding-top:clamp(18px,2vw,26px);
  border-top:1px solid var(--hair);
}
.check-alt-title{
  margin:0 0 6px;
  color:var(--ink);
  font-size:clamp(14px,1.05vw,18px);
  font-weight:800;
  letter-spacing:-.015em;
}
.check-alt-sub{
  margin:0 0 clamp(14px,1.6vw,20px);
  max-width:56ch;
  color:var(--ink-mid);
  font-size:clamp(12.5px,.9vw,14.5px);
  line-height:1.55;
}

/* Das fruehere Formular im Check-Overlay (check-form/-field/-submit)
   baut kein JS mehr — der Weg ist der Termin-Knopf (.check-self).
   CSS ENTFERNT; Weg zurueck: Git vor dem Aufraeumen (1.655.0). */

.check-note{
  margin:0;
  max-width:56ch;
  color:var(--ink-soft);
  font-size:clamp(10.5px,.76vw,12.5px);
  line-height:1.5;
}
.check-self{
  display:inline-block;
  /* Ist jetzt ein Button (oeffnet das Terminformular), soll aber
     weiter wie ein schlichter Textlink aussehen. */
  padding:0;
  border:0;
  background:none;
  cursor:pointer;
  font-family:inherit;
  margin-top:clamp(10px,1.2vw,16px);
  color:var(--accent-deep);
  font-size:clamp(11px,.82vw,13px);
  font-weight:800;
  text-decoration:none;
  border-bottom:1px solid rgba(10,142,165,.35);
}
.check-self:hover,
.check-self:focus-visible{
  outline:none;
  color:var(--accent-ink);
  border-bottom-color:currentColor;
}

@media (max-width:760px){
  .sale-banner,
  .check-fab{
    bottom:12px;
  }
  .sale-banner{ left:10px; height:42px; font-size:10px }
  .check-fab{ right:10px; height:26px; font-size:8.5px; padding-right:10px }
  .check-fab-label{ display:none }
  .check-fab{ padding:0 8px }
}

@media (prefers-reduced-motion:reduce){
  .sale-banner,
  .check-fab{ transition:opacity .3s ease; transform:none }
  .sale-banner-flag::after,
  .check-fab-wave{ animation:none }
  .check-fab-wave{ opacity:0 }
}

/* =========================================================
   16f2 — CHAT-KNOPF
   ---------------------------------------------------------
   Er ist auf JEDER Szene da. Damit er nie etwas verdeckt,
   liegt er in derselben Ecke wie der Verfuegbarkeits-Knopf und
   schiebt sich hoch, sobald der erscheint (--chat-lift). So
   kollidiert nichts, egal welche Szene gerade laeuft.
   ========================================================= */
.chat-fab{
  position:fixed;
  z-index:125;
  right:clamp(16px,2vw,34px);
  bottom:calc(clamp(18px,3vh,34px) + var(--chat-lift,0px));
  display:inline-flex;
  align-items:center;
  /* Ruhezustand ist ein Kreis. Als breite Pille lag er staendig auf
     Seiteninhalt -- auf dem Hero mitten in der Vorteilsleiste. Die
     Beschriftung kommt beim Ueberfahren dazu; wer nur liest, sieht
     einen Knopf von der Groesse eines Daumens. */
  gap:0;
  /* DAUMENGROSS (1.790.0, Zuruf Erguen 28.08.: "chatfab zu klein") — 34-40 px
     waren auf grossen Bildschirmen kaum zu sehen; 52-60 px ist zugleich die
     Touch-Mindestgroesse. Icon und Punkt wachsen mit (s. u.). */
  height:clamp(52px,3.6vw,60px);
  width:clamp(52px,3.6vw,60px);
  padding:0;
  justify-content:center;
  overflow:hidden;
  border:1px solid rgba(255,255,255,.6);
  border-radius:999px;
  background:linear-gradient(140deg,#16333d,#0b1f27);
  color:#eafcff;
  font:900 clamp(10.5px,.75vw,12.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  white-space:nowrap;
  cursor:pointer;
  box-shadow:0 8px 20px rgba(8,38,48,.26);
  transition:bottom .42s cubic-bezier(.2,.8,.2,1),
             width .34s cubic-bezier(.2,.8,.2,1),
             gap .34s cubic-bezier(.2,.8,.2,1),
             padding .34s cubic-bezier(.2,.8,.2,1),
             transform .3s cubic-bezier(.2,.8,.2,1),
             box-shadow .3s ease;
}
/* Ist jemand erreichbar, bleibt der Knopf dauerhaft ausgefahren --
   das ist die Ausnahme und die Information, die den Besucher
   interessiert. Offline bleibt er ein zurueckhaltender Kreis. */
.chat-fab.is-online,
.chat-fab:hover,
.chat-fab:focus-visible{
  width:clamp(158px,11vw,184px);
  gap:7px;
  padding:0 clamp(12px,.9vw,15px) 0 clamp(10px,.7vw,12px);
  justify-content:flex-start;
}
.chat-fab-label{
  max-width:0;
  opacity:0;
  transition:max-width .34s cubic-bezier(.2,.8,.2,1), opacity .2s ease;
}
.chat-fab.is-online .chat-fab-label,
.chat-fab:hover .chat-fab-label,
.chat-fab:focus-visible .chat-fab-label{
  max-width:130px;
  opacity:1;
}
/* Erreichbar wird auch farblich deutlich, nicht nur ueber den Punkt. */
.chat-fab.is-online{
  background:linear-gradient(140deg,#0f4a3a,#0a2f26);
  border-color:rgba(61,220,132,.45);
}
/* Waehrend das Chat-Skript nachlaedt: ausgefahren wie im Online-
   Zustand, damit "Wird geoeffnet" lesbar ist, und stumpf gegen den
   zweiten Klick. Ohne das wirkt der Knopf in der Ladesekunde kaputt. */
.chat-fab.is-busy{
  width:clamp(158px,11vw,184px);
  gap:7px;
  padding:0 clamp(12px,.9vw,15px) 0 clamp(10px,.7vw,12px);
  justify-content:flex-start;
  cursor:progress;
}
.chat-fab.is-busy .chat-fab-label{
  max-width:130px;
  opacity:1;
}
.chat-fab.is-busy .chat-fab-dot{
  animation:chatPulse 1s ease-in-out infinite;
}

/* Der Nebenweg "Trotzdem im Chat versuchen" (13.08. frueh) ist mit
   der Zeiten-Tabelle entfallen: der Chat-Knopf oeffnet seit dem
   13.08. abends IMMER den Chat; ob jemand da ist, entscheidet
   das Chat-Widget ueber die Erreichbarkeit. */

/* --chat-lift haelt den Knopf frei von dem, was am unteren Rand
   der jeweiligen Szene steht. Gemessen, nicht geschaetzt: */
html[data-scene="hero"]{
  /* die Vorteilsleiste im Hero -- ihre Hoehe steht als Variable fest */
  --chat-lift:var(--benefit-h,104px);
}
html[data-scene="internet"]{
  /* der Verfuegbarkeits-Knopf in derselben Ecke */
  --chat-lift:clamp(60px,4.6vw,74px);
}
html[data-scene="accessories"]{
  /* der Shop-Knopf des Zubehoer-Bereichs in derselben Ecke */
  --chat-lift:clamp(60px,4.6vw,74px);
}
html[data-scene="appointment"]{
  /* die Fusszeile am Ende der Seite */
  --chat-lift:clamp(76px,7vh,104px);
}
.chat-fab:hover{
  transform:translateY(-2px);
  box-shadow:0 18px 42px rgba(8,38,48,.36);
}
.chat-fab:focus-visible{
  outline:none;
  box-shadow:0 0 0 3px rgba(18,199,224,.55);
}
html.shop-open .chat-fab{
  opacity:0;
  pointer-events:none;
}

.chat-fab-icon{
  display:inline-flex;
  width:20px;
  height:20px;
  flex:0 0 auto;
}
.chat-fab-icon svg{ width:100%; height:100% }

/* Punkt zeigt, ob gerade jemand erreichbar ist. Grau heisst
   nicht "kaputt", sondern "schreib uns" -- der Knopf oeffnet
   dann das Kontaktformular. */
.chat-fab-dot{
  width:10px;
  height:10px;
  border-radius:50%;
  background:#7f9198;
  box-shadow:0 0 0 3px rgba(127,145,152,.22);
  transition:background .3s ease, box-shadow .3s ease;
}
.chat-fab.is-online .chat-fab-dot{
  background:#3ddc84;
  box-shadow:0 0 0 3px rgba(61,220,132,.28);
  animation:chatPulse 2.4s ease-in-out infinite;
}
@keyframes chatPulse{
  50%{ box-shadow:0 0 0 7px rgba(61,220,132,0) }
}

@media (max-width:760px){
  .chat-fab{
    right:10px;
    height:46px;
    width:46px;
  }
  /* Auf dem Handy gibt es kein Ueberfahren -- der Knopf bleibt rund.
     .is-online/.is-busy muessen hier mitgenannt werden: zwei Klassen
     schlagen sonst die einfache Grundform, und der Knopf wuerde sich
     zu einer leeren Pille ausfahren -- die Beschriftung ist hier ja
     ausgeblendet. Erreichbarkeit zeigen Farbe und Punkt. */
  .chat-fab.is-online,
  .chat-fab.is-busy,
  .chat-fab:hover,
  .chat-fab:focus-visible{
    width:46px;
    gap:0;
    padding:0;
    justify-content:center;
  }
  .chat-fab-label{ display:none }
}
@media (prefers-reduced-motion:reduce){
  .chat-fab{ transition:none }
  .chat-fab:hover{ transform:none }
  .chat-fab.is-online .chat-fab-dot,
  .chat-fab.is-busy .chat-fab-dot{ animation:none }
}

/* =========================================================
   16g0 — PRAESENTATOR-LICHT
   ---------------------------------------------------------
   Weiches Licht folgt der Maus, feiner Ring sitzt auf dem
   Zeiger. Ueber den Hero-Hotspots zieht der Effekt an.
   Liegt vollstaendig ueber der Seite — der Hero selbst
   bleibt unveraendert.
   ========================================================= */
.presenter{
  position:fixed;
  inset:0;
  z-index:150;
  pointer-events:none;
  opacity:0;
  transition:opacity .5s ease;
}
html.presenter-on .presenter{ opacity:1 }

.presenter-beam,
.presenter-dot{
  position:absolute;
  left:0;
  top:0;
  border-radius:50%;
  will-change:transform;
}

/* Das Licht: multipliziert sich in die helle Seite, dadurch
   wirkt es wie eine Lampe und nicht wie ein Overlay. */
.presenter-beam{
  width:460px;
  height:460px;
  margin:-230px 0 0 -230px;
  background:radial-gradient(circle,
              rgba(23,199,222,.20) 0%,
              rgba(23,199,222,.10) 32%,
              rgba(23,199,222,.03) 58%,
              transparent 72%);
  mix-blend-mode:multiply;
  filter:blur(6px);
  transition:width .45s cubic-bezier(.2,.8,.2,1),
             height .45s cubic-bezier(.2,.8,.2,1),
             margin .45s cubic-bezier(.2,.8,.2,1),
             opacity .45s ease;
}
/* Ueber einem Hotspot: groesser und deutlicher */
.presenter.is-hot .presenter-beam{
  width:640px;
  height:640px;
  margin:-320px 0 0 -320px;
  background:radial-gradient(circle,
              rgba(23,199,222,.32) 0%,
              rgba(23,199,222,.16) 34%,
              rgba(23,199,222,.05) 60%,
              transparent 74%);
}

/* Der Ring sitzt exakt auf dem Zeiger. */
.presenter-dot{
  width:26px;
  height:26px;
  margin:-13px 0 0 -13px;
  border:1.5px solid rgba(16,178,201,.55);
  box-shadow:0 0 0 1px rgba(255,255,255,.5) inset;
  transition:width .3s cubic-bezier(.2,.8,.2,1),
             height .3s cubic-bezier(.2,.8,.2,1),
             margin .3s cubic-bezier(.2,.8,.2,1),
             border-color .3s ease;
}
.presenter.is-hot .presenter-dot{
  width:44px;
  height:44px;
  margin:-22px 0 0 -22px;
  border-color:rgba(16,178,201,.9);
}
/* kleiner Kern, damit der Zeiger auch ohne Ring erkennbar ist */
.presenter-dot::after{
  content:"";
  position:absolute;
  left:50%;
  top:50%;
  width:4px;
  height:4px;
  margin:-2px 0 0 -2px;
  border-radius:50%;
  background:rgba(16,178,201,.85);
}

/* --- Hero-Hotspot unter dem Zeiger --- */
/* Zusaetzliche Ebene im Hotspot; die bestehenden Hover-Regeln
   aus hero.css bleiben unangetastet. */
.hero-zone::before{
  z-index:1;
}
.hero-zone.is-lit{
  background:rgba(31,210,233,.05) !important;
}
.hero-zone.is-lit::before{
  opacity:1 !important;
  box-shadow:
    inset 0 0 0 1.5px rgba(57,224,242,.7),
    inset 0 0 30px rgba(40,216,238,.10) !important;
}
/* Licht genau dort, wo der Zeiger steht — folgt ihm weich. */
.hero-zone::after{
  content:"" !important;
  display:block !important;
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  opacity:0;
  background:radial-gradient(circle at var(--lit-x,50%) var(--lit-y,50%),
              rgba(214,252,255,.55) 0%,
              rgba(120,232,250,.22) 18%,
              rgba(60,214,240,.06) 38%,
              transparent 58%);
  transition:opacity .3s ease;
  animation:none !important;
  transform:none !important;
}
.hero-zone.is-lit::after{
  opacity:1;
}

@media (pointer:coarse),(prefers-reduced-motion:reduce){
  .presenter{ display:none }
  .hero-zone::after{ display:none !important }
}

/* =========================================================
   16g1 — MOTIV-BANNER (vertikal, am Szenenrand)
   ---------------------------------------------------------
   Schmaler Streifen, der zeigt worum es im Bereich geht.
   Bewusst zurueckhaltend: er soll die Szene lesbar machen,
   nicht mit ihr konkurrieren.
   ========================================================= */
.scene-banner{
  position:absolute;
  z-index:5;
  top:50%;
  transform:translateY(-50%);
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:clamp(7px,1vh,13px);
  /* Breite aus der Hoehe ableiten: so passt der Streifen auch
     bei sechs Kacheln immer in den Viewport und stoesst weder
     oben an den Header noch unten an den Aktionsbanner.
     DER FESTE 74-PX-SOCKEL WAR DER FEHLER (Befund Erguen 14.08.):
     unterhalb von rund 880 px Fensterhoehe greift nicht mehr 8.4vh,
     sondern das Minimum — die Kachel bleibt 74 px hoch (aspect-ratio 1),
     waehrend der Platz schrumpft. GEMESSEN lief die Spalte dann bis zu
     80 px aus ihrem eigenen Deckel heraus, und ab 740 px Fensterhoehe
     lag das Aktionsband auf der untersten Kachel (71 x 46 px).
     Rechnung fuer die sechs Zubehoer-Kacheln bei 660 px Hoehe:
     18 Ueberschrift + 6 x (56 Kachel + 12 Beschriftung + 7 Abstand)
     = 468 — passt in die 76vh (501). */
  width:clamp(56px,8.4vh,124px);
  max-height:76vh;
  pointer-events:none;
}
.scene-banner.is-left{ left:clamp(14px,1.8vw,30px) }
/* Rechts weicht der Streifen der beschrifteten Fortschrittsleiste aus
   (Befund 13.08.: die Service-Kacheln lagen unter den Bereichsnamen). */
.scene-banner.is-right{ right:calc(clamp(84px,7.4vw,120px) + var(--rail-gutter,0px)) }

.banner-title{
  color:var(--accent-deep);
  font:900 clamp(9px,.68vw,11.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.2em;
  text-transform:uppercase;
  white-space:nowrap;
}

.banner-list{
  display:flex;
  flex-direction:column;
  gap:clamp(6px,.9vh,12px);
  margin:0;
  padding:0;
  list-style:none;
  width:100%;
}

.banner-item{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:5px;
  /* Kacheln kommen nacheinander, gesteuert vom Szenenfortschritt.
     GEMESSEN (1.699.0, Befund Erguen "blasse Service-Icons"): am Rastpunkt
     der Reparatur-Szene steht --r bei 0,488 — mit dem alten Faktor 1,9 kam
     die unterste Kachel dort auf 0,29 Deckkraft und war praktisch
     unsichtbar (Displaytausch 0,93 · Akkutausch 0,77 · Wasserschaden 0,61 ·
     Diagnose 0,45 · Einrichtung 0,29). Der Auftakt bleibt — er beginnt nur
     frueher und ist am Rastpunkt FERTIG: Faktor 3,2, Versatz 0,12 ergibt
     dort 1,56 bis 1,08, also alle fuenf voll. Beim Einfahren (--r 0,2) sind
     es 0,64 bis 0,16 — die Staffelung ist weiter zu sehen. */
  opacity:calc((var(--r,1) * 3.2) - (var(--i) * 0.12));
  transform:translateY(calc((1 - var(--r,1)) * 14px));
}

.banner-tile{
  position:relative;
  display:grid;
  place-items:center;
  width:100%;
  aspect-ratio:1;
  border:1px solid rgba(9,58,72,.11);
  border-radius:18px;
  background:linear-gradient(150deg,
              rgba(255,255,255,.94),rgba(232,250,253,.72));
  color:var(--accent-ink);
  overflow:hidden;
}
/* feiner Lichtrand oben — gibt der Kachel Tiefe ohne Schatten */
.banner-tile::after{
  content:"";
  position:absolute;
  inset:0;
  border-radius:inherit;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9);
  pointer-events:none;
}

.banner-motif{
  display:block;
  width:62%;
}
.banner-motif svg{
  display:block;
  width:100%;
  height:auto;
}
/* Fotos fuellen die Kachel randlos */
.banner-photo{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
}

.banner-label{
  /* DUNKLER ALS --ink-soft (1.699.0). GEMESSEN: rgb(107,127,136) auf dem
     Grund rgb(248,251,252) ergibt 4,03:1 — unter den 4,5:1, die kleiner
     Text braucht, und die Beschriftung ist 8-11 px klein. Dieser Wert
     ergibt 6,6:1. NUR hier gesetzt, nicht an --ink-soft: das Token traegt
     die ganze Seite, und die Fliesstexte stehen groesser. */
  color:#3d565f;
  font:800 clamp(8px,1.05vh,11px)/1.2 Inter,system-ui,sans-serif;
  letter-spacing:.05em;
  text-transform:uppercase;
  text-align:center;
  /* KEINE SILBENTRENNUNG (Befund Erguen 14.08.: "WASSERSCHA-DEN").
     Das war kein Trennungs-, sondern ein PLATZproblem: die Kachelspur
     ist 76 px breit, "Wasserschaden" braucht 101 — mit hyphens:auto
     trennt der Browser mitten im Wort, und wer kein Trennwoerterbuch
     hat (headless Chromium), sieht es ueberhaupt nicht.
     Die Beschriftung bleibt deshalb EINZEILIG und darf ueber die
     Kachel hinausragen: sie ist zentriert, der Ueberhang verteilt sich
     symmetrisch in den freien Rand daneben. */
  hyphens:none;
  white-space:nowrap;
}

/* KLICKBARE KATEGORIE-KACHELN (Zuruf Erguen 19.08.: "wenn user auf die
   linken icon klickt öffnet der shop"): der Zubehoer-Streifen traegt je
   Kachel einen echten button (motifBanner, cfg.klick). Der Streifen
   selbst bleibt pointer-events:none (Deko-Regel von 1.617.0) — erst der
   Knopf schaltet den Zeiger wieder ein; der Service-Streifen der
   Reparatur-Szene bekommt keine Knoepfe und bleibt unangetastet. */
.banner-btn{
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:5px;
  width:100%;
  margin:0;
  padding:0;
  border:0;
  background:none;
  font:inherit;
  color:inherit;
  cursor:pointer;
  pointer-events:auto;
}
.banner-btn .banner-tile{
  transition:transform .24s cubic-bezier(.2,.8,.2,1),
             border-color .24s ease, box-shadow .24s ease;
}
.banner-btn:hover .banner-tile,
.banner-btn:focus-visible .banner-tile{
  transform:translateY(-3px);
  border-color:rgba(18,199,224,.55);
  box-shadow:0 10px 22px rgba(9,58,72,.16);
}
.banner-btn:focus-visible{ outline:none }
.banner-btn:focus-visible .banner-tile{ box-shadow:0 0 0 3px rgba(18,199,224,.4) }
@media (prefers-reduced-motion:reduce){
  .banner-btn:hover .banner-tile,
  .banner-btn:focus-visible .banner-tile{ transform:none }
}

/* Schmale Schirme: der Streifen wuerde die Szene zerdruecken */
/* Schmale oder sehr flache Schirme: der Streifen wuerde die
   Szene zerdruecken. */
@media (max-width:1100px), (max-height:620px){
  .scene-banner{ display:none }
  /* Ohne Leiste kein Freihalte-Streifen — sonst begaenne der Text auf
     schmalen Schirmen ohne Grund weit innen. */
  :root{ --banner-gutter:0px }
}
@media (prefers-reduced-motion:reduce){
  .banner-item{ transform:none }
}

/* =========================================================
   16g2 — FORMULARE (Termin · Verfuegbarkeit · Kontakt)
   ---------------------------------------------------------
   Ein Stil fuer alle drei. Zwoelfspaltiges Raster, ruhige
   Felder, klarer Fokus, sichtbarer Sendestatus.
   ========================================================= */
/* Erklaert, warum hier ein Formular steht und kein Chat. */
.form-notice{
  display:flex;
  gap:10px;
  margin:clamp(14px,1.6vw,20px) 0 0;
  padding:clamp(12px,1.2vw,16px) clamp(14px,1.4vw,18px);
  border:1px solid rgba(9,58,72,.14);
  border-left:3px solid var(--ink-soft);
  border-radius:0 12px 12px 0;
  background:rgba(9,58,72,.04);
  color:var(--ink-mid);
  font-size:clamp(12px,.9vw,14px);
  line-height:1.55;
  max-width:62ch;
}

.pf-block{ margin-top:clamp(18px,2vw,26px) }

.pf-form{
  display:grid;
  grid-template-columns:repeat(12,1fr);
  gap:clamp(12px,1.2vw,18px);
}
/* Die display-Regel oben schlaegt das hidden-Attribut (Spezifitaet gegen
   den UA-Default) — ohne diese Gegenregel stuende das Formular nach dem
   Absenden NEBEN der Erfolgskarte. Von der Sonde gefunden: der Zweig,
   der das Formular versteckt, war bis zur Chat-Umstellung toter Code. */
.pf-form[hidden]{
  display:none;
}

.pf-field{
  display:flex;
  flex-direction:column;
  gap:7px;
  min-width:0;
}
.pf-label{
  display:flex;
  align-items:center;
  gap:4px;
  color:var(--ink-soft);
  font:800 clamp(10px,.7vw,11px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.13em;
  text-transform:uppercase;
}
.pf-req{
  color:var(--accent-deep);
  font-style:normal;
}

.pf-field input,
.pf-field select,
.pf-field textarea{
  width:100%;
  padding:clamp(11px,1vw,14px) clamp(12px,1.1vw,16px);
  border:1px solid rgba(9,58,72,.16);
  border-radius:14px;
  background:rgba(255,255,255,.92);
  color:var(--ink);
  font:600 clamp(13px,.95vw,15px)/1.35 Inter,system-ui,sans-serif;
  transition:border-color .22s ease, box-shadow .22s ease,
             background .22s ease;
  -webkit-appearance:none;
  appearance:none;
}
.pf-field textarea{
  resize:vertical;
  min-height:96px;
  line-height:1.5;
}
/* eigener Pfeil, damit Select wie die Inputs aussieht */
.pf-field select{
  padding-right:38px;
  background-image:
    linear-gradient(45deg,transparent 50%,var(--ink-soft) 50%),
    linear-gradient(135deg,var(--ink-soft) 50%,transparent 50%);
  background-position:
    calc(100% - 19px) calc(50% + 1px),
    calc(100% - 14px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;
  background-repeat:no-repeat;
}
.pf-field input::placeholder,
.pf-field textarea::placeholder{ color:var(--ink-soft) }

.pf-field input:hover,
.pf-field select:hover,
.pf-field textarea:hover{
  border-color:rgba(9,58,72,.28);
}
.pf-field input:focus,
.pf-field select:focus,
.pf-field textarea:focus{
  outline:none;
  border-color:var(--accent-deep);
  background:#fff;
  box-shadow:0 0 0 3px rgba(18,199,224,.18);
}
/* Fehler erst zeigen, wenn der Nutzer das Feld auch angefasst
   hat — :user-invalid statt :invalid, sonst ist jedes leere
   Pflichtfeld sofort rot. */
.pf-field input:user-invalid,
.pf-field select:user-invalid,
.pf-field textarea:user-invalid{
  border-color:rgba(226,80,110,.65);
  box-shadow:0 0 0 3px rgba(226,80,110,.12);
}

.pf-consent{
  display:flex;
  align-items:flex-start;
  gap:11px;
  margin-top:clamp(2px,.4vw,6px);
  color:var(--ink-mid);
  font-size:clamp(12px,.86vw,13px);
  line-height:1.5;
}
.pf-consent input{
  flex:0 0 auto;
  width:19px;
  height:19px;
  margin-top:1px;
  accent-color:var(--accent-deep);
  cursor:pointer;
}
.pf-consent-link{
  padding:0;
  border:0;
  background:none;
  color:var(--accent-ink);
  font:inherit;
  font-weight:800;
  cursor:pointer;
  text-decoration:underline;
  text-underline-offset:3px;
}
.pf-consent-link:focus-visible{ outline:2px solid var(--accent-deep); outline-offset:2px }

.pf-actions{
  grid-column:span 12;
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:clamp(12px,1.4vw,20px);
  margin-top:clamp(4px,.6vw,10px);
}
.pf-submit[disabled]{
  opacity:.6;
  cursor:progress;
}
/* Der Honigtopf (Feld name="website"): fuer Menschen unsichtbar und
   unerreichbar, fuer Bots ein gewoehnliches Textfeld. BEWUSST nicht
   display:none — manche Bots lassen versteckte Felder dann aus;
   ausserhalb des Bildes liegt es fuer beide gleich. */
.pf-hp{
  position:absolute;
  left:-9999px;
  width:1px;
  height:1px;
  opacity:0;
  pointer-events:none;
}
.pf-status{
  margin:0;
  font-size:clamp(12px,.86vw,13px);
  font-weight:700;
  color:var(--ink-soft);
}
.pf-status.is-busy{ color:var(--accent-ink) }
.pf-status.is-err{ color:#c8385c }

/* Bestaetigung ersetzt das Formular */
.pf-done{
  padding:clamp(22px,2.4vw,34px);
  border:1px solid rgba(18,199,224,.32);
  border-radius:20px;
  background:linear-gradient(150deg,
              rgba(232,252,255,.9),rgba(255,255,255,.86));
}
.pf-done-title{
  margin:0 0 8px;
  color:var(--ink);
  font-size:clamp(18px,1.6vw,26px);
  font-weight:900;
  letter-spacing:-.03em;
}
.pf-done-text{
  margin:0 0 clamp(16px,1.8vw,24px);
  max-width:52ch;
  color:var(--ink-mid);
  font-size:clamp(13px,.95vw,15px);
  line-height:1.6;
}

/* ---------------------------------------------------------
   FORMULAR-OVERLAYS PASSEN AUFS BILD
   ---------------------------------------------------------
   Befund Erguen (13.08., mit Bildschirmfoto): "Nachricht
   senden" lag unter der Fensterkante, der Kasten musste
   gerollt werden. GEMESSEN, nicht geschaetzt: der Kasten
   brauchte 908 px; ein Laptop mit 768 px Fensterhoehe zeigt
   davon 705 -- es fehlten 203 px.

   Gekuerzt wird nur, was NICHT gelesen oder getippt wird:
   Polster, Abstaende und der Titel. 46 px sind eine
   Ueberschrift fuer eine Bildseite, nicht fuer ein Formular.
   Die Schrift der FELDER bleibt unangetastet -- dort wird
   gearbeitet, und kleiner heisst dort schlechter.

   Gilt nur fuer .form-overlay (Termin + Kontakt). Die
   Shop-Auswahl lebt von ihren grossen Karten und bleibt, wie
   sie ist -- deshalb der eigene Selektor und keine Aenderung
   an .shop-panel selbst.
   --------------------------------------------------------- */
.form-overlay .shop-panel{
  padding:clamp(20px,2.1vw,32px) clamp(20px,2.4vw,40px)
          clamp(16px,1.7vw,26px);
}
.form-overlay .shop-title{
  font-size:clamp(21px,2vw,30px);
  line-height:1.08;
}
.form-overlay .shop-eyebrow{ margin-bottom:7px }
.form-overlay .shop-sub{
  margin:clamp(7px,.7vw,10px) 0 clamp(11px,1.1vw,16px);
  font-size:clamp(13px,.9vw,14px);
  line-height:1.5;
}
.form-overlay .form-notice{
  margin-top:clamp(9px,.9vw,12px);
  padding:clamp(9px,.9vw,11px) clamp(11px,1.1vw,15px);
  font-size:clamp(12px,.85vw,13px);
  line-height:1.5;
}
.form-overlay .pf-block{ margin-top:clamp(11px,1.1vw,16px) }
.form-overlay .pf-form{ gap:clamp(9px,.9vw,13px) }
.form-overlay .pf-field{ gap:5px }
.form-overlay .pf-field textarea{ min-height:72px }
.form-overlay .pf-consent{ margin-top:0 }
.form-overlay .pf-actions{ margin-top:clamp(2px,.3vw,5px) }

/* Flache Fenster (Laptop mit vielen Leisten, geteilter Schirm):
   dort zaehlt jede Zeile. Gemessen gegen die FENSTERHOEHE, nicht
   die Breite -- die Enge kommt von oben und unten. */
@media (max-height:820px){
  .form-overlay .shop-panel{ padding-top:20px; padding-bottom:16px }
  .form-overlay .shop-title{ font-size:clamp(20px,1.7vw,25px) }
  .form-overlay .shop-sub{ margin-bottom:9px }
  .form-overlay .form-notice{ margin-top:9px }
  .form-overlay .pf-block{ margin-top:11px }
  .form-overlay .pf-form{ gap:10px }
  .form-overlay .pf-field textarea{ min-height:62px }
}

/* Drei Felder nebeneinander tragen erst ab einer gewissen Breite.
   Darunter zurueck auf zwei Spalten -- eine E-Mail-Adresse in einem
   190-px-Feld liest niemand gegen. Zwischen 640 und 900 gilt also
   wieder die alte Aufteilung.
   pfField setzt die Spaltenzahl als INLINE-Stil -- dagegen kommt eine
   gewoehnliche Regel nicht an, deshalb hier !important. */
@media (max-width:900px){
  .form-overlay .pf-field[data-field="name"],
  .form-overlay .pf-field[data-field="phone"]{ grid-column:span 6 !important }
  .form-overlay .pf-field[data-field="email"]{ grid-column:span 12 !important }
}

/* Auf schmalen Schirmen steht alles untereinander */
@media (max-width:640px){
  .pf-field{ grid-column:span 12 !important }
}
@media (prefers-reduced-motion:reduce){
  .pf-field input,
  .pf-field select,
  .pf-field textarea{ transition:none }
}

/* "Nachricht schreiben" in den Filialkarten sieht aus wie die
   anderen Links daneben, ist aber ein Button. */
.fin-location-link.is-action{
  padding:0;
  border:0;
  background:none;
  font:inherit;
  cursor:pointer;
}

/* =========================================================
   16h — RECHTSTEXTE (Impressum / Datenschutz)
   ---------------------------------------------------------
   Lange Dokumente lesbar halten: fester Kopf mit
   Lesefortschritt, Sprungleiste, ruhige Typo, begrenzte
   Zeilenlaenge.
   ========================================================= */
.legal-panel{
  width:min(860px,100%);
  padding:0;
  scroll-behavior:smooth;
}
@media (prefers-reduced-motion:reduce){
  .legal-panel{ scroll-behavior:auto }
}

.legal-head{
  position:sticky;
  top:0;
  z-index:3;
  padding:clamp(24px,2.8vw,40px) clamp(22px,3.2vw,52px)
          clamp(16px,1.8vw,24px);
  /* VOLLSTAENDIG deckend. Mit einem Verlauf nach transparent
     scrollte der Text sichtbar durch Ueberschrift und Sprungleiste. */
  background:#fcfeff;
  border-radius:clamp(20px,2vw,30px) clamp(20px,2vw,30px) 0 0;
}
/* weiche Kante nach unten, damit der Text nicht hart abgeschnitten wirkt */
.legal-head::after{
  content:"";
  position:absolute;
  left:0;
  right:0;
  top:100%;
  height:14px;
  pointer-events:none;
  background:linear-gradient(180deg,#fcfeff,rgba(252,254,255,0));
}
.legal-title{
  margin:6px 56px 0 0;
  color:var(--ink);
  font-size:clamp(26px,2.9vw,44px);
  font-weight:900;
  letter-spacing:-.045em;
  line-height:1;
}
/* Lesefortschritt als Haarlinie am Kopfende */
.legal-progress{
  position:absolute;
  left:0;
  right:0;
  bottom:0;
  height:2px;
  background:linear-gradient(90deg,var(--accent),var(--accent-deep));
  transform:scaleX(0);
  transform-origin:left center;
}

.legal-toc{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin-top:clamp(14px,1.6vw,20px);
}
.legal-chip{
  padding:8px 14px;
  border:1px solid rgba(9,58,72,.14);
  border-radius:999px;
  background:rgba(255,255,255,.8);
  color:var(--ink-mid);
  font:800 clamp(10px,.72vw,12px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.04em;
  cursor:pointer;
  white-space:nowrap;
  transition:border-color .25s ease, color .25s ease,
             background .25s ease, transform .25s ease;
}
.legal-chip:hover,
.legal-chip:focus-visible{
  outline:none;
  transform:translateY(-1px);
  border-color:rgba(18,199,224,.6);
  background:rgba(224,250,254,.9);
  color:var(--accent-ink);
}

.legal-body{
  padding:clamp(6px,.8vw,12px) clamp(22px,3.2vw,52px)
          clamp(30px,3.4vw,52px);
}
.legal-h{
  margin:clamp(30px,3vw,46px) 0 clamp(10px,1vw,14px);
  color:var(--ink);
  font-size:clamp(18px,1.5vw,24px);
  font-weight:900;
  letter-spacing:-.025em;
  line-height:1.15;
  scroll-margin-top:clamp(150px,16vw,210px);
}
.legal-h:first-child{ margin-top:0 }
/* Kapitelmarke links neben der Ueberschrift */
.legal-h:not(.is-sub){
  padding-top:clamp(18px,2vw,28px);
  border-top:1px solid var(--hair);
}
.legal-h.is-sub{
  margin:clamp(20px,2vw,30px) 0 clamp(6px,.6vw,10px);
  color:var(--accent-ink);
  font-size:clamp(13px,1vw,16px);
  font-weight:800;
  letter-spacing:.02em;
  border-top:0;
  padding-top:0;
}
.legal-p{
  margin:0 0 clamp(11px,1.1vw,16px);
  max-width:68ch;
  color:var(--ink-mid);
  font-size:clamp(13px,.95vw,15px);
  line-height:1.68;
}
.legal-list{
  margin:0 0 clamp(14px,1.4vw,20px);
  padding:0;
  list-style:none;
  display:grid;
  gap:7px;
  max-width:68ch;
}
.legal-list li{
  position:relative;
  padding-left:20px;
  color:var(--ink-mid);
  font-size:clamp(13px,.95vw,15px);
  line-height:1.55;
}
.legal-list li::before{
  content:"";
  position:absolute;
  left:2px;
  top:.62em;
  width:6px;
  height:6px;
  border-radius:50%;
  background:var(--accent-deep);
}
.legal-address{
  display:grid;
  gap:3px;
  margin:0 0 clamp(16px,1.6vw,24px);
  padding:clamp(14px,1.4vw,20px) clamp(16px,1.6vw,24px);
  border:1px solid rgba(9,58,72,.12);
  border-radius:16px;
  background:linear-gradient(150deg,
              rgba(255,255,255,.9),rgba(233,250,253,.62));
  color:var(--ink);
  font-size:clamp(14px,1.05vw,17px);
  font-style:normal;
  font-weight:700;
  line-height:1.45;
  width:fit-content;
}
.legal-link{
  color:var(--accent-ink);
  text-decoration:none;
  border-bottom:1px solid rgba(13,126,146,.34);
  word-break:break-word;
  transition:border-color .2s ease;
}
.legal-link:hover,
.legal-link:focus-visible{
  outline:none;
  border-bottom-color:currentColor;
}

@media (max-width:760px){
  .legal-chip{ padding:7px 11px }
}

/* =========================================================
   16i — TV-EDITOR (?tv=1)
   ---------------------------------------------------------
   Nur sichtbar, wenn js/tv-editor.js aktiv wird. Ohne den
   Schalter in der Adresszeile existiert nichts davon im DOM.
   ========================================================= */
body.tv-editing .tv-slideshow{
  /* Der Bildschirm ist im Betrieb durchklickbar (pointer-events:
     none) — zum Ausrichten muss er den Zeiger annehmen. Und er
     muss UEBER die Hotspots: die liegen auf z-index 20 und
     faengen sonst jeden Klick ab, bevor er ankommt. */
  pointer-events:auto !important;
  z-index:80 !important;
  cursor:move;
  outline:2px solid #18cce4;
  outline-offset:4px;
}
/* Hotspots und Vorteilsleiste stoeren beim Ausrichten nur. */
body.tv-editing .hero-zone,
body.tv-editing .benefit-bar{
  pointer-events:none !important;
}

.tv-handle{
  position:absolute;
  z-index:40;
  width:12px;
  height:12px;
  margin:-6px 0 0 -6px;
  border:1.5px solid #0a90a8;
  border-radius:3px;
  background:#eafdff;
  box-shadow:0 1px 4px rgba(4,40,50,.45);
}
.tv-handle-n,.tv-handle-s{ cursor:ns-resize }
.tv-handle-e,.tv-handle-w{ cursor:ew-resize }
.tv-handle-nw,.tv-handle-se{ cursor:nwse-resize }
.tv-handle-ne,.tv-handle-sw{ cursor:nesw-resize }
.tv-handle-rot{
  left:50%;
  top:-26px;
  border-radius:50%;
  cursor:grab;
  background:#18cce4;
}

.tv-editor-panel{
  position:fixed;
  z-index:400;
  right:16px;
  bottom:16px;
  width:250px;
  padding:16px;
  border:1px solid rgba(9,58,72,.16);
  border-radius:14px;
  background:rgba(252,254,255,.97);
  box-shadow:0 18px 50px rgba(6,38,48,.28);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
  font:600 12px/1.4 Inter,system-ui,sans-serif;
  color:var(--ink);
}
.tv-editor-title{
  margin:0 0 12px;
  font-size:11px;
  font-weight:900;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--accent-deep);
}
.tv-editor-grid{
  display:grid;
  gap:6px;
}
.tv-editor-row{
  display:grid;
  grid-template-columns:1fr 76px 22px;
  align-items:center;
  gap:6px;
}
.tv-editor-row span{ color:var(--ink-mid); font-size:11px }
.tv-editor-row i{ color:var(--ink-soft); font-style:normal; font-size:10px }
.tv-editor-row input{
  width:100%;
  padding:5px 7px;
  border:1px solid rgba(9,58,72,.2);
  border-radius:7px;
  background:#fff;
  font:700 11px/1 Inter,system-ui,sans-serif;
  font-variant-numeric:tabular-nums;
  color:var(--ink);
}
.tv-editor-row input:focus{
  outline:none;
  border-color:var(--accent-deep);
  box-shadow:0 0 0 2px rgba(18,199,224,.2);
}
.tv-editor-hint{
  margin:11px 0 0;
  color:var(--ink-soft);
  font-size:10px;
  line-height:1.45;
}
.tv-editor-actions{
  display:flex;
  gap:7px;
  margin-top:11px;
}
.tv-editor-btn{
  flex:1;
  padding:8px 6px;
  border:1px solid rgba(9,58,72,.2);
  border-radius:8px;
  background:#fff;
  font:800 10px/1 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--ink);
  cursor:pointer;
}
.tv-editor-btn.is-primary{
  border-color:transparent;
  background:var(--ink);
  color:#fff;
}
.tv-editor-btn:hover{ filter:brightness(1.08) }
.tv-editor-code{
  display:block;
  width:100%;
  height:150px;
  margin-top:9px;
  padding:8px;
  border:1px solid rgba(9,58,72,.18);
  border-radius:8px;
  background:#f4fbfd;
  font:500 10px/1.45 ui-monospace,SFMono-Regular,Menlo,monospace;
  color:var(--ink);
  resize:vertical;
}
.tv-editor-code[hidden]{ display:none }

/* =========================================================
   17 — DEBUG (?debug=1)
   ========================================================= */
.debug-panel{
  position:fixed;
  z-index:900;
  left:12px;
  bottom:12px;
  min-width:230px;
  padding:12px 14px;
  border-radius:12px;
  background:rgba(4,18,24,.88);
  color:#c8fbff;
  font:600 11px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;
  pointer-events:none;
  display:none;
}
html.is-debug .debug-panel{
  display:block;
}
.debug-panel b{
  color:#5ef0ff;
}
html.is-debug .story-section{
  outline:1px dashed rgba(255,0,110,.5);
  outline-offset:-1px;
}
html.is-debug .story-stage{
  outline:1px solid rgba(0,180,255,.45);
  outline-offset:-2px;
}
html.is-debug .scene-portal{
  outline:1px solid rgba(255,190,0,.7);
}
html.is-debug .debug-zones{
  display:block;
}
.debug-zones{
  position:absolute;
  inset:0;
  z-index:130;
  display:none;
  pointer-events:none;
}
.debug-zone{
  position:absolute;
  left:0;
  right:0;
  top:0;
  height:calc(100% - var(--benefit-h));
  clip-path:polygon(var(--zone-poly));
  -webkit-clip-path:polygon(var(--zone-poly));
  background:rgba(255,0,110,.14);
  box-shadow:inset 0 0 0 2px rgba(255,0,110,.6);
}

/* =========================================================
   18 — REDUCED MOTION
   ---------------------------------------------------------
   Keine Kamerafahrten, keine langen Parallaxsequenzen.
   Inhalte bleiben vollstaendig sichtbar und nutzbar.
   ========================================================= */
@media (prefers-reduced-motion:reduce){
  .anim-rise,
  .anim-line > span,
  .provider,
  .net-speed,
  .acc-chip,
  .rep-service,
  .fin-word,
  .fin-sub,
  .fin-actions{
    transform:none !important;
  }

  .device,
  .rep-layers,
  .acc-object,
  .net-marquee{
    transform:none !important;
  }

  .net-screen{
    transform:translate(-50%,-50%) !important;
  }

  .device-stage{
    transform:translate(-50%,-50%) !important;
  }

  .rep-device{
    transform:translate(-50%,-50%) !important;
  }

  .acc-object{
    transform:translate(-50%,-50%) !important;
  }

  .scroll-cue i{
    animation:none;
  }

  /* Das Polygon-Morphing wird zur reinen Ueberblendung. */
  .scene-portal{
    clip-path:none !important;
    -webkit-clip-path:none !important;
  }
  .portal-shot,
  .portal-skirt,
  .portal-edge{
    display:none;
  }
}


/* =========================================================
   BEREICHS-INTRO (13.08.)
   ---------------------------------------------------------
   Beim Wechsel in einen Bereich steht kurz sein Name gross in
   der Mitte — der Uebergang bekommt ein Gesicht, und die
   Einstiegs-Strecke einer Szene ist nie mehr leer (Zuruf
   Erguen: "banner beim wechsel des bereiches das kurz in der
   mitte erscheint"). Rein scrollgesteuert ueber data-anim —
   keine Timer, rueckwaerts wie vorwaerts identisch.
   ========================================================= */
.scene-intro{
  position:absolute;
  inset:0;
  z-index:4;
  display:grid;
  place-items:center;
  text-align:center;
  pointer-events:none;
  opacity:var(--r,0);
}
.scene-intro-inner{
  transform:
    translate3d(0,calc((1 - var(--ri,0)) * 30px),0)
    scale(calc(.96 + var(--ri,0) * .04 + var(--ro,0) * .06));
}
.scene-intro-nr{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:16px;
  color:var(--accent-deep);
  font:800 clamp(11px,.9vw,14px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.34em;
  text-transform:uppercase;
}
.scene-intro-nr::before,
.scene-intro-nr::after{
  content:"";
  width:clamp(30px,3.4vw,54px);
  height:1px;
  background:var(--accent);
  transform:scaleX(var(--ri,0));
}
.scene-intro-nr::before{ transform-origin:right center }
.scene-intro-nr::after{ transform-origin:left center }
.scene-intro-word{
  display:block;
  margin-top:clamp(10px,1.6vh,20px);
  color:var(--ink);
  font:900 clamp(44px,7.4vw,118px)/1.02 Inter,system-ui,sans-serif;
  letter-spacing:-.03em;
  text-transform:uppercase;
}

/* =========================================================
   E-SCOOTER MIT SOMMER-FAHNE (Auftrag Erguen 14.08.)
   ---------------------------------------------------------
   Der Wagen sitzt FEST am unteren Rand und wandert per transform von
   RECHTS NACH LINKS — die Position setzt js/scooter.js aus dem
   Scrollfortschritt. Sichtbar nur zwischen Mobilfunk und Reparatur.

   MASSE BEWUSST KLEIN ("duerfen nicht zu gross sein"): 190 px breite
   Leinwand, Fahne darueber. Wie BREIT der Scooter darin erscheint,
   entscheidet das Seitenverhaeltnis der Kamera — das rechnet
   js/scooter.js aus genau diesen Zahlen. Wer sie hier aendert, aendert
   den Bildausschnitt mit; eine feste Zahl im Skript daneben waere die
   Stelle, an der beide auseinanderlaufen (genau das war der Befund
   "sieht gequtescht aus").

   Der Wagen sitzt tief genug, um dem Aktionsband links und dem
   Chat-Knopf rechts nicht in die Quere zu kommen; wo er sie doch
   streift, faehrt er ueber z-index dahinter vorbei.
   ========================================================= */
.scooter-fahrt{
  position:fixed;
  left:0; bottom:0;
  width:190px; height:132px;
  /* UNTER den schwebenden Knoepfen (Erguen: "ohne moeglichst zu
     ueberlappen"). Rechts unten sitzt der Zubehoer-Knopf; gemessen lief
     der Scooter mit 11400 px2 darueber. Er faehrt jetzt DAHINTER vorbei
     — die Knoepfe bleiben sichtbar und klickbar, und ein kurzes
     Passieren liest sich als Bewegung, nicht als Fehler. */
  z-index:108;
  opacity:0; visibility:hidden;
  pointer-events:none;
  transition:opacity .45s ease, visibility 0s linear .45s;
  cursor:pointer;
  will-change:transform;
}
.scooter-fahrt.is-da{
  /* NUR DAS GEZEICHNETE NIMMT DEN ZEIGER (beim Nachmessen der
     Reparatur-Ecke gefunden, 14.08.): der Wagen ist 132 px hoch, der
     Scooter samt Fahne endet aber bei rund 98 px — der leere Rest oben
     lag ueber der Knopfzeile der Szene (die beginnt bei 96–150 px) und
     schluckte dort jeden Klick. `elementFromPoint` traf in der Mitte von
     „Reparatur anfragen" den Wagen. Der Scooter ist `position:fixed` mit
     z-index 108, die Szene liegt im Stage bei z-index 6 — sie kann ihn
     also NICHT ueberholen; die Loesung ist, dem leeren Kasten den Zeiger
     zu nehmen. Anklickbar bleibt, was man wirklich sieht: Leinwand und
     Fahne (Vorgabe Erguen 1.615.0 „ganzer bereich anklickbar"). */
  opacity:1; visibility:visible;
  transition:opacity .45s ease, visibility 0s;
}
.scooter-fahrt.is-da .scooter-canvas,
.scooter-fahrt.is-da .scooter-fahne{ pointer-events:auto }
.scooter-canvas{
  position:absolute; left:0; bottom:2px;
  width:190px; height:96px; display:block;
}
/* Die Fahne haengt am Lenker und weht. Der Mast ist eine duenne Linie,
   das Tuch traegt den Text — deshalb DOM und nicht 3D: so bleibt die
   Schrift scharf und ohne neues Modell aenderbar. */
.scooter-fahne{
  /* AUF DEM HINTEREN RAD (Erguen 14.08.: "fahre ueber dem hinteren rad").
     Er faehrt nach LINKS, hinten ist also RECHTS. Vorher stand der Mast
     frei hinter dem Geraet und sah aus, als schwebe er.
     DIE 144 PX SIND GERECHNET, nicht geschaetzt: der Scooter wird von
     x=31 bis x=158 gezeichnet (127 px fuer 1.60 Modelleinheiten = 79.4 px
     je Einheit), das hintere Rad sitzt bei Modell-x +0.61 — also
     31 + (0.61+0.81) * 79.4 = 144. Aendert sich die Leinwand oder die
     Skalierung, wandert diese Zahl mit; window.__scooterMass nennt beides. */
  position:absolute; left:144px; bottom:24px;
  /* DAS TUCH HAENGT AM OBEREN ENDE DER STANGE (Zuruf Erguen 14.08.:
     "fahne höher an das ende der stange beim scooter"). Vorher sass es
     mit flex-end am Mastfuss und sah aus wie ein Schild auf halber Hoehe;
     eine Fahne haengt oben. */
  display:flex; align-items:flex-start; gap:0;
  transform-origin:left bottom;
}
.scooter-mast{
  width:2px; height:54px; border-radius:2px;
  background:linear-gradient(180deg,#2b3f47,#7d8f97);
  flex:0 0 auto;
}
.scooter-tuch{
  position:relative;
  /* Am oberen Mastende, ein Haar unterhalb der Spitze — so sitzt die
     Fahne AN der Stange und schwebt nicht ueber ihr. */
  margin-top:2px;
  padding:5px 10px;
  border-radius:0 8px 8px 0;
  background:linear-gradient(135deg,#0f8ea3,#12b3c9);
  color:#fff;
  /* Groesser auf Zuruf ("fahnentext groesser"): 8,5 -> 12 px. Damit ist
     die Fahne breiter als der Scooter — das ist gewollt, sie ist der
     Anlass, er ist der Hingucker. */
  font:800 12px/1.2 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
  white-space:nowrap;
  box-shadow:0 4px 14px rgba(10,90,105,.28);
  transform-origin:left center;
  animation:scooter-wehen 1.5s ease-in-out infinite;
}
@keyframes scooter-wehen{
  0%,100%{ transform:skewY(-2.2deg) scaleY(1) }
  50%    { transform:skewY(2.4deg)  scaleY(.97) }
}
@media (prefers-reduced-motion:reduce){
  .scooter-tuch{ animation:none }
  /* Wer weniger Bewegung will, bekommt beim Ueberfahren trotzdem eine
     Antwort — nur eben Schatten und Rand statt Anheben und Zoomen. */
  .ang-karte:hover,.ang-karte:focus-visible,.ang-karte:has(:focus-visible){ transform:none }
  .ang-karte:hover .mang-bild,
  .ang-karte:focus-visible .mang-bild,
  .ang-karte:has(:focus-visible) .mang-bild{ transform:none }
}
/* Schmale Schirme: unten ist der Platz ohnehin von Aktionsband und
   Chat-Knopf belegt — dort faehrt niemand. */
@media (max-width:900px){
  .scooter-fahrt{ display:none }
}

/* =====================================================================
   SZENE 05 — TV   (14.08.)
   Der Bereichsname kommt aus MOS; die Gestalt ist bewusst die der
   uebrigen Szenen: Text links, Karte rechts. Ein eigenes Aussehen
   fuer einen Bereich, den der Haendler auch anders benennen kann,
   waere ein zweiter Stil ohne Grund.
   ================================================================== */
.tv-copy{
  position:absolute;
  left:var(--edge);
  top:50%;
  transform:translateY(-50%);
  max-width:min(46vw,620px);
  /* UEBER DER CANVAS (19.08.). Die 3D-Flaeche ist 140 % der Buehne und
     traegt bei geladenem Modell `pointer-events:auto`; sie steht im
     Markup NACH der Kopfzeile und lag damit ueber ihr. Bei der kleinen
     Buehne fiel das nicht auf (67 px Ueberlappung, rechts neben den
     Knoepfen) — mit dem groesseren Fernseher reicht sie bis in die
     Knopfzeile hinein. Ein z-index kostet nichts und ist die richtige
     Reihenfolge: Text gehoert nie unter eine durchsichtige Leinwand.
     Dieselbe Bauart wie .net-copy in der Internet-Szene. */
  z-index:6;
}
.tv-copy > *{ pointer-events:auto }
.tv-copy .scene-headline{ font-size:clamp(30px,4.2vw,72px) }
/* Die Knopfzeile ist ein eigener Block im Textfluss — ohne eigenen
   Abstand lag sie auf der zweiten Zeile der Unterzeile (am Bild
   gesehen, nicht gerechnet). */
.tv-copy .scene-actions{ margin-top:clamp(16px,2.4vh,30px) }

/* DER FERNSEHER (14.08.). Er steht zwischen Text (links) und der
   Monatsangebot-Karte (rechts).
   left 46% -> 50% und Breite 27vw/380 -> 40vw/640 (Zuruf Erguen 19.08.:
   "fernseher weiter in die mitteund den fernseher höher machen"): die
   Buehne steht in der BILDMITTE und der Fernseher wird deutlich groesser.

   DIE BREITE IST AN DEN BILDPUNKTEN GEMESSEN, NICHT AN window.__modellMass
   — und das ist die teuerste Lehre dieser Runde. __modellMass ist eine
   MOMENTAUFNAHME VOM LADEN (device-3d.js schreibt sie einmal nach dem
   Aufbau); der Fernseher schwenkt danach in seine Endlage, und die alten
   Zahlen beschreiben eine Pose, die niemand sieht. Sie meldeten fuer die
   640er Buehne ein 368 px breites Geraet (57 %) — das Kontrollbild zeigte
   einen Fernseher, den die Angebotskarte anschneidet. Nachgemessen an den
   dunklen Bildpunkten (Nachbarn ausgeblendet, Screenshot Punkt fuer Punkt
   gelesen): der gezeichnete Fernseher ist **94 % der Buehnenbreite** —
   bei 640 px Buehne also 490..1094 gegen eine Karte ab 1037.
   MERKSATZ: wer wissen will, wie breit ein 3D-Modell WIRKLICH steht,
   fotografiert es und zaehlt Bildpunkte; eine Messhilfe, die einmal beim
   Laden geschrieben wurde, ist keine Aussage ueber das laufende Bild.

   Daraus die Zahlen: halbe Bildbreite = 0.472 x Buehnenbreite. Die freie
   Bahn zwischen der SICHTBAREN Ueberschrift und der Karte betraegt
   536..1037 (1600x900) bzw. 442..835 (1280x720) — die Ueberschrift wird
   dabei an ihren Buchstaben gemessen, nicht an `.anim-line`: das ist ein
   Block ueber die ganze Textspalte (74..626), und wer seinen Kasten
   nimmt, meldet eine Kollision mit leerem Rand.
   UND ER DREHT MIT DEM SCROLLEN (spin 0.35): die breiteste Pose liegt
   ab der Szenenmitte und misst 110 % der Buehnenbreite — wer nur den
   Landepunkt fotografiert, misst eine schmalere Zwischenpose und haelt
   eine Buehne fuer frei, die spaeter in die Karte laeuft (genau so
   passiert, 19 px Anschnitt bei 464er Buehne).
   Die Schrift wird dabei NUR im Hoehenband des Geraets gezaehlt — die
   Unterzeile und die Knopfzeile liegen tiefer und teilen sich mit ihm
   keine Zeile.
   Freie Bahn im Band (Schriftende..Kartenkante): 516..1037 (1600x900)
   bzw. 402..835 (1280x720); Bandmitte = 48,4 %. Breiteste Pose x 1.10
   plus 12 px Luft je Seite ergibt width:min(28.8vw,445px) bei
   left:48.4% — gegenueber dem ausgelieferten Stand (27vw/380 px bei
   46 %) waechst der Fernseher um 65 px (1600) bzw. 23 px (1280) und
   steht fuers Auge in der Mitte (sichtbare Mitte 774 bzw. 620).

   ZWEI STELLEN MUSSTEN DAFUER MIT (beide gemessen, nicht vermutet):
   (1) Die Canvas ist 140 % der Buehne — sie waechst mit und laege sonst
       ueber der Kopfzeile links; `.tv-copy` traegt deshalb jetzt einen
       z-index (siehe dort).
   (2) Der SALE-Anhaenger hing mittig ueber der Buehne und saesse mit
       diesem Fernseher auf seinem Bild; er steht in DIESER Szene links
       daneben (siehe .sale-rund-szene). */
.tv-stage{
  position:absolute;
  left:48.4%;
  /* 50% -> 43% (Zuruf Erguen 19.08.: "tv höher machen") — der Fernseher
     stand mit viel Luft darueber in der unteren Haelfte; jetzt sitzt er
     in der oberen Bildmitte. Tiefer als der SALE-Anhaenger am oberen
     Rand — der Abstand ist in der Sonde gemessen, nicht angenommen. */
  top:43%;
  width:min(28.8vw,445px);
  aspect-ratio:16 / 11;
  transform:translate(-50%,-50%);
  opacity:var(--r,0);
}
/* DAS TELEKOM-LOGO STEHT UEBER DER ANGEBOTS-KACHEL (Zuruf Erguen 20.08.:
   "telekom logo über den abgebote kachel" — bis 1.649.0 hing es ueber dem
   Fernseher). Logo und Karte wohnen in EINER Spalte an den Koordinaten,
   die die Karte bis dahin selbst trug; die Karte gibt ihre absolute Lage
   darin ab. So braucht die Lage der Karte keine zweite Rechnung, und das
   Logo sitzt IMMER genau ueber ihr, egal wie hoch die Karte gerade ist. */
.tv-ang-spalte{
  position:absolute;
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:50%;
  transform:translateY(-50%);
  width:clamp(272px,23vw,368px);
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:clamp(10px,1.6vh,18px);
}
.tv-ang-spalte .mob-angebot{
  position:static;
  right:auto;
  top:auto;
  transform:none;
  width:100%;
}
/* DIE MARKENREIHE UNTER DEM ANFRAGE-KNOPF (Zuruf Erguen 20.08.:
   "telekom logo mit vodafone und o2 logo unter tv paket anfragen button").
   Weisse Chips wie in der Mobilfunk-Reihe — dieselbe Bildsprache. */
.tv-marken{
  display:flex;
  gap:12px;
  margin-top:clamp(14px,2vh,22px);
  opacity:var(--r,0);
  transform:translate3d(0,calc((1 - var(--ri,0)) * 18px),0);
}
.tv-marke{
  width:clamp(72px,6vw,96px);
  height:clamp(38px,3.2vw,50px);
  object-fit:contain;
  padding:7px 10px;
  border-radius:12px;
  background:#fff;
  border:1px solid rgba(9,44,56,.10);
  box-shadow:0 6px 16px rgba(9,30,44,.08);
}

/* Ohne Modell bleibt ein schlichter dunkler Schirm — besser als eine leere
   Flaeche, und er sagt nichts, was das Modell nicht auch zeigt. */
.tv-screen-fallback{
  position:absolute;
  inset:0;
  border-radius:10px;
  background:linear-gradient(150deg,#0b1a22,#04101a 62%,#020a11);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.06),0 22px 48px rgba(6,26,34,.22);
}
.tv-stage.has-3d .tv-screen-fallback{ display:none }
/* Die Canvas ist groesser als die Buehne, damit der Schatten Platz hat.
   140 statt 170 Prozent: mit 170 lief der Fernseher unter die
   Monatsangebot-Karte (am Bild gesehen). */
.tv-stage.has-3d .device-3d-canvas{ width:140%; height:140% }

/* =====================================================================
   SZENE 06 — ANGEBOTE   (14.08.)
   Die Seite fuer einen Betrieb ohne eigenen Online-Shop. Sie steht
   ZENTRIERT und nutzt die volle Buehne — es ist eine Liste, keine
   Erzaehlung mit Motiv daneben.

   ALLES IN EINER SPALTE, NICHT DREI ABSOLUTE BLOECKE: der erste
   Entwurf setzte Text, Raster und Knoepfe je einzeln absolut — und
   das Raster lag prompt auf der Unterzeile (am Bild gesehen). Eine
   gemessene Zahl haette nur fuer DIESE Fensterhoehe gestimmt; im
   Fluss kann sich nichts mehr ueberlappen, bei keiner Groesse.
   ================================================================== */
/* DIE SEITE „ANGEBOTE" — voller Breite, ohne Ueberschrift
   (Vorgabe Erguen 14.08.: "keine überschrift volle breite der seite
   nutzen, auf der seite max. 10 kacheln also 5 oben und 5 unten").
   Die Flaeche steht zwischen Kopf und Knopfzeile und rollt NICHT: das
   Raster teilt sie in genau so viele Felder, wie es Angebote gibt. */
.ang-flaeche{
  position:absolute;
  left:var(--edge);
  /* Platz fuer die beschriftete Fortschrittsleiste rechts (Regel 1.613.0) —
     ohne den Gutter lagen die Bereichsnamen auf der letzten Kachelspalte
     (am Bild gesehen). Unter 1100 px ist der Gutter 0. */
  right:calc(var(--edge) + var(--rail-gutter,0px));
  top:clamp(104px,14vh,180px);
  /* SO TIEF WIE MOEGLICH (Zuruf Erguen 20.08.: "das angebote button muss
     soweit wie möglich nach unten"): der Goldbalken endet an dieser
     Unterkante (.ang-fuss traegt keinen Rand mehr) — sie liegt nur noch
     so hoch, dass der mittig schwebende Scroll-Hinweis frei bleibt
     (GEMESSEN an 1600x900 und 1280x720, Sonde 1654). Die alten
     clamp(96px,11vh,150px) stammten aus der Zeit der Nick-Pfeile. */
  bottom:clamp(52px,7vh,88px);
  display:flex;
  flex-direction:column;
  gap:clamp(10px,1.4vh,18px);
  min-height:0;
}

.ang-raster{
  flex:1;
  min-height:0;
  display:flex;
  align-items:center;
  justify-content:center;
  opacity:var(--r,0);
  overflow:hidden;
}
/* DER RASTER GIBT DAS CLIPPING FREI, SOLANGE EINE KACHEL UEBERFAHREN WIRD
   (Zuruf Erguen 15.08.: "durch den maus over effekt das das bild nach
   vorne geht kann ich in den warenkorb nicht anklicken"). GEMESSEN: das
   ausgefahrene Band lag bei y 630–778, `.ang-raster` endet aber an der
   Kachelkante und traegt overflow:hidden — der Knopf war weggeschnitten,
   elementFromPoint traf die Buehne. Die Ausnahme gilt NUR waehrend des
   Hovers; danach clippt der Raster wieder wie gebaut. */
.ang-raster:has(.ang-karte:hover),
.ang-raster:has(.ang-karte:focus-visible),
.ang-raster:has(.ang-karte :focus-visible){
  overflow:visible;
  /* UND ES LIEGT VORN (Zuruf Erguen 15.08.: "alle angebote kachel darf
     nicht die angebot kachel überdecken"). Die breite Kachel steht im
     Dokument NACH dem Raster und malte sich deshalb ueber das
     ausgefahrene Band — samt Warenkorb-Knopf darin. Das Freigeben des
     Clippings allein genuegt also nicht; solange eine Kachel ueberfahren
     wird, gehoert der Raster nach vorn. Danach faellt er zurueck, damit
     die breite Kachel im Ruhezustand nichts von ihm verdeckt. */
  position:relative;
  z-index:6;
}
/* DAS GITTER HAT EIN FESTES SEITENVERHAELTNIS — und genau daraus folgt
   das Kachelformat 2:3 (siehe .ang-karte.hat-bild; seit 1.650.0 exakt
   das Format, das die KI nativ liefert). Waeren die Zellen
   einfach `1fr` der ganzen Flaeche, haette jede Angebotszahl ein anderes
   Kachelformat (gemessen 1.28 / 1.05 / 5.89 / 3.25) — dann kann weder die
   KI im richtigen Format zeichnen noch ein hochgeladenes Bild randlos
   sitzen. So bleibt das Format gleich, das Gitter zentriert sich in der
   Flaeche, und die Kacheln fuellen ihre Zellen vollstaendig aus.
   SPALTEN UND ZEILEN KOMMEN AUS DER ANZAHL (--sp/--zeilen setzt
   experience.js): fuenf oben, fuenf unten — bei weniger Angeboten
   weniger Spalten, damit keine leeren Felder entstehen. */
.ang-gitter{
  display:grid;
  /* Die Spuren setzt angGitterMessen() in Bildpunkten — hier steht nur
     der Rueckfall, falls die Messung (noch) nicht gelaufen ist. */
  grid-template-columns:repeat(var(--sp,5),minmax(0,1fr));
  grid-template-rows:repeat(var(--zeilen,2),minmax(0,1fr));
  gap:clamp(10px,1.1vw,18px);
  max-width:100%;
  max-height:100%;
}
.ang-raster.ist-leer{
  display:flex;
  align-items:center;
  justify-content:center;
  text-align:center;
}
.ang-leer{
  margin:0 auto;
  max-width:520px;
  color:#5a6f78;
  font:600 clamp(13px,1vw,15px)/1.5 Inter,system-ui,sans-serif;
}

/* Dieselben inneren Klassen wie beim Angebot des Monats (mang-*) — EINE
   Bildsprache. Anders ist nur der Behaelter: dort absolut gesetzt und
   scrollgesteuert, hier eine Kachel im Raster.
   Die Kachel ist HOCHKANT wie die Vorlage: das Bild traegt sie, darunter
   Name und Preis, unten die Knopfzeile. Laeuft der Text ueber, rollt die
   KACHEL — nie die Seite. */
.ang-karte{
  display:flex;
  flex-direction:column;
  gap:6px;
  min-height:0;
  padding:clamp(10px,.9vw,16px);
  /* RANDLOS (Zuruf Erguen 15.08.: „alle angebote als randlose kachel zum
     anklicken"). Der Rand ist weg, der Schatten bleibt: er traegt die
     Kachel weiter vom Grund ab, ohne sie einzurahmen. */
  border:0;
  border-radius:18px;
  background:rgba(255,255,255,.94);
  box-shadow:0 12px 32px rgba(8,38,48,.12);
  pointer-events:auto;
  overflow:hidden;
  /* Lage UND Zoom in EINEM transform, beides ueber Variablen: die Kachel
     hat mehrere Zustaende (frisch nachgelegt, ueberfahren), und zwei
     transform-Deklarationen ersetzen einander statt sich zu ergaenzen. */
  transform:translateY(var(--khub,0px));
  transition:transform .28s cubic-bezier(.2,.8,.2,1),
             box-shadow .28s ease, border-color .28s ease,
             filter .26s ease, opacity .26s ease;
}
/* Ueberfahren (Zuruf Erguen 14.08.: „hover effekt bei allen
   angebotskacheln"). Seit die Kachel einen Warenkorb-Knopf traegt, ist sie
   ein Bedienelement — sie soll auch so antworten.
   DIE GANZE KACHEL WAECHST (Zuruf Erguen 15.08.: "soll bei den
   angebotskacheln nicht nur das bild zoomen sondern die ganze kachel bei
   maus over"). Vorher zoomte das BILD in der Kachel — an der Monatskarte
   der Szene legte es sich damit ueber die eigenen Knoepfe. Waechst die
   Kachel als Ganzes, behaelt alles darin sein Verhaeltnis zueinander.
   `:focus-visible` gehoert dazu, sonst zeigt die Tastaturbedienung nichts —
   ausdruecklich NICHT `:focus-within` (siehe Merksatz bei .mob-angebot:
   ein Mausklick auf den Warenkorb-Knopf liess die Kachel sonst
   vergroessert kleben, auch wenn der Zeiger laengst woanders stand). */
/* KEIN WACHSEN MEHR — NIRGENDS (Zuruf Erguen 20.08.: "kein vergrössern
   der kachel bei mouse over mehr"). Die 19.08.-Ausnahme "im shop können
   die kachel aber so bleiben" ist damit zurueckgenommen: auch auf der
   Seite "Alle Angebote" waechst keine Kachel mehr. Rueckmeldung geben
   das 4-px-Anheben (--khub), der staerkere Schatten und das Milchglas
   der Nachbarn — alles, was keine Flaeche dazugewinnt. */
.ang-karte .mang-bild{ transition:transform .4s cubic-bezier(.2,.8,.2,1) }
.ang-karte:hover,
.ang-karte:focus-visible,
.ang-karte:has(:focus-visible){
  --khub:-4px;
  box-shadow:0 22px 48px rgba(8,38,48,.2);
}

/* --- LED-RAHMEN UM DIE ANGEBOTSKACHELN (Zuruf Erguen 19.08.) ---------
   "die angebotskacheln mit einer led leuchte animiert umrahmen wie auf
   der hero seite" — dazu ein Foto der Ladenwand mit umlaufenden
   LED-Streifen an den Regalkanten.
   ES IST DIESELBE LEUCHTE WIE IM HERO, nicht eine zweite Erfindung: Farbe
   (#38dff2), Takt (4,4 s) und Kurve stammen aus `ledBreathe`
   (css/hero.css) — dort atmen die Konturlinien des Ladens. Ein eigener
   Keyframe-Name, weil die Werte anders sein muessen (ein Rahmen ist
   deckender als eine Konturlinie), aber derselbe Rhythmus: die Seite soll
   EIN Licht haben, nicht zwei.
   DER GLANZ LIEGT INNEN (`inset`), nicht aussen — die Kachel traegt
   `overflow:hidden` (fuer das Bild und das ausfahrende Band), und ein
   aeusserer Schatten des Pseudo-Elements wuerde daran abgeschnitten. Innen
   liegend sieht er ohnehin richtiger aus: wie ein Leuchtstreifen AN der
   Kante, genau wie auf Erguens Foto.
   `pointer-events:none` ist Pflicht — der Rahmen liegt ueber dem Inhalt
   (auch ueber dem Warenkorb-Knopf) und darf keinen Klick abfangen. */
.ang-karte{ position:relative }
.ang-karte::after{
  content:"";
  position:absolute;
  inset:0;
  border-radius:inherit;
  border:1.5px solid rgba(56,223,242,.55);
  pointer-events:none;
  z-index:4;
  animation:kachelLed 4.4s ease-in-out infinite;
}
/* Versetzt, damit nicht zehn Kacheln im Gleichtakt blinken — dieselbe
   Staffelung wie die vier Hero-Konturen (:nth-child(2..4) dort). */
.ang-karte:nth-child(4n+2)::after{ animation-delay:-1.2s }
.ang-karte:nth-child(4n+3)::after{ animation-delay:-2.2s }
.ang-karte:nth-child(4n+4)::after{ animation-delay:-3s }
@keyframes kachelLed{
  0%,100%{
    opacity:.34;
    box-shadow:inset 0 0 7px rgba(56,223,242,.14);
  }
  50%{
    opacity:1;
    box-shadow:inset 0 0 15px rgba(56,223,242,.34);
  }
}
/* Beim Ueberfahren steht das Licht still und hell — die Kachel ist dann
   gemeint, sie soll nicht weiteratmen. */
.ang-karte:hover::after,
.ang-karte:focus-visible::after,
.ang-karte:has(:focus-visible)::after{
  animation-play-state:paused;
  opacity:1;
  border-color:rgba(56,223,242,.85);
  box-shadow:inset 0 0 18px rgba(56,223,242,.4);
}
@media (prefers-reduced-motion:reduce){
  /* Kein Atmen, aber der Rahmen bleibt — er ist Gestalt, keine Bewegung. */
  .ang-karte::after{ animation:none; opacity:.6 }
}

/* =========================================================
   ENERGIEWEG AM RAHMEN DER MONATSKARTE (19.08.)
   Zuruf Erguen: "die energie wege sollten in den hauptbereichs
   angebot kachel animiert laufen wie auf der hero seite".

   Gezeichnet wird das SVG in js/experience.js (energieRahmen) —
   die drei Linien tragen DIESELBEN Klassen wie im Hero
   (.energy-path-soft/-base/-flow in css/hero.css) und damit
   dieselbe Farbe, denselben Schein und dieselben Filter. Hier
   steht nur, WO der Weg liegt und WIE SCHNELL er laeuft.

   pointer-events:none ist Pflicht: die ganze Karte ist ein
   Klickziel (sie oeffnet die Leistungen) — eine Ebene darueber,
   die Zeiger annimmt, machte sie unklickbar. Genau der Fehler,
   der die Maus auf der ganzen Seite lahmgelegt hatte (1.629.0).

   inset:0 liegt auf der PADDING-Box der Karte, nicht auf ihrer
   Border-Box — deshalb rundet der Pfad mit 19 statt 20 px.
   ========================================================= */
.mang-energie{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  overflow:visible;
  pointer-events:none;
  z-index:0;
  /* EIGENE KOMPOSITOR-EBENE (Zuruf Erguen 20.08.: "manchmal wird im
     zubehör angebotskachel die energiefluss animation falsch angezeigt
     und korrigiert erst beim neuladen der seite" — kurz darauf "jetzt
     auch bei den anderen", beide mit Bildschirmfoto: Rahmenlinien
     AUSSERHALB der Karte). Im Messharnisch NICHT nachstellbar — jeder
     nachgestellte Groessen-Wettlauf (verzoegertes 2:3-Bild, Karte
     waechst von 268 auf 737 px) heilt sauber ueber den ResizeObserver;
     viewBox und Pfad werden immer zusammen geschrieben, ein veralteter
     Pfad KANN geometrisch nicht ueber das SVG hinausragen. Die Fotos
     zeigen also keine veralteten DATEN, sondern eine veraltete
     MALSCHICHT: der endlos animierte Strich traegt zwei drop-shadow-
     Filter, und auf der geteilten Ebene der Karte koennen beim
     Groessenwechsel alte Filter-Kacheln stehen bleiben. Die eigene
     Ebene wird als Ganzes verworfen und neu gerastert — dazu die
     Selbstheilung beim Betreten der Szene (energieSelbstheilung in
     js/experience.js). */
  transform:translateZ(0);
}
/* Der Umlauf rechnet in pathLength="1000": der Dash-Wert steht
   deshalb FEST, obwohl der Umfang der Karte mit jeder Fenster-
   breite ein anderer ist. 180/820 = ein einzelner Lichtstrich
   mit langer Luecke — ein Impuls, der um die Kachel wandert, wie
   die LED-Leisten im Laden. Mehrere Striche gleichzeitig (Hero:
   20 in 190 auf einem ueber 1000 px langen Weg) waeren auf einer
   300-px-Kachel Kirmes. */
/* DIE FARBEN SIND FUER DIE KARTE ANDERE — und das ist kein Bruch der
   Regel "eine Farbwelt", sondern ihre Folge. Im Hero liegen die Wege auf
   dem DUNKLEN Shop-Motiv; dort ist der laufende Strich fast weiss
   (rgba(225,253,255,.98)) und leuchtet. Auf der weissen Angebotskarte ist
   genau dieses Weiss unsichtbar — am Kontrollbild gesehen: zu erkennen war
   nur sein tuerkiser Schein, nicht der Strich. Er traegt hier deshalb die
   LED-Farbe des Hauses (#38dff2, dieselbe wie kachelLed und die
   Hero-Konturen), Form, Takt und Filter bleiben unveraendert. Derselbe
   Fall wie das Shop-Logo im hellen Design (1.616.0): nicht die Marke
   aendert sich, sondern der Untergrund. */
.mang-energie .energy-path-soft{ stroke:rgba(56,223,242,.26) }
.mang-energie .energy-path-base{ stroke:rgba(23,205,229,.34) }
.mang-energie .energy-path-flow{
  animation-name:mangEnergieFlow;
  stroke:#16c3dd;
  filter:
    drop-shadow(0 0 4px rgba(56,223,242,.95))
    drop-shadow(0 0 10px rgba(31,213,236,.45));
}
/* Die Punkte ebenso: ein weisser Punkt auf weisser Karte ist ein Loch,
   kein Licht. */
.mang-energie .energy-particle{
  fill:#12bdd8;
  stroke:rgba(234,252,255,.9);
}
/* AUF DER GOLDENEN KACHEL LEUCHTET ER WARMWEISS (Zuruf Erguen 19.08.:
   „hier auch den energiefluss", mit Bildschirmfoto der breiten Kachel
   „Alle Angebote"). NICHT tuerkis: #16c3dd und das Gold #d4a437 liegen
   fast auf derselben Helligkeit — der Strahl waere darauf kaum zu sehen,
   dieselbe Falle wie Weiss auf der weissen Karte, nur mit anderen
   Farben. Ein warmweisser Strahl mit goldenem Schein hebt sich klar ab
   und laesst das Gold Gold bleiben (Regel 1.376.0: die Farbe gehoert der
   HANDLUNG, und diese Kachel IST die Handlung der Szene). Die Grundlinie
   traegt hier ein dunkles Braun statt eines hellen Tons — auf Gold ist
   ein heller Ruhestrich unsichtbar. */
.ang-mehr .energy-path-soft{ stroke:rgba(255,241,206,.30) }
.ang-mehr .energy-path-base{ stroke:rgba(90,62,8,.26) }
.ang-mehr .energy-path-flow{
  stroke:#fff6dd;
  filter:
    drop-shadow(0 0 4px rgba(255,246,221,.95))
    drop-shadow(0 0 10px rgba(255,205,90,.55));
}
.ang-mehr .energy-particle{ fill:#fffaf0; stroke:rgba(120,84,10,.55) }
/* AUF DEN SZENEN-KACHELN LIEGT DER WEG UEBER DEM BILD (Zuruf 19.08.:
   "energiefluss effekte in die kacheln aussen bauen"). Die Plakat-Kachel
   fuellt sich randlos mit ihrem Bild (z-index-Ebene ueber der Grundflaeche)
   — mit dem Vorgabewert 0 laege der Rahmen DARUNTER und waere unsichtbar.
   pointer-events:none traegt das SVG ohnehin; ueber dem Band stoert die
   duenne Randlinie nichts, sie laeuft an der Kachelkante entlang. */
.ang-karte > .mang-energie{ z-index:4 }
/* KEINE eigene Dauer. hero.css setzt am Ende
   `.energy-path-flow{animation-duration:9s !important}` ("Generell
   langsamere Energieanimation") — ein zweites !important dagegen waere
   ein Wettruesten um eine Zahl, die im Haus schon entschieden ist.
   Neun Sekunden je Umlauf sind auf der Kachel ohnehin richtig: im Hero
   sind es 9 s fuer 190 px auf einem ueber 1000 px langen Weg, hier 9 s
   fuer die GANZE Runde. Wer die Zahl aendert, aendert sie dort — und
   ENERGIE_S in js/experience.js zieht mit (die Sparks laufen sonst in
   einem anderen Takt als der Strich). */
@keyframes mangEnergieFlow{
  to{ stroke-dashoffset:-1000 }
}
/* Beim Ueberfahren steht der Impuls still und hell — dieselbe
   Regel wie beim LED-Rahmen der Angebotskacheln: die Karte ist
   dann gemeint, sie soll nicht weiterlaufen. */
.mob-angebot:hover .mang-energie .energy-path-flow,
.mob-angebot:focus-visible .mang-energie .energy-path-flow,
.mob-angebot:has(:focus-visible) .mang-energie .energy-path-flow,
/* Die goldene Kachel haelt beim Ueberfahren ebenso an — sie traegt
   denselben Weg, also auch dasselbe Verhalten. */
.ang-mehr:hover .mang-energie .energy-path-flow,
.ang-mehr:focus-visible .mang-energie .energy-path-flow{
  animation-play-state:paused;
}
@media (prefers-reduced-motion:reduce){
  /* Kein Wandern, aber die Kontur bleibt — sie ist Gestalt, keine
     Bewegung. Die Sparks legt js/hero.js in diesem Fall gar nicht
     erst an. */
  .mang-energie .energy-path-flow{ animation:none; stroke-dasharray:none; opacity:.5 }
}
/* DIE UEBRIGEN KACHELN TRETEN ZURUECK (Zuruf Erguen 15.08.: "wenn ein
   angebot den rest der angebote milchglaseffekt damit das ausgewaehlte im
   fokus ist"). Milchglas ist Weichzeichner PLUS etwas weniger Farbe und
   Deckkraft — `opacity` allein saehe nur nach "ausgegraut" aus.

   PFLICHT: `pointer-events` bleibt unangetastet. Ein Weichzeichner aendert
   nur die DARSTELLUNG, nicht die Trefferflaeche — schaltete man die zurueck-
   getretenen Kacheln zusaetzlich fuer den Zeiger ab, kaeme man von einer
   Kachel nicht mehr zur naechsten: der Zeiger muss auf dem Weg dorthin ueber
   sie hinweg, und die Kachel unter ihm waere in dem Moment tot.

   Die Bedingung haengt am RASTER, nicht an der Kachel: nur wenn wirklich eine
   ueberfahren wird, treten die anderen zurueck. Ohne Zeiger sieht alles aus
   wie immer. Beide Raster tragen sie — die Szene (.ang-raster) und die Seite
   „Alle Angebote" (.ang2-raster). */
.ang-raster:has(.ang-karte:hover) .ang-karte:not(:hover),
.ang-raster:has(.ang-karte:focus-visible) .ang-karte:not(:focus-visible):not(:has(:focus-visible)),
.ang-raster:has(.ang-karte :focus-visible) .ang-karte:not(:focus-visible):not(:has(:focus-visible)),
.ang2-raster:has(.ang-karte:hover) .ang-karte:not(:hover),
.ang2-raster:has(.ang-karte:focus-visible) .ang-karte:not(:focus-visible):not(:has(:focus-visible)),
.ang2-raster:has(.ang-karte :focus-visible) .ang-karte:not(:focus-visible):not(:has(:focus-visible)){
  filter:blur(2.5px) saturate(.75);
  opacity:.62;
}
@media (prefers-reduced-motion:reduce){
  .ang-karte:hover,
  .ang-karte:focus-visible,
  .ang-karte:has(:focus-visible){ --khub:0px }
  /* Der Weichzeichner selbst ist keine Bewegung und bleibt — nur der
     Uebergang dorthin faellt weg. */
  .ang-karte{ transition:none }
}

/* DIE GANZE KACHEL IST EIN KLICKZIEL (Zuruf Erguen 15.08.) — seit dem
   zweiten Zuruf desselben Tages fuehrt sie in die LEISTUNGEN, nicht mehr
   auf die Angebote-Seite. Der Zeiger sagt es; die Knoepfe darin behalten
   ihren eigenen Klick. */
.ang-karte.ang-klick,
.mob-angebot.ang-klick{ cursor:pointer }
.ang-karte.ang-klick:focus-visible{
  outline:none;
  box-shadow:0 22px 48px rgba(8,38,48,.2), 0 0 0 3px rgba(18,199,224,.5);
}
/* Statt der Leistungsliste steht an der Kachel nur noch ihr Merkzeichen
   („4 Leistungen ansehen"). Ohne das waere die Kachel klickbar, ohne es
   zu zeigen — und die Liste selbst kostete genau die Hoehe, die dem Bild
   fehlt (Zuruf Erguen 15.08.: "statt als text unter der kachel eine
   infobox"). */
.mang-mehrhin{
  margin:2px 0 0;
  color:var(--accent-ink);
  font:800 clamp(10px,.72vw,12px)/1.3 Inter,system-ui,sans-serif;
  letter-spacing:.02em;
}
.mang-mehrhin::after{ content:" ›"; opacity:.7 }

/* ---------------------------------------------------------
   INFOBOX: die Leistungen eines Angebots
   Zuruf Erguen 15.08.: "wenn man auf ein angebot klickt soll sich ein
   fenster mit den Leistungen öffnen". Bildsprache der uebrigen Fenster
   (weisses Panel, 18-px-Radius, Kopfzeile mit Schliessen), nur schmaler:
   hier steht Text, kein Raster.
   --------------------------------------------------------- */
.angi-panel{
  position:relative;
  width:min(720px,94vw);
  max-height:92vh;
  margin:4vh auto;
  display:flex;
  flex-direction:column;
  border-radius:18px;
  background:#fff;
  box-shadow:0 30px 80px rgba(6,30,40,.3);
  overflow:auto;
  -webkit-overflow-scrolling:touch;
}
.angi-kopf{
  position:sticky;
  top:0;
  z-index:2;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:12px;
  padding:clamp(14px,2vh,22px) clamp(16px,2.4vw,28px);
  background:#fff;
  border-bottom:1px solid rgba(10,60,74,.12);
}
.angi-kopf h2{
  margin:0;
  color:var(--ink);
  font:900 clamp(17px,1.5vw,24px)/1.2 Inter,system-ui,sans-serif;
  letter-spacing:-.02em;
}
.angi-rumpf{
  display:grid;
  grid-template-columns:minmax(0,200px) minmax(0,1fr);
  gap:clamp(14px,2vw,26px);
  padding:clamp(16px,2.4vh,24px) clamp(16px,2.4vw,28px);
}
/* Ohne Bild nimmt der Text die ganze Breite — eine leere Spalte waere
   ein Loch neben dem Text. */
.angi-rumpf:not(:has(.angi-bild)){ grid-template-columns:minmax(0,1fr) }
.angi-bild{
  align-self:start;
  border-radius:14px;
  overflow:hidden;
  background:#f2f6f8;
  /* 2:3 wie die Kachel (1.650.0) — sonst zeigte das Info-Fenster einen
     anderen Ausschnitt als die Kachel daneben. */
  aspect-ratio:2 / 3;
}
.angi-bild img{ width:100%; height:100%; object-fit:cover; display:block }
.angi-text > *{ margin:0 0 10px }
.angi-sub{ color:#3d5c68; font:600 clamp(13px,1vw,15px)/1.5 Inter,system-ui,sans-serif }
.angi-preis{ color:var(--ink); font:900 clamp(22px,2.2vw,32px)/1 Inter,system-ui,sans-serif }
.angi-preis span{ font-size:.5em; font-weight:800 }
.angi-note{ color:#4d6d79 }
.angi-tarif{ color:#0b2f3a; font:800 clamp(12px,.95vw,14px)/1.4 Inter,system-ui,sans-serif }
.angi-lt{
  margin:16px 0 8px;
  color:var(--accent-ink);
  font:900 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
}
.angi-liste{ margin:0; padding:0; list-style:none }
.angi-liste li{
  position:relative;
  padding:6px 0 6px 24px;
  color:#20404b;
  font:600 clamp(13px,1vw,15px)/1.45 Inter,system-ui,sans-serif;
  border-bottom:1px solid rgba(10,60,74,.08);
}
.angi-liste li:last-child{ border-bottom:0 }
/* Der Haken ist gezeichnet, kein Emoji (Hausregel). */
.angi-liste li::before{
  content:"";
  position:absolute;
  left:4px; top:14px;
  width:9px; height:5px;
  border-left:2px solid var(--accent);
  border-bottom:2px solid var(--accent);
  transform:rotate(-45deg);
}
.angi-flies{
  margin:0 0 8px;
  font:500 14px/1.6 Inter,system-ui,sans-serif;
  color:rgba(10,32,40,.86);
  text-transform:none;
  letter-spacing:normal;
}
.angi-hinweis{ color:#5a7480; font:600 11.5px/1.5 Inter,system-ui,sans-serif }
.angi-leer{ color:#5a7480; font:600 clamp(13px,1vw,15px)/1.5 Inter,system-ui,sans-serif }
.angi-fuss{
  position:sticky;
  bottom:0;
  display:flex;
  align-items:center;
  gap:12px;
  padding:clamp(12px,1.8vh,18px) clamp(16px,2.4vw,28px);
  background:#fff;
  border-top:1px solid rgba(10,60,74,.12);
}
.angi-fuss .ang-korb{ height:44px; flex:1 1 auto }
@media (max-width:640px){
  .angi-rumpf{ grid-template-columns:minmax(0,1fr) }
  .angi-bild{ max-width:220px }
}

/* DIE HOVER-AUSFAHRT IST ENTFERNT (Zuruf Erguen 20.08.: "der hover
   mouse over effekt der die angebotskacheln vergrössern sollte, sollte
   entfernt werden"). Bis 1.650.0 schob sich beim Ueberfahren das Band
   unter der Kachel heraus (overflow:visible + z-index + grosser
   Schatten) — auf dem Bildschirm las sich das als Vergroesserung und lag
   auf der Pflichtangaben-Zeile. Die Kachel zeigt jetzt in Ruhe wie beim
   Ueberfahren dasselbe Bild; die Rueckmeldung tragen allein die
   LED-Rahmen und der Grund-Schatten. */
/* DAS FORMAT DER KACHEL IST 4:5 — und das ist keine gewaehlte Zahl,
   sondern die GEMESSENE: die Angebotsflaeche ist 1331 x 630 px; fuenf
   Spalten und zwei Zeilen ergeben 253 x 315 = 4:5, drei Spalten in einer
   Zeile 504 x 630 = ebenfalls 4:5. Bis dahin war die Bildzone elastisch
   (`flex:1 1 auto`) und wechselte ihr Verhaeltnis mit der Anzahl der
   Angebote — bei sechs Kacheln blieb ein 68 px hoher Streifen, aus dem
   `cover` die Bildmitte schnitt (Befund Erguen mit Bildschirmfoto).

   Die Kachel FUELLT die Zeilenhoehe und rechnet ihre Breite daraus
   (`height:100%; width:auto`) — damit stimmt das Verhaeltnis bei jeder
   Fenstergroesse, ohne dass irgendwo eine Pixelzahl steht.

   Das BILD liegt darunter und fuellt sie ganz; Titel, Preis und Knoepfe
   stehen als Band darauf. Ein Werbebild traegt seine Angaben ohnehin
   selbst — sie darunter zu wiederholen kostete genau die Hoehe, die dem
   Bild dann fehlte. */
/* Die Zelle IST schon 2:3 (siehe .ang-gitter) — die Kachel fuellt sie
   vollstaendig aus, das Bild liegt randlos darin. */
/* EIN SCHMALER RAHMEN UM DAS WERBEBILD (Zuruf Erguen 20.08.: "da manche
   werbungen bis zur kante gehen waere es gut wenn es einen kleinen
   aussern rahmen fuer die kachel gibt das die werbung komplett rahmenlos
   aussieht"). Auf seinem Bild lief das Motiv jeder Kachel bis an die
   Kante — ein Bild mit eigenem Grund (o2 blau, Telekom magenta) sah damit
   ABGESCHNITTEN aus statt vollstaendig. Der helle Kachelgrund tritt jetzt
   als schmaler Rand hervor; das Werbebild bekommt seine eigene Kante und
   wirkt dadurch fertig.
   Der Rand steht als GROESSE da (--ang-rahmen), weil Bild, Band und
   Plakette mit ihm rechnen — drei feste Zahlen liefen beim naechsten
   Feinschliff auseinander. Der innere Radius ist der aeussere MINUS dem
   Rand: nur so laufen beide Kanten parallel statt sich zu schneiden. */
.ang-karte.hat-bild{
  --ang-rahmen:clamp(5px,.45vw,9px);
  padding:0;
  position:relative;
  overflow:hidden;
}
.ang-karte.hat-bild .mang-bild{
  position:absolute;
  /* GEMESSENE FALLE: ein `inset:<wert>` mit `width/height:auto` spannt ein
     BILD nicht auf — fuer ersetzte Elemente gewinnt die eigene Groesse des
     Bildes, und `right`/`bottom` werden uebergangen (gemessen: 7 px links,
     328 px rechts). Deshalb Kante und Groesse ausdruecklich rechnen. */
  left:var(--ang-rahmen);
  top:var(--ang-rahmen);
  right:auto;
  bottom:auto;
  width:calc(100% - 2 * var(--ang-rahmen));
  height:calc(100% - 2 * var(--ang-rahmen));
  object-fit:cover;
  border-radius:calc(18px - var(--ang-rahmen));
}
.ang-karte.hat-bild .mang-badge{
  position:absolute;
  top:calc(10px + var(--ang-rahmen));
  left:calc(10px + var(--ang-rahmen));
  z-index:2;
}
/* Das Band traegt Namen und Knoepfe. Der Verlauf haelt die Schrift
   lesbar, egal wie hell das Bild an dieser Stelle ist.
   KOMPAKT SEIT 1.686.0 (Zuruf Erguen 23.08.: der Knopf und der Rest
   ueberdeckten einen Grossteil der Kachel): Textspalte links (.ang-btx,
   Titel zweizeilig geklemmt, Preis eine Zeile), rechts der runde
   Icon-Korb — zusammen zwei, drei flache Zeilen statt eines Stapels
   ueber dem halben Motiv. Beim Ueberfahren bzw. Fokus waechst nur der
   Titel auf (bis vier Zeilen); die volle Auskunft bleibt das
   Infofenster, das der Kachel-Klick oeffnet. */
.ang-karte.hat-bild .ang-band{
  position:absolute;
  left:var(--ang-rahmen); right:var(--ang-rahmen); bottom:var(--ang-rahmen);
  z-index:2;
  display:flex;
  flex-direction:row;
  align-items:flex-end;
  gap:10px;
  padding:clamp(16px,2.4vh,30px) clamp(10px,.9vw,16px) clamp(9px,.8vw,13px);
  background:linear-gradient(to top,rgba(4,22,30,.94) 34%,rgba(4,22,30,.5) 72%,rgba(4,22,30,0));
  border-radius:0 0 calc(18px - var(--ang-rahmen)) calc(18px - var(--ang-rahmen));
}
.ang-btx{
  flex:1 1 auto;
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:3px;
}
/* Ein Angebot OHNE gepflegten Titel und Preis (reines Werbebild) traegt
   trotzdem den Korb-Kreis (1.687.0, Zuruf Erguen): die leere Textspalte
   verschwindet, der Kreis rueckt an den rechten Rand. */
.ang-btx:empty{ display:none }
.ang-karte.hat-bild .ang-band .ang-kakt{ margin-left:auto }
.ang-karte.hat-bild .ang-band .mang-title{
  color:#fff; margin:0;
  font-size:clamp(13.5px,1vw,17px);
  line-height:1.25;
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  overflow:hidden;
}
.ang-karte.hat-bild:hover .ang-band .mang-title,
.ang-karte.hat-bild:focus-visible .ang-band .mang-title,
.ang-karte.hat-bild:has(:focus-visible) .ang-band .mang-title{ -webkit-line-clamp:4 }
/* SIE STEHT UEBER DER KACHEL (Zurufe Erguen 20.08.: "hier fehlen die
   kachel überschriften aus welchem bereich das angebot ist" + "sie
   sollten dezent über der kachel sein"). Das Rasterfeld ist die ZELLE,
   die Kachel darin behaelt ihr 2:3 — angGitterMessen rechnet die
   Zeilenhoehe um die gemessene Kopfhoehe hoeher.
   `min-height:0` an beiden: ohne das kann ein Flex-Kind nicht unter
   seine Inhaltshoehe schrumpfen und die Kachel spraenge aus der Zelle. */
.ang-zelle{
  display:flex;
  flex-direction:column;
  min-height:0;
}
.ang-zelle > .ang-karte{
  flex:1 1 auto;
  min-height:0;
}
.ang-zelle > .ang-bereich{
  flex:0 0 auto;
  margin:0 0 6px;
  padding-left:2px;
  font-size:clamp(10.5px,.78vw,12.5px);
  font-weight:800;
  letter-spacing:.14em;
  text-transform:uppercase;
  /* Zurueckgenommen — sie ordnet ein, sie wirbt nicht. */
  color:rgba(11,26,34,.5);
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
/* Die Fassung IM Band ist mit ihr entfallen. Weg zurueck: Git (1.655.0). */
.ang-karte.hat-bild .ang-band .mang-sub{ color:rgba(255,255,255,.82) }
/* Der Preis steht AUF dem Bild — er braucht die helle Schrift. In der
   dunklen Grundfarbe war er auf dem Plakat praktisch unsichtbar (am
   Bild gesehen). */
.ang-karte.hat-bild .ang-band .mang-preis,
.ang-karte.hat-bild .ang-band .mang-preis strong{ color:#fff; margin:0 }
.ang-karte.hat-bild .ang-band .mang-wa,
.ang-karte.hat-bild .ang-band .mang-note{ color:rgba(255,255,255,.86) }
/* Kompakter Preis auf dem Plakat: EINE Zeile, deutlich kleiner als die
   32-px-Schaufenstergroesse der Textkachel — das Motiv ist das Plakat,
   der Preis bleibt lesbar, traegt aber nicht mehr die halbe Bandhoehe. */
.ang-karte.hat-bild .ang-band .mang-preis{
  display:flex; align-items:baseline; gap:6px; flex-wrap:wrap;
}
.ang-karte.hat-bild .ang-band .mang-preis strong{ font-size:clamp(17px,1.3vw,21px) }
.ang-karte.hat-bild .ang-band .mang-wa{ font-size:clamp(11px,.8vw,13px) }
.ang-karte.hat-bild .ang-band .mang-note{ font-size:clamp(10px,.72vw,12px) }
/* Die Unterscheidungszeile bei gleichen Titeln (1.686.0) — auf dem Band
   hell und einzeilig, auf der Textkachel gedaempft. */
.mang-variante{
  margin:0;
  font-size:clamp(10.5px,.75vw,12.5px);
  color:rgba(11,26,34,.62);
}
.ang-karte.hat-bild .ang-band .mang-variante{
  color:rgba(255,255,255,.78);
  font-weight:700;
  letter-spacing:.02em;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
.ang-karte.hat-bild .ang-kakt{ margin-top:0; flex:0 0 auto }
.ang-karte.hat-bild .ang-kakt .mang-cta{
  border-color:rgba(255,255,255,.45); color:#fff;
}
/* DER RUNDE ICON-KORB AUF DEM PLAKAT (1.686.0): derselbe Knopf wie
   ueberall (korbKnopf), nur die Gestalt ist hier der Kreis — der Text
   wandert unsichtbar mit (.ak-tx, fuer Vorleser bleibt aria-label am
   Knopf), die Mengen-Plakette .ak-n sitzt an der Kreiskante. Auf der
   Knopfzeile aller anderen Orte bleibt der Textknopf: dort ist .ak-ic
   ausgeblendet (Vorgaberegel weiter unten bei .ang-korb). */
.ang-karte.hat-bild .ang-band .ang-korb{
  flex:0 0 auto;
  width:clamp(42px,3vw,48px);
  height:clamp(42px,3vw,48px);
  padding:0;
  border-radius:50%;
  position:relative;
  display:grid;
  place-items:center;
  box-shadow:0 10px 22px rgba(4,22,30,.35);
}
.ang-karte.hat-bild .ang-band .ang-korb .ak-tx{
  position:absolute; width:1px; height:1px; overflow:hidden;
  clip:rect(0 0 0 0); white-space:nowrap;
}
.ang-karte.hat-bild .ang-band .ang-korb .ak-ic{
  display:grid; place-items:center; width:22px; height:22px;
}
.ang-karte.hat-bild .ang-band .ang-korb .ak-n{
  display:grid; place-items:center;
  position:absolute; top:-4px; right:-4px;
  min-width:18px; height:18px; padding:0 4px;
  border-radius:999px;
  background:#0c1a20; color:#fff;
  font:800 10.5px/1 Inter,system-ui,sans-serif;
}
/* Ohne Bild bleibt die Kachel, was sie war: eine Textkachel, die die
   Flaeche fuellt. */
.ang-karte .mang-bild{
  flex:1 1 auto;
  min-height:0;
  width:100%;
  object-fit:cover;
  border-radius:12px;
}
.ang-karte .mang-title{ font-size:clamp(15px,1.15vw,20px); margin:0 }
.ang-karte .mang-sub{ font-size:clamp(11.5px,.8vw,13.5px); margin:0 }
.ang-karte .mang-preis strong{ font-size:clamp(22px,1.8vw,32px) }
.ang-karte .mang-wa{ font-size:clamp(14px,1vw,17px) }
.ang-karte .mang-liste{ display:none }
.ang-karte .mang-hinweis{ font-size:clamp(10.5px,.72vw,12px); margin:0 }
.ang-karte .mang-cta{ height:clamp(32px,2.2vw,38px) }

/* Knopfzeile IN der Kachel: „In den Warenkorb" fuehrt, der bisherige
   Weg (Angebot anfragen) bleibt als leiser zweiter Weg daneben. */
.ang-kakt{
  margin-top:auto;
  display:flex;
  align-items:center;
  gap:8px;
  flex-wrap:wrap;
}
.ang-korb{
  flex:1 1 auto;
  height:clamp(32px,2.2vw,38px);
  padding:0 14px;
  border:0;
  border-radius:999px;
  background:linear-gradient(135deg,#0f8ea3,#12b3c9);
  color:#fff;
  font:900 clamp(10px,.7vw,11.5px)/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  cursor:pointer;
  transition:transform .2s ease,filter .2s ease;
}
.ang-korb:hover,.ang-korb:focus-visible{ transform:translateY(-1px); filter:brightness(1.06) }
.ang-korb:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(18,199,224,.3) }
.ang-korb.ist-drin{ background:linear-gradient(135deg,#1f9d55,#2eb86a) }
/* Der Knopf traegt Icon und Text als eigene Spans (korbKnopfMalen,
   1.686.0). VORGABE ist der Textknopf: Icon und Mengen-Plakette sind
   aus — nur das Plakat-Band (oben) dreht die Rollen um. */
.ang-korb .ak-ic{ display:none }
.ang-korb .ak-ic svg{ width:100%; height:100%; display:block }
.ang-korb .ak-n{ display:none }
/* Der fruehere "Beraten lassen"-Ersatzknopf (.ang-beraten, 1.682.0) ist mit
   1.684.0 ersatzlos ausgebaut: der Korb steht immer, ausser der Artikel ist
   nicht auf Vorrat (Zuruf Erguen 23.08.). Weg zurueck: Git. */
/* Der Korb ist der HAUPTWEG und nimmt die ganze Zeile; „Anfragen" bleibt
   daneben als leiser zweiter Weg — als gefuellte Goldpille daruntergesetzt
   sah es aus wie zwei gleichrangige Knoepfe (am Bild gesehen). */
.ang-korb{ flex:1 1 100% }
.ang-karte .ang-kakt .mang-cta{
  flex:0 0 auto;
  height:26px;
  padding:0 12px;
  background:transparent;
  border:1px solid rgba(11,58,72,.2);
  color:#0b2f3a;
  font-size:10px;
}
.ang-karte .ang-kakt .mang-cta::after{ display:none }
.ang-karte .ang-kakt .mang-cta:hover{ border-color:var(--accent); background:transparent }

/* Derselbe Korb-Knopf am Angebot des Monats in der Szene. Dort ist die
   Goldpille der eingefuehrte Weg in die Beratung — der Korb steht als
   gleich hoher Partner darueber, nicht als kleinerer Nebenknopf.
   `flex:1 1 100%` von oben wuerde ihn in der QUERliegenden Zubehoer-Karte
   auf eine eigene Zeile zwingen; dort steht er neben der Pille. */
.mang-akt .ang-korb{ height:clamp(40px,2.9vw,46px); flex:0 0 auto }
.mob-angebot.ist-unten .mang-akt .ang-korb{ padding:0 16px }

/* Der Weg von der Monatskachel zu den uebrigen Angeboten (Zuruf Erguen
   14.08.). Bewusst ZURUECKGENOMMEN: der Warenkorb-Knopf darueber bleibt
   die Handlung, das hier ist der Nebenweg. */
.mang-mehr{
  display:block;
  width:100%;
  margin:10px 0 0;
  padding:9px 12px;
  border:1px solid rgba(6,20,26,.16);
  border-radius:999px;
  background:transparent;
  color:#0d5563;
  font:900 10.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
  cursor:pointer;
  transition:border-color .2s ease, background .2s ease;
}
.mang-mehr:hover,.mang-mehr:focus-visible{ border-color:var(--accent); background:rgba(18,199,224,.08) }
/* GLOW UND PULSIEREN (Zuruf Erguen 14.08.). Der Weg zu den uebrigen
   Angeboten ist der Nebenweg neben dem Warenkorb — er soll auffallen,
   ohne den Hauptweg zu ueberstrahlen: deshalb der ruhige Atem der
   Haus-Knoepfe (Bauart ctaBreathe) in der Akzentfarbe, NICHT in Gold.
   Beim Ueberfahren haelt er an (der Zustand ist dann ohnehin sichtbar),
   und bei `prefers-reduced-motion` bleibt allein der ruhige Schein. */
@keyframes mangMehrAtem{
  0%,100%{ border-color:rgba(6,20,26,.16); box-shadow:0 0 0 0 rgba(18,199,224,0) }
  50%{ border-color:rgba(18,199,224,.75); box-shadow:0 0 0 6px rgba(18,199,224,.14) }
}
.mang-mehr{ animation:mangMehrAtem 2.8s ease-in-out infinite }
.mang-mehr:hover,.mang-mehr:focus-visible{ animation-play-state:paused }
@media (prefers-reduced-motion:reduce){
  .mang-mehr{ animation:none; border-color:rgba(18,199,224,.55); box-shadow:0 0 0 4px rgba(18,199,224,.1) }
}

/* Kopfzeile der Angebotsseite: zwei Zeilen, nicht mehr. Sie sagt, was die
   Seite ist (Zuruf Erguen 14.08.), und laesst dem Raster seine Flaeche —
   der frueher entfernte grosse Titelblock nahm die halbe Seite. */
.ang-kopf{
  flex:0 0 auto;
  margin:0 0 clamp(8px,1.1vh,16px);
  text-align:center;
  opacity:var(--r,0);
}
.ang-kopf-t{
  margin:0;
  color:var(--ink);
  /* GROESSER (Zuruf Erguen 19.08.: "überschrift direkt im shop - grösser
     machen"): 19..30 -> 26..44. Sie bleibt EINE Zeile — die Flaeche
     darunter gehoert weiter dem Raster, nur die Zeile selbst traegt mehr
     Gewicht. Die Unterzeile waechst im selben Verhaeltnis mit, sonst
     saehe sie neben der grossen Zeile verloren aus. */
  font:900 clamp(26px,2.5vw,44px)/1.1 Inter,system-ui,sans-serif;
  letter-spacing:-.03em;
}
.ang-kopf-s{
  margin:6px 0 0;
  color:#40606c;
  font:600 clamp(13px,1vw,17px)/1.4 Inter,system-ui,sans-serif;
}
/* Die Pflichtangaben stehen jetzt in einem eigenen Kasten DIREKT unter dem
   Raster (Zuruf Erguen 14.08.), nicht mehr in der Knopfzeile. */
.ang-rechtbox{
  flex:0 0 auto;
  margin:clamp(6px,.9vh,12px) 0 0;
  opacity:var(--r,0);
}
.ang-fuss{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:clamp(8px,1vw,14px);
  flex-wrap:wrap;
  opacity:var(--r,0);
}
/* EINE DURCHGEHENDE BREITE KACHEL STATT EINER PILLE (Zuruf Erguen 15.08.:
   "warum ist alle angebote nicht in einer durchgehenden breiten kachel über
   die ganze seite wie besprochen?"). Der Weg dahinter traegt das GANZE
   Sortiment — als Pille am rechten Rand las er sich wie eine Nebenaktion.
   Die Zeile ist damit ein Block: die Kachel nimmt die volle Breite von
   `.ang-flaeche`, und die haelt links `--edge` und rechts zusaetzlich den
   `--rail-gutter` frei (Regel 1.613.0) — sie laeuft also nie in die
   Fortschrittsleiste. Ein eigenes `padding-right` braucht es hier NICHT
   mehr; das war die alte Ausweich-Mechanik der Pille.
   SO WEIT WIE MOEGLICH NACH UNTEN (Zurufe Erguen 20.08.: "den goldenen
   button nach unten weil zu viel leerer platz", dann "das angebote
   button muss soweit wie möglich nach unten"): der Fuss traegt KEINEN
   eigenen Abstand mehr — er endet an der Unterkante der .ang-flaeche,
   und DEREN bottom-Offset ist auf das Minimum verkleinert, das der
   mittig schwebende Scroll-Hinweis braucht (siehe .ang-flaeche; die
   Grenze ist GEMESSEN, keine Zahl aus dem Kopf). Die freigewordene
   Hoehe bekommt das Raster darueber — die zwei Kacheln wachsen mit
   (angGitterMessen rechnet die Zelle aus der Rasterhoehe). */
.ang-fuss{
  display:block;
  margin-bottom:0;
}
.ang-mehr{
  /* Bezugsrahmen fuer den Pfeil darunter (Zuruf 19.08.). */
  position:relative;
  display:flex;
  width:100%;
  align-items:center;
  /* NAME UND ZAHL STEHEN MITTIG (Zuruf Erguen 15.08.: "alle angebote text
     mittig und keinen pfeil nach rechts"). Die Kachel ist so breit wie das
     Raster darueber; linksbuendig sass die Beschriftung in einer sonst
     leeren Flaeche. */
  justify-content:center;
  gap:clamp(12px,1.4vw,22px);
  /* UM DIE HAELFTE KLEINER (Zuruf Erguen 20.08.: "alle angebote button
     um die haelfte kleiner und die beiden kachel grösser für die
     angebote") — genau die Haelfte der 19.08.-Werte (100–144 px, damals
     "viel höher"): die Hoehe, die der Balken abgibt, bekommt das Raster
     darueber, und die beiden 2:3-Kacheln wachsen von selbst mit. Der
     vh-Anteil laesst ihn auf flachen Fenstern weiter mitschrumpfen. */
  min-height:clamp(50px,5.5vh,72px);
  padding:clamp(8px,1vh,13px) clamp(18px,2vw,30px);
  /* Randlos wie die Angebotskacheln darueber — derselbe Radius, derselbe
     Schatten; die Kachel gehoert sichtbar zu ihnen. */
  border-radius:18px;
  /* GOLD (Zuruf Erguen 15.08.: "farbe in gold aendern"). Das ist KEIN
     Bruch der Hausregel 1.376.0 — Gold gehoert der HANDLUNG, und dieser
     Weg ist die Handlung dieser Szene: er fuehrt ins ganze Sortiment.
     Auf Gold traegt die Schrift dunkel; weiss waere darauf nicht lesbar.
     DIESELBEN WERTE WIE DER SHOP-KNOPF im Kopf (.shop-fab) — EIN Gold auf
     der Seite, nicht zwei.
     KEIN `var(--gold)`: das ist ein MOS-Token und auf der Haendlerseite
     NICHT definiert. Eine unbekannte Variable macht die ganze Deklaration
     ungueltig, und heraus kaeme `background:none` — von der Sonde
     gemessen. MERKSATZ: Farben aus MOS reisen nicht mit. */
  background:linear-gradient(140deg,#e6bc50,#c99a2e);
  color:#231903;
  border:1px solid #a8801f;
  /* Schrift und Zeichen wachsen mit der Kachel — eine doppelt so hohe
     Flaeche mit 12-px-Schrift saehe leer aus statt auffaellig. */
  /* GROESSER (Zuruf Erguen 20.08.: "die schrift grösser für alle
     angebote") — die Kachel ist hoch genug, die Schrift wuchs mit. */
  font:900 clamp(20px,1.9vw,30px)/1.2 Inter,system-ui,sans-serif;
  letter-spacing:.14em;
  text-transform:uppercase;
  text-align:center;
  cursor:pointer;
  transition:transform .28s cubic-bezier(.2,.8,.2,1),
             background .28s ease, box-shadow .28s ease;
}
.ang-mehr-t{ flex:0 1 auto }
/* DIE MENGENZAHL IST ENTFALLEN (Zuruf Erguen 20.08.: "keine mengenzahl
   beim angebote button") — sie wird auch nicht mehr gebaut (angFussMalen);
   die Anzahl traegt weiter das aria-label und die Seite dahinter. */
/* DER STRICH RECHTS IST ENTFALLEN (Zuruf Erguen 15.08.: "keinen pfeil nach
   rechts"). Er zog den Blick an den Rand, waehrend die Beschriftung jetzt in
   der Mitte steht — und die ganze Kachel ist ohnehin der Weg, nicht ein
   Zeichen an ihrem Ende. Die Regel bleibt ERSATZLOS weg; das Element wird
   auch nicht mehr gebaut (angFussMalen in js/experience.js). */
.ang-mehr:hover,.ang-mehr:focus-visible{
  outline:none;
  transform:translateY(-3px);
  background:linear-gradient(140deg,#f0cc68,#d8a83a);
  box-shadow:0 20px 44px rgba(150,110,20,.30);
}
.ang-mehr:focus-visible{ box-shadow:0 0 0 3px rgba(201,154,46,.5) }
/* „es soll pulsieren": ruhiger Schein in der Akzentfarbe, KEIN Gold — das
   traegt im Haus die Handlung, und der Warenkorb bleibt der Hauptweg
   (Regel 1.376.0). Beim Ueberfahren haelt er an. */
@keyframes angMehrAtem{
  0%,100%{ box-shadow:0 0 0 0 rgba(201,154,46,0) }
  50%{     box-shadow:0 0 0 8px rgba(201,154,46,.30) }
}
.ang-mehr{ animation:angMehrAtem 2.8s ease-in-out infinite }
.ang-mehr:hover,.ang-mehr:focus-visible{ animation-play-state:paused }
/* DIE BEIDEN NICK-PFEILE AN DER GOLDENEN KACHEL SIND ENTFALLEN (Zuruf
   Erguen 20.08.: "den goldenen button nach unten weil zu viel leerer
   platz"). Die Kachel steht seither an der SZENEN-UNTERKANTE — ein Pfeil
   darunter hinge auf dem Scroll-Hinweis. angFussMalen (js/experience.js)
   baut die spans nicht mehr; die Regeln (.angm-pfeil, .angm-pfeil-r samt
   Keyframes) sind MIT dem Markup entfernt (Hausregel: kein toter
   Codeweg). Der Weg zurueck liegt im Git-Verlauf (1.651.0/1.652.0). */
/* Der Einkaufswagen vor der Beschriftung (Zuruf Erguen 15.08.: „hier
   auch"). Er faerbt sich ueber `currentColor` mit — auf dem goldenen Grund
   also dunkel, ohne zweite Farbregel — und nimmt keinen Zeiger. Etwas
   groesser als am schwebenden Knopf: die Kachel ist bis zu 74 px hoch. */
.ang-mehr-sym{
  width:clamp(24px,1.9vw,30px);
  height:clamp(24px,1.9vw,30px);
  flex:0 0 auto;
  pointer-events:none;
}
@media (prefers-reduced-motion:reduce){
  .ang-mehr{ animation:none; box-shadow:0 0 0 5px rgba(201,154,46,.2) }
}
/* Pflichtangaben: eine ruhige Zeile ueber die volle Breite. Klein, aber
   nicht versteckt — mit echtem Kontrast (nicht ausgegraut), sonst waere
   die Kennzeichnung nur formal vorhanden. */
.ang-recht{
  flex:1 1 100%;
  margin:0;
  text-align:center;
  color:#40606c;
  font:600 clamp(9.5px,.62vw,11px)/1.5 Inter,system-ui,sans-serif;
}


/* =========================================================
   WARENKORB UND ZWEITE ANGEBOTE-SEITE
   Auftrag Erguen 14.08.: "wir wollen im prinzip einen online shop
   simulieren aber abholung im shop".
   ========================================================= */
.korb-fab{
  position:relative;
  /* DER KOPF IST space-between, und die Navigation liegt ABSOLUT in der
     Mitte — sie zaehlt also nicht als Flex-Kind. Ohne diese Zeile stuenden
     Logo, Korb und Shop-Knopf gleichmaessig verteilt da, und der Korb saesse
     mitten auf dem Wort "Reparatur" (am Bild gesehen). `margin-left:auto`
     schiebt Korb UND Shop-Knopf gemeinsam nach rechts. */
  margin-left:auto;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:40px; height:40px;
  /* Abstand zum goldenen Knopf (Befund Erguen 14.08.: "zu nah einander
     dran mehr abstad") — bei 10 px sassen Korbring und Pille fast
     aneinander. */
  margin-right:clamp(16px,1.5vw,26px);
  border:1px solid rgba(6,20,26,.16);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  cursor:pointer;
  transition:border-color .25s ease,transform .25s ease;
}
.korb-fab:hover,.korb-fab:focus-visible{ border-color:var(--accent); transform:translateY(-1px) }
.korb-fab:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(18,199,224,.28) }
.korb-fab svg{
  width:19px; height:19px;
  fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.korb-fab circle{ fill:currentColor; stroke:none }
/* Die Zahl steht NUR da, wenn wirklich etwas im Korb liegt — eine
   dauerhafte 0 waere eine Aufforderung ohne Anlass. */
.korb-zahl{
  position:absolute;
  top:-5px; right:-5px;
  min-width:18px; height:18px;
  padding:0 5px;
  border-radius:999px;
  background:#0f8ea3;
  color:#fff;
  font:900 10.5px/18px Inter,system-ui,sans-serif;
  text-align:center;
  opacity:0;
  transform:scale(.6);
  transition:opacity .2s ease,transform .2s ease;
}
.korb-fab.ist-voll .korb-zahl{ opacity:1; transform:scale(1) }

/* ANIMATION BEIM HINEINLEGEN (Zuruf Erguen 15.08.: "wenn was in den warenkorb
   gelegt wird eine animation machen"). Bewusst OHNE zusaetzliches Element und
   ohne `position`-Eingriff: der Ring ist ein wachsender box-shadow, und der
   traegt sich auch an einem Knopf, der `fixed`, `relative` oder gar nicht
   positioniert ist — eine ::after-Loesung haette sich am naechsten
   positionierten Vorfahren aufgehaengt (Fallenklasse 1.516.0).
   Angesprochen werden BEIDE Korb-Knoepfe ueber die gemeinsame Klasse. */
@keyframes korbPuls{
  0%{   transform:scale(1);    box-shadow:0 0 0 0 rgba(15,142,163,.55) }
  35%{  transform:scale(1.13) }
  100%{ transform:scale(1);    box-shadow:0 0 0 18px rgba(15,142,163,0) }
}
@keyframes korbZahlPop{
  0%{ transform:scale(1) }
  40%{ transform:scale(1.45) }
  100%{ transform:scale(1) }
}
.korb-puls{ animation:korbPuls .62s cubic-bezier(.2,.8,.2,1) }
.korb-puls .korb-zahl,
.korb-puls .zsh-wkzahl{ animation:korbZahlPop .62s cubic-bezier(.2,.8,.2,1) }
@media (prefers-reduced-motion: reduce){
  .korb-puls,
  .korb-puls .korb-zahl,
  .korb-puls .zsh-wkzahl{ animation:none }
}

/* --- zweite Seite ---------------------------------------------- */
.ang2-panel{
  position:relative;
  z-index:1;
  width:min(94vw,1500px);
  /* DIE VOLLE FENSTERHOEHE (Zuruf Erguen 15.08.: "das overlay ist zu klein
     von der höhe, bei hover verschwindet der warenkorbbutton und man muss
     scrollen … nutze die volle höhe des browsers aus").
     GRUND: beim Ueberfahren faehrt das Band mit Preis und Warenkorb-Knopf
     UNTER die Kachel hinaus (Regel 1.627.0) — es braucht also Luft unter
     der letzten Kachelreihe. Bei 78vh Mindesthoehe und 88vh Deckel lag die
     Reihe zu dicht am unteren Rand, und der Knopf wanderte aus dem Bild.
     Jetzt fuellt das Fenster die Hoehe bis auf einen schmalen Rand; die
     Mindesthoehe bleibt, damit es bei zwei Karten kein flacher Streifen
     wird (Zuruf 14.08.). */
  min-height:min(88vh,940px);
  max-height:96vh;
  margin:2vh auto;
  /* Das Polster steht als eigene Groesse da, weil die klebende Leiste es
     nach beiden Seiten wieder aufheben muss (siehe .ang2-fest). */
  --ang2-pad:clamp(16px,2vw,28px);
  padding:0 var(--ang2-pad) var(--ang2-pad);
  border-radius:22px;
  background:rgba(255,255,255,.97);
  box-shadow:0 30px 80px rgba(6,20,26,.28);
  overflow:auto;
}
/* DER SHOP ALS EIGENER TAB (Zuruf Erguen 19.08.: "… den eigenen shop in
   einem neuen fenster und volle höhe und breit im neuen tab öffnen").
   html.ang-tab steht, wenn die Seite mit #angebote geladen wurde (Inline-
   Zeile im <head>) — dann fuellt der Kasten das ganze Fenster: kein Rand,
   kein Radius, kein Schatten-Fenster-in-Fenster. Die Regel gilt fuer BEIDE
   .ang-overlay-Seiten (Angebote UND Zubehoer), damit der Alkaya-Weg im Tab
   dieselbe volle Flaeche bekommt.
   Das #angOverlay ist im Tab schon VOR dem ersten Skriptlauf sichtbar —
   sonst blitzte der Hero der Erzaehlseite auf, bis angebote-shop.js die
   Seite oeffnet. Der leere weisse Kasten ist der ehrlichere Wartebildschirm. */
html.ang-tab #angOverlay{
  opacity:1;
  visibility:visible;
  pointer-events:auto;
  transition:none;
}
html.ang-tab .ang-overlay{ padding:0 }
html.ang-tab .ang-overlay .ang2-panel{
  width:100vw;
  min-height:100vh;
  max-height:100vh;
  margin:0;
  border-radius:0;
  box-shadow:none;
  background:#fff;
}
html.ang-tab .ang-overlay .ang2-fest{ border-radius:0 }

/* KOPF UND KATEGORIE-LEISTE BLEIBEN BEIM ROLLEN STEHEN (Zuruf Erguen
   14.08.: „beim scrollen soll der bereich fest bleiben … damit der user
   besser zwischen katagorien wechseln kann bei bedarf" — und davor
   „wo ist das schliessen button?").
   GEMESSEN war es ein echter Mangel: nach dem Rollen ans Ende stand der
   Zurueck-Knopf bei y = -1624..-1582, also weit ausserhalb des Kastens —
   der Weg hinaus war nur noch ueber Escape zu finden.
   Das seitliche Polster wird aufgehoben und im Kasten selbst gesetzt,
   damit die Leiste ueber die volle Breite deckt; ohne das schoebe sich
   eine Kachel links und rechts an ihr vorbei. Der Grund ist VOLL weiss
   (nicht .97 wie das Fenster) — sonst schimmerte die Kachel darunter
   durch. */
.ang2-fest{
  position:sticky;
  top:0;
  z-index:3;
  margin:0 calc(-1 * var(--ang2-pad));
  /* OBEN EIGENSTAENDIG KLEIN (Zuruf Erguen 31.08.: "der header ist zu hoch.
     maximal sollte es bis zum unteren rand des logos sein") — das grosse
     Seitenpolster gab dem Kopf auch oben 28 px Luft. */
  padding:12px var(--ang2-pad) 10px;
  background:#fff;
  border-radius:22px 22px 0 0;
  box-shadow:0 10px 18px -14px rgba(6,20,26,.5);
}
/* Traegt die Leiste NUR den Kopf (Zubehoer-Seite — dort bleiben Suche und
   Filterzeilen bewusst draussen), gaebe der Kopf-Abstand von 16 px
   zusammen mit dem Leisten-Polster von 10 px einen zu breiten weissen
   Streifen. Auf der Angebote-Seite folgt die Kategorieleiste, dort bleibt
   der Abstand noetig. */
.ang2-fest > .ang2-kopf:last-child{ margin-bottom:4px }
/* Steht die Suchzeile MIT in der Leiste (Zubehoer-Seite), traegt die
   Leiste ihr Polster nach unten — der eigene Rand der Zeile stuende
   doppelt. Der 16-px-Abstand zum Kopf darueber bleibt und ist genau das
   „etwas runter" aus dem Zuruf. */
.ang2-fest > .zsh-suche{ margin-bottom:0 }
.ang2-kopf{
  /* DIE HOEHE DER WORTMARKE STEHT AN EINER STELLE (1.703.0). Sie wird zweimal
     gebraucht: von `.ang2-logo` als eigene Hoehe und hier als Untergrenze fuer
     den Kopf. Zwei getippte Zahlen liefen beim naechsten "Logo groesser"
     auseinander. */
  --ang2-logo-h:clamp(30px,2.6vw,42px);
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:14px;
  margin-bottom:10px;
  /* DER KOPF MUSS DIE MARKE AUFNEHMEN (Befund 1.703.0, am BILD gesehen).
     `.ang2-marke` ist absolut positioniert und traegt deshalb NICHT zur Hoehe
     bei — die richtet sich nach dem, was im Fluss steht, also nach der
     Knopfgruppe. Solange dort nur das Logo hing, passte das zufaellig; mit der
     Standortzeile darunter ragte die Marke unten heraus und wurde abgeschnitten.
     Am Zahlenwert war das nicht zu sehen, erst am Bild.
     Gerechnet: Logohoehe + 5 px Abstand + rund 14 px Zeilenhoehe. */
  min-height:calc(var(--ang2-logo-h) + 19px);
  /* Bezugsrahmen fuer das mittige Logo — ohne ihn wanderte das absolute
     Bild zum naechsten positionierten Vorfahren (Lehre 1.516.0). */
  position:relative;
}
/* DAS LOGO MITTIG OBEN (Zuruf Erguen 19.08. an der Shop-Tab-Seite: "in
   der mitte oben unser logo"): die phoneshop-Wortmarke steht absolut in
   der Mitte der Kopfzeile — Titel links und Knoepfe rechts bleiben, das
   Bild nimmt keinen Zeiger (reine Marke, kein Knopf). DIESELBE Datei wie
   die Kopfleiste der Erzaehlseite (assets/logo-phoneshop-640.webp) — eine
   zweite Fassung waere eine zweite Wahrheit. Unter 900 px Fensterbreite
   faellt es weg: dort traefe die Mitte den Titel. */
/* DIE MARKE ALS BLOCK (1.703.0): Wortmarke und Standortzeile stehen
   untereinander und werden ALS GRUPPE mittig gehalten. Bis dahin war das Logo
   selbst absolut zentriert; eine Zeile darunter haette es aus der optischen
   Mitte geschoben — zentriert war dann das Logo, nicht die Marke. */
.ang2-marke{
  position:absolute;
  left:50%;
  top:50%;
  translate:-50% -50%;
  display:flex;
  flex-direction:column;
  align-items:center;
  /* Der ABSTAND zwischen Wortmarke und Orten. 5 px: eng genug, dass beides als
     EINE Marke gelesen wird, weit genug, dass die Versalien nicht am
     Logo-Unterschnitt kleben. */
  gap:5px;
  /* Reine Marke, kein Bedienelement — sie darf keinen Klick abfangen. */
  pointer-events:none;
  /* Damit die Zeile die Kopfmitte nicht sprengt, wenn viele Orte gepflegt
     sind: sie bricht dann lieber um, als den Kopf zu verbreitern. */
  max-width:min(46vw,520px);
}
/* DIE STANDORTZEILE. Gestalt bewusst zurueckhaltend: sie ist eine ANGABE unter
   der Marke, kein zweiter Titel — deshalb klein, in Versalien, weit gesperrt
   und in der gedaempften Hausfarbe. Die weite Sperrung ist das, was eine
   solche Zeile typografisch traegt; ohne sie sieht sie aus wie vergessener
   Fliesstext. Der Trenner ist ein Mittelpunkt (siehe PhoneshopOrteSchreiben). */
.ang2-orte{
  margin:0;
  font:700 10.5px/1.25 Inter,system-ui,sans-serif;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--ink-soft);
  text-align:center;
  white-space:nowrap;
}
/* Wird die Zeile umbrochen (viele Orte), darf sie nicht mehr auf einer Zeile
   bestehen — sonst schoebe sie den Kopf auseinander. */
@media (max-width:1200px){ .ang2-orte{ white-space:normal } }
/* `hidden` gewinnt gegen die eigene Regel nur mit dieser Zeile — ohne sie
   stuende die leere Zeile trotz hidden im Bild (Hausregel, sechs Faelle). */
.ang2-orte[hidden]{ display:none }
/* Das Logo liegt jetzt IM Marken-Block und braucht seine eigene Zentrierung
   nicht mehr; die Masse bleiben unveraendert. */
.ang2-logo{
  /* Groesser seit 1.688.0 (Zuruf Erguen 23.08.: "logo vom phoneshop
     grösser") — die Wortmarke traegt den Kopf, sie soll ihn auch fuellen.
     Die Zahl steht in `--ang2-logo-h` am Kopf: der rechnet seine Mindesthoehe
     daraus (siehe dort). */
  height:var(--ang2-logo-h);
  width:auto;
  pointer-events:none;
}
/* Unter 900 px faellt die ganze MARKE weg, nicht nur das Logo — dort traefe
   die Mitte den Titel bzw. die Knopfgruppe. Eine allein stehengebliebene
   Standortzeile mitten im Kopf waere schlimmer als keine. */
@media (max-width:900px){ .ang2-marke{ display:none } }
.ang2-kopf h2{
  margin:0;
  color:var(--ink);
  font:900 clamp(20px,2vw,30px)/1.1 Inter,system-ui,sans-serif;
  letter-spacing:-.02em;
}
/* WARENKORB UND „ZUR STARTSEITE" BLEIBEN RECHTS (Befund Erguen 24.08.:
   „warenkorb und zur startseite rechts auf der seite wie vorher").
   URSACHE, gemessen: seit die Ueberschrift „Alle Angebote" nur noch fuers
   Vorlesen da ist (1.702.0), liegt sie ABSOLUT positioniert — also ausserhalb
   des Flusses. `justify-content:space-between` verteilt aber nur, was IM Fluss
   steht, und das war danach genau EIN Kind: die Knopfgruppe. Ein einzelnes
   Kind schiebt space-between an den ANFANG, also nach links.
   `margin-left:auto` haengt die Gruppe unabhaengig von der Zahl ihrer
   Geschwister rechts an — es traegt auch dann, wenn dort eines Tages wieder
   ein sichtbarer Titel steht. Das mittige Logo bleibt davon unberuehrt: es ist
   ebenfalls absolut und nimmt am Fluss nicht teil. */
.ang2-kopf .zsh-kopfrechts{ margin-left:auto }
/* DIE RAHMENZEILE DES SHOPS (23.08.): der Korb ist eine RESERVIERUNG mit
   Abholung — das stand bisher erst im Korb-Fenster. Reiner Text, kein
   Bedienelement; auf BEIDEN Koepfen (Angebote- und Zubehoer-Seite, ein
   Bauer in angebote-shop.js). SEIT 31.08. WOHNT SIE IM KOPF SELBST
   (Zuruf Erguen: "der header ist zu hoch") — links im Fluss neben dem
   mittigen Logo; unter 900 px faellt die Marke weg, dann darf sie breiter. */
.ang2-abhol{
  margin:0;
  /* Bis zur LINKEN Kante des mittigen Logos (halbe Logobreite 210 + Puffer) —
     44% liefen auf 1280/1000 px hinein (gemessen). Unter 900 px ist die Marke
     weg, dann darf die Zeile breiter. */
  max-width:calc(50% - 240px);
  color:rgba(6,20,26,.6);
  font:600 12.5px/1.35 Inter,system-ui,sans-serif;
}
@media (max-width:900px){ .ang2-abhol{ max-width:60% } }
/* DIE ZWEI KNOEPFE OBEN RECHTS (Zuruf Erguen 15.08.: „oben rechts die
   button verbessern"). Vorher trugen Warenkorb und Weg-hinaus DIESELBE
   Klasse und sahen zeichengleich aus — zwei weisse Versal-Pillen
   nebeneinander, und nichts sagte, welcher der Hauptweg ist. Jetzt ist
   `.ang2-zu` der NEBENweg (helle Pille mit Richtungszeichen), `.ang2-wk`
   der HAUPTweg (dunkel gefuellt, Wagen-Symbol). */
.ang2-zu{
  flex:0 0 auto;
  display:inline-flex;
  align-items:center;
  gap:8px;
  /* 34 -> 42 px: der Weg zurueck war der kleinste Knopf im ganzen
     Fenster (Zuruf Erguen 14.08.). */
  height:42px;
  padding:0 18px;
  border:1px solid rgba(6,20,26,.16);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  font:900 11.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em;
  text-transform:uppercase;
  cursor:pointer;
  transition:background .18s ease, border-color .18s ease,
             color .18s ease, box-shadow .18s ease;
}
/* Das Symbol ist GEZEICHNET (kein Emoji, Hausregel) und faerbt sich ueber
   `currentColor` mit — auf der dunklen Korb-Flaeche wird es damit von
   selbst weiss, ohne zweite Farbregel. */
.ang2-ksym{
  width:17px; height:17px; flex:0 0 auto;
  /* Das Symbol nimmt keinen Zeiger — sonst waere `e.target` bei einem
     Klick darauf ein SVG-Pfad, und jede Wache, die am KNOPF haengt,
     muesste ihn erst wieder heraufsuchen. */
  pointer-events:none;
}
.ang2-zu:hover,.ang2-zu:focus-visible{
  border-color:var(--accent);
  background:rgba(19,203,228,.08);
}
/* DER WARENKORB IST DAS ZIEL DIESER SEITEN — hier wird gelegt, also darf
   er nicht aussehen wie der Ausgang daneben. Dunkle Hausflaeche, KEIN
   Gold: das traegt auf derselben Seite die breite Kachel „Alle Angebote"
   und im Kopf der Haendlerseite der Shop-Knopf (Regel 1.376.0) — zwei
   goldene Flaechen in einem Bild heben sich gegenseitig auf. Die dunkle
   Flaeche ist im Haus die zweite Stufe (Regel 1.576.0). */
.ang2-zu.ang2-wk{
  border-color:transparent;
  background:#0c1a20;
  color:#fff;
  box-shadow:0 8px 18px -8px rgba(6,20,26,.7);
}
.ang2-zu.ang2-wk:hover,.ang2-zu.ang2-wk:focus-visible{
  background:#123039;
  border-color:transparent;
  box-shadow:0 12px 24px -8px rgba(6,20,26,.75);
}
/* SCHMALE SCHIRME: nur das Symbol. GEMESSEN — bei 390 px liefen „Warenkorb"
   (159 px) und „Schließen" (156 px) neben der Ueberschrift bis x=462 aus
   dem Bild. Ein Wagen und ein Kreuz versteht man ohne Wort; den Namen
   traegt das `aria-label` weiter (siehe kopfKnopf in angebote-shop.js). */
@media (max-width:640px){
  .ang2-zu{ padding:0; width:42px; justify-content:center; gap:0 }
  .ang2-ktext{ display:none }
  /* Der Korb behaelt seine Zahl — sie ist der eigentliche Inhalt. */
  .ang2-wk.ang2-zu:has(.zsh-wkzahl:not([hidden])){ width:auto; padding:0 12px; gap:6px }
}
/* Kategorie-Leiste (Vorgabe Erguen 14.08.: „kategorie filter oben als
   leiste"): Pillen wie ueberall im Haus, die gewaehlte gefuellt. */
/* EINE DURCHGEHENDE KACHEL-LEISTE (Zuruf Erguen 15.08.: "menü als
   durchgehende kachel leisten menü und höher machen die kachel"). Die
   Pillen standen frei auf dem Fenstergrund; als Reihe sahen sie aus wie
   verstreute Knoepfe. Jetzt liegen sie in EINER Flaeche ueber die ganze
   Breite — das Menue ist damit als Menue zu erkennen, und die gewaehlte
   Pille hebt sich vom ruhigen Grund ab statt vom Weiss des Fensters. */
.ang2-filter{
  display:flex;
  flex-wrap:wrap;
  gap:8px;
  margin:0;
  padding:10px 12px;
  border-radius:16px;
  background:rgba(10,60,74,.06);
  border:1px solid rgba(10,60,74,.10);
}
/* HOEHER, DAMIT MAN SIE ERKENNT (Zuruf Erguen 15.08.: "button höher machen
   damit man es besser erkennen kann"). 30 px waren fuer eine 11-px-Versalie
   eine schmale Leiste — die Reihe las sich wie eine Beschriftung, nicht wie
   eine Wahl. ALLE Pillen wachsen gemeinsam: eine hoehere Pille neben
   niedrigen sieht nach einem Fehler aus, nicht nach einer Hervorhebung. */
.ang2-pille{
  /* „höher machen die kachel" (Zuruf 15.08., zweite Stufe nach 40 px). */
  height:48px;
  padding:0 20px;
  border:1px solid rgba(10,60,74,.28);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  font:800 12px/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  cursor:pointer;
}
.ang2-pille:hover{ border-color:var(--accent) }
/* DIE ZUBEHOER-RUBRIK SIEHT AUS WIE JEDE ANDERE PILLE (Zuruf Erguen
   15.08.: „alkaya wie die anderen button darstellen").
   Bis hierher war sie dunkel gefuellt und trug einen Pfeil, weil sie
   etwas anderes tut als die uebrigen: die filtern DIESE Liste, sie
   fuehrt auf eine eigene Seite. Der Unterschied stimmt weiterhin — nur
   ist er dem Betrieb keine eigene Gestalt wert: in einer Reihe aus sechs
   hellen Pillen las sich die eine dunkle wie ein fremder Knopf.
   Sie bekommt deshalb KEINE eigene Regel mehr; `.ang2-zub` bleibt allein
   als Anker fuer das Einsortieren in der Reihe (angebote-shop.js).
   EHRLICHE FOLGE, benannt statt verschwiegen: dass der Klick auf eine
   ANDERE Seite fuehrt, kuendigt jetzt nichts mehr optisch an — das sagt
   allein der Name „Alkaya Zubehör". */
.ang2-pille.an{
  background:linear-gradient(140deg,#13cbe4,#0a90a8);
  border-color:transparent;
  color:#03242b;
}
/* VIER JE SEITE IM KACHELFORMAT 4:5 (Vorgabe Erguen 14.08.). Der Kasten
   rollt senkrecht, die Breite ist also die Grenze — deshalb reicht hier
   reines CSS: Spalten aus der Anzahl (--sp2), Hoehe aus aspect-ratio.
   Die Bilder sitzen absolut (.ang-karte.hat-bild) und fuellen die Zelle
   randlos, egal wie gross sie geraet. */
.ang2-raster{
  display:grid;
  grid-template-columns:repeat(var(--sp2,4),minmax(0,1fr));
  gap:clamp(10px,1.1vw,18px);
  /* MEHR HOEHE, MITTIG (Zuruf Erguen 14.08.: „kacheln mittig und mehr
     höhe nutzen da unten noch viel platz").
     Die Kachel ist 4:5 — ihre HOEHE folgt also der SPALTENBREITE, und
     genau die war mit 300 px gedeckelt: bei EINER Kachel stand sie
     300x375 in einem rund 640 px hohen Fenster, darunter blieb es leer.
     Der Deckel rechnet jetzt aus der Fensterhoehe zurueck (46vh x 1.25
     = 57.5vh Kachelhoehe) und bleibt bei 420 px stehen, damit eine
     einzelne Kachel auf sehr hohen Schirmen nicht ins Riesenhafte
     waechst. Bei vier Spalten greift ohnehin die Breite des Kastens. */
  --k2:min(420px,46vh);
  max-width:calc(var(--sp2,4) * var(--k2) + (var(--sp2,4) - 1) * 18px);
  margin-inline:auto;
  /* Den Abstand zur Leiste traegt jetzt das Raster — die Leiste selbst
     sitzt im klebenden Kasten und darf keinen unteren Rand haben, sonst
     bliebe unter ihr ein durchsichtiger Streifen stehen. */
  margin-top:clamp(12px,1.6vh,20px);
  /* PLATZ FUER DAS AUSGEFAHRENE BAND (Befund Erguen 15.08.: „bei hover
     verschwindet der warenkorbbutton und man muss scrollen"). Beim
     Ueberfahren faehrt das Band mit Preis und Warenkorb-Knopf UNTER die
     Kachel hinaus — in der letzten Reihe lief es sonst aus dem Fenster.
     Der Streifen ist so hoch wie das Band selbst; er kostet nichts, weil
     darunter ohnehin nur die Blaetterzeile folgt. */
  padding-bottom:clamp(72px,9vh,104px);
}
.ang2-raster .ang-karte,.ang3-karten .ang-karte{ aspect-ratio:2/3; min-height:0; overflow:hidden }

/* ========================= DIE BUEHNE (1.683.0) =========================
   Startzustand der Seite "Alle Angebote" (Entwurf am Bild freigegeben,
   23.08.): Top-Angebot, Kategorien, Bereichs-Reihen, Alkaya-Zone,
   Beratung. Die Karten in den Reihen sind DIESELBEN .ang-karte wie im
   Raster (Regel eine Zeile hoeher); Gold traegt hier genau EINE Flaeche —
   "Termin anfragen" (die mang-cta der Beratungszone). */
.ang3-buehne{ display:flex; flex-direction:column; gap:26px; padding-top:6px }
.ang3-held{
  display:grid; grid-template-columns:minmax(240px,340px) 1fr;
  background:linear-gradient(115deg,#0c1a20 0%,#123039 58%,#17505e 100%);
  border-radius:22px; overflow:hidden; color:#fff;
  box-shadow:0 18px 40px -18px rgba(6,20,26,.55);
}
.ang3-held.ohne-bild{ grid-template-columns:1fr }
/* DER BILDFOND (1.687.0, Zuruf Erguen: "das banner thema ist nicht gut
   gelöst" — die 3:2-Box allein liess links ein grosses leeres dunkles
   Feld): dasselbe Banner-Bild fuellt die GANZE Buehne weichgezeichnet,
   der Schleier haelt die Schrift lesbar, das scharfe Bild bleibt
   unbeschnitten in seiner Box. Beide Lagen fangen keine Klicks.
   Ersetzte Elemente spannen mit inset allein nicht auf (gemessene
   Falle) — width/height stehen ausdruecklich. scale(1.18) zieht den
   vom Blur aufgehellten Rand aus dem Bild. */
.ang3-held{ position:relative }
.ang3-bannerfond{
  position:absolute; left:0; top:0; width:100%; height:100%;
  object-fit:cover;
  /* WENIGER WEICH, HELLER, WENIGER GEZOOMT (Zuruf Erguen 23.08. am
     Live-Stand: "im shopbanner weniger blur effekt und etwas heller und
     die kachel weniger rauszoomen"): blur 26->12, scale 1.18->1.06 (der
     Ueberstand muss nur noch die kleinere Unschaerfe decken), dazu eine
     leichte Aufhellung. Der Schleier darunter nimmt ebenfalls Deckkraft
     heraus — die Textseite links bleibt die dunkelste Stelle, damit die
     weisse Schrift lesbar bleibt. */
  filter:blur(12px) saturate(1.08) brightness(1.12);
  transform:scale(1.06);
  pointer-events:none;
}
.ang3-bannerschleier{
  position:absolute; left:0; top:0; width:100%; height:100%;
  background:linear-gradient(90deg,rgba(6,26,35,.78) 0%,rgba(6,26,35,.48) 42%,rgba(6,26,35,.12) 100%);
  pointer-events:none;
}
/* Die eigene, hellere Schleier-Fassung des Nur-Banner-Falls ist mit 1.698.0
   ersatzlos ausgebaut: eine Banner-Flaeche traegt keinen Text mehr und
   deshalb ueberhaupt keinen Schleier. Der Schleier oben gilt weiter fuer den
   Kachelbild-Held, auf dem Titel, Preis und Knoepfe stehen. */
.ang3-held.hat-banner > *:not(.ang3-bannerfond):not(.ang3-bannerschleier):not(.ang3-bannervoll){
  position:relative; z-index:1;
}
/* VOLLFLAECHIGER Banner (1.693.0, Entscheidung Erguen "1").
   NICHTS WIRD MEHR ABGESCHNITTEN (1.697.0, Befund Erguen 24.08.: "das
   panorama bild das durch die ki erstellt wird passt nicht 1:1 in die
   kachel sondern wird abgeschnitten"). GEMESSEN war die Ursache:
   object-fit:cover in einer ~5,7:1-Flaeche bei einem 3:2-Bild wirft rund
   zwei Drittel der Bildhoehe weg — und darin stand die Schrift.
   Jetzt gilt contain: das Bild steht IMMER vollstaendig im Band. Passt
   sein Format nicht genau, fuellt der weichgezeichnete Fond dahinter die
   Flaeche (er liegt darunter und ist dafuer da). Zugeschnitten wird im
   Studio, wo der Mensch sieht, was wegfaellt — nicht hier, still.
   Deko-Lage wie Fond und Schleier: pointer-events:none, aria-hidden. */
.ang3-bannervoll{
  position:absolute; left:0; top:0; width:100%; height:100%;
  object-fit:contain;
  pointer-events:none;
}
/* EIN BANDFORMAT FUELLT DIE BUEHNE GANZ (1.701.0). Die Marke `ist-band` setzt
   angebote-shop.js am Bild selbst, sobald es geladen ist und sein Verhaeltnis
   mindestens 4:1 betraegt — dort steht die gemessene Begruendung. Ein Bild in
   einem anderen Format behaelt contain und seinen Fond. */
.ang3-bannervoll.ist-band{ object-fit:cover }
/* DER SLIDER DER MONATSANGEBOTE (1.689.0; Schiebe-Effekt + Taktleiste seit
   1.691.0, Zuruf Erguen 23.08.: "besseren slide effekt und der user soll
   verstehen dass weitere angebote kommen"): beim Wechsel SCHIEBT die neue
   Folie von rechts herein, die alte gleitet gedimmt nach links darunter
   hinaus. min-height haelt die Buehne beim Wechsel zwischen Banner- und
   Kachelbild-Folien ruhig; overflow:hidden kappt die hereinfahrende Folie
   an der Buehnenkante. */
.ang3-slider{ position:relative; min-height:clamp(320px,27vw,450px); overflow:hidden;
  transition:min-height .5s ease }
/* VOLLFLAECHIGE Folien sind ein FLACHERES Panorama-Band (Zuruf Erguen
   23.08. am Live-Stand: "das panorama bild ist zu hoch"): traegt die
   AKTUELLE Folie einen Voll-Banner, senkt das Skript die Buehne auf
   Bandhoehe — beim Wechsel zu einer Kachelbild-Folie waechst sie sanft
   zurueck (transition oben). */
/* Die Bandhoehe ist EIN FUENFTEL der Breite (1.697.0) — dasselbe 5:1, in
   dem der Studio-Editor zuschneidet (PANORAMA_FORM). GERECHNET: die Buehne
   ist rund 96 % der Fensterbreite, 19vw ergibt damit 5,0:1 bis 5,1:1 — ein
   dort gebautes Banner fuellt das Band praktisch genau aus, ohne Beschnitt
   und ohne sichtbare Raender. Die Deckel halten es auf sehr breiten und
   sehr schmalen Schirmen im Rahmen; dort passt contain (oben) das Bild
   sanft ein, statt es zu beschneiden. */
.ang3-slider.flach{ min-height:clamp(230px,19vw,380px) }
/* Der NUR-Banner-Fall (Banner ohne Monatsangebot) braucht die Hoehe
   SELBST: vollflaechig ist das Bild absolut — ohne diese Regel kollabierte
   die Flaeche auf null (Folgefehler aus 1.693.0, beim Messen gefunden). */
.ang3-held.nur-banner.voll-banner{ min-height:clamp(230px,19vw,380px) }
/* Die Folie FUELLT die Slider-Mindesthoehe (Zuruf Erguen 23.08. mit
   Screenshots: die Navigation hing bei niedrigen Folien im Weissraum
   unter der Karte) — inherit zieht den gerechneten Wert des Sliders. */
.ang3-folie{ min-height:inherit }
.ang3-folie.rein{ position:relative; z-index:2; animation:ang3Rein .65s cubic-bezier(.22,.61,.36,1) both }
.ang3-folie.raus{ position:absolute; inset:0; z-index:1; pointer-events:none;
  animation:ang3Raus .65s cubic-bezier(.22,.61,.36,1) both }
@keyframes ang3Rein{ from{ transform:translateX(100%) } to{ transform:none } }
@keyframes ang3Raus{ from{ transform:none; opacity:1 } to{ transform:translateX(-26%); opacity:.35 } }
/* Die sichtbare Slider-Steuerung (Pfeile, Punkte, Play/Pause) ist mit
   1.691.0 ersatzlos ausgebaut (Zuruf Erguen: "ohne player funktionen die
   angezeigt werden") — der Wechsel laeuft von selbst. Weg zurueck: Git.
   GEBLIEBEN ist eine reine ANZEIGE: je Folie ein Strich, der aktive
   fuellt sich bis zum Wechsel — nicht klickbar (pointer-events:none),
   kein Bedienelement, nur das Zeichen "hier kommt noch mehr". Die
   Fuelldauer kommt als --a3takt aus dem Skript (EINE Quelle:
   ANG3_SLIDE_MS); der Wert hier ist nur der Rueckfall. */
.ang3-takt{ position:absolute; left:50%; transform:translateX(-50%); bottom:13px;
  display:flex; gap:7px; z-index:3; pointer-events:none }
.ang3-takt i{ display:block; width:34px; height:4px; border-radius:999px;
  background:rgba(255,255,255,.26); overflow:hidden; position:relative }
.ang3-takt i.um{ background:rgba(255,255,255,.6) }
.ang3-takt i.an::after{ content:""; position:absolute; inset:0; border-radius:999px;
  background:#fff; transform-origin:left; transform:scaleX(0);
  animation:ang3Takt var(--a3takt,5s) linear forwards }
.ang3-slider.halt .ang3-takt i.an::after{ animation-play-state:paused }
@keyframes ang3Takt{ from{ transform:scaleX(0) } to{ transform:scaleX(1) } }
/* Der Bereichs-Held ueber dem Raster — dieselbe Flaeche, nur mit Abstand
   zur Kachelliste darunter. */
.ang2-bheld{ margin:0 0 18px }
/* .ang3-heldbild ist mit 1.690.0 ersatzlos ausgebaut: die cover-Spalte
   schnitt die 2:3-Kachelbilder ab (Zuruf Erguen mit Screenshots) — jede
   Folie nutzt jetzt die Fond+Box-Bauart. Weg zurueck: Git. */
/* DER EIGENE BANNER, seit 1.685.0 UNBESCHNITTEN (Zuruf: "der banner ist
   nicht passend"): die KI kann kein Panorama — ihr groesstes Querformat ist
   1536x1024 (3:2). Die Buehne zeigt das Bild deshalb KOMPLETT in einer
   echten 3:2-Box rechts neben dem Text; die Box ist exakt im Bildformat,
   object-fit:cover ruehrt so kein Byte an. Ohne Monats-Angebot steht die
   Box mittig als reines Motiv. */
.ang3-held.hat-banner{ grid-template-columns:minmax(0,1fr) auto; align-items:center }
.ang3-held.hat-banner .ang3-heldtxt{ order:1 }
.ang3-bannerbox{
  order:2; flex:0 0 auto;
  /* GROESSER seit 1.689.0 (Zuruf Erguen: "möglichst den breit und höhe
     füllend") — das Bild traegt die Folie, der Fond fuellt den Rest. */
  height:clamp(280px,25vw,400px); aspect-ratio:3/2;
  margin:14px 14px 14px 0; border-radius:14px; overflow:hidden;
}
.ang3-bannerbox img{ width:100%; height:100%; object-fit:cover; display:block }
/* Die HOCHKANTE Box fuer 2:3-Kachelbilder (1.690.0): dasselbe Muster,
   nur das Format des Bildes — nichts wird beschnitten. */
.ang3-bannerbox.hochkant{ aspect-ratio:2/3; height:clamp(300px,25vw,410px) }
.ang3-held.hat-banner.nur-banner{ grid-template-columns:1fr; justify-items:center }
.ang3-heldtxt{ padding:clamp(22px,2.4vw,36px); display:flex; flex-direction:column; gap:11px; align-items:flex-start }
.ang3-badge{
  background:linear-gradient(140deg,#e6bc50,#c99a2e); color:#231903;
  font:900 10.5px/1 Inter,system-ui,sans-serif; letter-spacing:.14em;
  text-transform:uppercase; padding:7px 12px; border-radius:999px;
}
.ang3-heldtitel{ margin:0; font:900 clamp(22px,2.2vw,31px)/1.1 Inter,system-ui,sans-serif; letter-spacing:-.01em }
.ang3-heldsub{ margin:0; color:rgba(255,255,255,.8); font:500 clamp(13px,1vw,14.5px)/1.5 Inter,system-ui,sans-serif; max-width:60ch }
.ang3-heldpreis{ margin:0; color:rgba(255,255,255,.85); font:600 15px/1.2 Inter,system-ui,sans-serif }
.ang3-heldpreis strong{ font-size:clamp(26px,2.3vw,34px); color:#fff }
.ang3-heldakt{ display:flex; gap:10px; margin-top:6px; flex-wrap:wrap; align-items:center }
.ang3-heldakt .ang-korb{ flex:0 0 auto; height:44px; padding:0 22px }
.ang3-heldakt .mang-cta{ margin-top:0; height:44px; padding:0 22px }
.ang3-mehr{
  height:44px; padding:0 22px; border:1px solid rgba(255,255,255,.45);
  border-radius:999px; background:transparent; color:#fff;
  font:900 12px/1 Inter,system-ui,sans-serif; letter-spacing:.08em;
  text-transform:uppercase; cursor:pointer;
  transition:background .2s ease,border-color .2s ease;
}
.ang3-mehr:hover,.ang3-mehr:focus-visible{ background:rgba(255,255,255,.12); border-color:rgba(255,255,255,.7) }
.ang3-kat{ display:grid; grid-template-columns:repeat(auto-fit,minmax(180px,1fr)); gap:14px }
/* Waagerechte Kachel mit SYMBOL-Chip (1.685.0, Zuruf: "die kategorien besser
   darstellen, die kachel gehen unter") — zwischen dunklem Aufmacher und
   bunten Plakaten brauchen sie eigenes Gewicht. */
/* DOPPELTE HOEHE (1.701.0, Vorgabe Erguen 24.08.: „die bereichskacheln doppelte
   höhe"). GEMESSEN war die Kachel 74 px hoch — sie stand als schmale Zeile
   zwischen dem grossen Banner darueber und den Plakat-Karten darunter und ging
   dazwischen unter. `min-height:148px` verdoppelt sie an EINER Stelle; Polster
   und Symbolchip wachsen mit, damit der Inhalt in der Mitte steht statt oben zu
   kleben. Die Kachel ist ein Flex-Kasten mit `align-items:center` — der Inhalt
   zentriert sich damit von selbst. */
.ang3-kk{
  display:flex; align-items:center; gap:16px;
  min-height:148px;
  background:#fff; border:1px solid rgba(10,60,74,.12); border-radius:16px;
  padding:18px 20px; cursor:pointer; text-align:left; font-family:inherit;
  transition:border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.ang3-kk:hover,.ang3-kk:focus-visible{ border-color:var(--accent); transform:translateY(-1px); box-shadow:0 10px 22px -14px rgba(6,20,26,.4) }
/* Der Symbolchip waechst mit der Kachel (1.701.0): in einer 148 px hohen
   Flaeche wirkte der alte 42-px-Chip verloren. */
.ang3-kkic{
  width:58px; height:58px; flex:0 0 auto; border-radius:16px;
  display:grid; place-items:center;
  background:rgba(15,142,163,.12); color:#0f8ea3;
}
.ang3-kkic svg{ width:30px; height:30px }
.ang3-kktx{ display:flex; flex-direction:column; gap:3px; min-width:0 }
.ang3-kk b{ font:900 17.5px/1.2 Inter,system-ui,sans-serif; color:var(--ink) }
.ang3-kk .ang3-kktx span{ color:#5a6b74; font:600 13.5px/1.35 Inter,system-ui,sans-serif }
.ang3-kkalk{ background:rgba(10,60,74,.05) }
.ang3-kkalk .ang3-kkic{ background:#0c1a20; color:#7fd6e4 }
.ang3-kkalk b:after{ content:" \2192"; color:#0f8ea3 }
.ang3-rkopf{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:12px }
.ang3-rkopf h3{ margin:0; font:900 clamp(16px,1.35vw,19px)/1.2 Inter,system-ui,sans-serif; color:var(--ink) }
.ang3-alle{
  border:0; background:none; color:#0f8ea3;
  font:800 13px/1 Inter,system-ui,sans-serif; cursor:pointer; padding:4px 2px;
}
.ang3-alle:hover,.ang3-alle:focus-visible{ text-decoration:underline }
.ang3-alle:after{ content:" \2192" }
.ang3-karten{ display:grid; grid-template-columns:repeat(4,1fr); gap:16px }
.ang3-alk{
  display:flex; align-items:center; gap:22px;
  background:#fff; border:1px solid rgba(10,60,74,.12); border-radius:20px;
  padding:22px 26px;
}
.ang3-alktxt{ flex:1 1 auto; min-width:0 }
.ang3-alktxt h3{ margin:0 0 4px; font:900 17px/1.2 Inter,system-ui,sans-serif; color:var(--ink) }
.ang3-alktxt p{ margin:0; color:#5a6b74; font:500 13.5px/1.5 Inter,system-ui,sans-serif }
.ang3-pillen{ display:flex; flex-wrap:wrap; gap:8px; margin-top:12px }
.ang3-pille{
  border:1px solid rgba(10,60,74,.18); border-radius:999px; padding:7px 14px;
  font:700 12px/1 Inter,system-ui,sans-serif; color:#28424e;
  background:rgba(10,60,74,.04); cursor:pointer;
  transition:border-color .18s ease, background .18s ease;
}
.ang3-pille:hover,.ang3-pille:focus-visible{ border-color:var(--accent); background:rgba(19,203,228,.08) }
.ang3-sortiment{
  flex:0 0 auto; height:42px; padding:0 18px; border:0; border-radius:999px;
  background:#0c1a20; color:#fff; font:900 11.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.12em; text-transform:uppercase; cursor:pointer;
  box-shadow:0 8px 18px -8px rgba(6,20,26,.7);
  transition:background .18s ease;
}
.ang3-sortiment:hover,.ang3-sortiment:focus-visible{ background:#123039 }
.ang3-beratung{
  display:flex; align-items:center; gap:24px;
  background:linear-gradient(115deg,#0c1a20,#123039); color:#fff;
  border-radius:20px; padding:26px 30px; margin-bottom:8px;
}
.ang3-bertxt{ flex:1 1 auto; min-width:0 }
.ang3-bertxt h3{ margin:0 0 6px; font:900 clamp(17px,1.5vw,21px)/1.2 Inter,system-ui,sans-serif }
.ang3-bertxt p{ margin:0; color:rgba(255,255,255,.78); font:500 13.5px/1.5 Inter,system-ui,sans-serif }
.ang3-filialen{ display:flex; flex-wrap:wrap; gap:16px; margin-top:12px; font:600 12.5px/1.4 Inter,system-ui,sans-serif; color:rgba(255,255,255,.85) }
.ang3-filialen b{ display:block; font-size:13px; color:#fff }
.ang3-filialen a{ color:rgba(255,255,255,.85); text-decoration:none }
.ang3-filialen a:hover,.ang3-filialen a:focus-visible{ color:#fff; text-decoration:underline }
.ang3-beratung .mang-cta{ margin-top:0; flex:0 0 auto; height:46px; padding:0 24px }
@media (max-width:900px){
  .ang3-held{ grid-template-columns:1fr }
  /* Schmal stapeln Text und Banner-Box untereinander; die Box behaelt ihr
     3:2 ueber die Breite. */
  .ang3-held.hat-banner{ grid-template-columns:1fr }
  .ang3-bannerbox{ order:0; height:auto; width:calc(100% - 28px); margin:14px auto 0 }
  /* Die Reihen rollen seitlich statt zu stapeln — vier 2:3-Karten
     untereinander waeren ein halber Kilometer Seite. */
  .ang3-karten{ display:flex; overflow-x:auto; padding-bottom:8px; -webkit-overflow-scrolling:touch }
  .ang3-karten .ang-karte{ flex:0 0 46% }
  .ang3-alk{ flex-direction:column; align-items:flex-start }
  .ang3-beratung{ flex-direction:column; align-items:flex-start }
}
@media (max-width:560px){
  .ang3-karten .ang-karte{ flex-basis:70% }
}
/* Blaetterzeile */
/* Nachgelegte Kacheln blenden sich ein (Zuruf Erguen 14.08.: "mit
   übergang aufdecken"). Die Klasse .ist-da kommt erst im naechsten Bild,
   sonst gaebe es keinen Uebergang. */
/* DIE EINBLENDUNG SETZT KEIN transform MEHR, sondern --khub — sonst
   schlaegt sie den Hover-Zoom. GEMESSEN: `.ang2-neu.ist-da` (zwei Klassen)
   und `.ang-karte:hover` (Klasse + Pseudoklasse) sind gleich stark, und die
   spaetere gewinnt; die frisch nachgelegte Kachel blieb beim Ueberfahren
   deshalb stehen (transform:none). Ueber die Variablen gibt es diesen
   Kampf nicht — sie ergaenzen sich, statt sich zu ersetzen (Falle 1.562.0,
   hier in ihrer stillen Form: es gab keinen Fehler, nur keine Wirkung). */
.ang2-neu{ opacity:0; --khub:16px; transition:opacity .5s ease, transform .5s ease }
.ang2-neu.ist-da{ opacity:1; --khub:0px }
@media (prefers-reduced-motion:reduce){
  .ang2-neu{ opacity:1; --khub:0px; transition:none }
}
/* Der Fuehler steht unter dem Raster; kommt er in Sicht, wird nachgelegt.
   Er ist absichtlich hoch genug, um bei ruhigem Rollen sicher getroffen
   zu werden — sehen soll man ihn nicht. */
.ang2-fuehler{ height:8px; margin-top:18px }
.ang2-seiten{
  display:flex;
  align-items:center;
  gap:14px;
  margin-top:clamp(12px,1.8vh,22px);
}
.ang2-blatt{
  height:34px;
  padding:0 16px;
  border:1px solid rgba(10,60,74,.3);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  font:800 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  cursor:pointer;
}
.ang2-blatt:hover:not(:disabled){ border-color:var(--accent) }
.ang2-blatt:disabled{ opacity:.4; cursor:default }
.ang2-stand{
  color:var(--ink-soft);
  font:600 12px/1 Inter,system-ui,sans-serif;
}

/* --- Warenkorb-Fenster ------------------------------------------ */
.wk-panel{
  position:relative;
  z-index:1;
  width:min(94vw,780px);
  /* Volle Fensterhoehe wie die Angebotsseite (Zuruf Erguen 15.08.). */
  max-height:96vh;
  margin:2vh auto;
  padding:clamp(16px,2vw,26px);
  border-radius:22px;
  background:rgba(255,255,255,.97);
  box-shadow:0 30px 80px rgba(6,20,26,.28);
  overflow:auto;
}
.wk-kopf{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:14px;
  margin-bottom:14px;
}
.wk-kopf h2{
  margin:0;
  color:var(--ink);
  font:900 clamp(19px,1.8vw,26px)/1.1 Inter,system-ui,sans-serif;
  letter-spacing:-.02em;
}
.wk-leer{
  margin:0;
  padding:18px 0;
  color:var(--ink-mid);
  font:600 13.5px/1.5 Inter,system-ui,sans-serif;
}
.wk-liste{ display:flex; flex-direction:column; gap:10px }
.wk-zeile{
  display:grid;
  grid-template-columns:64px minmax(0,1fr) auto auto;
  gap:12px;
  align-items:center;
  padding:10px;
  border:1px solid rgba(6,20,26,.1);
  border-radius:14px;
}
.wk-bild{
  width:64px; height:64px;
  border-radius:10px;
  background:#eef4f6;
  overflow:hidden;
}
.wk-bild img{ width:100%; height:100%; object-fit:cover; display:block }
.wk-txt{ display:flex; flex-direction:column; gap:2px; min-width:0 }
.wk-txt strong{
  color:var(--ink);
  font:800 14px/1.3 Inter,system-ui,sans-serif;
}
.wk-sub,.wk-preis{
  color:var(--ink-mid);
  font:600 12px/1.4 Inter,system-ui,sans-serif;
}
.wk-preis{ color:#0f8ea3; font-weight:800 }
.wk-menge{ display:flex; align-items:center; gap:6px }
.wk-menge button{
  width:26px; height:26px;
  border:1px solid rgba(6,20,26,.16);
  border-radius:8px;
  background:#fff;
  color:var(--ink);
  font:900 14px/1 Inter,system-ui,sans-serif;
  cursor:pointer;
}
.wk-menge span{
  min-width:18px;
  text-align:center;
  font:800 13px/1 Inter,system-ui,sans-serif;
}
.wk-weg{
  border:0;
  background:transparent;
  color:#96606a;
  font:800 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
  cursor:pointer;
}
.wk-weg:hover,.wk-weg:focus-visible{ color:#b3323f; text-decoration:underline }
/* EIGENES Raster statt der 12-Spalten-Maschinerie der Szenenformulare:
   die baut der JS-Erzeuger mit Spannweiten je Feld — von Hand gesetzt
   waeren die Spannen geraten (am Bild gesehen: der Hinweis wurde zur
   schmalen Saeule, die Felder winzig). Die FELDER selbst nutzen weiter
   dieselben Klassen (.pf-field/.pf-label) — EINE Bildsprache. */
.wk-form{
  margin-top:16px;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:clamp(10px,1.1vw,16px);
}
.wk-form[hidden]{ display:none }
.wk-voll{ grid-column:1 / -1 }
.wk-abschluss{
  display:flex;
  align-items:center;
  gap:14px;
  flex-wrap:wrap;
}
.wk-hinweis{
  grid-column:1 / -1;
  margin:0 0 4px;
  padding:10px 12px;
  border-radius:12px;
  background:rgba(18,199,224,.10);
  color:#0b3a48;
  font:600 12.5px/1.5 Inter,system-ui,sans-serif;
}

/* =========================================================
   ZUBEHOER-SORTIMENT (1.623.0) — die eigene Seite aus dem
   Lieferanten-Shop. Rahmen, Pillen und Blaetter-Knoepfe kommen
   aus dem ang2-Bestand (dieselbe Bildsprache wie "Alle
   Angebote"); eigen ist nur die Artikelkarte.
   ========================================================= */
.zsh-kopfrechts{
  display:flex;
  align-items:center;
  gap:10px;
}
/* Die Menge am Warenkorb-Knopf: eine gefuellte Zahl, die nur dasteht,
   wenn wirklich etwas drin liegt (Zuruf Erguen 14.08.). Eine dauerhafte
   0 waere eine Aufforderung ohne Anlass. */
.zsh-wk .zsh-wkzahl{
  display:inline-grid;
  place-items:center;
  min-width:20px; height:20px;
  margin-left:8px; padding:0 6px;
  border-radius:999px;
  background:#0f8ea3;
  color:#fff;
  font:900 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:0;
}
/* Im KOPF sitzt die Zahl seit 1.635.0 in einem Flex-Knopf mit eigenem
   `gap` — der alte Rand kaeme oben drauf und stuende doppelt. Und auf der
   dunklen Korb-Flaeche braucht sie den hellen Akzent: `#0f8ea3` auf
   `#0c1a20` ist Dunkel auf Dunkel. */
.ang2-wk .zsh-wkzahl{
  margin-left:0;
  background:#13cbe4;
  color:#03242b;
}
.zsh-wk .zsh-wkzahl[hidden]{ display:none }
.zsh-suche{
  display:flex;
  align-items:center;
  gap:10px;
  margin-bottom:12px;
  flex-wrap:wrap;
}
.zsh-suche input{
  flex:1 1 240px;
  min-width:0;
  padding:9px 14px;
  border:1px solid rgba(9,44,56,.22);
  border-radius:999px;
  background:#fff;
  color:var(--ink);
  font:600 13.5px/1.2 Inter,system-ui,sans-serif;
}
.zsh-suche input:focus-visible{ outline:2px solid var(--accent); outline-offset:1px }
.zsh-filter{ margin-bottom:6px }
.zsh-unter{
  margin-top:2px;
  padding-left:14px;
  border-left:3px solid rgba(18,199,224,.35);
}
/* Hersteller- und Modellzeile (Zuruf Erguen 14.08.). Bewusst ANDERS als
   die Kategorie-Pillen: die Kategorie ist der Aufbau des Sortiments, diese
   beiden sind eine Einschraenkung darin — deshalb die Beschriftung davor
   und der ruhigere Grund. */
.zsh-fzeile{
  align-items:center;
  margin-top:4px;
}
.zsh-flabel{
  flex:0 0 auto;
  margin-right:2px;
  color:var(--muted,#5a6b73);
  font:800 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.1em;
  text-transform:uppercase;
}
/* „+ N weitere" ist KEIN Filter, sondern ein WEG: er klappt die restlichen
   Modelle auf. Zwischen zwanzig gleich aussehenden Filterpillen ging er unter
   (Zuruf Erguen 15.08.: "weitere sollte eine andere hintergrundfarbe haben
   damit man es besser erkennen kann"). Getoente Flaeche in der Akzentfarbe,
   KEIN Gold — das traegt im Haus die Handlung, und die Handlung ist hier die
   Auswahl, nicht das Aufklappen. */
.zsh-mehr{
  font-size:12px;
  background:rgba(18,199,224,.14);
  border-color:rgba(18,199,224,.45);
  color:#0b5566;
  font-weight:800;
}
.zsh-mehr:hover,.zsh-mehr:focus-visible{
  background:rgba(18,199,224,.26);
  border-color:rgba(18,199,224,.72);
}
.zsh-raster{
  display:grid;
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(12px,1.4vw,20px);
  margin-top:10px;
}
.zsh-karte{
  display:flex;
  flex-direction:column;
  gap:6px;
  padding:14px;
  border-radius:18px;
  border:1px solid rgba(9,44,56,.10);
  background:#fff;
  box-shadow:0 10px 26px rgba(6,20,26,.08);
  transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.zsh-karte:hover,.zsh-karte:focus-visible,.zsh-karte:has(:focus-visible){
  transform:translateY(-3px);
  box-shadow:0 16px 36px rgba(6,20,26,.14);
  border-color:rgba(18,199,224,.5);
}
/* Das Produktfoto wird EINGEPASST, nie beschnitten — es ist das Bild
   des Lieferanten, sein Motiv entscheidet er. */
.zsh-bild{
  aspect-ratio:1/1;
  border-radius:12px;
  background:#f4f8fa;
  overflow:hidden;
  display:flex;
  align-items:center;
  justify-content:center;
}
.zsh-bild img{
  width:100%;
  height:100%;
  object-fit:contain;
  display:block;
}
.zsh-bild.ohne::after{
  content:"Ohne Bild";
  font:700 11px/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:rgba(9,44,56,.35);
}
.zsh-kat{
  font:800 10.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:#0b7d90;
}
.zsh-name{
  margin:0;
  font:800 14.5px/1.35 Inter,system-ui,sans-serif;
  color:var(--ink);
  /* Lange Shop-Namen: zwei Zeilen, dann Auslassung — die Karte bleibt
     im Raster, der volle Name steht im Warenkorb. */
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
  min-height:2.7em;
}
/* MERKZEICHEN + KLICKZIEL (Zuruf Erguen 15.08.: "per klick infobox über
   den artikel aber nur wenn von alkaya die infos vorhanden"). Beides steht
   NUR an Kacheln mit Beschreibung — wo alkaya keinen Text liefert, gibt es
   weder Zeichen noch Zeiger. */
.zsh-mehrhin{
  margin:2px 0 0;
  font:800 11.5px/1.3 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
  color:var(--accent-ink,#0a7f93);
}
.zsh-mehrhin::after{ content:" \203A"; opacity:.7 }
.zsh-karte.zsh-klick{ cursor:pointer }
.zsh-karte.zsh-klick:hover{ border-color:var(--accent) }
.zsh-karte.zsh-klick:focus-visible{
  outline:none;
  box-shadow:0 0 0 3px rgba(18,199,224,.35);
}
.zsh-fuss{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:8px;
  margin-top:auto;
}
.zsh-preis{
  font:900 16px/1 Inter,system-ui,sans-serif;
  color:var(--ink);
}
.zsh-verf{
  font:800 10.5px/1 Inter,system-ui,sans-serif;
  letter-spacing:.06em;
  text-transform:uppercase;
  padding:5px 9px;
  border-radius:999px;
}
.zsh-verf.da{ background:rgba(35,170,110,.14); color:#12724a }
.zsh-verf.aus{ background:rgba(179,50,63,.12); color:#b3323f }
.zsh-korb{
  margin-top:4px;
  padding:10px 14px;
  font-size:12.5px;
  justify-content:center;
  text-align:center;
}
.zsh-korb:disabled{
  opacity:.55;
  cursor:default;
  filter:grayscale(.4);
}
.zsh-korb.ist-drin{ filter:saturate(1.3) }


/* DIE SLIDE-PFEILE SIND ENTFERNT (Zuruf Erguen 20.08.: "die paging
   button ausblenden"). Der Stationen-Mechanismus selbst ist mit 1.652.0
   zurueckgebaut ("du solltest bei der 8 seiten kurzversion bleiben"). */

/* =========================================================
   GOLD-SHIMMER-ZEILEN (Zuruf Erguen 20.08.: "die goldenen
   ueberschriftteile sollen einen echten goldeffekt haben und die
   buchstaben animiert sein in gold ganz leicht. diesen effekt hatten
   wir im financejournal projekt").
   ---------------------------------------------------------
   1:1 die Bauart von .tjHeroHL2 aus financejournal.se (helle Seite =
   die body.light-Fassung dort): nahtlos kachelbarer Gold-Verlauf
   (0% = 100% = Basis-Gold, kein Loop-Sprung), als Text-Maske
   (background-clip:text), und die Position wandert in 10 s einmal um
   die eigene Breite — das ist das "ganz leicht" animierte Glaenzen.
   KEIN `var(--gold)`: MOS-Token, hier nicht definiert (Regel 1.632.0).
   Die Regel steht NACH .fin-word und .ang-kopf-t — bei gleicher
   Spezifitaet gewinnt die spaetere, sonst bliebe color:var(--ink)
   stehen (Falle 1.562.0). */
.zeile-gold{
  background:linear-gradient(90deg,#a07010 0%,#c9a227 18%,#e8c840 30%,#c9a227 42%,#7a5500 50%,#a07010 58%,#c9a227 70%,#e8c840 82%,#c9a227 92%,#a07010 100%);
  background-size:200% auto;
  -webkit-background-clip:text;
  background-clip:text;
  -webkit-text-fill-color:transparent;
  color:transparent;
  animation:zeileGoldShimmer 10s linear infinite;
  /* Kopfraum fuer Umlautpunkte: background-clip:text bemalt nur die
     HINTERGRUNDFLAECHE des Elements — die Punkte des grossgestellten
     Oe ("ZUBEHOER.", "PERSOENLICHE") liegen ueber der Versalhoehe und
     waeren sonst transparent OHNE Verlauf, also unsichtbar (am Bild
     gemessen, nicht am Code). Padding weitet die Flaeche nach oben,
     der negative Rand nimmt den Layoutversatz zurueck (an Inline-
     Wirten wie .ang-kopf-t wirkt der Rand ohnehin nicht). */
  padding-top:.14em;
  margin-top:-.14em;
  /* TEXTBREITE, nicht Zeilenbox (Zuruf Erguen 20.08.: "bei internet ist
     der gold effekt falsch und schwach"): als display:block war der Span
     so breit wie die ganze Zeile — der Verlauf (200% der BOXbreite) lag
     bei kurzem Text in breiter Box ("Internet." in .net-copy) zum
     groessten Teil NEBEN den Buchstaben, ueber der Schrift blieb ein
     blasser Ausschnitt. inline-block schrumpft auf den Text; der Verlauf
     spannt damit ueberall exakt ueber die Buchstaben — wie im
     financejournal-Original. Zentrierte Szenen zentrieren weiter ueber
     text-align des Wirts. */
  display:inline-block;
  /* KEIN GEERBTER SCHEIN AUF DEM GOLD (Zuruf Erguen 20.08.: "achte auf
     den unterschied der goldenen farbe bei internet", zwei
     Bildschirmfotos: "DEIN SMARTPHONE." sattes Gold, "INTERNET."
     blasses Champagner). GEMESSEN, nicht geraten: die Internet-Zeile
     ERBT von .net-copy .scene-headline den weissen Lesbarkeits-Schein
     (text-shadow 0 0 16px/40px weiss — Regel 16e, gebaut fuer die Zeit,
     als die Ueberschrift ueber dem Bildschirm lag). Ein text-shadow
     malt die WEICHE GLYPHENFORM HINTER die Buchstaben — und weil die
     Fuellung hier transparent ist (background-clip:text), scheint das
     Weiss DURCH die Buchstaben hindurch: der Blaukanal der Goldpixel
     lag bei ~140 statt ~45, in JEDER Phase der Animation (die
     Phasen-Vermutung war damit widerlegt — kein Verlaufsanker hat mehr
     als Blau 64, das Weiss kam von aussen). Die dunkle ZWEITE Zeile der
     Internet-Ueberschrift behaelt ihren Schein — sie hat eine deckende
     Fuellung, dort traegt er die Lesbarkeit statt sie zu waschen. */
  text-shadow:none;
}
/* Die Grundregel `.anim-line > span{display:block}` wiegt (0,1,1) und
   schluege die eine Klasse oben — hier ausdruecklich uebersteuern. */
.anim-line > span.zeile-gold{ display:inline-block; }
@keyframes zeileGoldShimmer{
  0%{background-position:0% center}
  100%{background-position:200% center}
}
/* Auf der Angebote-Seite steht "Dein Shop." in Versalien (Zuruf:
   "DEIN SHOP. Direkt bei uns abholbar.") — und VIEL GROESSER als der Rest
   der Zeile (Zuruf Erguen 20.08.: "dein shop viel grösser schreiben").
   Die eigene Schriftgroesse sitzt am SPAN, nicht an .ang-kopf-t: der
   zweite Teil ("Direkt bei uns abholbar.") behaelt seine 26..44 px.
   line-height:1 haelt die gemeinsame Zeilenbox flach — beide Teile
   stehen auf DERSELBEN Grundlinie (Standard-vertical-align), so liest
   sich die Zeile als eine Aussage in zwei Gewichten. Der Kopfraum fuer
   Umlautpunkte (.zeile-gold, .14em) rechnet in em und waechst mit. */
.ang-kopf-gold{
  text-transform:uppercase;
  font-size:clamp(40px,4.4vw,76px);
  line-height:1;
}
@media (prefers-reduced-motion:reduce){
  .zeile-gold{ animation:none }
}


/* ===========================================================================
   MAUSZEIGER-SCHEIN (1.702.0, Vorgabe Erguen 24.08.: "maus cursor effekt im
   shop wie auf der webseite erstellen").
   Nachgebaut nach `.cursor-glow` auf intramos.de.
     - FARBE: DIESELBE wie auf der Website — rgba(22,199,163,.1), abgelesen aus
       `web/styles.css` (Zuruf Erguen 24.08.: "den selben mauseffekt fuer den
       shop bitte"). Bis dahin trug der Shop seine Hausfarbe --accent (#12c7e0,
       11 %); das war der EINZIGE sichtbare Unterschied zur Website, und
       gewuenscht ist kein Verwandter, sondern derselbe Schein. Der Wert steht
       hier ROH und nicht als Token: `var(--gold)`-artige Namen gelten nur im
       Haus, das sie definiert (Regel 1.632.0), und ein Shop-Token waere genau
       die zweite Wahrheit, die beim naechsten Hausanstrich auseinanderliefe.
       Wer die Website umfaerbt, zieht diese Zeile mit — die Sonde misst gegen
       den in `web/styles.css` GELESENEN Wert und wird sonst rot.
     - pointer-events:none, wie an jeder Deko-Auflage: sonst faengt der Kreis
       die Klicks der ganzen Seite ab (Regel 1.629.0/1.642.0).
     - z-index ZWISCHEN den Shop-Overlays und den Bedienoberflaechen. Das ist
       die eine Zahl, die BEWUSST von der Website abweicht (dort 30) — sie
       braucht sie nicht, sie hat keine Overlays.
       BEFUND Erguen 24.08.: „der blau mouse effekt … wurde im shop nicht
       eingebaut". Er WAR eingebaut — aber mit z-index 30, und die Shop-Seiten
       (Angebote, Zubehoer) sind OVERLAYS mit z-index 200. Der Schein lag
       dahinter und war auf genau den Seiten unsichtbar, auf denen der Betrieb
       ihn sucht. Gemessene Ebenen im Shop: 200 shop-overlay, 210 seiten-balken,
       400 tv-editor-panel, 900 debug-panel. 220 liegt ueber den Seiten und
       UNTER den Bedienoberflaechen — ueber einem Editor waere ein Lichtschein
       im Weg. Die eigene Sonde hatte den Fall nicht gemessen: sie prueft die
       ERZAEHLseite, wo es kein Overlay gibt.
   Auf Touch-Geraeten und bei "weniger Bewegung" erscheint er gar nicht — dort
   gibt es keinen Zeiger, dem er folgen koennte.
   =========================================================================== */
.cursor-glow{
  position:fixed;left:0;top:0;width:420px;height:420px;border-radius:50%;
  background:radial-gradient(circle,rgba(22,199,163,.1),transparent 68%);
  pointer-events:none;z-index:220;mix-blend-mode:screen;
  opacity:0;transition:opacity .3s;
  will-change:transform;
}
/* AUF WEISS ADDIERT `screen` NICHTS (1.705.0, Befund Erguen: "maus effekt
   nicht zu sehen im shop"). GEMESSEN am Bild, nicht an Zahlen: auf der dunklen
   Erzaehlseite (Untergrund rgb(146,129,140)) aendert der Schein bis zu 172
   Farbstufen — auf der Angebote- und der Zubehoer-Seite (Untergrund
   rgb(255,255,255)) exakt NULL. Das ist kein schwacher Effekt, sondern gar
   keiner: `screen` addiert Licht, und auf reinem Weiss ist alles Licht schon
   da. Jede Zahl der bisherigen Sonde stimmte — Farbe, Deckkraft, Lage,
   Stapelposition —, nur die eigentliche Frage war nie gestellt: sieht man ihn?
   `multiply` dunkelt statt aufzuhellen und wirkt damit genau dort, wo `screen`
   ausfaellt. Die 18 % sind GEMESSEN, nicht geschaetzt: sie treffen auf Weiss
   dieselbe Wirkstaerke wie der Schein auf der Erzaehlseite (mittlere
   Pixelaenderung 32,5 gegen 31 — Abstand 1,5). 10 % waeren zu schwach, 26 %
   aufdringlich.
   `multiply` und nicht `normal`: auf reinem Weiss messen beide gleich, aber auf
   einer hellgrauen Karte dunkelt multiply PROPORTIONAL ab, waehrend normal
   ueberall denselben Schleier legt.
   Der Schalter ist `html.shop-open` — die Klasse, die der Shop-Router setzt,
   solange eine der hellen Seiten offen ist (abgelesen, nicht geraten). Ohne sie
   gilt weiter `screen`, damit die Erzaehlseite unveraendert bleibt. */
html.shop-open .cursor-glow{
  mix-blend-mode:multiply;
  background:radial-gradient(circle,rgba(22,199,163,.18),transparent 68%);
}
@media(pointer:coarse){.cursor-glow{display:none}}
@media(prefers-reduced-motion:reduce){.cursor-glow{display:none}}


/* NUR FUERS VORLESEN (1.702.0). Das Element bleibt im Baum und traegt den Namen
   des Overlays (aria-labelledby), ist aber nicht zu sehen. `display:none` waere
   hier falsch: es nimmt den Text auch dem Screenreader weg, und das Fenster
   haette dann gar keine Beschriftung mehr. */
.ang2-nurvorlesen{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}
