/* ==========================================================================
   SCHAKAL SPORTS — Seitenbausteine
   ========================================================================== */

/* --- Ladesequenz --------------------------------------------------------
   Eine Eröffnung in drei Ebenen: die Wortmarke hinter der Ware, die Ware,
   und darüber der zweite Teil des Namens. Der Handschuh fliegt herein,
   bleibt schwebend stehen und geht am Ende an den Auftakt über — deshalb
   trägt der Vorhang dieselben Bilddateien wie der Hero und dieselben
   Fassungs-Tokens.

   Die Zeiten stehen nicht hier, sondern in bootSequence(): Sie gehören zur
   Dramaturgie und müssen sich gegenseitig kennen. Was hier steht, sind die
   beiden Zustände, zwischen denen die Klassen umschalten.                 */
.boot {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--bg);
  display: grid;
  grid-auto-flow: row;
  align-content: center;
  justify-items: center;
  gap: clamp(1.5rem, 4svh, 3rem);
  overflow: hidden;
  /* Der Grund geht als Letztes — erst wenn der Handschuh unterwegs zu
     seiner Zielposition ist, sonst sähe man ihn über einer leeren Fläche
     fliegen statt über der Seite, in die er hineinfliegt. */
  transition: opacity .55s var(--ease) .1s, visibility .55s .1s;
}
.boot.is-done { opacity: 0; visibility: hidden; }

/* Der Lichthof. Er geht als Erstes an: eine Bühne, bevor jemand darauf
   steht. Ohne ihn stünde der Handschuh vor einer leeren Fläche. */
.boot__licht {
  position: absolute;
  left: 50%; top: 50%;
  width: min(150vw, 62rem); aspect-ratio: 1;
  transform: translate(-50%, -50%) scale(.45);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 48%,
    var(--spot), color-mix(in srgb, var(--spot) 30%, transparent) 44%, transparent 70%);
  opacity: 0;
  transition: opacity .9s var(--ease), transform 1.3s var(--ease-flow);
  pointer-events: none;
}
.boot.is-licht .boot__licht { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* Drei Geschwister in einer Rasterzelle. Die Reihenfolge im Markup gibt
   nur die Vorlage; wer vorn liegt, entscheidet z-index. */
.boot__buehne {
  display: grid;
  place-items: center;
  width: min(88vw, 44rem);
  position: relative;
}
.boot__buehne > * { grid-area: 1 / 1; }

.boot__wort {
  display: block;
  overflow: hidden;             /* die Maske, aus der die Zeile aufsteigt */
  padding-top: .1em; margin-top: -.1em;
  font-family: var(--f-display);
  font-weight: 900;
  font-stretch: 118%;
  line-height: .84;
  letter-spacing: -.04em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
}
.boot__wort > span {
  display: block;
  transform: translateY(105%);
  transition: transform .82s var(--ease-out);
}
.boot.is-wort-hinten .boot__wort--hinten > span,
.boot.is-wort-vorn   .boot__wort--vorn   > span { transform: none; }

/* SCHAKAL — groß genug, dass der Handschuh die Mitte deckt. Das ist die
   Bedingung für den ganzen Effekt: Läge die Zeile schmaler als die Ware,
   sähe man nur eine Überschrift mit Bild davor. */
.boot__wort--hinten {
  z-index: 1;
  font-size: clamp(3.4rem, 16vw, 11rem);
  color: var(--fg);
}
/* SPORTS schließt den Namen ab, gesperrt und klein gegen die Wucht
   darüber — zwei gleich laute Zeilen wären ein Logo, keine Choreografie.
   Es steht unter der Ware, nicht darauf: Auf der Manschette des
   Handschuhs steht dasselbe Wort bereits gedruckt. */
.boot__wort--vorn {
  z-index: 1;
  /* Unterhalb der Bühne statt in ihr: Als Rasterfeld läge es in derselben
     Zelle wie die Ware und damit hinter dem Etikett. */
  position: absolute;
  left: 50%; top: 100%;
  transform: translateX(-50%);
  margin-top: clamp(.5rem, 1.4svh, 1.1rem);
  font-family: var(--f-mono);
  font-weight: 500;
  font-size: clamp(.7rem, 2.4vw, 1.15rem);
  letter-spacing: .58em;
  text-indent: .58em;           /* die Sperrung hinter dem letzten Zeichen ausgleichen */
  color: var(--fg-mute);
}

/* Die Ware. Sie kommt von unten und aus der Tiefe, mit Bewegungsunschärfe:
   Ein Handschuh, der einblendet, ist ein Bild; einer, der hereinfliegt und
   scharf wird, ist ein Gegenstand. */
.boot__glove-in {
  z-index: 2;
  display: block;
  width: min(78vw, 52svh, 29rem);
  transform: translate3d(6%, 46%, 0) scale(.58) rotate(-19deg);
  filter: blur(14px);
  opacity: 0;
  transition:
    transform 1.05s var(--ease-flow),
    filter .7s var(--ease-out),
    opacity .5s var(--ease);
  will-change: transform, filter;
}
.boot.is-ware .boot__glove-in {
  transform: none;
  filter: blur(0);
  opacity: 1;
}
/* Die Übergabe an den Auftakt: bootSequence() schreibt den Weg als
   Inline-Transform, hier steht nur, wie lange er dauert. Der Weichzeichner
   kommt zurück — ein Gegenstand, der beschleunigt, wird wieder unscharf,
   und er verdeckt zugleich, dass am Ziel ein zweiter Handschuh übernimmt. */
.boot.is-uebergabe .boot__glove-in {
  transition:
    transform .78s var(--ease-flow),
    opacity .3s var(--ease) .42s,
    filter .4s var(--ease) .3s;
  opacity: 0;
  filter: blur(6px);
}
.boot__glove-float { display: block; }
/* Dieselbe freie Bahn wie im Auftakt, nur weiter — hier hält nichts den
   Handschuh, er ist gerade erst angekommen. */
.boot.is-ware .boot__glove-float { animation: bootSchweben 6s var(--ease-loop) .9s infinite; }
@keyframes bootSchweben {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  25%  { transform: translate3d(-1.4%, -1.8%, 0) rotate(-.9deg); }
  50%  { transform: translate3d(0, -3%, 0) rotate(0deg); }
  75%  { transform: translate3d(1.4%, -1.6%, 0) rotate(1.2deg); }
  100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}
/* Dieselben Tokens wie im Auftakt: In Hell steht der schwarze Handschuh,
   in Dunkel der weiße. Sonst wechselte die Ware beim Übergang die Farbe. */
.boot__glove-img { width: 100%; height: auto; }
.boot__glove-img--hell { opacity: var(--glove-hell); }
.boot__glove-img--dunkel { position: absolute; inset: 0; opacity: var(--glove-dunkel); }

/* Das Angebot — und die dritte Ebene. Es liegt VOR dem Handschuh, auf
   seiner Manschette, und es ist ein Etikett mit eigener Fläche statt einer
   Textzeile: Zwischen dem schwarzen Handschuh der hellen Fassung und dem
   weißen der dunklen gibt es keine Schriftfarbe, die auf beiden läge.
   Eine Fläche löst das, ohne dass die Fassung davon wissen muss — und sie
   nimmt zugleich vorweg, was eine Sekunde später im Auftakt steht: ein
   Preisschild, das an der Ware hängt. */
.boot__zeile {
  position: absolute;
  z-index: 3;
  left: 50%; bottom: 17%;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: .75rem;
  padding: .55rem .7rem .55rem 1rem;
  border-radius: var(--r-voll);
  background: var(--surface);
  box-shadow: var(--shadow-l);
  font-family: var(--f-mono);
  font-size: clamp(.6rem, 1.5vw, .74rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--fg-faint);
  opacity: 0;
  transform: translate(-50%, 14px) scale(.94);
  transition: opacity .45s var(--ease), transform .6s var(--ease-back);
}
.boot.is-zeile .boot__zeile { opacity: 1; transform: translate(-50%, 0) scale(1); }
/* Auf schmalen Geräten trägt das Etikett nur Preis und Ersparnis — der
   Name des Pakets passt dort nicht neben beides, und was wegfällt, ist
   das, was am wenigsten überrascht. */
@media (max-width: 520px) {
  .boot__zeile-txt { display: none; }
}

/* Der Vorhang auf schmalen Geräten -------------------------------------
   Die Rechnung des Effekts ist ein Verhältnis, keine Größe: Die Wortmarke
   muss breiter sein als die Ware, sonst sieht man kein Wort mehr, hinter
   dem etwas steht, sondern zwei Buchstaben mit einem Handschuh dazwischen.
   Gemessen auf 390 px: SCHAKAL war bei 16vw 363 px breit, die Bühne
   343 — das Wort lief in die Maske und wurde beidseitig abgeschnitten,
   während der Handschuh mit 304 px den Rest deckte.

   Deshalb hier kein rem-Mindestmaß mehr, sondern reine Viewport-Breite für
   beide: Bei 14,6vw bleibt das Wort immer knapp unter der Bühne, und bei
   56vw stehen links und rechts von der Ware rund 55 px Schrift frei. */
@media (max-width: 620px) {
  .boot__wort--hinten { font-size: 14.6vw; }
  .boot__glove-in { width: min(50vw, 36svh, 14rem); }
  .boot__zeile { bottom: 13%; }
}
.boot__zeile b {
  font-family: var(--f-preis); font-size: 1.55em; font-weight: 600;
  letter-spacing: -.02em; color: var(--fg); font-variant-numeric: tabular-nums;
}
.boot__zeile-spar {
  padding: .3rem .55rem;
  border-radius: var(--r-voll);
  background: var(--accent);
  color: var(--bone);
  font-size: .94em;
  letter-spacing: .1em;
}

/* Der Fortschritt als Haarlinie statt als Prozentzahl. Eine Zahl, die in
   900 ms von 00 auf 100 springt, misst nichts — sie behauptet nur, dass
   gemessen wird. Die Linie sagt dasselbe, ohne zu lügen: Sie ist so lang
   wie die Sequenz. */
.boot__bahn {
  position: absolute;
  left: 50%; bottom: clamp(2.5rem, 8svh, 5rem);
  transform: translateX(-50%);
  width: min(58vw, 13rem); height: 2px;
  border-radius: var(--r-voll);
  background: var(--line);
  overflow: hidden;
}
.boot__bahn i {
  display: block; height: 100%; width: 100%;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
}
@media (prefers-reduced-motion: reduce) { .boot { display: none; } }

/* --- Hero --------------------------------------------------------------- */
/* Volle Bildschirmhöhe (Festlegung vom 5.8.2026). Vorher war der Auftakt
   bewusst niedriger, damit die erste Ware anreißt — dieses Argument ist
   entfallen, weil die Ware jetzt IM Auftakt steht: der Handschuh auf der
   Bühne und das Preisschild daneben. Was unten anreißen muss, ist damit
   nicht mehr das Sortiment, sondern der Hinweis, dass es weitergeht. */
.hero {
  position: relative;
  /* Genau ein Bildschirm, nicht mindestens einer.

     Der Betreiber am 25.8.2026: „Aufm Handy und aufm Desktop sollte
     eigentlich der Header ein einzelner Abteil sein, sozusagen der Anfang
     sein, wenn man die Seite sieht." Mit `min-height` wuchs der Auftakt,
     sobald sein Inhalt mehr Platz brauchte — auf 390 x 740 waren es 879 px,
     und der Lead reichte angeschnitten in den nächsten Abschnitt.

     `height` statt `min-height` macht ihn zu einem Feld mit fester Kante.
     Was nicht hineinpasst, muss weichen (siehe .hero__lead) — das ist die
     ehrlichere Reihenfolge: erst entscheiden, was in den ersten Bildschirm
     gehört, dann den Bildschirm danach bemessen. */
  /* `min-height`, nicht `height`: Der Inhalt passt per Konstruktion (die
     Bühne rechnet mit `calc(100svh - 400px)`), also schneidet nichts ab —
     und es braucht keine Media-Query als Notbremse, die auf iOS beim
     Ein- und Ausfahren der Adressleiste umschalten würde. */
  min-height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  /* Unten muss der Scroll-Hinweis Platz haben, ohne in die
     Vertrauenszeile zu laufen — er ist rund 4,5 rem hoch. */
  padding-bottom: clamp(7rem, 11vw, 9rem);
  padding-top: calc(6rem + var(--announce-h));

  /* Ein eigener Grund und eine eigene Kante — seit dem 26.8.2026.

     Der Betreiber: „Der sieht schön aus und alles gut, aber vielleicht kann
     man das irgendwie noch so bisschen nicht nahtlos machen mit dem Rest."
     Er hatte recht: Der Auftakt trug denselben Grund wie die ganze Seite
     und endete an keiner sichtbaren Linie. Was danach kam, war nicht der
     nächste Abschnitt, sondern einfach mehr Seite.

     Der Ton ist der, auf dem im Projekt Ware liegt (`--stage-flat`) — der
     Auftakt IST eine Bühne. Der Unterschied zum Seitengrund ist klein
     (#e9e8e5 gegen #e2e0db), also fällt er nicht als zweite Farbe auf; die
     Haarlinie darunter macht die Kante endgültig, und die
     Vertrauensleiste ragt weiter darüber hinaus und verzahnt beides,
     statt es zu stapeln.

     Der flache Ton, nicht `--stage` mit seinem Lichtkegel: Den trägt die
     Bühne selbst, und zwei Kegel übereinander sind kein Licht mehr,
     sondern ein Fleck. */
  background: var(--stage-flat);
  border-bottom: 1px solid var(--line);
}
/* Auf dem Handy zählt jede Zeile: Dort steht die Bühne im Fluss zwischen
   Überschrift und Text, also muss oben Luft weichen, damit Ware und Preis
   gemeinsam ins Bild passen. */
@media (max-width: 1019px) {
  .hero { padding-top: calc(4.5rem + var(--announce-h)); }
}

/* **Diese Notbremse ist am 25.8.2026 abends ersatzlos entfallen — sie war
   die Ursache des Sprungs beim Scrollen auf iOS.**

   Hier stand `@media (max-height: 700px) { .hero { height: auto;
   min-height: 100svh } }`, damit `height` + `overflow: hidden` auf flachen
   Fenstern nicht die Überschrift abschneidet.

   Auf einem iPhone 12 sind das 664 px mit sichtbarer Adressleiste und rund
   740 px, sobald sie beim Scrollen einfährt. **Die Schwelle liegt genau
   dazwischen** — mitten im Scrollen schaltete der Auftakt zwischen zwei
   Regelsätzen um. Der Betreiber: „sobald ich runterscrolle und oben die
   URL klein wird, dann springt irgendwie alles in groß rein."

   Gebraucht wird sie nicht mehr: Seit die Bühne mit
   `calc(100svh - 400px)` gerechnet wird, passt der Inhalt per Konstruktion.
   `.hero` steht deshalb wieder auf `min-height` (siehe oben) — ein
   Abschnitt, der im Zweifel wächst, kann nichts abschneiden und hat keine
   Schwelle, die umschalten könnte. */
/* Das untere Polster hält den Scroll-Hinweis frei. Der erscheint erst ab
   700 px Breite und 620 px Höhe — darunter standen dort bis zu 9 rem
   Polster für ein Element, das gar nicht da ist, und schoben Preis und
   Knöpfe unter die Falz. */
@media (max-width: 699px), (max-height: 619px) {
  .hero { padding-bottom: clamp(2.5rem, 7vw, 3.5rem); }
}
/* Der Fototisch: ein flacher Lichtabfall zu den Rändern hin. Er ist der
   Grund, warum die Fläche nicht wie eine leere Seite aussieht — dieselbe
   Idee wie beim Freisteller in der Karte, nur über die ganze Breite.
   Kein Foto mehr dahinter: Das trug den Auftakt, machte die Seite aber
   dunkler als alles danach. Die Aufnahme steht jetzt als eigene Bahn
   weiter unten (.band), wo sie die volle Breite bekommt. */
.hero::after {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 78% 62% at 62% 42%, var(--spot), transparent 68%),
    linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--stage-flat) 62%, transparent) 100%);
}

/* Der Schakal als Wasserzeichen — man sieht ihn erst beim zweiten Hinsehen */
.hero__mark {
  position: absolute;
  right: -6%;
  top: 46%;
  width: min(58vw, 46rem);
  transform: translateY(-50%);
  z-index: 1;
  opacity: var(--mark-opacity);
  mix-blend-mode: var(--mark-blend);
  pointer-events: none;
  /* Kein will-change mehr: Das Wasserzeichen hing bis zum 10.8.2026 am
     Parallax des Auftakts. Der ist weg, bewegt wird hier nichts — die
     Ankündigung hielt seitdem nur noch eine eigene Ebene für ein 78 vw
     breites Bild frei, auf dem Handy der teuerste Posten im Auftakt. */
}
/* auf schmalen Geräten kleiner und innerhalb der Kante — sonst schiebt das
   Wasserzeichen die Seite seitlich auf */
@media (max-width: 760px) { .hero__mark { right: -4%; width: 78vw; opacity: calc(var(--mark-opacity) * .9); } }

/* Der Schakal driftet beim Wegscrollen — und diesmal gratis.
   Bis zum 10.8.2026 hing das Wasserzeichen am Parallax des Auftakts, einem
   Takt, der bei jedem Scrollbild Geometrie las und Stile schrieb. Er ist
   entfallen, und mit ihm die Tiefe: Seither steht ein 78 vw breites Bild
   vollkommen still, während sich alles darüber bewegt.

   Eine Scroll-Zeitachse holt sie zurück, ohne dass ein Skript beteiligt
   ist — sie läuft auf dem Compositor mit dem Scrollen selbst. Der Versatz
   ist bewusst klein: Ein Wasserzeichen, das man beim zweiten Hinsehen
   entdeckt, darf sich nicht in den Vordergrund bewegen. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero__mark {
      animation: markDrift linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    @keyframes markDrift {
      from { transform: translateY(-50%) translate3d(2%, -5%, 0) scale(1.05); }
      to   { transform: translateY(-50%) translate3d(-2%, 6%, 0) scale(1); }
    }
  }
}

/* Ein Raster mit benannten Feldern, nicht zwei Spalten mit Inhalt darin:
   nur so kann die Bühne auf schmalen Geräten zwischen Überschrift und
   Fließtext rutschen, statt hinter allem zu landen. */
/* Einspaltig steht die Handlung VOR dem Fließtext, zweispaltig dahinter.
   Auf einem Handy ist der Platz über der Falz nach Überschrift, Ware und
   Preisschild aufgebraucht — stünde der Lead dazwischen, läge beides,
   was man tun kann, darunter. Der Lead erklärt das Sortiment; wer den
   Preis gesehen hat und handeln will, soll nicht daran vorbeilesen
   müssen. Am Schreibtisch ist der Platz da, dort bleibt die gewohnte
   Reihenfolge. */
.hero__inner {
  position: relative; z-index: 2; width: 100%;
  display: grid;
  align-content: center;
  grid-template-columns: minmax(0, 1fr);
  /* Einspaltig steht der Preis direkt unter der Ware und noch VOR dem
     Knopf: Er ist das Angebot, nicht ein Nachtrag. Der Lead erklärt und darf
     unter die Falz — wer den Preis gesehen hat und handeln will, soll nicht
     daran vorbeilesen müssen.

     Seit dem 6.9.2026 ohne `tag`: Das Preisschild an der Bühne ist entfallen,
     weil es einen zweiten Preis neben die Schlagzeile stellte. Preis und
     Inhalt stehen jetzt in der Textspalte, wo gelesen wird.

     **Auf dem Telefon steht der Knopf VOR der Inhaltsliste**, am Schreibtisch
     dahinter. Nachgemessen auf 390 × 664: Die drei Zeilen mit Haken kosten
     73 px, und damit landete der Kaufknopf bei 744 px — 80 px unter der
     Falz. Getauscht steht er bei 599 px und ist ohne Scrollen erreichbar.
     Die Liste verliert dadurch nichts: Sie bestätigt, was im Paket liegt,
     und das liest man nach dem Preis, nicht vor dem Griff zum Knopf. */
  grid-template-areas: 'eyebrow' 'title' 'stage' 'wahl' 'preis' 'cta' 'inhalt' 'lead' 'trust';
}
.hero__eyebrow { grid-area: eyebrow; }
.hero__title   { grid-area: title; }
.hero__lead    { grid-area: lead; }
.hero__stage   { grid-area: stage; }
.hero__preis   { grid-area: preis; }
.hero__inhalt  { grid-area: inhalt; }
.hero__wahl    { grid-area: wahl; }
.hero__cta     { grid-area: cta; }
.hero__trust   { grid-area: trust; }

/* Bis 1019 px löst sich die Hülle auf, damit Bühne und Preisschild eigene
   Felder bekommen. Darüber ist sie eine Spalte und hält beides zusammen. */
.hero__ware { display: contents; }

@media (min-width: 1020px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1fr) minmax(17rem, 28rem);
    grid-template-areas:
      'eyebrow ware'
      'title   ware'
      'lead    ware'
      'preis   ware'
      'inhalt  ware'
      'cta     ware'
      'trust   trust';
    column-gap: clamp(2rem, 5vw, 5rem);
  }
  .hero__ware {
    display: block;
    grid-area: ware;
    position: relative;
    align-self: center;
  }

  /* Die Überschrift teilt sich die Breite jetzt mit der Bühne, deshalb
     eine eigene Staffelung statt der 7,3vw aus .d-xl: Bei der käme das
     längste Wort („PRÄZISION") am Umbruchpunkt 1020 px breiter heraus
     als seine Spalte und bräche mitten in einer Maske um. */
  .hero__title { font-size: clamp(2.4rem, 5.4vw, 6rem); }
}

/* Mittig unter der Bühne, nicht linksbündig: Sie gehört zum Gegenstand
   darüber, nicht zur Textspalte daneben. Der Abstand nach oben ist knapp —
   je näher die Punkte am Handschuh stehen, desto klarer ist, was sie tun. */
.hero__wahl {
  display: flex;
  justify-content: center;
  /* Rückt an den Handschuh heran — den negativen Abstand trug bisher das
     Preisschild, um in den Lichtkegel der Bühne zu greifen. Jetzt steht die
     Farbwahl dazwischen und übernimmt ihn: Die Punkte gehören zur Ware, das
     Schild zum Angebot. */
  margin-top: clamp(-3.4rem, -7vw, -1.8rem);
  margin-bottom: var(--s-4);
  position: relative;
  z-index: 3;
}
/* Ohne das legt sich das Schild mit seinem eigenen negativen Abstand über
   die Punkte — gemessen 24 px Überdeckung, und die untere Reihe der Punkte
   verschwand darunter. Steht eine Farbwahl davor, hört die Überlappung des
   Schildes auf: Es hat dann keine Bühne mehr zu überlappen. */
.hero__wahl + .hero__tag { margin-top: var(--s-4); }

.hero__eyebrow {
  display: flex; align-items: center; gap: var(--s-4);
  margin-bottom: var(--s-5);
}
.hero__eyebrow::before {
  content: ''; width: clamp(1.5rem, 5vw, 4rem); height: 1px;
  background: var(--accent);
}
.hero__title { margin-bottom: var(--s-5); }
/* Die dritte Zeile ist offen gezeichnet: zwei volle Zeilen, eine hohle.
   Das ist die eine Stelle, an der die Typo selbst etwas behauptet — und
   sie behauptet, was dort steht. Als Fläche eingefärbt war dieselbe Zeile
   auf hellem Grund ein roter Block, der die beiden darüber erschlug.
   `paint-order` gibt es hier nicht zu bedenken: Die Kontur läuft nach
   innen wie außen, deshalb der halbe Wert und die feste Grundfarbe im
   Rückfall — wo -webkit-text-stroke fehlt, bleibt die Zeile lesbar. */
.hero__title em {
  font-style: normal;
  color: var(--fg);
}
@supports (-webkit-text-stroke: 1px black) {
  .hero__title em {
    color: transparent;
    -webkit-text-stroke: clamp(1.2px, .028em, 3.5px) var(--fg);
  }
  /* **Kleine Schrift braucht relativ mehr Strich.**

     `.028em` hält die Kontur proportional zur Schriftgröße — rechnerisch
     also auf dem Telefon dasselbe Bild wie am Schreibtisch. Gesehen ist es
     das nicht: Bei 38 px Versalhöhe steht eine 1,2-px-Linie um einen viel
     kleineren Binnenraum, und die Zeile fällt neben der vollflächigen
     darüber ab. Am 6.9.2026 im Rahmen nebeneinander verglichen — „DEIN
     ERSTES" trug, „TRAINING." verschwand fast.

     Das ist die klassische optische Korrektur: Was proportional stimmt,
     stimmt wahrnehmungsseitig noch lange nicht. */
  @media (max-width: 1019px) {
    .hero__title em { -webkit-text-stroke-width: clamp(1.7px, .042em, 3.5px); }
  }
}
/* Einspaltig steht der Lead hinter den Knöpfen — dann trägt er den Abstand
   nach oben, nicht nach unten. */
.hero__lead { margin-top: var(--s-5); max-width: 46ch; }
@media (min-width: 1020px) {
  .hero__lead { margin-top: 0; margin-bottom: var(--s-6); }
}
/* Auch der Preis im Fließtext: Er steht wenige Zentimeter neben dem großen
   auf dem Preisschild, und zwei verschiedene Kommas nebeneinander fallen auf. */
.hero__lead b {
  color: var(--fg); font-weight: 600;
  font-family: var(--f-preis); font-variant-numeric: tabular-nums;
}
.hero__cta { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; }

/* --- Die Bühne: Licht, Ware, Preisschild -------------------------------- */
/* Einspaltig ist die Breite doppelt gedeckelt, und der zweite Deckel ist
   der wichtigere: Der Handschuh ist quadratisch, seine Breite ist also
   seine Höhe. Nur an 21 rem gebunden war er auf einem flachen Fenster
   rund 340 px hoch und schob den Preis unter die Falz — genau das, was
   der Auftakt zeigen soll. `44svh` bindet ihn stattdessen an das, was
   tatsächlich knapp ist: die verfügbare Höhe. Auf einem üblichen Handy
   greift weiterhin die 21 rem, auf einem flachen Fenster gibt der
   Handschuh nach, statt den Preis zu verdrängen. */
/* Die Bühne teilt sich den ersten Bildschirm mit Titel, Preis und Knopf.
   `44svh` war zu großzügig: Der Kaufknopf stand damit auf jedem iPhone
   unter der Falz, und das ist der wichtigste Knopf der Seite.

   **Gerechnet, nicht geschätzt.** Alles im Auftakt außer der Bühne misst
   zusammen 407 px (Kopfzeile, Ortszeile, Titel, Farbwahl, Preis, Knopf) —
   gemessen am 6.9.2026. Die Knopf-Unterkante ist also 407 + Bühnenhöhe:

     |            | Falz | Bühne 36svh | Knopf | Bühne 32svh | Knopf |
     |------------|------|-------------|-------|-------------|-------|
     | 375 × 635  | 635  |     229     |  636  |     203     |  610  |
     | 390 × 664  | 664  |     239     |  646  |     212     |  619  |
     | 393 × 684  | 684  |     246     |  653  |     219     |  626  |
     | 430 × 745  | 745  |     268     |  675  |     238     |  645  |

   Bei 36svh scheitert das kleinste iPhone um einen Pixel. 32svh trägt auf
   allen vieren mit mindestens 25 px Luft.

   **Im Rahmen lässt sich das nicht nachmessen:** `svh` bezieht sich dort auf
   das äußere Fenster, nicht auf den Rahmen — eine Messung in `_mobilcheck`
   oder `_vorschau` fällt deshalb zu pessimistisch aus. Die Gegenprobe gehört
   aufs Gerät, über `tools/vorschau-server.py 8800 --netz`.

   Die Obergrenze von 21rem greift ab etwa 1050 px Höhe ohnehin zuerst. */
.hero__stage {
  position: relative;
  width: min(100%, 21rem, 32svh);
  margin: 0 auto var(--s-5);
}
@media (min-width: 1020px) {
  .hero__stage { width: auto; margin: 0; }
}


/* Der Lichtkegel vom Fototisch — dieselbe Idee wie in der Produktkarte,
   nur größer. Er geht kurz VOR dem Handschuh an: erst Licht, dann Ware. */
.hero__spot {
  position: absolute;
  inset: -14% -10% -8%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 58% 54% at 50% 52%,
    var(--spot), color-mix(in srgb, var(--spot) 35%, transparent) 42%, transparent 72%);
  transform: scale(.86);
  transition: opacity 1.1s var(--ease-out), transform 1.1s var(--ease-out);
}
/* Nach dem Auftakt atmet das Licht weiter — 9 s gegen die 7 s des
   Handschuhs, damit die beiden nie im Gleichtakt laufen und es organisch
   bleibt statt getaktet. */
.hero__spot.is-in {
  transform: none;
  animation: heroLicht 9s var(--ease-loop) 1.9s infinite;
}

/* Der Aufprall. Ein einzelner Lichtstoß in dem Moment, in dem der
   Handschuh steht — er macht aus dem Eintreffen ein Ereignis. Läuft
   genau einmal und liegt auf dem Pseudoelement, damit er sich nicht mit
   dem Atmen der Fläche darunter ins Gehege kommt. */
.hero__spot::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 44% 40% at 50% 50%,
    var(--treffer), transparent 66%);
  opacity: 0;
}
.hero__spot.is-in::after { animation: heroTreffer 1s var(--ease-out) .34s both; }

/* Drei Ebenen, weil drei Bewegungen sonst auf demselben transform
   kollidieren: Eintritt (Übergang) · Atmen (Keyframes) · Kippung nach
   der Maus (Skript, rAF-Takt) — von außen nach innen. */
.hero__glove-in {
  position: relative;
  z-index: 1;
  display: block;
  /* Weiter draußen und stärker gedreht als zuvor, dazu Bewegungsunschärfe:
     Der Handschuh soll einschlagen, nicht einblenden. */
  transform: translate3d(17%, 13%, 0) scale(.87) rotate(-12deg);
  filter: blur(9px);
  transition:
    opacity .5s var(--ease-out),
    transform .95s var(--ease-back),
    filter .55s var(--ease-out);
}
.hero__glove-in.is-in { transform: none; filter: blur(0); }

/* Nach dem Vorhang fliegt hier nichts mehr ein. Der Handschuh der
   Ladesequenz ist genau an diese Stelle geflogen und blendet dort aus,
   während dieser hier aufblendet — zwei Bilder derselben Ware, eine halbe
   Sekunde übereinander. Behielte dieser seinen Eintritt, sähe man den
   Gegenstand landen und sofort noch einmal von außen hereinkommen. */
.hero.is-uebergeben .hero__glove-in {
  transform: none;
  filter: none;
  transition: opacity .5s var(--ease) .1s;
}

/* Die Fassung entscheidet, welcher der beiden Handschuhe oben liegt. Sie
   liegen übereinander, nicht nebeneinander: Beim Umschalten wechselt die
   Ware sichtbar die Ausführung, statt dass ein Bild ausgetauscht wird. */
.hero__glove { transition: opacity .4s var(--ease); }
.hero__glove--hell   { opacity: var(--glove-hell); }
.hero__glove--dunkel {
  position: absolute; inset: 0;
  opacity: var(--glove-dunkel);
}

/* Eigene Ebene für die Mauskippung — der Eintritt und das Schweben liegen
   darüber, und drei Bewegungen auf einem transform schlagen einander. */
/* Die Kippung nach der Maus gibt es nur dort, wo es eine Maus gibt —
   initHeroTilt() steigt auf Touch aus. Die Ankündigung gehört deshalb an
   dieselbe Bedingung: Auf dem Handy hielte sie eine Ebene für eine
   Bewegung frei, die nie kommt. */
.hero__glove-kipp {
  display: block;
  position: relative;
}
@media (hover: hover) and (pointer: fine) {
  .hero__glove-kipp { will-change: transform; }
}

.hero__glove-float {
  display: block;
  perspective: 1000px;
  will-change: transform;
}
/* Setzt erst ein, wenn der Eintritt durch ist (.38 s + .95 s), sonst
   überschriebe die Schleife die Landung mitten in der Bewegung. */
.hero__glove-in.is-in .hero__glove-float {
  animation: heroSchweben 7s var(--ease-loop) 1.5s infinite;
}

.hero__glove {
  width: 100%; height: auto;
  /* Weiß hat genug Eigenkontrast (rim 0 in data.js) und braucht keine
     Lichtkante — nur den Schatten, der ihn auf die Fläche stellt. */
  filter: drop-shadow(0 2rem 3rem var(--pack-shadow));
  will-change: transform;
}

/* Angehalten, sobald der Auftakt aus dem Bild ist — initRuhe() setzt die
   Klasse. Angehalten, nicht abgeschaltet: Wer zurückscrollt, findet die
   Bewegung dort wieder, wo sie stehen geblieben ist. */
.hero.is-ruht .hero__spot,
.hero.is-ruht .hero__spot::after,
.hero.is-ruht .hero__glove-float { animation-play-state: paused; }

@keyframes heroTreffer {
  0%   { opacity: 0;  transform: scale(.72); }
  26%  { opacity: .8; }
  100% { opacity: 0;  transform: scale(1.16); }
}
/* Frei schwebend, nicht auf und ab.
   Zwei Stützpunkte ergeben eine Pendelbewegung — das ist ein Gegenstand an
   einer Schnur, kein schwerelos treibender. Vier Stützpunkte auf einer
   flachen Acht sehen aus wie Trägheit: Der Handschuh driftet seitlich weg,
   während er steigt, und kommt auf der anderen Seite zurück. Die Drehung
   läuft in halber Frequenz mit, damit sich die beiden nie decken und die
   Bahn nie zweimal gleich aussieht. */
@keyframes heroSchweben {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); }
  25%  { transform: translate3d(-.9%, -1.2%, 0) rotate(-.55deg); }
  50%  { transform: translate3d(0, -2%, 0) rotate(0deg); }
  75%  { transform: translate3d(.9%, -1.1%, 0) rotate(.75deg); }
  100% { transform: translate3d(0, 0, 0) rotate(0deg); }
}
@keyframes heroLicht {
  0%, 100% { opacity: .84; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.06); }
}

/* Das Preisschild hängt am Handschuh, statt als Satz danebenzustehen.
   Es ragt bewusst in die Bildfläche — der Freisteller hat unten
   transparenten Rand, verdeckt wird dadurch nichts. */
.hero__tag {
  position: relative;
  z-index: 2;
  display: block;
  width: min(100%, 23rem);
  /* Der negative Abstand gilt nur dort, wo das Schild direkt unter der
     Bühne hängt. Steht die Farbwahl davor — am Schreibtisch immer —, hebt
     `.hero__wahl + .hero__tag` ihn auf: Die Punkte liegen schon in der
     Bühne, ein zweites Hineinziehen verdeckte sie. */
  margin: -2.5rem 0 0 auto;
  border: 1px solid var(--edge);
  border-radius: var(--r-3);
  overflow: hidden;
  box-shadow: var(--shadow-l);
  /* Schnappt ein statt sanft aufzublenden — dieselbe Sprache wie der
     Handschuh daneben. transform steht hier nach der Grundregel aus
     base.css, damit der Druck-Zustand weiter unten sie schlagen kann. */
  transform: translateY(20px) scale(.96);
  transition:
    opacity .45s var(--ease-out), transform .7s var(--ease-back),
    border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.hero__tag.is-in { transform: none; }
@media (hover: hover) and (pointer: fine) {
  .hero__tag:hover {
    border-color: var(--edge-2);
    box-shadow: var(--shadow-l), 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent);
  }
}
.hero__tag.is-in:active { transform: scale(.98); transition-duration: .16s; }

/* Kopfleiste auf der Akzentfläche: Sie trägt den Namen und hebt das
   Schild vom Foto ab, ohne dass etwas leuchten muss. */
.hero__tag__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4);
  padding: .5rem var(--s-4);
  background: var(--accent);
}
.hero__tag__name {
  font-family: var(--f-mono); font-size: .66rem; font-weight: 500;
  letter-spacing: .15em; text-transform: uppercase; color: var(--bone);
}
/* Heller Chip auf der Akzentfläche — die Umkehrung zieht den Blick auf
   die Ersparnis, die sonst die leiseste Zahl des Schildes wäre. */
.hero__save {
  font-family: var(--f-mono); font-size: .62rem; font-weight: 600;
  letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent); background: var(--bone);
  padding: .2rem .45rem; white-space: nowrap;
}
/* Die Pointe des Auftakts: Der Preis steht, dann knallt die Ersparnis
   darauf. Beginnt bei .72 statt bei null — nichts erscheint aus nichts. */
.hero__tag.is-in .hero__save { animation: heroSpar .55s var(--ease-back) .95s both; }
@keyframes heroSpar {
  0%   { opacity: 0; transform: scale(.72); }
  100% { opacity: 1; transform: scale(1); }
}

.hero__tag__body {
  /* Ohne das trägt der <span> sein Padding nicht und der Preis klebt an
     der Kante — ein Etikett ist ein Block, kein Textfluss. */
  display: block;
  padding: var(--s-5);
  background: var(--glass-2);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}
.hero__price { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-3); }
.hero__price b {
  font-family: var(--f-preis); font-weight: 600;
  /* Kleiner als bis zum 26.8.2026 (2,6 rem), und das ist kein Rückschritt:
     Der Preis steht jetzt über drei Inhaltszeilen, die ihn erklären. Die
     Karte wuchs dadurch um 84 px, und die hätten die Auftakthöhe gekostet —
     auf einem 800 px hohen Fenster wäre ihr Fuß unter die Falz gerutscht. */
  font-size: clamp(1.7rem, 2.4vw, 2rem);
  line-height: 1; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.hero__price s {
  font-family: var(--f-mono); font-size: .8rem;
  color: var(--fg-faint); text-decoration-thickness: 1px;
}
/* --- Was im Paket liegt -------------------------------------------------
   Drei Zeilen unter dem Preis, seit dem 26.8.2026. Der Betreiber über den
   Auftakt: „Es ist da, man erkennt es, aber man übersieht es auch schnell."

   Der Haken steht in der Akzentfarbe und die Warengruppe in der
   Schriftfarbe, die Variante daneben leiser: Wer die Karte überfliegt,
   liest drei Dinge — wer stehen bleibt, liest auch 4 m und Senior. */
.hero__tag__liste {
  display: flex; flex-direction: column; gap: .22rem;
  margin-top: var(--s-4);
}
.hero__teil {
  display: flex; align-items: baseline; gap: .5rem;
  font-size: .78rem; line-height: 1.28;
}
.hero__teil b { font-weight: 500; color: var(--fg); }
/* Die Zusatzangabe („4 m", „Senior", „Farbe und Gewicht wählbar").

   **`--fg-mute` statt `--fg-faint` seit dem 6.9.2026.** Die Liste stand
   vorher auf dem Preisschild und damit auf `--surface`; seit sie in der
   Textspalte des Auftakts steht, liegt sie auf `--stage-flat` (#e2e0db),
   und dort kommt `--fg-faint` nur auf **4,45** — knapp unter den
   geforderten 4,5 bei 11 px. `--fg-mute` erreicht 6,51.

   Gefunden hat das `_design.html`, nicht das Auge: 0,05 sieht niemand, ein
   Prüfwerkzeug schon. */
.hero__teil > span:last-child {
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .04em;
  color: var(--fg-mute);
}
.hero__teil__hk {
  flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: .95rem; height: .95rem;
  /* Der Haken sitzt auf der Grundlinie des Textes, nicht darüber: Eine
     Reihe von Häkchen, die je nach Zeilenhöhe wandert, liest sich als
     Aufzählung mit Schluckauf. */
  transform: translateY(.12rem);
  color: var(--accent-br);
}
.hero__teil__hk svg { width: 100%; height: 100%; }

.hero__tag__foot {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-3); padding-top: var(--s-3);
  border-top: 1px solid var(--edge);
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .06em;
  /* Der Fuß ist seit dem 26.8.2026 die Handlung, nicht mehr die
     Inhaltsangabe — die steht jetzt darüber. Deshalb in der Schriftfarbe
     und nicht in der leisen: „Paket ansehen" ist das, was man tun soll. */
  color: var(--fg);
}
/* Flache Fenster am Schreibtisch. Die rechte Spalte trägt Bühne (448 px)
   und Angebotskarte übereinander; auf 800 px Fensterhöhe bleiben dafür nach
   Abzug der Polster rund 554 px. Bis zum 26.8.2026 ging die Rechnung knapp
   auf, mit den drei Inhaltszeilen nicht mehr — der Fuß der Karte rutschte
   62 px unter die Falz.

   Die Schwelle liegt bei 900 px und damit außerhalb des Bereichs, den die
   Adressleiste mobiler Browser überstreicht (620–900). Sie darf keine
   Schwelle im Scrollen sein: Ein Auftakt, der beim Ein- und Ausfahren der
   Leiste umschaltet, ist genau der Fehler vom 25.8.2026. Hier ist sie
   zusätzlich an `min-width: 1020px` gebunden, gilt also nur dort, wo es
   überhaupt eine zweispaltige Fassung gibt. */
@media (min-width: 1020px) and (max-height: 900px) {
  /* Auch die Spalte wird schmaler, und damit die quadratische Bühne
     flacher: 25 rem statt 28 sind 48 px, die dem Angebot fehlen. Der Tausch
     ist bewusst — die Ware 11 % kleiner, dafür die Karte vollständig über
     der Falz. Auf dem Telefon gilt das ausdrücklich nicht: Dort ist die
     Ware am 25.8.2026 beanstandet worden und die Karte ohnehin aus. */
  .hero__inner { grid-template-columns: minmax(0, 1fr) minmax(17rem, 25rem); }
  .hero__tag__head { padding: .42rem var(--s-4); }
  .hero__tag__body { padding: var(--s-4); }
  .hero__price b   { font-size: 1.75rem; }
  .hero__teil      { font-size: .74rem; line-height: 1.25; }
  .hero__tag__liste { gap: .16rem; margin-top: var(--s-3); }
  .hero__tag__foot { margin-top: var(--s-3); padding-top: var(--s-3); }
}

.hero__tag__foot svg {
  width: .9rem; height: .9rem; margin-left: auto; flex-shrink: 0;
  color: var(--accent-br);
  transition: transform .18s var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .hero__tag:hover .hero__tag__foot svg { transform: translateX(3px); }
}

/* Vertrauenszeile statt Kennzahlenblock: dieselben Zusagen auf einer Zeile,
   damit der Auftakt unter einer Bildschirmhöhe bleibt und die Ware anreißt. */
.hero__trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  border-top: 1px solid var(--edge);
  font-family: var(--f-mono);
  font-size: .68rem;
  letter-spacing: .07em;
  color: var(--fg-mute);
  line-height: 1.4;
}
.hero__trust b {
  color: var(--fg); font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.hero__trust .stars svg { width: .8rem; height: .8rem; }
/* Trennpunkt zwischen den Zusagen */
.hero__trust i {
  width: 3px; height: 3px;
  background: var(--fg-faint);
  transform: rotate(45deg);
  margin-inline: .35rem;
  flex-shrink: 0;
}

/* Der Hinweis steht mittig unten statt seitlich: Seit der Auftakt den
   ganzen Bildschirm füllt, reißt unten keine Ware mehr an — dass es
   weitergeht, muss jetzt jemand sagen. Zentriert ohne transform, weil
   die Ladechoreografie aus base.css genau diese Eigenschaft belegt. */
.hero__scroll {
  position: absolute;
  left: 0; right: 0;
  margin-inline: auto;
  width: max-content;
  bottom: clamp(1.5rem, 3vw, 2.5rem);
  z-index: 3;
  display: none;
  flex-direction: column;
  align-items: center;
  gap: .7rem;
  font-family: var(--f-mono);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  /* Eine Stufe lauter als die leiseste, seit der Auftakt seinen eigenen
     Grund hat: Auf `--stage-flat` kommt `--fg-faint` nur noch auf 4,45 —
     gemessen von der Designprüfung, nötig sind 4,5. Dieselbe Lehre wie am
     16.8.2026: Sobald eine Farbe irgendwo Fläche wird, gilt jeder Text
     darauf als Text auf dieser Fläche. */
  color: var(--fg-mute);
}
/* Auf flachen Fenstern (Handy quer) läge er sonst über dem Preisschild */
@media (min-width: 700px) and (min-height: 620px) { .hero__scroll { display: flex; } }
.hero__scroll { transition: color var(--t-fast) var(--ease); }
.hero__scroll:hover { color: var(--fg); }
.hero__scroll i {
  position: relative;
  display: block;
  width: 1px; height: 3.5rem;
  background: var(--line-2);
  overflow: hidden;
}
.hero__scroll i::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent, var(--accent-br));
  animation: scrollHint 2.4s var(--ease) infinite;
}
@keyframes scrollHint {
  0%   { transform: translateY(-100%); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(0); opacity: 0; }
}

/* --- Einspaltig: das Schild rutscht über die Ware -----------------------
   Gemessen am 16.8.2026 auf 390 × 770: Bühne 463 px, Preisschild bei 573,
   Knöpfe bei 767 — auf einem echten Telefon mit Adressleiste steht damit
   weder das Angebot noch die erste Handlung im Bild. Der Auftakt zeigte
   eine Ware ohne Preis und einen Preis ohne Weg.

   Zwei Hebel, und beide sind billiger als „alles kleiner machen": Der
   Handschuh gibt Höhe ab (36 svh statt 44), und das Schild legt sich mit
   seiner Kopfleiste ÜBER seine Unterkante. Das ist kein Trick, um Platz zu
   sparen — ein Etikett, das an der Ware hängt, gehört auf die Ware. Was es
   verdeckt, ist die Handschuhspitze, nicht der Schakalkopf. */
@media (max-width: 1019px) {
  .hero__eyebrow { margin-bottom: var(--s-4); }
  .hero__title { margin-bottom: 0; }
  /* --- Die Ware, 25.8.2026 neu ----------------------------------------
     Bis dahin stand hier `min(100%, 20rem, 30svh)` — auf 390 x 740 waren
     das 222 px, und der Betreiber hat genau das beanstandet: „das Bild für
     mit dem Handschuh, Mundschutz, Bandage und so weiter viel zu klein …
     das hapert auch irgendwie so komisch in der Mitte."

     Beides stimmt, und beides hatte denselben Grund: In den Auftakt mussten
     Überschrift, Ware, Farbwahl, PREISSCHILD und Knopf zusammen über die
     Falz. Fünf Dinge in einen Bildschirm gehen nur, wenn eines davon klein
     bleibt — und das war die Ware.

     Das Preisschild fliegt jetzt (siehe .hero__tag darunter). Damit ist
     Platz da, und die Rechnung auf 390 x 710 geht so auf:
       oben fest 79 + Polster 72 + Titel 110 + Bühne X + Wahl 9 + Knopf 87
       + Polster unten 40  ≤  710   →   X ≤ 313

     Die Bühne steht deshalb rechtsbündig und bricht über den Gutter hinaus:
     Angelehnt wirkt dieselbe Fläche größer als mittig, und der Anschnitt
     nimmt ihr das Schwebende, das als „komisch in der Mitte" gemeldet war. */
  .hero__stage {
    /* **Gerechnet, nicht geschätzt.**

       Bis zum 25.8.2026 abends stand hier `42svh` — ein Anteil der
       Bildschirmhöhe. Das geht nicht auf: Was über und unter der Ware steht,
       ist FEST (Kopfzeile, Polster, Überschrift, Farbwahl, Knopf), nicht
       anteilig. Je kleiner das Gerät, desto mehr Prozent frisst das Feste —
       und desto kleiner wurde ausgerechnet dort die Ware.

       Die Summe des Festen, gemessen: oben 79 (Ankündigung + Kopfzeile),
       Polster 72, Titel 110 (drei Zeilen), Farbwahl 9, Knopf 62,
       Größenlink 24, Polster unten 40 — rund 400 px auf jedem Gerät.

       `calc(100svh - 400px)` gibt der Ware genau das, was übrig bleibt:
       235 px auf einem iPhone SE, 345 px auf einem Pro Max. Und der
       Leerraum unter dem Knopf verschwindet mit, weil der Inhalt den
       Bildschirm jetzt füllt statt darin zu schwimmen. */
    width: min(84vw, 22rem, calc(100svh - 400px));
    justify-self: end;
    /* Über den Gutter hinaus — die Ware liegt an der Kante an, statt in der
       Spalte zu schweben. */
    margin-right: calc(-1 * var(--gutter));
    /* Nur noch -.5rem statt -1.2rem: Der Freisteller hat oben rund 8 %
       leeren Rand, den man unter die Überschrift schieben kann. Bei einer
       rechtsbündigen Bühne sitzt sie dabei aber neben dem Titelende — und
       je kleiner sie war, desto mehr sah das nach einem Fremdkörper in der
       Ecke aus. Gemessen waren es 19 px Überlappung auf jedem Gerät. */
    margin-top: -.5rem;
    margin-bottom: 0;
    z-index: 0;
  }
  /* **Das Preisschild steht auf dem Handy nicht mehr im Auftakt.**
     Es trug Paketpreis, Ersparnis und die Zeile „Handschuh · Bandagen ·
     Mundschutz" — und genau das steht zwei Zentimeter darüber schon in der
     Ankündigungsleiste, die auf jeder Seite mitläuft.

     Dieselbe Begründung, mit der der Betreiber am 25.8.2026 den
     Startpaket-Block gestrichen hat: „das sieht man ja schon beim Header."
     Es kostete 139 px plus Polster — die Höhe, die der Ware gefehlt hat.

     Am Schreibtisch bleibt es: Dort steht es NEBEN der Ware, kostet keine
     Höhe und ist das Angebot in Sichtweite des Preises. */
  .hero__tag { display: none; }
  /* Dasselbe Schild, enger gesetzt. Am Schreibtisch trägt das Polster die
     Ruhe; auf 700 px Bildschirmhöhe kostet dieselbe Ruhe genau die Zeile,
     in der der Knopf steht. Der Preis selbst bleibt unangetastet — er ist
     die Aussage, nicht der Rahmen darum. */
  .hero__tag__head { padding: .42rem var(--s-4); }
  .hero__tag__body { padding: var(--s-4); }
  .hero__tag__foot { margin-top: var(--s-3); padding-top: var(--s-3); }
  /* Der Knopf trägt die ganze Breite: Auf einem Telefon ist ein Ziel, das
     man ohne Zielen trifft, mehr wert als eine Schaltfläche, die ihre
     Beschriftung eng umschließt. Der Größenhinweis daneben ist die zweite
     Frage und darf unter der Kante anreißen. */
  .hero__cta { gap: var(--s-3); }
  .hero__cta .btn { flex: 1 1 100%; }

  /* **Der Lead entfällt auf dem Handy.**

     Er stand als letztes Feld des Rasters — also NACH dem Kaufknopf, und
     damit gemessen bei 655–764 px auf einem 740 px hohen Bildschirm. Das
     war der Grund, warum der Auftakt 879 px hoch war und unten überlief:
     Der Betreiber wollte ihn als abgeschlossenen ersten Abschnitt.

     Ein Absatz zwischen Preis und Kaufknopf ist auf einem Telefon ohnehin
     ein Hindernis, kein Text. Was er sagt, steht im Titel („59,99 €. Der
     Rest ist Aufschlag.") und in der Ankündigungsleiste; die Rechnung, auf
     die er verweist, steht weiter unten auf derselben Seite. Am
     Schreibtisch bleibt er — dort steht er neben der Ware und kostet
     keine Höhe. */
  .hero__lead { display: none; }

  /* **Die Bewertungszeile steht auf dem Handy nicht mehr im Auftakt.**

     Sie trug „4,8/5 aus über 100 Bewertungen · Lieferung in 1–3 Werktagen ·
     14 Tage Rückgabe" — und zwei dieser drei Angaben stehen unmittelbar
     darunter noch einmal, als Kacheln der Vertrauensleiste. Auf dem
     Screenshot des Betreibers vom 25.8.2026 sind beide gleichzeitig im
     Bild.

     Sie kostet 55 px plus Abstand, und genau die fehlten: Mit ihr war der
     Auftakt auf einem iPhone 12 **712 px** hoch bei 664 px Bildschirm — die
     Notbremse griff, der Abschnitt lief unten über, und die Bewertungszeile
     selbst stand halb unter der Falz.

     Der bessere Tausch: die Wiederholung streichen, nicht die Ware
     verkleinern. Die Note bleibt am Schreibtisch und steht auf dem Handy
     weiterhin an jeder Produktkarte. */
  .hero__trust { display: none; }

  /* Enger als am Schreibtisch, aus demselben Grund wie beim Schild: Auf
     700 px Bildschirmhöhe kostet jedes Polster die Zeile, in der der Knopf
     steht. Das Tippziel bleibt 44 px — verkleinert wird der Abstand, nicht
     die Fläche, die der Finger trifft. */
  .hero__wahl {
    margin-top: -2.2rem;
    margin-bottom: var(--s-3);
  }
  .hero__wahl + .hero__tag { margin-top: 0; }
}

/* Flache Fenster — iPhone SE, Landschaft, Browser mit zwei Leisten.
   Dort bleiben von 667 px Gerätehöhe rund 550 nutzbare übrig, und die
   Rechnung oben geht nicht mehr auf. Der Handschuh gibt weiter nach: Er
   ist das einzige Element im Auftakt, das kleiner werden kann, ohne dass
   eine Aussage verlorengeht. */
/* **Die Schwelle war falsch gewählt.**

   Dieser Block hieß „Flache Fenster — iPhone SE, Landschaft, Browser mit
   zwei Leisten" und sollte den Ausnahmefall abdecken. Tatsächlich greift
   `max-height: 700px` auf **jedem normalen iPhone im Hochformat**: Von
   812 px Gerätehöhe bleiben mit Safari-Leisten rund 635 übrig, beim
   iPhone 15 sind es 684.

   Damit galt dort `25svh` — auf einem iPhone 12 also 166 px Bühne. Genau
   das hat der Betreiber am 25.8.2026 gemeldet: „viel zu klein". Und es
   fiel bei keinem meiner Tests auf, weil ich auf 740 px Höhe gemessen
   habe — knapp ÜBER der Schwelle.

   Die Bühne braucht hier keine eigene Regel mehr: `calc(100svh - 400px)`
   oben rechnet flache Fenster von selbst mit. Was bleibt, sind die
   Anpassungen, die wirklich nur bei wenig Höhe nötig sind. */
@media (max-width: 1019px) and (max-height: 620px) {
  .hero__tag__body { padding: var(--s-3) var(--s-4); }
  .hero__price b { font-size: 1.75rem; }
  /* Der negative Abstand bleibt hier KLEINER als in der Regel darüber,
     nicht größer. Der transparente Rand des Freistellers ist ein Anteil
     seiner Höhe: Je kleiner die Bühne, desto weniger Rand gibt es zu
     nutzen. Mit -2.6rem lagen die Punkte auf 560 px Höhe gemessen auf der
     Manschette. Die fehlende Höhe kommt aus der Bühne, nicht von hier. */
  .hero__wahl { margin-top: -1.4rem; margin-bottom: var(--s-2); }
  /* Die Zeile „Handschuh · Bandagen · Mundschutz" wiederholt, was die
     Ankündigungsleiste über der Seite schon sagt. Auf 560 px nutzbarer
     Höhe ist sie die billigste Zeile, die zu holen ist — der Preis und die
     Ersparnis darüber bleiben unangetastet. */
  .hero__tag__foot { display: none; }
}


/* --- Bild-Bruchkante (Text überlappt Bild) ------------------------------ */
.overlap { position: relative; }
.overlap__img { position: relative; overflow: hidden; border-radius: var(--r-4); }
.overlap__img img { width: 100%; height: 100%; object-fit: cover; }
.overlap__cap {
  position: absolute;
  left: 0; bottom: 0;
  padding: var(--s-5);
  background: var(--bg);
  border-radius: 0 var(--r-3) 0 var(--r-4);
  max-width: 22rem;
}
@media (min-width: 900px) {
  .overlap__cap { left: -3rem; bottom: -2rem; padding: var(--s-6); }
}

/* Maskiertes Aufziehen beim Einscrollen ----------------------------------
   Kürzer als früher (1,15 s), und das ist keine Geschmacksfrage: Die
   Enthüllung läuft von oben nach unten über die ganze Bildhöhe. Bei einem
   850 px hohen Bild war sie langsamer als das Scrollen — die untere
   Hälfte wurde erst frei, wenn sie schon wieder aus dem Bild lief. Der
   zugehörige Auslöser liegt jetzt ebenfalls früher, siehe initReveal(). */
.reveal-img { overflow: hidden; border-radius: var(--r-4); }

/* **Das Bild füllt seinen Rahmen** (6.9.2026). Bis dahin setzte diese Regel
   nur `clip-path` und `transform` — keine Größe. Wo der Rahmen ein eigenes
   `aspect-ratio` trägt (auf `faq.html` ein Quadrat) und die Aufnahme ein
   anderes Format hat (`athlet-4.jpg` ist 1400 × 932), blieben darunter
   **162 px leere Fläche**, und `object-fit: fill` verzerrte obendrein.

   `cover` statt `fill`: Lieber beschneiden als stauchen. In `.reveal-img`
   stehen ausschließlich Trainingsaufnahmen, keine Freisteller — bei denen
   wäre `contain` richtig, und die stehen in `.pgruppe` und `.gallery`. */
.reveal-img img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  clip-path: inset(0 0 100% 0);
  transform: scale(1.06);
  transition: clip-path .72s var(--ease-out), transform .95s var(--ease-out);
}
.reveal-img.is-in img { clip-path: inset(0 0 0 0); transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal-img img { clip-path: none; transform: none; }
}

/* Dasselbe Aufziehen, ohne clip-path ---------------------------------------
   `clip-path` läuft nicht auf der Grafikeinheit. Jedes Bild der Animation
   heißt: Bild neu beschneiden, neu rastern, neu zusammensetzen — bei einer
   Aufnahme von 1400 px Breite, über 720 ms, und das ausgerechnet in dem
   Moment, in dem gescrollt wird. Am Schreibtisch fällt es nicht auf, auf dem
   Telefon ist es genau der Ruckler, den man sieht, wenn „die neuen Elemente
   erscheinen".

   Dieselbe Bewegung geht auch mit transform allein: Der Rahmen schneidet
   ohnehin ab (`overflow: hidden`), das Bild fährt von unten herein. Das
   liegt auf der Grafikeinheit und kostet im Lauf gar nichts. Sichtbar ist
   der Unterschied nur darin, dass das Bild mitwandert statt stillzustehen —
   was ihm sogar besser steht. */
@media (hover: none) {
  .reveal-img img {
    clip-path: none;
    transform: translateY(14%) scale(1.06);
    opacity: 0;
    transition:
      transform .62s var(--ease-out),
      opacity .38s var(--ease);
  }
  .reveal-img.is-in img {
    transform: none;
    opacity: 1;
  }
}

/* --- Zwei-Spalten-Erzählblock ------------------------------------------ */
.split {
  display: grid;
  gap: var(--s-7);
  align-items: center;
}
@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; gap: clamp(3rem, 6vw, 6rem); }
  .split--wide-l { grid-template-columns: 1.25fr 1fr; }
  .split--wide-r { grid-template-columns: 1fr 1.25fr; }
}
.split__body { display: flex; flex-direction: column; gap: var(--s-5); align-items: flex-start; }

/* --- Zitatblock --------------------------------------------------------- */
.quote {
  position: relative;
  padding-left: var(--s-6);
  border-left: 2px solid var(--accent);
  border-radius: var(--r-1);
}
.quote blockquote {
  font-family: var(--f-display);
  font-weight: 600;
  font-stretch: 105%;
  font-size: clamp(1.4rem, 3vw, 2.35rem);
  line-height: 1.14;
  letter-spacing: -.022em;
  text-wrap: balance;
}
.quote figcaption {
  margin-top: var(--s-4);
  font-family: var(--f-mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fg-faint);
}

/* --- Produktdetail ------------------------------------------------------ */
.pdp {
  display: grid;
  /* Einspaltig kleiner als die alten 3 rem: Zwischen Bild, Kaufbereich und
     Wegweiser sind 48 px Leerraum kein Atem, sondern eine Bildschirmhöhe,
     die sich über die Seite summiert. */
  gap: var(--s-5);
  padding-top: calc(5rem + var(--announce-h));
}
/* Der Wegweiser steht über allem. Er stand bis zum 16.8.2026 im
   Kaufbereich und damit einspaltig UNTER dem Produktbild — also erst da,
   wo die Frage „wo bin ich" längst beantwortet sein müsste. */
.pdp__crumb {
  display: flex; align-items: center; gap: .6rem;
  flex-wrap: wrap;
}
.pdp__crumb a { color: var(--fg-faint); transition: color var(--t-fast) var(--ease); }
.pdp__crumb a:hover { color: var(--accent-br); }

@media (min-width: 980px) {
  .pdp {
    grid-template-columns: minmax(0, 1.15fr) minmax(21rem, .85fr);
    /* Zeilen- und Spaltenabstand getrennt: Der Spaltenabstand trennt Bild
       und Kaufbereich, der Zeilenabstand nur den Wegweiser vom Rest — und
       der darf nicht so weit weg stehen wie zwei Spalten voneinander. */
    column-gap: clamp(2.5rem, 5vw, 5rem);
    row-gap: var(--s-5);
    align-items: start;
    padding-top: calc(7.5rem + var(--announce-h));
  }
  .pdp__crumb { grid-column: 1 / -1; }
  .pdp__info { position: sticky; top: calc(6.5rem + var(--announce-h)); }
  /* Die Breite der Galerie folgt der Fensterhöhe, nicht nur der Spalte:
     Sie ist quadratisch, also bestimmt ihre Breite, wie tief sie reicht.
     In der Spalte ausgereizt wuchs sie auf einem 786 px hohen Fenster auf
     718 px und schob die Vorschaubilder 270 px unter die Falz — den
     einzigen Hinweis darauf, dass es mehr als eine Aufnahme gibt. Mit dem
     Deckel sind es 85 px; ganz darüber zu heben hieße, das Produktbild auf
     478 px zu stauchen, und das ist der schlechtere Tausch. Ab etwa 940 px
     Fensterhöhe greift die Regel nicht mehr — dort füllt die Galerie ihre
     Spalte wie zuvor. */
  .gallery { max-width: min(100%, calc(100svh - 14rem)); }
}

.gallery { display: flex; flex-direction: column; gap: var(--s-3); }
.gallery__main {
  position: relative;
  /* Quadratisch, weil die Produktaufnahmen es sind: Der Handschuh steht
     mittig mit Luft oben und unten, und die beginnt bei 9–15 % der
     Bildhöhe. Ein 4:3-Rahmen nimmt bei object-fit:cover 16,7 % je Seite —
     das schnitt jeder Studio- und Heroaufnahme die Handschuhspitze ab.
     Die Freisteller sind ebenfalls quadratisch, die Vorschaubilder auch. */
  aspect-ratio: 1;
  /* Lichtkegel für die Freisteller; die Trainingsfotos decken ihn ohnehin ab */
  background: var(--stage);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  overflow: hidden;
}
.gallery__main img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  /* Eine halbe Sekunde war für die Antwort auf einen Fingertipp zu lang —
     das ist keine Überblendung im Film, sondern eine Bedienung. */
  transition: opacity .3s var(--ease), transform .34s var(--ease-out);
}
.gallery__main img.is-on { opacity: 1; }
/* Während der Finger zieht, folgt das Bild ohne Übergangszeit — sonst
   hinkte es der Hand um eine Drittelsekunde hinterher. */
.gallery__main img.is-zieht { transition: opacity .3s var(--ease); }
/* Freisteller werden eingepasst statt beschnitten */
.gallery__main img.is-pack { padding: 6% 6% 7%; }
.gallery__main img { cursor: zoom-in; }

/* Lupe als sichtbarer Hinweis, dass sich das Bild öffnen lässt */
.gallery__lupe {
  position: absolute;
  right: var(--s-4); bottom: var(--s-4);
  z-index: 2;
  width: 2.4rem; height: 2.4rem;
  border-radius: var(--r-voll);
  display: grid; place-items: center;
  border: 1px solid var(--line-2);
  background: var(--glass);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--fg-mute);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.gallery__lupe svg { width: 1rem; height: 1rem; }
.gallery__lupe:hover { color: var(--fg); border-color: var(--steel); }

/* --- Bildbetrachter ----------------------------------------------------- */
.lbox {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
  padding: clamp(3rem, 7vw, 4.5rem) clamp(.75rem, 3vw, 2.5rem);
  background: var(--scrim-voll);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  transition: opacity .26s var(--ease);
}
/* Pflicht, nicht Kosmetik: display aus einer Klassenregel schlägt das
   display:none des hidden-Attributs. Ohne diese Zeile liegt der Betrachter
   unsichtbar über der ganzen Seite und schluckt jeden Klick. */
.lbox[hidden] { display: none; }
.lbox:not(.is-on) { pointer-events: none; }
.lbox.is-on { opacity: 1; pointer-events: auto; }

.lbox__buehne {
  display: flex; flex-direction: column; align-items: center; gap: var(--s-4);
  min-width: 0; height: 100%;
  justify-content: center;
}
.lbox__bild {
  max-width: 100%;
  max-height: calc(100svh - 12rem);
  object-fit: contain;
  cursor: zoom-in;
  transition: transform .4s var(--ease-out);
}
.lbox__bild.is-pack { padding: 2%; }
.lbox__bild.is-zoom { transform: scale(2.2); cursor: zoom-out; }

.lbox__zeile {
  display: flex; align-items: baseline; gap: var(--s-4); flex-wrap: wrap;
  justify-content: center; text-align: center;
  font-family: var(--f-mono); font-size: .68rem;
  letter-spacing: .06em; color: var(--fg-faint);
  max-width: 60ch;
}
.lbox__zaehler { color: var(--fg-mute); font-variant-numeric: tabular-nums; }

.lbox__zu {
  position: absolute;
  top: clamp(.75rem, 2vw, 1.5rem); right: clamp(.75rem, 3vw, 2.5rem);
  width: 2.75rem; height: 2.75rem;
  border-radius: var(--r-voll);
  display: grid; place-items: center;
  border: 1px solid var(--line-2);
  color: var(--fg-mute);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.lbox__zu svg { width: 1.1rem; height: 1.1rem; }
.lbox__zu:hover { color: var(--fg); border-color: var(--contrast); }

.lbox__nav {
  width: clamp(2.5rem, 5vw, 3.5rem);
  height: clamp(2.5rem, 5vw, 3.5rem);
  display: grid; place-items: center;
  border: 1px solid var(--line-2);
  color: var(--fg-mute);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.lbox__nav svg { width: 1.3rem; height: 1.3rem; }
.lbox__nav:hover { color: var(--fg); border-color: var(--contrast); }
@media (prefers-reduced-motion: reduce) {
  .lbox, .lbox__bild { transition: none; }
}
.gallery__thumbs { display: grid; grid-template-columns: repeat(auto-fit, minmax(4.5rem, 1fr)); gap: var(--s-3); }
/* Auf dem Telefon blättert man mit dem Daumen, nicht mit den kleinen
   Bildern darunter. Sie bleiben als Übersicht — wie viele Aufnahmen gibt
   es, wo stehe ich —, aber sie brauchen dafür keine 80 px Höhe: Das ist
   ein Achtel des Bildschirms für eine Nebenrolle, und es steht genau
   zwischen dem Produktbild und seinem Preis. */
@media (max-width: 979px) {
  .gallery__thumbs {
    grid-template-columns: repeat(auto-fit, 3.4rem);
    justify-content: center;
    gap: var(--s-2);
  }
}
.gallery__thumb {
  position: relative;
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  overflow: hidden;
  background: var(--stage);
  transition: border-color var(--t-med) var(--ease);
}
.gallery__thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease-out); }
.gallery__thumb img.is-pack { padding: 9%; }
@media (hover: hover) and (pointer: fine) {
  .gallery__thumb:hover img { transform: scale(1.07); }
}
.gallery__thumb[aria-current='true'] { border-color: var(--accent-br); }

.pdp__head { display: flex; flex-direction: column; gap: var(--s-3); }
.pdp__title {
  font-size: clamp(2rem, 3.8vw, 3.1rem);
  font-weight: 800;
  font-stretch: 112%;
  letter-spacing: -.028em;
}
.pdp__rating { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.pdp__rating span { font-family: var(--f-mono); font-size: .7rem; letter-spacing: .1em; color: var(--fg-mute); }

.pdp__price {
  display: flex; align-items: baseline; gap: var(--s-3);
  flex-wrap: wrap;
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  margin-block: var(--s-5);
}
/* Der Preis bleibt in einer Zeile, auch wenn der Zusatz daneben umbricht */
.pdp__price b {
  font-family: var(--f-preis);
  font-size: 1.85rem; font-weight: 600; letter-spacing: -.02em;
  white-space: nowrap; flex-shrink: 0;
}
.pdp__price small {
  font-size: .68rem; letter-spacing: .08em; color: var(--fg-faint);
  line-height: 1.5;
}
.pdp__price s { color: var(--fg-faint); }

.opt { display: flex; flex-direction: column; gap: var(--s-3); margin-bottom: var(--s-5); }
.opt__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4); }
.opt__val { font-family: var(--f-mono); font-size: .72rem; letter-spacing: .08em; color: var(--fg); }
.opt__list { display: flex; flex-wrap: wrap; gap: .5rem; }

.chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .6rem .85rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  font-family: var(--f-mono);
  font-size: .74rem;
  letter-spacing: .06em;
  color: var(--fg-mute);
  line-height: 1;
  transition:
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform .12s var(--ease-out);
}
.chip:hover { border-color: var(--steel); color: var(--fg); }
.chip:active { transform: scale(.96); }
.chip[aria-pressed='true'],
.chip[aria-current='page'] { border-color: var(--contrast); color: var(--fg); }
.chip[aria-pressed='true']::after,
.chip[aria-current='page']::after {
  content: ''; position: absolute; inset: -1px;
  border: 1px solid var(--contrast); border-radius: var(--r-2);
  pointer-events: none;
}
.chip.is-out { opacity: .34; cursor: not-allowed; }
.chip.is-out::before {
  content: ''; position: absolute; left: .3rem; right: .3rem; top: 50%;
  height: 1px; background: currentColor;
}

/* --- Mengenwähler --------------------------------------------------------
   Er stand bis zum 16.8.2026 über die volle Breite des Kaufbereichs
   gezogen — rund 340 px für eine Zahl zwischen 1 und 9. Der Grund war
   nicht die Breite selbst, sondern `inline-flex` in einem Spalten-Flex:
   Ohne eigene Ausrichtung streckt der Container jedes Kind auf seine
   Breite, und `inline` hilft dagegen nicht.

   Jetzt so groß wie sein Inhalt, und als Pille statt als Kasten. Das ist
   keine Laune: Ein Stepper ist kein Eingabefeld, sondern ein Bedienelement
   mit zwei Enden — die runde Form sagt das, ohne es zu beschriften, und sie
   trennt ihn von den eckigen Chips darüber, die eine Auswahl sind. */
.qty {
  display: inline-flex;
  align-self: flex-start;
  align-items: stretch;
  border: 1px solid var(--line-2);
  border-radius: var(--r-voll);
  overflow: hidden;
  background: var(--surface);
}
.qty button {
  width: 2.5rem; height: 2.5rem;
  display: grid; place-items: center;
  font-size: 1.05rem; line-height: 1;
  color: var(--fg-mute);
  transition: color var(--t-fast) var(--ease), background var(--t-fast) var(--ease), transform .12s var(--ease-out);
}
.qty button:hover { color: var(--fg); background: var(--line); }
.qty button:active { transform: scale(.88); }
.qty input {
  width: 2.4rem; text-align: center; background: transparent; border: 0;
  font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-size: .92rem;
  -moz-appearance: textfield;
}

/* Menge und Beschriftung in eine Zeile. Über dem Wähler stand „MENGE" als
   eigene Zeile, während „Ausführung" und „Gewicht" darüber ihre Angabe
   längst rechts daneben tragen — dieselbe Sache, zwei Anordnungen. */
.opt:has(.qty) {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
}
.qty input::-webkit-outer-spin-button, .qty input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.pdp__buy { display: flex; gap: var(--s-3); align-items: stretch; margin-bottom: var(--s-5); flex-wrap: wrap; }
.pdp__buy .btn { flex: 1 1 12rem; }

.pdp__notes { display: flex; flex-direction: column; gap: var(--s-3); margin-block: var(--s-5); }
.pdp__note { display: flex; align-items: center; gap: .7rem; font-size: .85rem; color: var(--fg-mute); }
.pdp__note svg { width: 1rem; height: 1rem; color: var(--accent-br); flex-shrink: 0; stroke-width: 1.6; }

/* --- Paketseite ---------------------------------------------------------
   Die Bühne trägt die Paketgruppe: alle drei Teile arrangiert, nicht der
   Handschuh mit zwei Anhängseln darunter. Der Baustein steht in
   components.css, weil er auch den Auftakt der Startseite trägt. */
.paket__bild {
  position: relative;
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--stage);
  /* Der Bezug für die Größenabfrage der Zeichen in der Gruppe */
  container-type: inline-size;
}
.paket__bild .pgruppe {
  width: min(100%, 82%);
  /* Das Bild ist 4:3, die Gruppe quadratisch — sie richtet sich nach der
     knapperen Seite, sonst ragt sie oben und unten heraus. */
  max-height: 92%;
  aspect-ratio: 1;
}
.paket__bild img { transition: opacity var(--t-med) var(--ease); }

/* --- Größenberater ------------------------------------------------------ */
.sizer {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  padding: clamp(1.5rem, 4vw, 3rem);
}
.sizer__stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(13rem, 30vw, 20rem);
  margin-bottom: var(--s-6);
}
/* Lichtkegel auf der Bühne: der freigestellte Handschuh steht darin wie
   auf dem Fototisch, statt als Kachel auf dem Kasten zu liegen. */
.sizer__stage::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 46% 44% at 50% 48%, var(--spot), transparent 72%);
  pointer-events: none;
}
.sizer__glove {
  position: relative;
  width: clamp(8.5rem, 22vw, 14rem);
  transition: transform .55s var(--ease-out);
  transform: scale(var(--glove-scale, 1));
}
/* **Der Ring misst sich an seiner Bühne, nicht am Fenster.**

   `clamp(14rem, 38vw, 24rem)` band ihn an die Fensterbreite: Auf 1440 px
   waren das 384 px — in einer Bühne von 294 px. Der gestrichelte Kreis
   schnitt dadurch über beide Kanten der Ergebniskarte hinaus, und auf den
   Screenshots vom 7.9.2026 sah die Karte aus, als liefe etwas über.

   **Die Deckelung muss die Skalierung einrechnen.** Ein erster Anlauf mit
   `118%` reichte nicht: `transform: scale(var(--ring-scale))` vergrößert
   den Ring zusätzlich, und zwar bis **1,22** — `shop.js` setzt
   `1 + i * 0.11`, bei 16 OZ ist i = 2. Aus 384 px berechneter Breite wurden
   damit 426 px gerenderte, und der Kreis stand wieder 13 px über beiden
   Kartenkanten.

`88%` der Bühne mal 1,22 bleibt in **jeder** Lage innerhalb der Karte.
   Durchgerechnet für Kartenbreiten von 360 bis 400 px und Polster von 20
   bis 36 px: 92 % reißt bei schmalem Polster aus (404 px in einer 400er
   Karte), 88 % hält überall mit mindestens 14 px Luft. Der Überstand über
   die **Bühne** bleibt erhalten — er ist gewollt, der Ring soll den
   Handschuh (max. 264 px) umfassen, nicht in ihm sitzen.

   **Nicht am gerenderten Rechteck nachmessen.** `transform` läuft hier über
   eine Transition, und die steht im Hintergrundfenster still: Chrome
   liefert dann den eingefrorenen Zwischenwert, meist `matrix(1)`. Am
   7.9.2026 hat das eine halbe Stunde Fehlersuche gekostet — der Ring
   skalierte einwandfrei, nur der Messwert war eingefroren. Geprüft wird
   deshalb die **berechnete** Breite mal der größten Stufe (`1 + 2 × 0.11`),
   nicht das, was gerade auf dem Schirm steht. */
.sizer__ring {
  position: absolute;
  width: min(clamp(14rem, 38vw, 24rem), 88%);
  aspect-ratio: 1;
  border: 1px dashed var(--line-2);
  border-radius: 50%;
  transform: scale(var(--ring-scale, 1));
  transition: transform .55s var(--ease-out);
}
/* --- Fragen des Beraters ------------------------------------------------ */
.sizer__form {
  display: flex;
  flex-direction: column;
  gap: var(--s-6);
  width: 100%;
  counter-reset: frage;
}
.frage { display: flex; flex-direction: column; gap: var(--s-3); }
.frage__kopf {
  display: flex; align-items: baseline; gap: .7rem;
  font-family: var(--f-display); font-weight: 600; font-stretch: 105%;
  font-size: 1.12rem; letter-spacing: -.01em;
}
.frage__nr::before {
  counter-increment: frage;
  content: counter(frage, decimal-leading-zero);
  font-family: var(--f-mono); font-size: .68rem; font-weight: 400;
  letter-spacing: .1em; color: var(--accent-br);
}
.frage__wahl { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: .5rem; }
.wahl {
  display: flex; flex-direction: column; gap: .25rem;
  padding: .8rem .9rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  text-align: left;
  transition:
    border-color var(--t-fast) var(--ease),
    background var(--t-fast) var(--ease),
    transform .12s var(--ease-out);
}
.wahl b { font-size: .88rem; font-weight: 500; line-height: 1.25; }
.wahl span {
  font-family: var(--f-mono); font-size: .62rem;
  letter-spacing: .05em; color: var(--fg-faint); line-height: 1.35;
}
.wahl:hover { border-color: var(--steel); }
.wahl:active { transform: scale(.985); }
.wahl[aria-pressed='true'] { border-color: var(--contrast); background: var(--line); }
.wahl[aria-pressed='true'] b { color: var(--fg); }
/* Die Beschriftung steigt eine Ebene mit.
   --line ist die Linienfarbe, hier aber die Fläche der gewählten Antwort —
   und darauf reicht --fg-faint nicht mehr: 3,96 in Hell, 4,26 in Dunkel,
   verlangt sind 4,5. Ausgerechnet die GEWÄHLTE Antwort war damit schlechter
   zu lesen als die daneben. --fg-mute kommt auf 5,79 beziehungsweise 5,62.
   Dass es auffällt, ist Zufall gewesen: Der Selbsttest maß --fg-faint gegen
   --bg und --surface, also gegen die Farben, die als Grund GEDACHT sind.
   Er prüft jetzt jede Farbe, die tatsächlich als Fläche vorkommt. */
.wahl[aria-pressed='true'] span { color: var(--fg-mute); }

/* --- Ergebnis ----------------------------------------------------------- */
.sizer__oz {
  display: flex; align-items: baseline; gap: .5rem;
  font-family: var(--f-display); font-weight: 800; font-stretch: 115%;
  font-size: clamp(3rem, 7vw, 4.6rem); line-height: .9;
  letter-spacing: -.03em;
  margin-block: var(--s-3) var(--s-4);
}
.sizer__oz span { font-size: .3em; letter-spacing: .06em; color: var(--fg-mute); }
/* Die Grundlage der Empfehlung — eine Zeile, kein Datenblatt.
   Löst `.sizer__weg` ab (die vier `spec__row`-Blöcke), siehe die
   Begründung in `shop.js`. */
.sizer__basis {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line);
  font-family: var(--f-mono);
  font-size: .72rem;
  letter-spacing: .04em;
  color: var(--fg-mute);
}
/* Eine Anpassung, die das Ergebnis verschoben hat, steht direkt darunter
   und braucht keinen zweiten Strich. */
.sizer__basis--plus { border-top: 0; padding-top: 0; margin-top: var(--s-2); }
.sizer__basis--plus b { color: var(--fg); font-weight: 500; }
.sizer__weg { margin-top: var(--s-5); }
.sizer__vorbehalt { margin-top: var(--s-5); }

/* --- Kaufbereich des Beraters ------------------------------------------- */
.sizer__kauf {
  margin-top: var(--s-6);
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
}
.sizer__kauf .opt { margin-bottom: var(--s-4); }
.sizer__kauf-zeile {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
}
.sizer__kauf-info { display: flex; flex-direction: column; gap: .3rem; }
.sizer__kauf-info b {
  font-family: var(--f-preis); font-size: 1.35rem; font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -.02em;
}
.sizer__kauf-info .label { text-transform: none; letter-spacing: .05em; }
input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 3px;
  border-radius: var(--r-voll);
  background: var(--line-2);
  /* `outline: 0` stand hier ohne Ersatz — der Regler ließ sich mit den
     Pfeiltasten bedienen, zeigte aber nicht, dass er dran war. Er ist die
     einzige Stelle der Website, an der ein Bedienelement den Fokus
     verschluckte. Der Ring kommt jetzt am Element selbst, mit Abstand,
     damit er nicht in der 3 px schmalen Bahn verschwindet. */
  outline: 0;
}
input[type='range']:focus-visible {
  outline: 2px solid var(--accent-br);
  outline-offset: 6px;
  border-radius: var(--r-voll);
}
input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 1.15rem; height: 1.15rem;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--surface);
  cursor: pointer;
  transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  input[type='range']::-webkit-slider-thumb:hover { transform: scale(1.22); }
}
/* Derselbe Griff wie in Chrome — er stand auf `border-radius: 0` und war
   damit in Firefox ein Quadrat, wo er überall sonst ein Kreis ist. */
input[type='range']::-moz-range-thumb {
  width: 1.15rem; height: 1.15rem; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--surface); cursor: pointer;
}
.sizer__out { margin-top: var(--s-6); padding-top: var(--s-5); border-top: 1px solid var(--line); }
.sizer__out h3 { font-size: 1.35rem; margin-bottom: var(--s-3); }

/* --- Seitenkopf für Unterseiten ---------------------------------------- */
.phead {
  position: relative;
  padding-top: calc(clamp(7rem, 14vw, 10.5rem) + var(--announce-h));
  padding-bottom: clamp(2.5rem, 6vw, 4.5rem);
}
/* Unter dem Seitenkopf stand bis zum 1.10.2026 ebenfalls ein Seil — auf
   jeder Unterseite dasselbe. Entfallen mit allen übrigen Trennseilen
   (components.css, „Das Seil, nicht mehr als Trenner"). */

/* --- Zwei Seile hintereinander sind eine Trennung zu viel ---------------
   **Behoben am 6.9.2026**, nachdem der Betreiber es auf der Athletenseite
   gesehen hat: *„zwei Striche und zwei Überschriften übereinandergestapelt
   und auch richtig kacke gemacht."*

   Er hat recht, und es betraf **alle zwölf Unterseiten mit Seitenkopf**:
   `.phead::after` schließt den Kopf mit einem Seil ab, und der erste
   Abschnitt darunter beginnt mit demselben Seil. Dazwischen lagen 64 px
   tote Fläche — zwei identische Linien, die nichts Verschiedenes trennen.

   Der Seitenkopf behält seines: Er markiert, wo der Inhalt beginnt. Der
   erste Abschnittskopf verliert es und behält nur den Abstand — sein Label
   („Das Rudel", „Im Einsatz") kennzeichnet ihn ohnehin.

   `.phead + section` statt `:has()`: derselbe Treffer, aber ohne Abhängigkeit
   von einer neueren Auswahlfunktion. Der Kombinator `+` überspringt
   Kommentare und Leerraum, nur Elemente zählen. */
.phead + section .sec-head,
.phead + div .sec-head {
  background-image: none;
  padding-top: var(--s-5);
}
.phead__inner { display: flex; flex-direction: column; gap: var(--s-4); align-items: flex-start; }
.phead__crumb { display: flex; align-items: center; gap: .6rem; }
.phead__crumb a { color: var(--fg-faint); transition: color var(--t-fast) var(--ease); }
.phead__crumb a:hover { color: var(--accent-br); }

/* --- Karte mit Bild oben (Story / Werte) ------------------------------- */
.tile {
  display: flex; flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
  overflow: hidden;
}
.tile__media { aspect-ratio: 4/3; overflow: hidden; background: var(--line); }
/* Hochformat für die Athletenaufnahmen: Die Serie ist in 9:16 aufgenommen,
   und ein 4:3-Zuschnitt nähme ihr 58 % der Höhe — also Kopf oder
   Handschuhe. 4:5 ist dasselbe Format wie die Porträts darüber; die Seite
   bleibt damit in einer Bildsprache statt in zwei. */
.tile__media--hoch { aspect-ratio: 4/5; }
.tile__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .9s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .tile:hover .tile__media img { transform: scale(1.05); }
}
.tile__body { padding: var(--s-5); display: flex; flex-direction: column; gap: var(--s-3); flex: 1; }
/* --- Nachwuchs: der Gym-Block ------------------------------------------
   Nur Abstände. Der Block bringt keinen eigenen Rahmen und keine eigene
   Fläche mit: Er steht innerhalb von `#nachwuchs` und wäre als Karte in
   einer Karte gelesen worden. Die Trennung nach oben leistet der Abstand,
   nicht eine zweite Linie — die `.posten`-Liste darüber trägt bereits eine
   `border-top`, und zwei Striche in Folge waren am 6.9.2026 schon einmal
   der Befund („doppelte Trennlinie"). */
.nw-gym { margin-top: var(--s-7); display: flex; flex-direction: column; gap: var(--s-6); }

/* Der Aufmacher: quer über die volle Breite des Blocks. `reveal-img`
   bringt Rundung und Einblendung mit, die Höhe steht als Verhältnis fest,
   damit beim Laden nichts springt. */
.nw-auf { margin: 0; aspect-ratio: 2/1; }
.nw-auf img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Solange die Aufnahme fehlt, dieselbe gestrichelte Fläche wie bei den
   Kacheln — ein Platzhalter sieht auf dieser Seite überall gleich aus. */
.nw-auf--leer {
  background: color-mix(in srgb, var(--warn) 5%, var(--surface));
  border: 1px dashed color-mix(in srgb, var(--warn) 62%, transparent);
  border-radius: var(--r-3);
  display: grid;
  place-items: center;
}
.nw-auf .ath__leerbild-marke { width: 3.2rem; height: auto; object-fit: contain; }
/* **Das Verhältnis bleibt auf jeder Breite 2:1.** Naheliegend wäre, das
   Bild auf dem Gerät hochkanter zu stellen, damit die Gesichter größer
   werden — aber `object-fit: cover` schneidet dann seitlich, und seitlich
   sitzen die Jugendlichen am Rand der Reihe. Lieber alle fünf klein als
   drei groß. */
.nw-gym__text { max-width: 46rem; }
.nw-gym .hinweis { margin-top: 0; }

/* Die noch leere Kachel. Derselbe gestrichelte Rahmen wie bei den
   Athletenkarten (`.ath__media--leer`), damit ein Platzhalter auf
   dieser Seite überall gleich aussieht. Er sitzt an der Fläche, nicht in
   der Zeichnung: Zwei gestrichelte Rechtecke ineinander sähen aus wie ein
   Fehler beim Zusammenbauen. */
.tile--leer .tile__media {
  background: color-mix(in srgb, var(--warn) 5%, var(--surface));
  border: 1px dashed color-mix(in srgb, var(--warn) 62%, transparent);
  border-radius: var(--r-2);
  /* `place-items` statt `height: 100%` am Platzhalter: Die Kachel bekommt
     ihre Höhe aus `aspect-ratio`, nicht aus einem gesetzten Wert, und eine
     Prozenthöhe hat darin nichts, worauf sie sich beziehen könnte. Der
     Kopf klebte deshalb oben. */
  display: grid;
  place-items: center;
}
/* **Zwei Klassen, nicht eine.** `.tile__media img` setzt `width: 100%` und
   `object-fit: cover`, weil dort sonst ein Foto steht. Der Schakalkopf des
   Platzhalters ist aber kein Foto, sondern ein Zeichen von 3,2 rem, und
   `.ath__leerbild-marke` allein (eine Klasse) verliert gegen `.tile__media
   img` (Klasse plus Element). Beim ersten Bau stand er deshalb
   formatfüllend in der Kachel. */
.tile__media .ath__leerbild-marke {
  width: 3.2rem;
  height: auto;
  object-fit: contain;
  transition: none;
}

/* Wer auf der Aufnahme zu sehen ist. Steht unten und leiser als der Titel:
   Die Kachel zeigt eine Situation, der Name ordnet sie zu. In derselben
   Größe gesetzt konkurrierten beide. */
.tile__wer {
  margin-top: auto;
  font-family: var(--f-mono);
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-br);
}

/* --- Kontaktangaben ----------------------------------------------------- */
.contact-list { display: flex; flex-direction: column; gap: var(--s-5); }
.contact-item { display: flex; flex-direction: column; gap: .35rem; }
.contact-item a { color: var(--fg); transition: color var(--t-fast) var(--ease); }
.contact-item a:hover { color: var(--accent-br); }
.contact-item p { color: var(--fg-mute); }

/* --- Tabelle (Größen) --------------------------------------------------- */
/* Eine Tabelle mit fünf Spalten passt auf 390 px nicht, und sie zu
   stauchen hilft niemandem — Zahlen, die man nicht lesen kann, sind keine
   Angabe mehr. Sie scrollt also seitlich. Nur sieht eine abgeschnittene
   Tabelle ohne Hinweis nach Fehler aus, nicht nach „hier geht es weiter":
   Der Verlauf an der rechten Kante sagt es, ohne ein Wort zu brauchen, und
   er verschwindet von selbst, sobald man am Ende angekommen ist.

   `mask-image` statt eines aufgelegten Verlaufs: Die Tabelle steht auf
   dem Seitengrund, und eine Fläche in --bg darüber wäre in jeder zweiten
   Fassung die falsche Farbe. Eine Maske kennt keine Farbe. */
.tbl-wrap {
  overflow-x: auto;
  border-radius: var(--r-2);
  scrollbar-width: thin;
}
@media (max-width: 720px) {
  .tbl-wrap {
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
            mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
  }
  /* Am Ende der Bahn gibt es nichts mehr anzudeuten. `animation-timeline`
     kennt nicht jeder Browser — wo es fehlt, bleibt der Verlauf stehen,
     und das ist der harmlosere der beiden Fälle. */
  @supports (animation-timeline: scroll(self inline)) {
    .tbl-wrap {
      animation: tblRand linear both;
      animation-timeline: scroll(self inline);
    }
    @keyframes tblRand {
      to {
        -webkit-mask-image: linear-gradient(90deg, #000 100%, transparent);
                mask-image: linear-gradient(90deg, #000 100%, transparent);
      }
    }
  }
}
table.tbl { width: 100%; border-collapse: collapse; min-width: 34rem; }
table.tbl th, table.tbl td {
  text-align: left;
  padding: var(--s-4) var(--s-4) var(--s-4) 0;
  border-bottom: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
table.tbl th {
  font-family: var(--f-mono); font-size: .68rem; font-weight: 500;
  letter-spacing: .13em; text-transform: uppercase; color: var(--fg-faint);
}
table.tbl td { color: var(--fg-mute); font-size: .95rem; }
table.tbl td:first-child { color: var(--fg); font-family: var(--f-mono); }
table.tbl tr.is-hi td { color: var(--fg); background: color-mix(in srgb, var(--accent) 9%, transparent); }

/* --- Anmelde-/Konto-Formular ------------------------------------------- */
.authbox {
  max-width: 26rem;
  border: 1px solid var(--line);
  background: var(--surface);
  padding: clamp(1.5rem, 4vw, 2.5rem);
  display: flex; flex-direction: column; gap: var(--s-5);
}
.authbox__tabs { display: flex; border-bottom: 1px solid var(--line); }
.authbox__tab {
  flex: 1;
  padding-block: var(--s-3);
  font-family: var(--f-mono); font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--fg-faint);
  border-bottom: 1px solid transparent;
  margin-bottom: -1px;
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.authbox__tab[aria-selected='true'] { color: var(--fg); border-bottom-color: var(--accent); }

/* --- Soziale Netzwerke (Startseite) -------------------------------------
   Links die beiden Konten, rechts die Beiträge. Das iframe entsteht erst
   nach einem Klick — solange steht dort eine eigene Kachel, siehe
   renderSocial() in app.js. */
/* **Eine Anordnung, keine zwei.**

   Bis zum 26.8.2026 stand hier ab 900 px ein zweispaltiges Raster: links
   die beiden Konten in einer festen 21-rem-Spalte, rechts die Beiträge.
   Gemessen kostete das die Beiträge genau diese 336 px plus Fuge — und
   weil sie zu dritt nebeneinander stehen, ein Drittel davon je Kachel:

   | Fenster | Kachel |
   |---|---|
   | 899 px (einspaltig) | 260 px |
   | **900 px (zweispaltig)** | **136 px** |
   | 1100 px | 195 px |
   | 1280 px | 247 px |

   Zwischen 900 und rund 1250 px waren die Kacheln damit **schmaler als
   auf dem Telefon** (dort 234–272 px) — ein größeres Fenster zeigte
   kleinere Bilder. Bei 136 px Breite ist ein Reel 242 px hoch, und der
   Titel darunter bricht mitten im Wort.

   Die Grenze zu verschieben hilft nicht: Die zweite Anordnung ist immer
   um dieselben 129 px je Kachel schmaler, der Sprung wandert nur mit.
   Aufgelöst wird er, indem es die zweite Anordnung nicht mehr gibt —
   die Beiträge stehen überall über die volle Breite, die Konten darunter.

   Das ist zugleich dieselbe Ordnung wie auf dem Telefon: erst zeigen,
   dann verlinken.

   **Der Block wird dabei höher, nicht niedriger** — die Konten stehen
   jetzt unter den Beiträgen statt daneben, und breitere Kacheln sind im
   Reel-Format auch höhere. Nachgemessen auf 1280 px: **1816 statt 1539 px**,
   also 277 px oder ein Drittel Bildschirm mehr. (Zusammensetzung: Kopf 302,
   zwei Reihen Kacheln 1186, Konten 120.)

   Das ist der Preis, und er ist genannt. Der Gegenwert: Die Kachel misst
   dort 283 statt 247 px, und zwischen 900 und 1250 px, wo sie vorher
   136–195 px maß, jetzt 260–283 — also mehr als das Doppelte.

   Wem der Zuwachs zu teuer ist, senkt `max-width` an `.social__posts`;
   der Selbsttest prüft nur, **dass** eine Schranke dasteht, nicht welche. */
.social { display: grid; gap: var(--s-6); }
.social__konten { display: flex; flex-direction: column; gap: var(--s-3); }
/* Zwei kleine Verweise nebeneinander, sobald Platz ist — untereinander
   wären sie am Schreibtisch eine Spalte aus zwei Zeilen auf voller
   Seitenbreite. */
@media (min-width: 620px) {
  .social__konten {
    flex-direction: row;
    gap: var(--s-4);
  }
  .social__konten > * { flex: 1 1 0; }
}

.social-konto {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--s-4);
  row-gap: .55rem;
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.social-konto:hover { border-color: var(--accent); background: var(--line); }
/* Dieselbe Rechnung wie bei der gewählten Antwort: Auf --line trägt die
   leiseste Textebene nicht mehr. */
.social-konto:hover .label,
.social-konto:hover .social-konto__was { color: var(--fg-mute); }
.social-konto__mark {
  display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  color: var(--accent-br);
}
.social-konto__mark svg { width: 1.15rem; height: 1.15rem; }
.social-konto__txt { display: flex; flex-direction: column; gap: .2rem; }
.social-konto__txt b { font-size: 1rem; font-weight: 500; line-height: 1.2; }
.social-konto > svg {
  width: .9rem; height: .9rem; color: var(--fg-faint);
  transition: transform var(--t-med) var(--ease-out), color var(--t-fast) var(--ease);
}
.social-konto:hover > svg { color: var(--accent-br); }
@media (hover: hover) and (pointer: fine) {
  .social-konto:hover > svg { transform: translateX(.25rem); }
}
.social-konto__was {
  grid-column: 1 / -1;
  font-family: var(--f-mono); font-size: .66rem; letter-spacing: .05em;
  color: var(--fg-faint); line-height: 1.45;
}

/* --- Ein Streifen zum Wischen, auf jeder Breite ------------------------

   Sechs Reels im Format 9:16 sind viel Fläche, und untereinander gestapelt
   werden es schnell zu viel. Gemessen auf 1280 px, bevor dieser Streifen
   überall galt:

   | Abschnitt | Höhe |
   |---|---|
   | **Social** (zwei Reihen à drei) | **1816 px — der größte der Seite** |
   | Ring | 1720 px |
   | Anatomie | 1532 px |
   | **Sortiment** (die Ware) | **953 px** |

   Die Videos nahmen damit fast doppelt so viel Raum wie die Produkte —
   auf einer Startseite, die seit dem 25.8.2026 ausdrücklich als Shop
   wirken soll. Auf dem Telefon war es dasselbe Bild: 1948 px, drei
   Reihen, jede Kachel 167 px breit.

   Der Streifen löst drei Dinge auf einmal:

   - **Eine Reihe statt zwei oder drei.** Der Block fällt auf rund 1050 px
     und ist damit kleiner als der Ring und in der Größenordnung des
     Sortiments.
   - **Die Kachel wird breiter**, weil sie sich die Zeile nicht mehr mit
     zwei anderen teilen muss.
   - **Kein Sprung zwischen zwei Anordnungen.** Vorher stand ab 900 px ein
     zweispaltiges Raster mit fester 21-rem-Kontenspalte; die nahm den
     Beiträgen 336 px, und ein Drittel davon je Kachel. Zwischen 900 und
     1250 px waren sie mit 136–195 px **schmaler als auf dem Telefon**.
     Die Grenze zu verschieben half nicht — die zweite Anordnung ist immer
     um dieselben 129 px je Kachel schmaler, der Sprung wandert nur mit.

   Wischen ist außerdem die Geste, die man von diesen Diensten kennt;
   niemand scrollt einen Feed senkrecht durch Kacheln. Am Schreibtisch
   tragen zwei Pfeilknöpfe die Bedienung — ein Wischbereich, den man mit
   der Maus nicht bedienen kann, ist für die Hälfte der Besucher keiner.

   Der Streifen bricht über den Gutter hinaus und schneidet rechts an: der
   Hinweis „hier geht es weiter", den ein Wischbereich braucht.

   `scroll-snap-type` ist hier unbedenklich — es sitzt an DIESEM Container,
   nicht am Dokument. Die Warnung vom 16.8.2026 galt dem Dokument, wo es
   für die ganze Seite gegolten hätte. */
.social__posts {
  display: flex;
  overflow-x: auto;
  /* **Pflicht, nicht Kosmetik.** `overflow-x: auto` allein macht die
     senkrechte Achse implizit MIT scrollbar: Sobald eine Achse nicht
     `visible` ist, wird die andere von `visible` zu `auto`. Damit hatte der
     Streifen einen eigenen senkrechten Scrollbereich — und weil die
     Kachelhöhe fraktional ist (gemessen 562,14 px), bleibt zwischen
     `clientHeight` und `scrollHeight` immer ein Pixel übrig.

     Die Folge war der Fehler, den der Betreiber am 26.8.2026 gemeldet hat:
     Zeiger über einer Kachel, und das Mausrad bewegte die Seite nicht mehr
     — es fiel in diesen einen Pixel. Gemessen war der Streifen 14 px
     scrollbar, während die Kacheln einblendeten, und danach einen.

     Mit `hidden` ist die Achse nicht mehr scrollbar, und das Rad geht wieder
     an die Seite. Geklippt wird dabei nichts: Der Startknopf klippt sein
     eigenes Bild, und die Kacheln blenden ohne senkrechten Weg auf (siehe
     AUTO_REVEAL_RUHIG in motion.js). */
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  gap: var(--s-4);
  margin-inline: calc(-1 * var(--gutter));
  padding-inline: var(--gutter);
  /* Ohne diese Zeile rastet `scroll-snap-align: start` an der Kante des
     Scrollports ein — also HINTER dem Polster. Gemessen stand der Streifen
     beim Laden deshalb auf `scrollLeft: 51`: Die erste Kachel klebte am
     Bildschirmrand statt im Textraster zu stehen, und der Zurück-Knopf war
     von Anfang an aktiv, obwohl es dort nur Polster zu sehen gibt. */
  scroll-padding-inline: var(--gutter);
  /* Die Leiste selbst stört im Bild — gewischt wird mit Daumen oder Knopf. */
  scrollbar-width: none;
}
.social__posts::-webkit-scrollbar { display: none; }
.social-post {
  flex: 0 0 min(70%, 17rem);
  scroll-snap-align: start;
}

/* Die beiden Knöpfe stehen unter dem Streifen, nicht über den Bildern:
   Auf einer Kachel verdecken sie das, was sie zeigen sollen, und auf dem
   Telefon wären sie ein Tippziel im Weg der Wischgeste.

   Sie erscheinen nur, wo gewischt werden muss UND wo ein Zeiger da ist —
   auf Touch ist die Geste selbstverständlich und zwei Knöpfe wären
   Beiwerk. `[hidden]` muss dabei ausdrücklich stehen: Die UA-Regel dafür
   hat geringere Spezifität als das `display: flex` darunter und würde
   verlieren. */
.social__blaettern { display: none; }
@media (hover: hover) and (min-width: 620px) {
  .social__blaettern { display: flex; gap: .5rem; justify-content: flex-end; }
}
.social__blaettern[hidden] { display: none; }
.social__pfeil {
  display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-voll);
  background: var(--surface);
  color: var(--fg-mute);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              opacity var(--t-fast) var(--ease);
}
.social__pfeil:hover:not(:disabled) { border-color: var(--accent); color: var(--fg); }
/* Am Ende angekommen: sichtbar, aber erkennbar ohne Ziel. Ausblenden
   würde die Zeile bei jedem Wisch springen lassen. */
.social__pfeil:disabled { opacity: .35; cursor: default; }
.social__pfeil svg { width: 1.1rem; height: 1.1rem; }
.social__pfeil--zurueck svg { transform: rotate(180deg); }

.social-post { display: flex; flex-direction: column; gap: .6rem; }
.social-post__start {
  position: relative;
  display: grid; place-items: center;
  width: 100%;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  color: var(--fg-mute);
  transition: border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
button.social-post__start { cursor: pointer; }
button.social-post__start:hover { border-color: var(--accent); color: var(--fg); }
.social-post__start img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .55;
  transition: opacity var(--t-med) var(--ease), transform var(--t-slow) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  button.social-post__start:hover img { opacity: .72; transform: scale(1.04); }
}
.social-post__play { position: relative; width: 2.6rem; height: 2.6rem; }
.social-post__play svg { width: 100%; height: 100%; stroke-width: 1.1; }
.social-post__netz {
  position: absolute; left: .5rem; top: .5rem;
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .25rem .5rem;
  border-radius: var(--r-voll);
  background: var(--glass);
  font-family: var(--f-mono); font-size: .58rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute);
}
.social-post__netz svg { width: .72rem; height: .72rem; }
.social-post iframe {
  width: 100%;
  aspect-ratio: 9 / 16;
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
}
.social-post figcaption { display: flex; flex-direction: column; gap: .3rem; }
.social-post figcaption b { font-size: .85rem; font-weight: 500; line-height: 1.3; }
.social-post figcaption span {
  font-family: var(--f-mono); font-size: .6rem; letter-spacing: .04em;
  color: var(--fg-faint); line-height: 1.45;
}
.social-post.is-live figcaption span { color: var(--fg-mute); }

/* --- Die Beiträge, 26.8.2026 -------------------------------------------
   Sechs Instagram-Posts, vier davon mit Standbild. */

/* Die Zeile über dem Titel — im Video steht sie dort auch. Sie gehört
   nicht in dieselbe Ebene wie der Datenschutzhinweis darunter, obwohl
   beide `span` sind: Der Claim ist Inhalt, der Hinweis eine Auskunft. */
.social-post__claim {
  font-family: var(--f-mono);
  font-size: .58rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent-br);
}
.social-post figcaption .social-post__claim { color: var(--accent-br); }

/* Das Standbild darf man sehen. `.55` war für den Platzhalter-Zustand
   gedacht, in dem nur ein Play-Knopf auf leerer Fläche stand; mit einem
   echten Cover ist das zu dunkel. Der Knopf bleibt lesbar, weil er einen
   eigenen Schatten trägt. */
.social-post__start img { opacity: .78; }
button.social-post__start:hover img { opacity: .92; }
.social-post__play {
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, .55));
  color: var(--bone);
}

/* --- Die Kachel ohne Standbild ----------------------------------------
   Instagram gibt das Cover nicht heraus, ohne dass die Seite dort
   anfragt — und genau das soll sie vor dem Klick nicht tun. Zwei der
   sechs Beiträge haben deshalb keins.

   Statt einer leeren Fläche mit Play-Knopf trägt die Kachel dann den
   Titel, so wie er im Video steht: groß, versal, mittig. Das ist keine
   Notlösung, die man als solche erkennt, sondern dieselbe Sache in einer
   zweiten Gestaltung. */
.social-post__titelbild {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: .6rem;
  padding: var(--s-5);
  text-align: center;
  background:
    radial-gradient(ellipse 90% 60% at 50% 38%, color-mix(in srgb, var(--accent) 18%, transparent), transparent 70%),
    var(--surface);
}
.social-post__titelbild em {
  font-family: var(--f-mono); font-style: normal;
  font-size: .56rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--accent-br);
}
.social-post__titelbild b {
  font-family: var(--f-display);
  font-weight: 800; font-stretch: 108%;
  /* Kleiner als zuerst gesetzt, und **ohne** Silbentrennung: Mit
     `hyphens: auto` stand dort „GESPRÄ-CHE LAU-FEN MANCH-MAL GANZ
     ANDERS" — sechs Zeilen, vier davon getrennt. Ein Titel, der in
     Silben zerfällt, liest sich nicht mehr als Titel.

     Bei normalem Wortumbruch und dieser Größe passt der längste der
     beiden Sätze in vier Zeilen. */
  font-size: clamp(.82rem, 2.4vw, 1.05rem);
  line-height: 1.15;
  letter-spacing: -.01em;
  text-transform: uppercase;
  color: var(--fg);
  hyphens: manual;
  text-wrap: balance;
}
/* Der Play-Knopf steht bei dieser Fassung unten, nicht in der Mitte —
   dort läge er im Titel. */
.social-post--titel .social-post__start { align-items: end; }
.social-post--titel .social-post__play { margin-bottom: var(--s-5); }

/* --- Die Unze zum Durchscrollen -----------------------------------------
   Der eine Abschnitt, der sich beim Scrollen nicht mitbewegt: Er bleibt
   stehen, während die Seite unter ihm weiterläuft, und geht dabei die drei
   Gewichte durch. Das ist kein Effekt um seiner selbst willen — die Unze
   ist die häufigste offene Frage vor dem Kauf, und eine Tabelle beantwortet
   sie nur denen, die sie lesen.

   Die Sperrhöhe hängt an .js und an prefers-reduced-motion: Ohne Skript
   bliebe sonst dreifache Bauhöhe ohne Inhalt stehen, und wer Bewegung
   abbestellt hat, bekommt einen gewöhnlichen Abschnitt.                   */
.gew { position: relative; }

.gew__fest { padding-block: var(--sec-y); }
.gew__raster { display: grid; gap: var(--s-7); align-items: center; }

@media (min-width: 900px) {
  .gew__raster {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    gap: clamp(2rem, 5vw, 5rem);
  }
}
/* Dasselbe auf dem Handy — nur andersherum ---------------------------------
   Bis zum 11.8.2026 hing der ganze Abschnitt an einer Mindestbreite von
   900 px. Darunter stand die Tafel als gewöhnliche Liste da: 14 OZ fest
   markiert, kein Wechsel, kein Wachsen. Ausgerechnet die Frage, die auf
   dem Handy am ehesten offen ist, bekam dort die stumme Fassung.

   Umgedreht wird, was klebt: Am Schreibtisch bleibt die ganze Tafel stehen
   und die Seite läuft darunter durch. Einspaltig ist dafür kein Platz —
   dort klebt die Bühne allein am oberen Rand, und die drei Stufen laufen
   darunter hindurch. Die Bewegung ist dieselbe: Wer die Liste durchgeht,
   sieht den Handschuh mitwachsen und die Zahl umspringen.

   `display: contents` löst den Textblock in seine Teile auf, damit die
   Bühne per `order` zwischen Fließtext und Liste rutschen kann. Ohne das
   stünde sie hinter der Liste — und klebte erst, wenn nichts mehr kommt,
   an dem man das Kleben bemerken könnte. */
@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  /* Flex, nicht Grid — und das ist keine Geschmacksfrage: Ein klebendes
     Rasterfeld klebt nur innerhalb SEINER Zelle, und die ist genau so hoch
     wie die Bühne selbst. Sie blieb damit sofort wieder stehen, während die
     Liste einfach an ihr vorbeizog. Im Flex-Container ist der Bereich der
     Container — die Bühne bleibt, bis der Abschnitt durch ist. */
  /* stretch, nicht center: Die Grundregel zentriert die beiden Spalten der
     breiten Fassung. In einer Spalte heißt dasselbe Wort etwas anderes —
     dort schrumpft jedes Teil auf seinen Inhalt. Die Bühne war damit
     176 px breit statt 342, deckte die Liste nicht ab, und die Stufen
     liefen sichtbar quer durch den Handschuh. */
  /* **Aufgegeben am 25.8.2026.** Hier stand die klebende Bühne: Der
     Handschuh blieb oben stehen, die drei Stufen liefen darunter hindurch,
     und ein deckender Grund plus Verlauf sollte den Übergang tragen.

     Der Betreiber auf dem Gerät: „der Bereich mit dem die richtige Wahl
     ist auf dem Handy komplett kaputt, also die Scrollanimation und Logik
     ergibt da gar keinen Sinn." Die Screenshots zeigen den Handschuh quer
     über dem Stufentext.

     Nachgemessen war jede einzelne Regel in Ordnung — flex column, stretch,
     sticky bei 110 px, deckender Grund, Bühne und Liste beide 350 px breit.
     **Das Konzept trägt trotzdem nicht:** Eine klebende Ebene über einer
     durchlaufenden verlangt zwei Bildebenen, und auf 390 x 740 gibt es dafür
     keinen Platz. Was am Schreibtisch eine Tafel ist, auf der etwas
     durchläuft, ist auf dem Telefon ein Bild, das im Text steht.

     Auf dem Handy steht die Tafel deshalb still: Titel, Ware, dann die drei
     Stufen vollständig untereinander. Kein Scroll-Trick, keine zweite
     Ebene, nichts, was sich überlagern kann. Die Auskunft ist dieselbe —
     sie kommt nur nicht mehr nacheinander, sondern auf einmal. */
  .js .gew__raster {
    display: flex; flex-direction: column;
    gap: var(--s-5); align-items: stretch;
  }
  .js .gew__text { display: contents; }
  .js .gew__liste { order: 5; margin-top: 0; }
  .js .gew__fuss  { order: 6; margin-top: var(--s-4); }

  .js .gew__buehne {
    order: 4;
    /* static, nicht sticky — siehe oben. */
    position: relative;
    z-index: 0;
    min-height: 0;
    height: min(34svh, 15rem);
    margin-top: var(--s-4);
    background: transparent;
  }
  /* In der begrenzten Höhe gibt die Höhe das Maß vor, nicht die Breite —
     sonst wächst der Handschuh über die Kante hinaus, statt in den Ringen
     zu stehen. */
  .js .gew__glove { width: auto; height: min(74%, 11rem); }
  .js .gew__ring   { width: auto; height: min(96%, 14rem); }
  .js .gew__ring--2 { width: auto; height: min(70%, 10rem); }
  .js .gew__marke { font-size: clamp(3.2rem, 15vw, 5rem); right: 0; bottom: 0; }
}

@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  /* Der Weg wird in PIXELN gemessen, nicht in Bildschirmhöhen — und das
     ist der Kern der Sache.

     Ein Mausrad-Tick ist rund 100 px. Immer. Er wird nicht größer, weil
     der Bildschirm größer ist. Solange die Bahn in vh stand, hing der Weg
     je Gewichtsstufe dagegen an der Fensterhöhe: auf einem 1145 px hohen
     Bildschirm 290 px, also weiterhin drei Ticks je Stufe — genau die
     Beanstandung, die eigentlich behoben sein sollte. Auf einem flachen
     Laptop wären es 160 gewesen. Dieselbe Seite, zwei völlig verschiedene
     Bedienungen.

     Jetzt: 480 px Weg, geteilt durch drei Stufen und die Randstauchung,
     macht rund 122 px je Stufe. Ein Tick, auf jedem Bildschirm derselbe.

     Und kein `scroll-snap` mehr. Es stand am Dokument, weil es nur einen
     Scrollbereich gibt — damit galt es für die ganze Seite, obwohl es nur
     drei Punkte auf 10 000 px gab. Gemeldet wurde genau das, was dabei
     herauskommt: mal passiert nichts, mal springt es über alles hinweg,
     mal landet man am Seitenende. Bei 122 px je Stufe braucht es das
     Einrasten auch nicht — ein Impuls ist eine Stufe. */
  /* 480 px Weg, davon 76 % auf drei Stufen — rund 122 px je Stufe, also
     ein Mausrad-Tick. Die Rechnung steht bei initGewicht() in motion.js;
     wer eine der drei Zahlen ändert, ändert das Scrollgefühl.

     **Diese Regel gilt nur am Schreibtisch** (siehe die Medienabfrage
     dieses Blocks: min-width 900px). Am 25.8.2026 habe ich sie versehentlich
     auf `auto` gesetzt, in der Annahme, sie gehöre zur mobilen Fassung —
     der Selbsttest hat es gemeldet („Der Weg steht in Pixeln"). Auf dem
     Handy gibt es gar keine Bahnregel: Dort ist die Bahn so hoch wie ihr
     Inhalt, und das ist seit dem Umbau vom 25.8. genau richtig. */
  .js .gew__bahn { height: calc(100svh + 480px); }

  /* Die Hervorhebung bleibt — sie greift jetzt nur anders.

     Erst hatte ich hier alle drei Stufen gleich hell gesetzt: Wenn nichts
     mehr durchläuft, dachte ich, ist eine gedämpfte Zeile nur schlechter
     lesbar. Gemessen zeigt sich das Gegenteil: `initGewicht()` setzt beim
     Start einmal die Standardstufe (14 OZ, der Allrounder) auf `is-an` und
     rührt sie danach nicht mehr an. Drei Zeilen, von denen eine
     hervorgehoben ist, sind damit keine Animation ohne Anlass, sondern
     eine Empfehlung — genau das, was die Tafel sagen soll.

     Die beiden anderen stehen in --fg-mute auf --bg, also auf Kontrast 7.
     Lesbar sind sie. */
  /* Die Tafel ist so hoch wie ihr Inhalt, nicht so hoch wie das Fenster.
     Auf die feste Fensterhöhe gebunden lief sie auf flachen Bildschirmen
     oben aus dem Bild — und ausgerechnet die Überschrift, die den Wechsel
     mitmacht, war das Erste, was fehlte. */
  .js .gew__fest {
    position: sticky;
    /* Der Anschlag liegt unter der Kopfzeile — sie fährt beim Abwärtslesen
       zwar weg, kommt beim Zurückscrollen aber sofort wieder und läge
       sonst auf der Überschrift. */
    top: calc(var(--announce-h) + 5rem);
    padding-block: clamp(.75rem, 3svh, 1.75rem);
  }
  /* Was hier steht, muss zwischen Kopfzeile und Unterkante passen. Passt es
     nicht, klebt die Tafel zwar — man sieht aber ihr unteres Drittel nie.
     Auf flachen Fenstern rückt deshalb alles enger zusammen. */
  @media (max-height: 860px) {
    .js .gew__text { gap: var(--s-3); }
    .js .gew__text .lead { font-size: 1rem; line-height: 1.5; max-width: 42ch; }
    .js .gew__titel { font-size: clamp(1.5rem, 2.6vw, 2.1rem); }
    .js .gew__buehne { min-height: clamp(12rem, 34svh, 22rem); }
    .js .gew__fuss { margin-top: 0; }
  }
}

.gew__text { display: flex; flex-direction: column; gap: var(--s-4); align-items: flex-start; }
.gew__text .lead { max-width: 46ch; }
.gew__titel em { font-style: normal; color: var(--accent-br); }
.gew__liste { width: 100%; margin-top: var(--s-2); }

/* Die inaktiven Stufen bleiben LESBAR. Sie abzublenden wäre die bequeme
   Lösung und nimmt genau denen die Information, die sie am ehesten
   brauchen — die aktive Stufe wird stattdessen hervorgehoben. */
.gew__stufe {
  position: relative;
  display: grid;
  grid-template-columns: 4.6rem minmax(0, 1fr);
  gap: var(--s-2) var(--s-4);
  align-items: baseline;
  padding: var(--s-3) 0 var(--s-3) var(--s-4);
  border-top: 1px solid var(--line);
  color: var(--fg-mute);
  transition: color .3s var(--ease);
}
.gew__stufe:last-child { border-bottom: 1px solid var(--line); }
.gew__stufe::before {
  content: '';
  position: absolute; left: 0; top: -1px; bottom: 0;
  width: 2px;
  background: var(--accent);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform .34s var(--ease-out);
}
.gew__stufe.is-an { color: var(--fg); }
.gew__stufe.is-an::before { transform: none; }
.gew__nr {
  display: flex; align-items: baseline; gap: .3rem;
  font-family: var(--f-display); font-weight: 800; font-stretch: 112%;
  font-size: 1.45rem; line-height: 1; letter-spacing: -.02em;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}
.gew__nr i {
  font-family: var(--f-mono); font-style: normal;
  font-size: .58rem; letter-spacing: .12em; color: var(--fg-faint);
}
.gew__was { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.gew__was b { font-weight: 500; font-size: .96rem; line-height: 1.3; color: inherit; }
.gew__was span { font-size: .88rem; line-height: 1.45; }
.gew__da {
  grid-column: 2;
  font-family: var(--f-mono); font-size: .62rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint);
}
.gew__fuss {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-4) var(--s-5);
  margin-top: var(--s-3);
}

/* Die Bühne: zwei Ringe, der Handschuh, die Zahl. Die Ringe sind der
   Maßstab — ohne sie wüchse der Handschuh vor einem leeren Grund, und
   Wachstum ohne Bezug sieht man nicht. */
.gew__buehne {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(15rem, 42svh, 30rem);
}
.gew__ring {
  position: absolute;
  width: min(88%, 27rem);
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: 50%;
  transform: scale(var(--gew, 1));
}
.gew__ring--2 {
  width: min(64%, 19.5rem);
  border-style: dashed;
  border-color: var(--line-2);
  transform: scale(calc(1 + (var(--gew, 1) - 1) * 1.5));
}
.gew__glove {
  position: relative;
  z-index: 1;
  width: min(58%, 19rem);
  height: auto;
  transform: scale(var(--gew, 1));
  /* Der Handschuh trägt einen Schatten (gemeinsame Freisteller-Regel) und
     wird beim Scrollen fortlaufend skaliert. Ohne Ankündigung heißt das:
     Schatten in jedem Bild neu rechnen, während gescrollt wird. Angekündigt
     wird einmal gerastert und danach nur noch skaliert. Weglassen ließe der
     Schatten sich nicht — in der dunklen Fassung ist seine Lichtkante das
     Einzige, was den schwarzen Handschuh vom Grund trennt. */
  will-change: transform;
}
/* Die Zahl liegt HINTER dem Handschuh und ist ausgehöhlt — dieselbe
   Behandlung wie die dritte Zeile im Auftakt. Zwei Stellen, ein Ton. */
.gew__marke {
  position: absolute;
  right: 2%;
  bottom: 2%;
  z-index: 0;
  font-family: var(--f-display); font-weight: 900; font-stretch: 118%;
  font-size: clamp(4rem, 11vw, 9rem);
  line-height: .8;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
  color: var(--line);
  pointer-events: none;
}
@supports (-webkit-text-stroke: 1px black) {
  .gew__marke { color: transparent; -webkit-text-stroke: 2px var(--line-2); }
}
/* Der Wechsel der Zahl läuft über einen kurzen Weichzeichner: Ohne ihn
   sieht man zwei Ziffern nebeneinander stehen, mit ihm eine, die sich
   verwandelt. */
.gew__marke.is-wechsel { animation: gewZahl .34s var(--ease-out); }
@keyframes gewZahl {
  0%   { opacity: 0; filter: blur(6px); transform: translateY(6px); }
  100% { opacity: 1; filter: blur(0);   transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .gew__marke.is-wechsel { animation: none; }
}

/* ==========================================================================
   Die Anatomie — was an dem Handschuh dran ist
   ==========================================================================
   Der Abschnitt, den es vorher nicht gab, und der Grund dafür, dass die
   Seite sich „leer" anfühlte: Vier Produktseiten beschrieben den Handschuh,
   ohne dass einmal stand, was ihn ausmacht. Hier steht es — und zwar am
   Gegenstand, nicht in einer Tabelle darunter.

   Gebaut wie die Gewichtstafel: Eine Bahn gibt den Scrollweg, die Bühne
   darin klebt, und beim Durchscrollen kommen vier Marker nacheinander an.
   Der Weg steht in PIXELN, nicht in vh — ein Mausrad-Tick sind rund 100 px,
   unabhängig von der Fensterhöhe. In vh gemessen wäre derselbe Abschnitt
   auf einem flachen Laptop doppelt so hakelig wie auf einem hohen Monitor.

   Kein scroll-snap. Der Schalter sitzt zwangsläufig am Dokument und gälte
   damit für die ganze Seite — dieselbe Falle, die am 16.8.2026 schon einmal
   zugeschlagen hat. Bei rund 130 px je Marker braucht es ihn nicht. */
.anat { position: relative; }

.anat__bahn {
  /* 100svh trägt die klebende Bühne, 520 px sind der eigentliche Weg:
     vier Marker plus ein Stück Vorlauf, macht rund 130 px je Marker —
     gut ein Mausrad-Tick. */
  height: calc(100svh + 520px);
}
.anat__fest {
  position: sticky; top: 0;
  height: 100svh;
  display: grid; align-content: center;
  overflow: hidden;
}
.anat__raster {
  display: grid;
  gap: var(--s-6);
  justify-items: center;
  /* Ohne das erbt das Rasterfeld `min-width: auto` und kann nicht unter die
     Mindestbreite seines Inhalts schrumpfen — bei verschachtelten Breiten
     nimmt der Browser dann die max-content-Breite und sprengt das Fenster. */
  min-width: 0;
}
.anat__fest > * { min-width: 0; }
.anat__text { text-align: center; max-width: 34ch; }

/* Der Halter, den das Skript füllt, darf im Raster nicht mitzählen: Als
   eigenes Rasterfeld wurde er 800 px breit (die Bühne darin blieb 352 und
   stand linksbündig), und der Handschuh saß damit 224 px links der Mitte.
   `display: contents` reicht die Bühne als Rasterfeld durch. */
.anat__halter { display: contents; }
/* Die Bühne ist absichtlich schmal: Links und rechts von ihr stehen die
   Karten, und die brauchen mehr Platz als das Bild. Die Prozentkoordinaten
   der Marker beziehen sich auf genau diese Fläche. */
.anat__buehne {
  position: relative;
  width: min(100%, 22rem);
  aspect-ratio: 1;
}
.anat__glove {
  width: 100%; height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 1.5rem 2.5rem var(--pack-shadow));
}

/* Der Pin sitzt mit seinem Ursprung AUF dem Punkt und lässt seinen Inhalt
   nach außen laufen. Nach rechts über `left`, nach links über
   `right: calc(100% - x)` mit umgekehrter Flussrichtung — dadurch steht die
   Karte auf beiden Seiten im selben Abstand vom Punkt, ohne zweite Zahl. */
.anat__pin {
  position: absolute;
  top: var(--y);
  display: flex;
  align-items: center;
  transform: translateY(-50%);
}
.anat__pin--rechts { left: var(--x); }
.anat__pin--links  { right: calc(100% - var(--x)); flex-direction: row-reverse; }

.anat__punkt {
  flex: none;
  width: .6rem; height: .6rem;
  border-radius: var(--r-voll);
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 4px var(--accent);
  /* Nie aus scale(0): Nichts in der Wirklichkeit erscheint aus dem Nichts. */
  transform: scale(.94);
  opacity: 0;
  transition: transform .3s var(--ease-out), opacity .3s var(--ease-out);
}
.anat__linie {
  flex: none;
  width: clamp(1.25rem, 3.5vw, 3rem);
  height: 1px;
  background: var(--line-2);
  transform: scaleX(0);
  transition: transform .34s var(--ease-out) .09s;
}
.anat__pin--rechts .anat__linie { transform-origin: left center; }
.anat__pin--links  .anat__linie { transform-origin: right center; }

.anat__karte {
  width: clamp(9rem, 15vw, 13rem);
  /* Kommt aus der Richtung, aus der die Linie zeigt — die Karte folgt der
     Linie, statt an ihrem Ende aufzutauchen. */
  transform: translateX(var(--karte-weg, -.75rem));
  opacity: 0;
  transition: transform .38s var(--ease-out) .2s, opacity .38s var(--ease-out) .2s;
}
.anat__pin--links .anat__karte { --karte-weg: .75rem; text-align: right; }

.anat__titel { display: block; font-size: .95rem; line-height: 1.3; }
/* Hieß bis zum 18.8.2026 ebenfalls .anat__text — wie der Abschnittskopf.
   Damit erbte jeder Kartentext dessen `max-width: 34ch` und `text-align:
   center`, und auf schmalen Geräten sprengte die Kette aus verschachtelten
   Breitenangaben das Raster um 473 px. Zwei Dinge, die verschieden
   aussehen sollen, dürfen nicht gleich heißen. */
.anat__ktext {
  display: block;
  margin-top: .3rem;
  font-size: .82rem; line-height: 1.5;
  color: var(--fg-mute);
}

/* Angekommen */
.anat__pin.is-an .anat__punkt { transform: scale(1); opacity: 1; }
.anat__pin.is-an .anat__linie { transform: scaleX(1); }
.anat__pin.is-an .anat__karte { transform: translateX(0); opacity: 1; }

/* Einspaltig: Die Karten haben neben einem 22rem-Bild keinen Platz. Sie
   stehen deshalb als nummerierte Liste darunter — dieselbe Entscheidung
   wie bei der Gewichtstafel, wo die Bühne klebt und die Stufen durchlaufen.
   Die Punkte auf dem Bild entfallen dabei; vier Marker auf einem 18rem
   breiten Handschuh wären ohnehin nicht mehr zu treffen. */
@media (max-width: 899px) {
  .anat__bahn { height: auto; }
  .anat__fest { position: static; height: auto; overflow: visible; }
  /* Kein Seitenverhältnis mehr: Einspaltig stehen die Pins als Liste IN der
     Bühne, und ein Container mit fester Höhe kann eine Liste nicht fassen.
     Das Bild trägt sein Format über width/height selbst. */
  .anat__buehne {
    width: 100%;
    aspect-ratio: auto;
  }
  .anat__glove {
    width: min(100%, 17rem);
    height: auto;
    margin-inline: auto;
    display: block;
  }
  .anat__pin {
    position: static;
    transform: none;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--s-4);
    align-items: start;
    padding-block: var(--s-4);
    border-top: 1px solid var(--line);
  }
  .anat__pin--links { flex-direction: row; }
  .anat__linie { display: none; }
  .anat__punkt {
    width: .5rem; height: .5rem;
    margin-top: .45rem;
    opacity: 1; transform: none;
  }
  .anat__karte {
    width: auto;
    transform: none;
    /* Nur noch aufblenden, kein Weg: Die Zeilen tragen eine Trennlinie, und
       eine wandernde Trennlinie sieht man wandern. */
    transition: opacity .4s var(--ease-out);
  }
  .anat__pin--links .anat__karte { text-align: left; }
}

/* Wer Bewegung abbestellt, bekommt den Endzustand — nicht nichts. */
@media (prefers-reduced-motion: reduce) {
  .anat__punkt, .anat__linie, .anat__karte {
    opacity: 1; transform: none; transition: none;
  }
}

/* Die kompakte Anatomie -------------------------------------------------
   Auf den Produktseiten ohne klebende Bahn. Die Seite ist dort schon lang,
   und ein zweiter Abschnitt über anderthalb Bildschirme stünde zwischen
   Kaufbereich und Datenblatt wie eine Sperre. Die vier Marker kommen
   stattdessen gestaffelt, sobald die Bühne im Bild steht.

   80 ms Versatz je Marker: Bei vier Markern und rund 500 ms Eigenlauf ist
   das eine Welle, die nach knapp 800 ms steht. Mehr Versatz ließe den
   letzten Marker auf sich warten, weniger sähe aus wie gleichzeitig. */
.anat--kompakt .anat__bahn { height: auto; }
.anat--kompakt .anat__fest {
  position: static;
  height: auto;
  overflow: visible;
}
.anat--kompakt .anat__punkt { transition-delay: calc(var(--i) * 80ms); }
.anat--kompakt .anat__linie { transition-delay: calc(var(--i) * 80ms + 90ms); }
.anat--kompakt .anat__karte { transition-delay: calc(var(--i) * 80ms + 200ms); }

/* ==========================================================================
   Der Ring — vier Aufnahmen, ein Scrollweg
   ==========================================================================
   Der große Moment der Startseite und der dunkle Anker der hellen Fassung.
   An dieser Stelle stand bis zum 18.8.2026 ein einzelnes Standbild mit
   Laufband; das Laufband ist geblieben und läuft jetzt unter dem Film.

   Der Raum ist in BEIDEN Fassungen dunkel und zieht seine Farben nicht aus
   den Tokens. Das ist die einzige Stelle der Website, an der das so ist, und
   sie ist der Grund: Ein Kinoraum, der in der hellen Fassung hell wäre, ist
   kein Kinoraum. Die Schrift darin ist deshalb fest hell gesetzt. */
.ring {
  position: relative;
  background: #100f13;
  color: #ede9e3;
}
.ring__bahn {
  /* 100svh trägt die klebende Bühne, 900 px sind der Weg: vier Stationen zu
     je rund 225 px. Bewusst länger als bei der Anatomie (130 px je Marker) —
     hier wechselt ein ganzes Bild, und ein Bildwechsel je Mausrad-Tick wäre
     ein Flackern, kein Film. */
  height: calc(100svh + 900px);
}
.ring__fest {
  position: sticky; top: 0;
  height: 100svh;
  display: grid;
  /* Die Bühne nimmt, was sie als Quadrat braucht; der Text bekommt den Rest.
     Vorher stand hier `1fr 22rem`: Die Bühne wurde damit so breit wie der
     Platz hergab (1025 px auf 595 px Höhe, also 1,72:1) und schnitt vom
     quadratischen Produktfoto **42 % weg** — man sah einen Ausschnitt, keinen
     Handschuh. Derselbe Fehler wie am 17.8.2026 in der Produktgalerie, und
     dieselbe Antwort: Der Rahmen richtet sich nach dem Bild. */
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: clamp(2rem, 4vw, 4.5rem);
  padding: clamp(1.5rem, 4vw, 3rem) clamp(1.25rem, 5vw, 5rem);
  overflow: hidden;
}

/* Wie bei der Anatomie: Der Halter, den das Skript füllt, darf im Raster
   nicht als eigenes Feld mitzählen — sonst säßen Bühne und Texte zusammen
   in der linken Spalte statt nebeneinander. */
.ring__halter { display: contents; }
/* Die Projektion */
.ring__buehne {
  position: relative;
  /* Quadratisch, weil die Aufnahmen quadratisch sind. Die Höhe ist der
     Engpass — sie bestimmt die Breite, nicht umgekehrt. */
  aspect-ratio: 1;
  /* 42rem statt 34: Bei 34rem blieben auf einem 900 px hohen Fenster oben
     und unten je 178 px leer — der Abschnitt sah aus, als hinge er in der
     Mitte statt den Raum zu füllen („sollte mehr nach oben"). Die Deckelung
     bleibt, sonst wächst die Bühne auf hohen Schirmen ins Unförmige. */
  height: min(76svh, 42rem);
  width: auto;
  max-width: 100%;
  border-radius: var(--r-5);
  overflow: hidden;
  /* Eine Kante, damit die Fläche im schwarzen Raum überhaupt eine Fläche ist */
  box-shadow: inset 0 0 0 1px rgba(237, 233, 227, .09);
  background: #17161b;
}
.ring__bild {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  /* Der Zoom läuft weiter, während das Bild schon steht — dadurch wirkt der
     Schnitt wie eine Kamerafahrt und nicht wie ein Diawechsel. */
  transform: scale(1.06);
  transition: opacity .75s var(--ease-flow), transform 1.6s var(--ease-flow);
  will-change: opacity, transform;
}
.ring__bild.is-an { opacity: 1; transform: scale(1); }

/* Die Texte */
.ring__texte { position: relative; min-height: 15rem; max-width: 30rem; }
.ring__station {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
  pointer-events: none;
}
.ring__station.is-an {
  opacity: 1; transform: none;
  pointer-events: auto;
  transition-delay: .12s;
}
.ring__station .label { color: var(--accent-br); }
.ring__titel { margin-top: var(--s-4); color: #ede9e3; }
.ring__text {
  margin-top: var(--s-4);
  font-size: 1.08rem; line-height: 1.65;
  color: rgba(237, 233, 227, .74);
  max-width: 32ch;
}

/* Der Fortschritt — vier Striche, keine Zahl. Man soll sehen, wie weit man
   ist, ohne es zu lesen. */
/* Die Striche standen bis zum 18.8.2026 unten links am Fensterrand — weit
   weg von Bild und Text, ohne Bezug zu irgendetwas. Sie gehören unter den
   Text, dessen Fortschritt sie zeigen. */
.ring__spur {
  display: flex; gap: .4rem;
  margin-top: var(--s-6);
}
.ring__strich {
  width: 2.2rem; height: 2px;
  background: rgba(237, 233, 227, .22);
  overflow: hidden;
}
.ring__strich::after {
  content: '';
  display: block; height: 100%;
  background: var(--accent-br);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .45s var(--ease-out);
}
.ring__strich.is-an::after { transform: scaleX(1); }

/* Einspaltig: Die Bühne klebt oben, die Texte laufen darunter durch —
   dieselbe Aufteilung wie bei der Gewichtstafel. Nebeneinander bliebe für
   das Bild auf 390 px keine Fläche, die eine Projektion verdient. */
@media (max-width: 899px) {
  .ring__fest {
    grid-template-columns: minmax(0, 1fr);
    align-content: center;
    gap: var(--s-5);
  }
  .ring__buehne { height: min(46svh, 22rem); }
  .ring__texte { min-height: 11rem; }
  .ring__spur { position: static; margin-top: var(--s-4); }
}

/* Ohne Bewegung bleibt es bei der ersten Station — vier Aufnahmen
   übereinander, von denen keine wechselt, wären vier geladene Bilder für
   nichts. Der Abschnitt behält Bild, Titel und Text. */
@media (prefers-reduced-motion: reduce) {
  .ring__bild { transition: none; transform: none; }
  .ring__station { transition: none; }
}

/* Der Schlag -------------------------------------------------------------
   Ein Klick auf den Handschuh, und er trifft. Die einzige rein verspielte
   Bewegung der Website — erlaubt, weil sie selbst ausgelöst wird und
   niemand sie hundertmal am Tag sieht.

   Der Stoß ist bewusst kurz (260 ms) und klein (3 % Skalierung, 6 px Weg).
   Ein Handschuh, der beim Klick durchs Bild fliegt, ist ein Gag; einer, der
   kurz anzieht und zurückfedert, ist ein Treffer. */
.kann-schlagen {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.kann-schlagen:focus-visible {
  outline: 2px solid var(--accent-br);
  outline-offset: 12px;
  border-radius: var(--r-3);
}
@media (hover: hover) and (pointer: fine) {
  /* Anspannung vor dem Schlag — die Einladung, ohne ein Wort. */
  .kann-schlagen:hover { transform: rotate(-3.5deg) scale(1.015); }
}
/* Die Grunddrehung der Paketgruppe muss in jedem Zustand mitgeschrieben
   werden: transform ist eine Eigenschaft, keine Liste, und ein zweiter Wert
   ersetzt den ersten, statt ihn zu ergänzen. */
.kann-schlagen {
  transition: transform .22s var(--ease-out);
}
.kann-schlagen.is-schlag {
  animation: schlagStoss .3s var(--ease-out);
}
/* Anziehen, treffen, zurückfedern. Der Rückweg ist länger als der Hinweg
   (38 % zu 62 %) — ein Schlag geht schnell raus und kommt langsamer
   zurück, alles andere sieht aus wie ein Zittern. */
@keyframes schlagStoss {
  0%   { transform: rotate(-3.5deg) scale(1); }
  22%  { transform: rotate(-4.6deg) scale(.985) translateY(3px); }
  38%  { transform: rotate(-1.6deg) scale(1.055) translateY(-10px); }
  100% { transform: rotate(-3.5deg) scale(1); }
}

/* Die Druckwelle startet am Zeiger, nicht in der Mitte: Ein Treffer, der
   immer an derselben Stelle aufblüht, ist eine Animation — einer, der dort
   aufblüht, wo man hingetippt hat, ist eine Reaktion. */
/* Die Druckwelle ist ein SVG, kein Kasten mit Rahmen.
   Vorher war sie ein 18-px-Kästchen mit 2-px-Rahmen, über transform auf das
   17-Fache skaliert — und ein skalierter Rahmen wird mitskaliert: aus zwei
   Pixeln wurden vierunddreißig unscharfe. Genau das war als „sehr schlecht
   und pixelig" gemeldet.

   `vector-effect: non-scaling-stroke` löst es an der Wurzel: Die Linie bleibt
   zwei Pixel dünn, egal wie groß der Kreis gezogen wird. */
.schlag__welle {
  position: absolute;
  left: 0; top: 0;
  width: 320px; height: 320px;
  margin: -160px 0 0 -160px;
  overflow: visible;
  pointer-events: none;
  animation: schlagWelle .66s var(--ease-out) forwards;
}
.schlag__ring {
  fill: none;
  stroke: var(--accent-br);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
@keyframes schlagWelle {
  0%   { transform: scale(.06); opacity: .95; }
  100% { transform: scale(1);   opacity: 0; }
}
/* Der Aufschlag: eine gefüllte Fläche, die sofort wieder weg ist. Sie gibt
   dem Treffer den Kern, den ein Ring allein nicht hat. */
.schlag__kern {
  fill: var(--accent-br);
  transform-origin: center;
  animation: schlagKern .24s var(--ease-out) forwards;
}
@keyframes schlagKern {
  0%   { opacity: .5;  transform: scale(1); }
  100% { opacity: 0;   transform: scale(2.4); }
}

/* Der Hinweis, und warum er zweimal umgezogen ist.

   **Erst** saß er auf `bottom: -.25rem`, also außerhalb der Bühne. Auf dem
   Handy zieht `.hero__wahl` die Farbpunkte mit -2.2rem über genau diese
   Kante — der Hinweis stand danach unter ihnen. Gemeldet am 25.8.2026:
   „Der Text für antippen für Information ist unter den Farbauswahl
   Buttons."

   **Dann** habe ich ihn auf `bottom: 4%` gesetzt, also nach innen. Damit
   war er auf dem Handy frei — und am Schreibtisch hinter den Knöpfen, weil
   dort dieselben 4 % einer viel größeren Bühne entsprechen und die
   Farbwahl direkt an der Unterkante steht. Am selben Abend gemeldet:
   „das mit dem Antippen ist jetzt aufm Desktop versteckt".

   **Jetzt** liegt er über der Bühne statt darin: `bottom: 100%` setzt ihn
   auf die Oberkante, ein kleiner Abstand darunter. Dort ist auf beiden
   Größen Platz — über der Ware steht nur die Überschrift, und die endet
   höher. Kein Prozentwert, der auf zwei Größen zwei Bedeutungen hat. */
.schlag__hinweis {
  /* Im Fluss, nicht absolut — die Begründung steht bei initSchlag() in
     motion.js. Kurz: Ein Prozentwert in der Bühne bedeutet auf 264 px
     etwas anderes als auf 448 px, und der Hinweis landete deshalb je nach
     Bildschirmgröße hinter den Farbpunkten oder hinter der Kopfzeile. */
  /* Volle Zeile im Flex-Container `.hero__cta`, über dem Knopf. */
  flex: 1 1 100%;
  margin: 0 0 -.2rem;
  font-family: var(--f-mono);
  font-size: .62rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg-faint);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .5s var(--ease-out), transform .5s var(--ease-out);
  pointer-events: none;
  white-space: nowrap;
}
.schlag__hinweis.is-da { opacity: 1; transform: none; }
/* Ein Schriftzug quer über der Ware ist auf 390 px kein Hinweis mehr,
   sondern eine Beschriftung. Auf dem Handy steht er deshalb kürzer und
   dichter am Bild. */
@media (max-width: 620px) {
  /* Auf dem Handy kleiner gesetzt — auf 390 px steht sonst eine
     Beschriftung quer unter der Ware statt eines Hinweises. */
  .schlag__hinweis { font-size: .58rem; letter-spacing: .1em; }
}

/* Reduzierte Bewegung: Der Stoß entfällt — er ist Bewegung ohne Aussage.
   Die Welle bleibt, sie ist die Rückmeldung auf eine Handlung. */
@media (prefers-reduced-motion: reduce) {
  .kann-schlagen, .kann-schlagen:hover { transform: rotate(-3.5deg); animation: none; }
  .schlag__welle { animation-duration: .4s; }
}

/* --- Zubehör als Warengruppen ------------------------------------------
   Zwei Blöcke statt sechs Produktkarten (Begründung bei WARENGRUPPEN in
   data.js). Der erste Anlauf am 27.8.2026 war kompakt und trotzdem falsch —
   der Betreiber am 28.8.: „Das wirkt mir sehr billig und nicht so premium
   wie der Rest der Seite."

   Nachgesehen, woran es lag, und es war nicht die Kompaktheit:

   1. **Die Ware hatte keine Bühne.** Überall sonst im Projekt liegt ein
      Freisteller auf `--stage`, einem Lichtkegel, und wirft `--pack-shadow`.
      Hier stand er auf derselben Fläche wie der Text und ohne Bodenschatten
      — er schwebte. Die Filterregel war von Hand nachgebaut statt der
      Sammelklasse in components.css entnommen, und dabei fiel der Schatten
      weg.
   2. **Die Farbtupfer sahen aus wie leere Checkboxen.** Ein weißes Quadrat
      mit Rahmen neben dem Wort „Weiß" ist die visuelle Sprache eines
      Formulars. Und redundant: Das Bild daneben zeigt die Farbe.
   3. **Nichts reagierte.** Keine Andeutung, dass die Kachel ein Ziel ist.
   4. **Die Beschriftung war Kleingedrucktes.** Der Produktname stand in
      11,8 px Mono-Grau — dieselbe Ebene wie eine Fußnote.                */
.zubg-halter { display: flex; flex-direction: column; gap: var(--s-5); }

.zubg {
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
  box-shadow: var(--shadow-s);
  padding: var(--s-5) var(--s-5) var(--s-4);
}

/* Kopf und Angaben in einer Zeile, solange Platz ist. Der Umbruch kommt
   über flex-wrap und nicht über eine Medienabfrage: Der Block steht auf der
   Sortimentsseite in einer 1.2fr-Spalte, im Anriss über die volle Breite —
   eine Fensterbreite sagt darüber nichts. */
.zubg__kopf {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5);
  align-items: baseline; justify-content: space-between;
}
.zubg__name {
  font-family: var(--f-display); font-weight: 800; font-stretch: 112%;
  font-size: clamp(1.05rem, 2.4vw, 1.35rem);
  text-transform: uppercase; letter-spacing: -.01em;
}
.zubg__kurz { color: var(--fg-mute); font-size: .9rem; margin-top: .2rem; }
.zubg__meta { display: flex; flex-direction: column; align-items: flex-end; gap: .15rem; }
.zubg__preis { font-weight: 600; font-size: 1.15rem; white-space: nowrap; }
.zubg__groessen {
  font-family: var(--f-mono); font-size: .72rem;
  color: var(--fg-mute); white-space: nowrap;
}

/* Die Ausführungen. So viele nebeneinander, wie hineinpassen — `auto-fit`
   mit einer Mindestbreite statt einer festen Spaltenzahl: Zwei Bandagen und
   vier Mundschutze stehen im selben Block, und eine getippte Zahl wäre für
   die eine Gruppe zu groß und für die andere zu klein. */
.zubg__liste {
  list-style: none; margin: 0; padding: 0; margin-top: var(--s-4);
  display: grid; gap: var(--s-3);
  /* Der Deckel gehört an die Spalte, seit die Kachel selbst die Bühne ist.
     Ohne ihn zogen sich zwei Bandagen auf je 346 px auseinander und die
     Gruppe mit ZWEI Artikeln stand 486 px hoch, die mit VIER nur 307 —
     weniger Ware nahm mehr Platz (gemessen am 28.8.2026, zum zweiten Mal).

     Und zentriert, nicht linksbündig: Zwei Kacheln am linken Rand lassen
     die rechte Hälfte leer, und eine leere Hälfte liest sich auf dunklem
     Grund als fehlender Inhalt. Symmetrisch verteilt wirkt derselbe
     Leerraum als Ruhe. */
  /* 10rem, nicht 10.5: Bei 10.5 brauchten vier Mundschutze 708 px in einer
     705 px breiten Liste — drei Pixel, und die vierte Kachel fiel in die
     zweite Reihe. Gemessen, nicht geschätzt. */
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 10rem));
  justify-content: center;
}
/* Die Ware läuft nach dem Kasten ein, gestaffelt. Der Kasten ist der
   Rahmen — er steht, dann kommt hinein, was verkauft wird.

   Als eigene Reveal-Elemente ginge es auch (`staffeln()` in motion.js kann
   das), aber dann stünden Kachel und Kasten in derselben Warteschlange und
   die Ware wartete auf sich selbst. So hängt sie am `is-in` ihrer Gruppe,
   und die Verzögerung kommt aus `--i`, das die Position mitbringt.

   55 ms je Stück: Emils Fenster für Staffelung liegt bei 30–80 ms; darüber
   wirkt eine Reihe wie Nachladen statt wie eine Welle. */
.zubg__teil {
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity var(--t-reveal) var(--ease-out),
    transform var(--t-reveal) var(--ease-out);
  transition-delay: calc(140ms + var(--i, 0) * 55ms);
}
.zubg.is-in .zubg__teil { opacity: 1; transform: none; }

.zubg__link {
  display: flex; flex-direction: column; gap: .7rem;
  text-decoration: none; color: inherit;
  border-radius: var(--r-2);
  /* Genau benannte Eigenschaften statt `all`: Sonst blendet beim Wechsel
     der Fassung auch der Grund mit über, und zwar in der Dauer, die hier
     fürs Anheben gedacht ist. */
  transition: transform .2s var(--ease-out);
}

/* Die Bühne — dieselbe, auf der im ganzen Projekt Ware liegt. Sie ist der
   Unterschied zwischen einem Produktfoto und einem Icon in einer Liste. */
.zubg__bild {
  position: relative;
  width: 100%; aspect-ratio: 1;
  border-radius: var(--r-2);
  background: var(--stage-flat);
  overflow: hidden;
  display: grid; place-items: center;
}
.zubg__bild::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 64% 54% at 50% 46%, var(--spot), transparent 72%);
  transition: opacity .28s var(--ease);
}
/* Zwei Bilder übereinander, wie auf der Produktkarte: der Freisteller auf
   der Bühne, dahinter die Aufnahme mit Grund. Beim Überfahren tauschen sie
   — mit Übergang, nicht als Schnitt. */
.zubg__bild img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  transition:
    opacity .28s var(--ease),
    transform .28s var(--ease-out);
}
/* Der Freisteller steht auf der Bühne und braucht Luft zum Rand — dieselbe
   Rolle wie `padding: 9%` an der Produktkarte. Lichtkante und Bodenschatten
   kommen aus der Sammelklasse in components.css; sie gelten nur ihm, nicht
   der Aufnahme dahinter: Ein Foto mit eigenem Grund braucht keinen
   Freisteller-Schatten, er läge als grauer Rand auf der Kante. */
.zubg__frei { object-fit: contain; padding: 12%; }
.zubg__alt  { object-fit: cover; opacity: 0; }

/* Der Name steht jetzt auf der Textebene, nicht im Kleingedruckten. Der
   Farbtupfer daneben ist weg: Das Bild darüber zeigt die Farbe, und ein
   weißes Kästchen neben dem Wort „Weiß" liest sich als leeres Formularfeld. */
.zubg__farbe {
  font-size: .92rem; line-height: 1.3; text-align: center;
  transition: color .2s var(--ease);
}
.zubg__aus {
  display: block; margin-top: .15rem;
  font-family: var(--f-mono); font-size: .62rem;
  text-transform: uppercase; letter-spacing: .08em; color: var(--warn);
}
.zubg__teil.is-out .zubg__link { opacity: .5; }

/* Reaktion — nur dort, wo es einen Zeiger gibt. Auf Touch löst :hover beim
   Tippen aus und bliebe danach hängen. */
@media (hover: hover) and (pointer: fine) {
  .zubg__link:hover { transform: translateY(-3px); }
  .zubg__link:hover .zubg__farbe { color: var(--accent-br); }

  /* Wo es ein zweites Bild gibt, wird getauscht — und der Lichtkegel weicht,
     weil die Aufnahme ihren eigenen Grund mitbringt. Zwei Lichtquellen
     übereinander sind kein Licht mehr, sondern ein Fleck. */
  .zubg__link:hover .zubg__bild:has(.zubg__alt)::before { opacity: 0; }
  .zubg__link:hover .zubg__bild:has(.zubg__alt) .zubg__frei { opacity: 0; }
  .zubg__link:hover .zubg__alt { opacity: 1; transform: scale(1.04); }

  /* Ohne zweites Bild bleibt es beim bisherigen Verhalten: Kegel heller,
     Ware wächst. */
  .zubg__link:hover .zubg__bild:not(:has(.zubg__alt))::before { opacity: .72; }
  .zubg__link:hover .zubg__bild:not(:has(.zubg__alt)) .zubg__frei { transform: scale(1.06); }
}
/* Der Druck gilt überall: Er ist die Rückmeldung, dass die Fläche den Tipp
   gehört hat — und die braucht ein Finger genauso wie ein Zeiger. Kürzer
   als das Anheben, weil das System antwortet und der Mensch nicht wartet. */
.zubg__link:active { transform: scale(.98); transition-duration: .12s; }
.zubg__link:focus-visible {
  outline: 2px solid var(--contrast);
  outline-offset: 3px;
}

/* Auf schmalen Geräten zwei Ausführungen nebeneinander — vier in einer
   Reihe wären auf 390 px je 74 px breit, und ein Mundschutz ist darin nicht
   mehr zu unterscheiden. */
@media (max-width: 560px) {
  .zubg { padding: var(--s-4); }
  .zubg__liste { grid-template-columns: repeat(2, 1fr); }
  .zubg__meta { align-items: flex-start; }
  .zubg__kopf { gap: var(--s-2) var(--s-4); }
}

/* --- Größenberater, lineare Fassung (27.8.2026) -------------------------
   Vorher ein Split: Fragen rechts, Bühne und Ergebnis links. Man las also
   rechts und die Antwort erschien links — ein Blicksprung bei jedem Klick,
   und auf dem Telefon standen die vier Fragen ohnehin untereinander.

   Jetzt fragen, antworten, kaufen — in dieser Reihenfolge, mittig, mit
   begrenzter Breite. */
.wrap--berater { max-width: 46rem; }

/* Am Schreibtisch stehen Fragen und Ergebnis nebeneinander, und das
   Ergebnis bleibt beim Scrollen stehen.

   Die lineare Fassung allein reichte nicht: Auf einem 786 px hohen Fenster
   stand die Antwort bei 1074 px — man musste scrollen, um zu sehen, was man
   gerade geklickt hat. Genau das war der Auftrag („direkt sehen und
   verstehen"), und untereinander ist er auf breiten Schirmen nicht zu
   erfüllen.

   Der Unterschied zur alten Anordnung ist die Richtung: Vorher standen die
   Fragen RECHTS und die Antwort links — man las also gegen die
   Leserichtung, und bei jedem Klick sprang der Blick zurück. Jetzt sind es
   Fragen links, Antwort rechts. Auf dem Telefon bleibt es untereinander:
   fragen, antworten, kaufen. */
/* Der Seitenkopf des Beraters steht knapper als anderswo.

   Gemessen am 28.8.2026 auf 1600x786: Ankündigung, Kopfzeile und
   Seitenkopf verbrauchten zusammen 553 px — mehr als zwei Drittel des
   Fensters, bevor die erste Frage kam. Das Ergebnis stand dadurch bei
   973 px, also unter der Falz, und der Auftrag lautete „direkt sehen und
   verstehen".

   Anderswo ist das große Polster richtig: Dort ist der Titel der Auftakt
   der Seite. Hier ist er die Frage, auf die zwei Zeilen tiefer geantwortet
   wird — und eine Frage, die eine halbe Bildschirmhöhe Anlauf nimmt, ist
   keine. */
.phead--knapp {
  padding-top: calc(clamp(4.5rem, 8vw, 6.5rem) + var(--announce-h));
  padding-bottom: clamp(1.5rem, 3vw, 2.25rem);
}
.phead--knapp .lead { margin-top: var(--s-3); }

@media (min-width: 900px) {
  .wrap--berater { max-width: 68rem; }
  /* **Zwei Spalten, drei Felder.**

     Der Hinweis ist das dritte Kind und legt sich unter die Fragen —
     sonst stünde er in der Ergebniskarte und machte sie 206 px höher, in
     einer Spalte, die ohnehin schon die längere war.

     `align-items: start` gilt weiter für die Karte; die Fragenspalte
     verteilt ihre zwei Felder über zwei Zeilen, die zweite nimmt den Rest
     (`auto 1fr`), damit der Hinweis nicht am Fragenblock klebt. */
  .berater {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 25rem);
    grid-template-rows: auto 1fr;
    gap: clamp(2rem, 4vw, 3.5rem);
    align-items: start;
  }
  .berater .sizer__form--breit { grid-column: 1; grid-row: 1; }
  .berater .sizer__vorbehalt   { grid-column: 1; grid-row: 2; margin-top: 0; }
  .berater .sizer--linear      { grid-column: 2; grid-row: 1 / -1; }
  .berater .sizer--linear {
    position: sticky;
    /* Derselbe Wert, den der Kaufbereich der Produktseiten benutzt
       (`.pdp__info`) — es ist dieselbe Kopfzeile, unter der es klebt. */
    top: calc(6.5rem + var(--announce-h));
  }
  .berater .sizer__form--breit { margin-bottom: 0; }
  /* Einspaltig steht die Bühne neben der Zahl; in der schmalen rechten
     Spalte wäre beides zu klein. Dort wieder untereinander — und die Zahl
     zuerst.

     Der Grund ist gemessen: Mit der Bühne oben stand die Unze bei 885 px
     auf einem 786 px hohen Fenster, also weiter unter der Falz. Die Zahl
     ist die Antwort; das Bild begleitet sie. In der Vorlesereihenfolge
     bleibt es beim Markup, und das ist richtig so — `.sizer__out` trägt
     `aria-live` und wird ohnehin angesagt, sobald es sich ändert. */
  .berater .sizer__ergebnis { grid-template-columns: 1fr; }
  .berater .sizer__out { order: -1; }
}

.sizer__form--breit {
  gap: var(--s-5);
  margin-bottom: var(--s-6);
}

/* Das Ergebnis ist die Antwort auf die Fragen darüber und steht deshalb
   auf eigener Fläche, nicht als weiterer Abschnitt in derselben. */
.sizer--linear { padding: clamp(1.25rem, 3.5vw, 2.25rem); }
.sizer--linear .sizer__stage { min-height: clamp(9rem, 22vw, 13rem); margin-bottom: 0; }
.sizer--linear .sizer__out { margin-top: 0; padding-top: 0; border-top: 0; }

/* Bühne und Zahl nebeneinander, sobald Platz ist: Die Unze ist das
   Ergebnis, der Handschuh zeigt es. Untereinander wäre die Zahl unter der
   Falz — und dann steht die Antwort außerhalb des Bildes. */
.sizer__ergebnis {
  display: grid;
  gap: var(--s-5);
  align-items: center;
}
@media (min-width: 640px) {
  .sizer__ergebnis { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); }
}

/* Die Feinjustierung. `details` statt eigener Auf-/Zuklapp-Logik: Der
   Browser bringt Tastaturbedienung, Vorlesehilfen-Rolle und den Zustand
   mit, und beim Drucken oder in der Suche des Browsers ist der Inhalt
   auffindbar, auch wenn er zu ist. */
.sizer__fein {
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  padding: var(--s-3) var(--s-4);
}
.sizer__fein summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem var(--s-4);
  cursor: pointer;
  font-family: var(--f-display); font-weight: 600; font-size: 1rem;
  /* Der Marker ist der einzige Hinweis auf Auf und Zu — er bleibt, und
     zwar der eigene des Browsers: nachgebaut wäre er in Safari eine
     zweite Zeichnung neben der echten. */
  padding-block: .35rem;
}
.sizer__fein summary::marker { color: var(--accent-br); }
.sizer__fein-hint {
  font-family: var(--f-mono); font-size: .66rem; font-weight: 400;
  letter-spacing: .05em; color: var(--fg-faint);
}
.sizer__fein[open] summary { margin-bottom: var(--s-4); }
.sizer__fein .frage + .frage { margin-top: var(--s-5); }

/* Die Nummerierung zählt nur die tragenden Fragen. Die beiden im
   Feinbereich sind keine Schritte auf dem Weg, sondern eine Möglichkeit —
   „03" und „04" an ihnen hieße, es seien vier zu beantworten. */
.sizer__fein .frage__nr { display: none; }

/* --- Der Auftakt, Fassung vom 29.9.2026 ---------------------------------
   Der Betreiber: „man liest zu viel … Ich hätte eher, dass … das Paket mit
   Handschuhen und Bandagen, Mundschutz im Mittelpunkt steht. Vielleicht
   einfach etwas größer in der Mitte hinpacken oder links hin." Und der
   Preis „nicht einfach links hingeschrieben, sondern schräg zum Handschuh
   hingepackt".

   Die Regeln stehen hier gesammelt und NACH den älteren Auftaktregeln weiter
   oben: Sie ersetzen deren Anordnung, ohne die Bewegung (Eintritt, Schweben,
   Kippung, Schlag) anzufassen, die dort begründet ist.

   Am Schreibtisch: Ware links und groß, rechts Überschrift, Inhalt, Knopf.
   Auf dem Telefon: Überschrift, Ware mit Aufkleber, Farbwahl, Knopf,
   Inhalt. Absatz und Bewertungszeile gibt es nicht mehr. */
.hero__inner {
  grid-template-areas: 'eyebrow' 'title' 'stage' 'wahl' 'cta' 'inhalt';
}
.hero__kleber { grid-area: preis; }
@media (min-width: 1020px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    /* Zwei leere Zeilen oben und unten nehmen die Höhe der Bühne auf. Ohne
       sie teilen die vier Textzeilen sie unter sich auf, und Überschrift,
       Inhalt und Knopf stehen weit auseinander. */
    grid-template-rows: 1fr auto auto auto auto auto 1fr;
    grid-template-areas:
      'ware .'
      'ware eyebrow'
      'ware title'
      'ware inhalt'
      'ware preis'
      'ware cta'
      'ware .';
    align-content: center;
    column-gap: clamp(2rem, 5vw, 5.5rem);
  }
  .hero__ware { align-self: center; }
  /* Die Textspalte ist schmaler als vorher (rund 45 % statt 60 %), die
     Überschrift deshalb eine Stufe kleiner. Gemessen an „DREI TEILE." */
  .hero__title { font-size: clamp(2.4rem, 4.5vw, 5.1rem); }
  .hero__title { margin-bottom: 0; }
  .hero__cta { margin-top: var(--s-6); }
  /* Die Bühne so groß, wie die Höhe es zulässt. Das Feste darüber und
     darunter (Ankündigung, Kopf, Farbwahl, Polster) sind rund 300 px. */
  .hero__stage {
    width: min(100%, calc(100svh - 300px), 40rem);
    margin-inline: auto;
  }
  /* Das Wasserzeichen wandert mit der Ware nach links: Es gehört hinter
     den Handschuh, nicht hinter den Text. */
  .hero__mark { right: auto; left: -8%; }
  .hero::after {
    background:
      radial-gradient(ellipse 70% 62% at 30% 48%, var(--spot), transparent 68%),
      linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--stage-flat) 62%, transparent) 100%);
  }
}

/* Der Inhalt ersetzt den Absatz. Am Schreibtisch mit etwas mehr Luft, weil
   er die einzige Auskunft zwischen Überschrift und Knopf ist. */
@media (min-width: 1020px) {
  .hero__inhalt { margin-top: var(--s-5); }
  .hero__inhalt .hero__teil { font-size: .9rem; }
}

/* --- Der Anhänger ---------------------------------------------------------
   Fünfte Fassung, 30.9.2026. Die vier davor, verworfen: Aufkleber („wie ein
   Sticker"), Medaille („katastrophal hässlich"), große rote Zahl („wie eine
   Aldi-, Netto-Werbung"), Acrylschild (zu statisch). Der Wunsch: etwas
   Organisches, Lebendiges, das den Blick fängt — aber nicht zu viel, weil
   das Paket daneben schon schwebt.

   Ein Preisetikett aus Karton an einer Schnur, an einem kleinen Haken. Die
   Bewegung folgt dem Leitfaden (7.1, 7.6):
     einmal      Einschwingen beim Laden, gedämpft, 2,6 s — ein Ereignis
     immer       Wiegen ±1°, 7 s je Zyklus — langsamer als das Schweben des
                 Pakets (7 s gegen dessen Takt), also Umgebung, nicht Signal
     auf Anlass  ein Stoß, wenn ein Zeiger vorbeistreicht (Skript, Feder)
   Beim Pendeln dreht sich die Karte leicht um die Schnur (rotateY), so sieht
   man, dass sie im Raum hängt — die Tiefe kommt aus der Bewegung, nicht aus
   einem Effekt.

   Karton statt Acryl: hell in beiden Fassungen, weil Papier Papier bleibt,
   und auf dem Anthrazit der dunklen Fassung gerade dadurch sichtbar. */
.hero__kleber {
  position: relative;
  z-index: 2;
  display: block;
  width: 12.5rem;
  margin-top: var(--s-5);
  /* Platz für Haken und Schnur über der Karte */
  padding-top: 2.1rem;
  perspective: 700px;
}
/* Der Haken: ein kleiner Stift in der Wand, er bewegt sich nicht. */
.hero__kleber::before {
  content: '';
  position: absolute;
  top: 0; left: 50%;
  width: .55rem; height: .55rem;
  margin-left: -.275rem;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #d9d7d2, #6e6c68 70%);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
  z-index: 2;
}
.hero__pendel,
.hero__stoss {
  display: block;
  /* Beide drehen um denselben Punkt: den Haken. Die Karte beginnt 2,1 rem
     darunter, der Drehpunkt liegt also über ihr. */
  transform-origin: 50% -1.85rem;
}
.hero__stoss { will-change: transform; }
/* Die Schnur: vom Haken bis in die Öse, sie hängt an der Karte und dreht
   deshalb mit. */
.hero__preis::before {
  content: '';
  position: absolute;
  left: 50%;
  /* Vom Mittelpunkt des Hakens (2,1 rem Abstand − 0,275 rem Radius über
     der Karte) bis in die Mitte der Öse (0,75 rem + 0,4 rem). Im ersten
     Entwurf endete sie eine Hand breit unter dem Haken. */
  top: -1.825rem;
  height: 2.975rem;
  width: 1px;
  margin-left: -.5px;
  background: linear-gradient(180deg, #8d8a84, #5e5b56);
}
.hero__preis {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: .45rem;
  padding: 2.1rem 1.1rem 1.15rem;
  /* Oben stärker gerundet als unten — die Form eines Anhängers. */
  border-radius: 1.6rem 1.6rem .55rem .55rem;
  color: var(--night);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .5), transparent 30%),
    linear-gradient(170deg, #f6f3ec, #e8e3d8);
  box-shadow:
    inset 0 0 0 1px rgba(23, 22, 26, .08),
    0 1px 1px rgba(23, 22, 26, .12),
    0 12px 22px -8px rgba(23, 22, 26, .28);
}
/* Die Öse: ein Metallring, durch den die Schnur läuft. */
.hero__oese {
  position: absolute;
  top: .75rem; left: 50%;
  width: .8rem; height: .8rem;
  margin-left: -.4rem;
  border-radius: 50%;
  background: radial-gradient(circle, var(--bg) 0 32%, #bdbab3 36%, #8a8781 62%, #d8d5cf 70%, #7c7973 100%);
  box-shadow: 0 1px 1px rgba(0, 0, 0, .25);
}
.hero__preis-kopf,
.hero__preis-fuss {
  font-family: var(--f-mono);
  font-size: .6rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(23, 22, 26, .6);
  white-space: nowrap;
}
/* Das Seil unter dem Kopf: drei Haarlinien, die mittlere rot. */
.hero__preis-kopf {
  padding-bottom: .55rem;
  background:
    linear-gradient(rgba(23, 22, 26, .16), rgba(23, 22, 26, .16)) 0 100% / 100% 1px no-repeat,
    linear-gradient(var(--accent), var(--accent)) 50% calc(100% - 2px) / 1.8rem 1px no-repeat,
    linear-gradient(rgba(23, 22, 26, .16), rgba(23, 22, 26, .16)) 0 calc(100% - 4px) / 100% 1px no-repeat;
}
.hero__preis b {
  font-family: var(--f-display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: 1.9rem;
  letter-spacing: -.01em;
  line-height: 1;
  color: var(--night);
}
.hero__preis s { text-decoration-thickness: 1px; }

/* --- Bewegung ------------------------------------------------------------
   Nur mit Bewegung erlaubt; bei reduzierter Bewegung hängt der Anhänger
   still. Das Wiegen pausiert, wenn der Auftakt aus dem Bild ist (.is-ruht,
   motion.js) — Umgebung, die niemand sieht, muss nicht laufen. */
@media (prefers-reduced-motion: no-preference) {
  .hero__kleber.is-in .hero__pendel {
    animation:
      anhSchwung 2.6s both,
      anhWiegen 7s 2.6s infinite;
  }
  .hero.is-ruht .hero__pendel { animation-play-state: paused; }
  /* Gedämpftes Pendeln: jede Umkehr ease-in-out, jede Auslenkung rund
     halb so groß wie die vorige. */
  @keyframes anhSchwung {
    0%   { transform: rotate(-16deg) rotateY(26deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    24%  { transform: rotate(9deg)   rotateY(-14deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    44%  { transform: rotate(-5deg)  rotateY(8deg);   animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    62%  { transform: rotate(2.6deg) rotateY(-4deg);  animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    80%  { transform: rotate(-1.1deg) rotateY(1.6deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    100% { transform: none; }
  }
  @keyframes anhWiegen {
    0%, 100% { transform: none; animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    25%      { transform: rotate(1deg) rotateY(-3deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
    75%      { transform: rotate(-1deg) rotateY(3deg); animation-timing-function: cubic-bezier(.45, 0, .55, 1); }
  }
}

/* Auf dem Telefon teilt sich der Anhänger das Feld der Bühne und hängt
   links oben neben dem Handschuh — dort ist Platz (gemessen: unten links
   läge er auf einer Bandage). */
@media (max-width: 1019px) {
  .hero__kleber {
    grid-area: stage; align-self: start; justify-self: start;
    width: 7.6rem; margin: 3% 0 0; padding-top: 1.7rem;
  }
  .hero__pendel, .hero__stoss { transform-origin: 50% -1.45rem; }
  .hero__preis::before { top: -1.425rem; height: 2.425rem; }
  .hero__preis { padding: 1.7rem .75rem .85rem; gap: .35rem; border-radius: 1.2rem 1.2rem .45rem .45rem; }
  .hero__oese { top: .6rem; }
  .hero__preis b { font-size: 1.3rem; }
  .hero__preis-kopf, .hero__preis-fuss { font-size: .5rem; letter-spacing: .08em; }
  .hero__cta { margin-top: var(--s-3); }
  .hero__inhalt { margin-top: var(--s-4); }
}

/* --- Was im Paket liegt --------------------------------------------------
   Drei Zeilen mit Haken, gefüllt aus paketInhaltMarkup(). Sie beantworten
   die Frage, die neben jedem Preis steht: wofür genau. */
.hero__inhalt {
  display: block;
  margin-top: var(--s-4);
}

/* --- Der Kaufknopf -------------------------------------------------------
   Eine Nummer größer als der Standardknopf: Er ist die einzige Handlung im
   ersten Bildschirm, und das darf man sehen. Das Druckfeedback (scale) sitzt
   auf .btn und gilt hier mit. */
.btn--gross {
  font-size: 1.02rem;
  padding-block: .95rem;
  padding-inline: 1.6rem;
}

@media (max-width: 30rem) {
  /* Auf dem Telefon nimmt er die volle Breite: Ein Knopf, der die Spalte
     füllt, ist auf Daumenreichweite leichter zu treffen als einer, der sich
     an den Text schmiegt. */
  .btn--gross { width: 100%; justify-content: center; }
}
