/* ==========================================================================
   SCHAKAL SPORTS — Bausteine
   ========================================================================== */

/* --- Schaltflächen ------------------------------------------------------ */
.btn {
  --btn-bg: var(--accent);
  --btn-fg: var(--bone);
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .7rem;
  padding: 1.05rem 1.9rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--f-mono);
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 1;
  overflow: hidden;
  isolation: isolate;
  transition: color var(--t-med) var(--ease);
  border: 1px solid transparent;
  border-radius: var(--r-2);
}
/* Füllung wischt von unten durch.

   **.28s statt .42s** (6.9.2026): Der Knopf ist das häufigste interaktive
   Element der Seite, und 420 ms liegen über dem 300-ms-Budget für UI. Der
   Wischer bleibt als Geste erhalten, er kommt nur schneller an. */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--contrast);
  transform: translateY(101%);
  transition: transform .28s var(--ease-out);
  z-index: -1;
}

.btn svg { width: .95rem; height: .95rem; flex-shrink: 0; }
.btn__arrow { transition: transform var(--t-med) var(--ease-out); }

/* **Nur mit echtem Zeiger.** Auf Touch löst jede Berührung `:hover` aus:
   Der Wischer lief bei jedem Antippen einmal durch, bevor die Navigation
   griff — ein Zucken auf dem Weg zum Produkt.

   Füllung und Textfarbe stehen zusammen in diesem Block, und das ist keine
   Ordnungsliebe: `--on-contrast` ist hell und nur auf der hellen Füllung
   lesbar. Gegatet man nur den Transform, bekäme ein Telefon hellen Text auf
   hellem Grund. Die beiden gehören zusammen oder gar nicht. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover::before { transform: none; }
  .btn:hover { color: var(--on-contrast); }
  .btn:hover .btn__arrow { transform: translateX(.28rem); }
}

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--fg);
  border-color: var(--line-2);
}
.btn--ghost:hover { border-color: var(--contrast); }

.btn--quiet {
  --btn-bg: transparent;
  --btn-fg: var(--fg-mute);
  padding: .5rem 0;
  border: 0;
}
.btn--quiet::before { display: none; }
.btn--quiet:hover { color: var(--accent-br); }

.btn--wide { width: 100%; }
.btn[disabled] { opacity: .38; pointer-events: none; }
/* Der Druck muss ankommen. Ohne diese vier Zeilen fühlt sich jeder Knopf
   der Seite an, als hätte er den Klick nicht bemerkt — die Antwort kommt
   erst, wenn die Seite wechselt. */
.btn:active { transform: scale(.975); }
.btn { transition: color var(--t-med) var(--ease), transform .12s var(--ease-out); }

/* Magnetischer Textlink mit Unterstrich-Aufbau */
.tlink {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--f-mono); font-size: .74rem;
  letter-spacing: .13em; text-transform: uppercase;
  color: var(--fg);
  padding-bottom: .3rem;
  position: relative;
}
.tlink::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--line-2);
}
.tlink::before {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--accent-br);
  transform: scaleX(0); transform-origin: left;
  /* .28s statt .45s — dieselbe Rechnung wie beim Knopf, und Textlinks
     werden noch häufiger gesehen. */
  transition: transform .28s var(--ease-out);
  z-index: 1;
}
.tlink svg { width: .85rem; height: .85rem; transition: transform var(--t-med) var(--ease-out); }

@media (hover: hover) and (pointer: fine) {
  .tlink:hover::before { transform: scaleX(1); }
  .tlink:hover svg { transform: translateX(.25rem); }
}

/* --- Freisteller auf dunklem Grund --------------------------------------
   Die Packshots sind transparent. Auf dem Anthrazit verschwände vor allem
   der schwarze Handschuh, deshalb zwei Mittel aus der Produktfotografie:
   ein weicher Lichtkegel im Grund und eine feine Lichtkante auf der
   Silhouette. Deren Stärke kommt pro Produkt aus --rim — Weiß braucht
   keine, Schwarz die kräftigste.                                         */
/* Jede Stelle, an der ein Freisteller steht — eine Regel, kein Duplikat. */
.card__img--main,
.zubg__frei,
.sizer__glove,
.gew__glove,
.gallery__main img.is-pack,
.gallery__thumb img.is-pack,
.cart-line__img,
.bundle__bild img,
.paket__bild img {
  object-fit: contain;
  filter:
    drop-shadow(0 0 1.5px rgba(237, 233, 227, calc(var(--rim, 0) * var(--rim-mul))))
    drop-shadow(0 var(--pack-y, .85rem) var(--pack-blur, 1.3rem) var(--pack-shadow));
}
/* kleine Kacheln vertragen keinen tiefen Schatten */
.gallery__thumb img.is-pack,
.cart-line__img,
.bundle__bild img {
  --pack-y: .2rem;
  --pack-blur: .45rem;
}
/* Auf dem Telefon gar keinen: Jeder drop-shadow ist ein eigener
   Rasterdurchgang, und auf einer Kachel von 40 px sieht ihn ohnehin
   niemand. Die Lichtkante der dunklen Fassung bleibt — sie trennt den
   schwarzen Handschuh vom Grund und ist deshalb keine Zier. */
@media (hover: none) {
  .gallery__thumb img.is-pack,
  .cart-line__img,
  .bundle__bild img,
  .deal__mini-kachel img {
    filter: drop-shadow(0 0 1.5px rgba(237, 233, 227, calc(var(--rim, 0) * var(--rim-mul))));
  }
  /* Der große Freisteller behält seinen Schatten, aber mit kleinerem Radius:
     Die Kosten eines Weichzeichners wachsen mit dem Quadrat des Radius. */
  .card__img--main { --pack-blur: .7rem; --pack-y: .45rem; }
}

/* --- Produktkarte ------------------------------------------------------- */
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  /* Der Zuschnitt gehört zur Rundung: Das Produktbild füllt die Kachel bis
     an die Kante, ohne ihn stünde es mit rechten Ecken in einer runden
     Karte. Der Schatten beim Anheben liegt außerhalb und bleibt davon
     unberührt. */
  border-radius: var(--r-3);
  overflow: hidden;
  /* Ein Hauch Höhe schon im Ruhezustand. Rahmen UND Schatten ist keine
     Dopplung, sondern die Arbeitsteilung, die eine Auslage von einer
     Tabelle unterscheidet: Der Rahmen zieht die Kante (Datenblatt), der
     Schatten hebt die Fläche vom Grund ab (Ware). Statisch gesetzt kostet
     er auch auf dem Telefon nichts — teuer wird ein Schatten erst, wenn er
     in jedem Bild neu gerechnet werden muss. */
  box-shadow: var(--shadow-s);
  /* Genau benannte Eigenschaften statt `all`: Sonst blendet beim Umschalten
     der Fassung auch der Grund der Karte über — und zwar mit der Dauer,
     die hier für das Anheben gedacht ist. */
  transition:
    border-color .2s var(--ease),
    transform .26s var(--ease-out),
    box-shadow .26s var(--ease-out);
}
/* Angehoben wird nur, wo es einen Zeiger gibt. Auf dem Touchgerät löst
   jede Berührung den Zeigezustand aus, und eine Karte, die beim Antippen
   springt, sieht nach Fehler aus, nicht nach Reaktion. */
@media (hover: hover) and (pointer: fine) {
  .card:hover {
    border-color: var(--line-2);
    transform: translateY(-4px);
    box-shadow: var(--shadow-m);
  }
}
/* Die Akzentkante fährt beim Zeigen über die Oberkante — ein Zug, kein
   Aufblinken: transform statt width, damit er auf der Grafikeinheit
   läuft. */
.card::after {
  content: '';
  position: absolute;
  top: -1px; left: -1px; right: -1px;
  height: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .34s var(--ease-out);
  z-index: 5;
  pointer-events: none;
}
/* Getrennt statt zusammen (6.9.2026): Der Tastaturfokus behält die Kante,
   der Zeiger bekommt sie nur mit echtem Zeiger. Als ein Selektor hätte das
   Gate auch `:focus-within` mitgenommen — und damit der Tastaturbedienung
   ihre Rückmeldung. */
.card:focus-within::after { transform: scaleX(1); }
@media (hover: hover) and (pointer: fine) {
  .card:hover::after { transform: scaleX(1); }
}

/* Der Freisteller steht im Lichtkegel wie auf dem Fototisch, das
   Trainingsfoto darunter ist dunkel. Beim Zeigen kippt die Karte von
   Auslage auf Einsatz — der stärkste Moment im Raster. */
.card__media {
  position: relative;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--surface);
}
/* der Lichtkegel liegt hinter den Bildern und weicht dem Trainingsfoto */
.card__media::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 64% 54% at 50% 46%, var(--spot), transparent 72%);
  transition: opacity .5s var(--ease);
}
/* Der Bildwechsel steht weiter unten geschlossen in einem Hover-Gate —
   Lichtkegel, Hauptbild und Zweitbild gehören zusammen. */

.card__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  transition: opacity .5s var(--ease), transform .8s var(--ease-out);
}
.card__img--main { padding: 9%; }
.card__img--alt {
  opacity: 1;
  /* Politur 29.9.2026: Der Wechsel lief mit dem Hauptbild über .5s. Er ist
     eine Hover-Antwort, die man im Raster Dutzende Male auslöst — unter
     300 ms, sonst hängt das Bild der Hand hinterher. Der langsame Zoom des
     Freistellers darunter bleibt: Er ist Stimmung, keine Antwort. */
  transition: opacity .28s var(--ease), transform .8s var(--ease-out);
}

/* **Der Bildwechsel nur mit echtem Zeiger** (6.9.2026). Auf Touch löste ihn
   jede Berührung aus: Beim Antippen einer Produktkarte blitzte kurz das
   Trainingsfoto auf und verschwand mit der Navigation wieder — auf dem Weg
   zum Kauf die falsche Rückmeldung.

   Die drei Regeln stehen zusammen, weil sie einen Vorgang bilden: Der
   Lichtkegel weicht, das Auslagenbild geht, das Einsatzbild kommt. Einzeln
   gegatet wäre die Karte auf Touch halb umgeschaltet.

   `.card:hover` selbst (das Anheben) hat sein eigenes Gate weiter oben —
   das war schon richtig und bleibt, wo es steht. */
/* **Seit dem 29.9.2026 in der anderen Richtung.** Vorher stand der
   Freisteller und das Motiv kam beim Zeigen. Der Betreiber wollte es
   umgekehrt: Das Motiv (die Ware im Raum) ist das erste Bild, beim Zeigen
   kommt die Detailansicht. Ohne Zeiger bleibt es beim Motiv, auch auf Touch.
   Das Motiv liegt im Markup nach dem Freisteller und deckt ihn deshalb von
   selbst ab; der Lichtkegel darunter gehört zum Freisteller und bleibt. */
@media (hover: hover) and (pointer: fine) {
  .card:hover .card__img--alt { opacity: 0; }
  .card:has(.card__img--alt):hover .card__img--main { transform: scale(1.04); }
}

/* Ein Etikett, das in der Ecke klebt, kann in einer gerundeten Karte nicht
   bleiben — der Zuschnitt schneidet ihm die Ecke ab. Es rückt deshalb ein
   und wird zur Pille: dieselbe Aussage, aber als Marke auf der Fläche statt
   als angeschnittene Fahne. */
.card__flag {
  position: absolute;
  top: var(--s-3); left: var(--s-3);
  padding: .42rem .75rem;
  border-radius: var(--r-voll);
  background: var(--bg);
  color: var(--fg-mute);
  font-family: var(--f-mono);
  font-size: .62rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  line-height: 1;
  z-index: 2;
}
.card__flag--out { background: var(--oxblood); color: var(--bone); }

/* Kaufleiste: fährt beim Zeigen über dem Bild hoch. Liegt über der
   Klickfläche der ganzen Karte, damit die Größe gewinnt, nicht der Link. */
.card__quick {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 4;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: var(--s-4);
  background: linear-gradient(180deg, transparent, var(--glass-2) 34%);
  transform: translateY(100%);
  opacity: 0;
  transition: transform .26s var(--ease-out), opacity .18s var(--ease);
}
.card:hover .card__quick,
.card:focus-within .card__quick { transform: none; opacity: 1; }
/* Ohne Zeiger gibt es kein Zeigen — dort steht die Leiste dauerhaft am
   unteren Bildrand. Absolut bleibt sie: static würde sie im Bildrahmen
   abschneiden, der die Kachel quadratisch hält. */
@media (hover: none) {
  .card__quick { transform: none; opacity: 1; }
}
.card__quick-lab {
  font-family: var(--f-mono); font-size: .6rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--fg-faint);
}
.card__quick-list { display: flex; flex-wrap: wrap; gap: .35rem; }
.card__quick-btn {
  flex: 1 1 auto;
  padding: .55rem .5rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  background: var(--glass);
  font-family: var(--f-mono);
  font-size: .68rem;
  letter-spacing: .06em;
  color: var(--fg);
  line-height: 1;
  white-space: nowrap;
  transition:
    background var(--t-fast) var(--ease),
    border-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),
    transform .12s var(--ease-out);
}
.card__quick-btn:hover { background: var(--accent); border-color: var(--accent); color: var(--bone); }
.card__quick-btn:active { transform: scale(.96); }
.card__quick-btn.is-done { background: var(--ok); border-color: var(--ok); color: var(--on-ok); }

.card__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  flex: 1;
}
.card__kopf { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
/* Verfügbarkeit als Punkt statt als Wort in Signalfarbe */
.card__lager {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--f-mono); font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-faint);
}
.card__lager::before {
  content: ''; width: .35rem; height: .35rem; border-radius: 50%;
  background: var(--ok);
}
.card__lager.is-out::before { background: var(--accent); }

.card__bew {
  display: flex; align-items: center; gap: .45rem;
  font-family: var(--f-mono); font-size: .66rem; letter-spacing: .06em;
  color: var(--fg-faint);
}
.card__bew b { color: var(--fg); font-weight: 500; }
.card__bew .stars svg { width: .72rem; height: .72rem; }
.card__title {
  font-family: var(--f-display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: 1.15rem;
  line-height: 1.1;
  letter-spacing: -.015em;
  text-transform: uppercase;
}
/* Preis links, Größen rechts — und wenn beides nicht nebeneinander passt,
   rutschen die Größen **als Gruppe** in die nächste Zeile.

   Auf 390 px ist die Zeile 134 px breit: Der Preis nimmt 59, der Abstand
   16, für drei Chips bleiben 59 — sie brauchen 84. Ohne die zweite Regel
   brach die Gruppe INNEN um und stand als 2 + 1 da, ein loser Chip unter
   zwei anderen. Mit `nowrap` innen passt die Gruppe nicht mehr neben den
   Preis, `wrap` außen setzt sie geschlossen darunter, und dort hat sie die
   volle Breite.

   Gemessen am 6.9.2026: Die Grenze liegt bei rund 159 px Zeilenbreite.
   390 px und 430 px stapeln, ab 768 px steht wieder alles in einer Zeile —
   ohne dass irgendwo eine Fensterbreite dafür aufgeschrieben werden muss.

   Eine Container-Query wäre der Lehrbuchweg, scheidet hier aber aus:
   `container-type` zieht `contain: layout` nach sich, und damit wäre
   `.card__body` der Bezug für `.card__link::after { inset: 0 }` — die
   klickbare Fläche endete unter dem Produktbild statt es einzuschließen. */
.card__row {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-top: auto;
}
.card__price {
  font-family: var(--f-preis);
  font-size: 1.05rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.card__sizes { display: flex; gap: .3rem; flex-wrap: nowrap; justify-content: flex-end; }
/* Auf dem Telefon **immer** untereinander, nicht nur wenn es eng wird.

   Die Regel darüber stapelt nach Bedarf — und genau das führte im
   Zubehörraster zu zwei Karten nebeneinander mit verschiedenem Aufbau:
   „12,99 €" mit einem einzelnen Chip in derselben Zeile, daneben
   „14,99 €" mit „Junior/Senior" darunter. Beides für sich richtig, zusammen
   unruhig.

   Deshalb hier eine Anordnung für die ganze Größenklasse statt einer
   Entscheidung je Karte. 480 px liegt über jedem Telefon (das breiteste
   meldet 430) und unter jedem Tablet — dort stehen die Karten wieder breit
   genug für eine Zeile. */
@media (max-width: 480px) {
  .card__row { flex-direction: column; align-items: flex-start; }
  .card__sizes { justify-content: flex-start; }
}
.card__sizes span {
  font-family: var(--f-mono); font-size: .6rem; letter-spacing: .06em;
  color: var(--fg-faint); border: 1px solid var(--line-2);
  padding: .2rem .34rem; line-height: 1;
  border-radius: var(--r-1);
}
.card__sizes span.is-out { opacity: .3; text-decoration: line-through; }

/* ganze Karte klickbar, Fokus bleibt am Link */
.card__link::after { content: ''; position: absolute; inset: 0; z-index: 3; }
.card:has(.card__link:focus-visible) { outline: 2px solid var(--accent-br); outline-offset: 3px; }

/* Farbtupfer -------------------------------------------------------------
   Der Rahmen ist bewusst kein Grauton, sondern ein heller Saum: Auf dem
   Anthrazit blieb der schwarze Tupfer sonst unsichtbar — man sah nur den
   Rahmen und musste die Farbe raten. Das ist derselbe Fall wie beim
   Freisteller, und er wird hier mit demselben Mittel gelöst: Was fast so
   dunkel ist wie der Grund, bekommt eine Lichtkante. Der zusätzliche
   Innensaum trennt Fläche und Rahmen, damit der Tupfer als Fläche lesbar
   bleibt und nicht als leeres Kästchen. */
.swatch {
  width: 1.15rem; height: 1.15rem;
  border: 1px solid var(--edge-2);
  border-radius: var(--r-1);
  flex-shrink: 0;
}
.swatch--grau    { background: var(--p-grau); }
.swatch--rot     { background: var(--p-rot); }
.swatch--weiss   { background: var(--p-weiss); }
.swatch--schwarz { background: var(--p-schwarz); }
/* Zubehör hat seit dem 26.8.2026 auch eine Farbwahl: Bandagen zwei,
   Mundschutz vier Ausführungen.

   Die vier Mundschutze sind **zweifarbig** — außen die eine, innen die
   andere. Ein einfarbiger Tupfer könnte „Schwarz/Rot" und „Schwarz/Weiß"
   nicht auseinanderhalten; beide wären schwarz. Deshalb ein Schnitt auf
   der Diagonalen: außen oben links, innen unten rechts, so wie man den
   Gegenstand im Bild sieht. */
.swatch--bandagen       { background: var(--p-schwarz); }
.swatch--bandagen-weiss { background: var(--p-weiss); }

.swatch--mundschutz,
.swatch--mundschutz-grau-schwarz,
.swatch--mundschutz-schwarz-weiss,
.swatch--mundschutz-weiss-schwarz { background: none; }
.swatch--mundschutz {
  background: linear-gradient(135deg, var(--p-schwarz) 50%, var(--p-rot) 50%);
}
.swatch--mundschutz-grau-schwarz {
  background: linear-gradient(135deg, var(--steel) 50%, var(--p-schwarz) 50%);
}
.swatch--mundschutz-schwarz-weiss {
  background: linear-gradient(135deg, var(--p-schwarz) 50%, var(--p-weiss) 50%);
}
.swatch--mundschutz-weiss-schwarz {
  background: linear-gradient(135deg, var(--p-weiss) 50%, var(--p-schwarz) 50%);
}

/* Dunkle und sehr helle Flächen brauchen eine Innenkante, sonst verlieren
   sie sich im Grund der jeweiligen Fassung. */
.swatch--schwarz,
.swatch--weiss,
.swatch--bandagen,
.swatch--bandagen-weiss,
.swatch--mundschutz,
.swatch--mundschutz-grau-schwarz,
.swatch--mundschutz-schwarz-weiss,
.swatch--mundschutz-weiss-schwarz { box-shadow: inset 0 0 0 1px var(--edge); }

/* --- Die Paketgruppe -----------------------------------------------------
   Drei Gegenstände, arrangiert wie auf einer Aufnahme — nicht drei Kacheln
   nebeneinander und nicht zwei Anhängsel unter einem Hauptbild.

   Das ist der Unterschied zwischen „hier sind drei Artikel" und „das ist
   ein Paket": Der Handschuh steht groß und leicht gedreht in der Mitte,
   Bandage und Mundschutz liegen davor und schneiden ihn an. Was einander
   überlappt und nicht auf einer Linie sitzt, liest sich als Gruppe.

   Die Anordnung steht in Prozent der Fläche, nicht in Pixeln: Derselbe
   Baustein trägt die Bühne der Paketseite (rund 600 px) und die Ware im
   Auftakt (rund 450 px, auf dem Telefon 240) — er muss in jeder Größe
   dasselbe Bild ergeben.

   Sobald echte Fotos vorliegen, wechseln nur die Quellen: Die Positionen,
   Drehungen und Größen bleiben, wie sie sind.                            */
.pgruppe {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
}
.pgruppe__teil {
  position: absolute;
  display: block;
}
.pgruppe__teil img {
  width: 100%; height: auto;
  display: block;
  /* Seit dem 26.8.2026 liegen hier echte Freisteller statt Zeichen — und
     zwei davon sind schwarz. Auf dem Anthrazit der dunklen Fassung
     verschwindet ein schwarzer Gegenstand ohne Lichtkante fast ganz;
     dieselbe Regel wie überall sonst, wo ein Packshot steht. Der Schatten
     hebt ihn zusätzlich vom Grund ab, statt ihn schweben zu lassen. */
  filter:
    drop-shadow(0 0 1.5px rgba(237, 233, 227, calc(var(--rim, 0) * var(--rim-mul))))
    drop-shadow(0 .4rem .8rem var(--pack-shadow));
}

/* Der Held. Leicht gegen die Senkrechte gedreht — ein Gegenstand, den
   jemand hingelegt hat, liegt nie ganz gerade. */
.pgruppe__teil--held {
  left: 13%; top: 0;
  width: 74%;
  z-index: 2;
  transform: rotate(-3.5deg);
}
/* Die beiden Zugaben liegen DAVOR, tiefer und nach außen versetzt: So
   entsteht ein Dreieck statt einer Reihe.

   Alles daran ist bewusst ungleich — verschiedene Größen, verschiedene
   Höhen, verschieden starke Drehungen in verschiedene Richtungen. Zwei
   gleich große Objekte auf gleicher Höhe sehen aus wie ein Symbolpaar
   unter einem Bild; zwei ungleiche sehen aus, als hätte sie jemand
   hingelegt. Das ist der ganze Unterschied zwischen Diagramm und
   Aufnahme.

   Und sie bleiben in der Fläche: Ein angeschnittener Gegenstand wirkt
   nicht arrangiert, sondern vergessen. */
/* Die Maße sind am 26.8.2026 gewachsen — auf Ansage des Betreibers: „die
   Bandagen und der Mundschutz sind noch bisschen zu klein im Verhältnis zu
   den Handschuhen."

   Nachgemessen war die Gruppe im Auftakt 448 px breit, die Bandage darin
   95 und der Mundschutz 77 px. Maßstäblich war das richtig: Eine
   Bandagenrolle hat rund ein Siebtel der Länge eines Handschuhs. Nur ist
   eine Produktkomposition kein Größenvergleich — was im Naturmaßstab
   daneben liegt, sieht aus wie Beiwerk, nicht wie Zugabe.

   Beim Mundschutz kommt hinzu, dass sein Freisteller nur die halbe
   Rahmenhöhe füllt (gemessen 49–52 %, gegen 81–86 % bei der Bandage): Die
   Fläche, die er einnimmt, ist also nur halb so groß, wie die Breitenangabe
   vermuten lässt. Deshalb wächst er stärker.

   Die Obergrenze steht im Selbsttest: Der Held muss mehr als doppelt so
   breit bleiben wie jede Zugabe, sonst ist es keine Gruppe mit Hauptsache
   mehr. Bei 74 % zu 33 % ist das gerade eingehalten.                    */
/* Die Ränder sind nachgerechnet, nicht geschätzt: Ein um 14° gedrehtes
   Quadrat braucht 24 % mehr Platz als seine Kantenlänge. Bei `right: 1%`
   ragte die Ecke des Mundschutzes über die Fläche — gemeldet von der
   Prüfung „Alles bleibt in der Fläche", nicht mit dem Auge gefunden. */
.pgruppe__teil--a {
  left: 5%; bottom: 9%;
  width: 33%;
  z-index: 3;
  transform: rotate(-14deg);
}
.pgruppe__teil--b {
  right: 4%; bottom: 15%;
  width: 31%;
  z-index: 3;
  transform: rotate(11deg);
}

/* Solange kein Foto vorliegt, steht dort ein Gegenstand aus Linien: eine
   runde Platte mit dem Zeichen darauf, mit demselben Schatten wie ein
   Freisteller. Sie ist bewusst kein UI-Chip — sie soll im Arrangement wie
   ein Ding liegen, nicht wie eine Beschriftung. Der gestrichelte Rand im
   Warnton sagt trotzdem, was Sache ist: Hier fehlt eine Angabe. */
.pgruppe__zeichen {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  /* Der Ton der Bühne, nicht Papierweiß: Eine weiße Scheibe auf hellem
     Grund ist ein Fleck, der mit der Ware konkurriert — und die Ware ist
     der Handschuh, nicht der Platzhalter. */
  background: var(--stage-flat);
  border: 1px dashed color-mix(in srgb, var(--warn) 55%, transparent);
  color: var(--warn);
  box-shadow: var(--shadow-s);
}
.pgruppe__zeichen svg {
  width: 52%; height: 52%;
  stroke-width: 1.5;
}
/* Der Container der Zugaben trägt selbst nichts — er löst sich auf, damit
   seine Kinder direkt in der Fläche der Gruppe liegen. */
.pgruppe__dazu { display: contents; }

/* Im Auftakt kommen sie nach dem Handschuh dazu.
   Der Ladevorhang schickt einen einzelnen Handschuh auf die Bühne; stünde
   dort im Moment der Landung schon das ganze Arrangement, wäre die
   Übergabe ein Schnitt statt einer Bewegung. So landet erst die Ware, dann
   legt sich das Zubehör dazu — dieselbe Reihenfolge, in der man ein Paket
   packt. */
.js .pgruppe__dazu--spaet > .pgruppe__teil {
  opacity: 0;
  transition: opacity .5s var(--ease), transform .7s var(--ease-back);
}
.js .pgruppe__dazu--spaet > .pgruppe__teil--a {
  transform: rotate(-14deg) translate3d(-14%, 22%, 0) scale(.7);
  transition-delay: .12s;
}
.js .pgruppe__dazu--spaet > .pgruppe__teil--b {
  transform: rotate(11deg) translate3d(16%, 20%, 0) scale(.7);
  transition-delay: .26s;
}
.hero__glove-in.is-in .pgruppe__dazu--spaet > .pgruppe__teil--a { opacity: 1; transform: rotate(-14deg); }
.hero__glove-in.is-in .pgruppe__dazu--spaet > .pgruppe__teil--b { opacity: 1; transform: rotate(11deg); }
@media (prefers-reduced-motion: reduce) {
  .js .pgruppe__dazu--spaet > .pgruppe__teil { opacity: 1; transition: none; }
  .js .pgruppe__dazu--spaet > .pgruppe__teil--a { transform: rotate(-14deg); }
  .js .pgruppe__dazu--spaet > .pgruppe__teil--b { transform: rotate(11deg); }
}

/* --- Jedes Ding schwebt für sich ----------------------------------------
   Bis zum 27.8.2026 trug die Bewegung nur der Container: `heroSchweben` an
   `.hero__glove-float` bewegte Handschuh, Bandage und Mundschutz als einen
   Block. Der Betreiber: „Momentan bewegt sich ja das ganze Element so leicht
   schwebend und glaube würde cleaner aussehen, wenn es sich etwas separat
   bewegt."

   Er hat recht, und der Grund ist derselbe wie bei der Anordnung selbst:
   Drei Gegenstände, die sich im Gleichschritt bewegen, sind ein Gegenstand.
   Erst wenn jeder seine eigene Bahn hat, liest sich die Gruppe als drei
   Dinge, die zusammen liegen.

   **Bewegt wird über `translate` und `rotate`, nicht über `transform`.** Das
   ist keine Stilfrage: Die Lage der Zugaben steht in `transform:
   rotate(-14deg)`, und die Einblendung setzt dort zusätzlich `translate3d`
   und `scale`. Eine Animation auf `transform` gewinnt gegen beide — die
   Zugabe stünde gerade statt gedreht, und der Einflug wäre weg. Die
   Einzeleigenschaften wirken VOR `transform` und lassen es unberührt.

   Die drei Dauern haben keinen gemeinsamen Teiler (7 / 5,6 / 6,4 s), damit
   sich die Bahnen nicht periodisch treffen und die Bewegung nie „einrastet".

   **Die Amplitude muss größer sein als die der Gruppe, nicht kleiner.** Der
   erste Anlauf lag bei 3 bis 4 % der eigenen Größe — nachgemessen änderte
   sich der Abstand zum Handschuh dabei um 1 bis 5 px, während die
   Gruppenbewegung selbst 9 px trägt. Die Eigenbewegung verschwand also in
   der gemeinsamen: sichtbar war weiter ein Block. Jetzt sind es 5 bis 6 %,
   also 8 bis 10 px auf eine 148 px breite Bandage, und der Abstand zum
   Handschuh wandert um mehr als zehn Pixel. Mehr wäre Zappeln: Die Zugaben
   sollen treiben, nicht wackeln.                                          */
.hero__glove-in.is-in .pgruppe__dazu--spaet > .pgruppe__teil--a {
  animation: zugabeTreiben 5.6s var(--ease-loop) 1.8s infinite;
}
.hero__glove-in.is-in .pgruppe__dazu--spaet > .pgruppe__teil--b {
  animation: zugabeTreibenB 6.4s var(--ease-loop) 2.1s infinite;
}
/* Angehalten, sobald der Auftakt aus dem Bild ist — dieselbe Regel wie für
   die Gruppe und das Licht (siehe pages.css, `.hero.is-ruht`). */
.hero.is-ruht .pgruppe__teil { animation-play-state: paused; }

@keyframes zugabeTreiben {
  0%   { translate: 0 0; rotate: 0deg; }
  30%  { translate: -3.4% -6%; rotate: 2deg; }
  60%  { translate: 2.4% 2.8%; rotate: -1.4deg; }
  100% { translate: 0 0; rotate: 0deg; }
}
/* Gegenläufig zur Bandage: Wo die eine steigt, sinkt der andere. Zwei
   gleiche Bahnen mit anderer Dauer wären wieder ein Gleichschritt, nur ein
   langsamer. */
@keyframes zugabeTreibenB {
  0%   { translate: 0 0; rotate: 0deg; }
  35%  { translate: 3.6% 4.4%; rotate: -2.2deg; }
  65%  { translate: -2.2% -4.6%; rotate: 1.5deg; }
  100% { translate: 0 0; rotate: 0deg; }
}

/* Der Wechsel der Ausführung. Die allgemeine `.tausch`-Regel greift hier
   nicht durch: Die Einblendregeln oben tragen vier Klassen und setzen
   `opacity: 1`, das schlägt jedes `.tausch.is-tauscht` mit zwei. Deshalb
   dieselbe Spezifität, und danach im Blatt — sonst wechselt die Zugabe hart
   ihr Bild, während der Handschuh daneben weich übergeht. */
.hero__glove-in.is-in .pgruppe__dazu > .pgruppe__teil.is-tauscht,
.pgruppe__dazu > .pgruppe__teil.is-tauscht {
  opacity: .35;
  filter: blur(4px);
}

/* Auf sehr kleinen Flächen (Auftakt auf dem Telefon) wachsen die Zugaben
   anteilig mit — aber ihr Zeichen darf nicht unter die Erkennbarkeit
   fallen. Unter 260 px Gruppenbreite tragen sie deshalb keinen Rand mehr,
   sondern nur noch die Form. */
@container (max-width: 260px) {
  .pgruppe__zeichen { border-style: solid; border-color: var(--line); }
  .pgruppe__zeichen svg { width: 54%; height: 54%; }
}

/* --- Paket-Streifen -----------------------------------------------------
   Drei Teile, eine offene Rechnung. Kein Rabattschild, sondern dieselbe
   Datenblatt-Logik wie überall: links was drin ist, rechts was es kostet. */
.bundle {
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  background: var(--surface);
  padding: clamp(1.35rem, 4vw, 2.75rem);
  display: grid;
  gap: var(--s-6);
}
@media (min-width: 900px) {
  .bundle:not(.bundle--kompakt) {
    grid-template-columns: minmax(0, 1fr) 19rem;
    column-gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
  .bundle:not(.bundle--kompakt) .bundle__head { grid-column: 1 / -1; }
}
.bundle__head { display: flex; flex-direction: column; gap: var(--s-3); }
.bundle__head .lead { max-width: 54ch; }

.bundle__teile { border-top: 1px solid var(--line); }
.bundle__teil {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 1fr) auto;
  gap: var(--s-4);
  align-items: center;
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--line);
}
.bundle__bild {
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--stage);
}
.bundle__bild img { width: 100%; height: 100%; padding: 8%; }
.bundle__txt { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.bundle__txt b { font-weight: 500; font-size: .96rem; line-height: 1.3; }
.bundle__ep {
  font-family: var(--f-mono); font-size: .82rem;
  color: var(--fg-faint); font-variant-numeric: tabular-nums;
}

.bundle__rechnung {
  border: 1px solid var(--line-2);
  border-radius: var(--r-3);
  padding: var(--s-5);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.bundle__zeile {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-4);
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  color: var(--fg-mute);
}
.bundle__zeile s { color: var(--fg-faint); }
.bundle__zeile--gross strong {
  font-family: var(--f-preis);
  font-size: 1.6rem; font-weight: 600; letter-spacing: -.02em; color: var(--fg);
}
.bundle__spar {
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent-br);
  padding-top: var(--s-3); border-top: 1px solid var(--line);
}
.bundle__rechnung .btn { margin-top: var(--s-2); }

/* --- Angebots-Aufmacher -------------------------------------------------
   Das Paket als erstes Handlungsangebot der Startseite. Bebildert und mit
   offener Rechnung, aber ohne Rabattschild: die Ersparnis steht als Zahl da,
   nicht als Signalfläche.                                                  */
.deal {
  display: grid;
  gap: var(--s-6);
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  background: var(--surface);
  overflow: hidden;
}
@media (min-width: 940px) {
  .deal { grid-template-columns: minmax(0, .92fr) minmax(0, 1fr); gap: 0; align-items: stretch; }
}

.deal__media {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-4);
  padding: clamp(1.5rem, 4vw, 2.75rem);
  background: var(--stage);
  border-bottom: 1px solid var(--line);
}
@media (min-width: 940px) {
  .deal__media { border-bottom: 0; border-right: 1px solid var(--line); }
}
.deal__gross {
  width: 100%;
  max-height: clamp(13rem, 26vw, 20rem);
  object-fit: contain;
  filter:
    drop-shadow(0 0 1.5px rgba(237, 233, 227, calc(var(--rim, 0) * var(--rim-mul))))
    drop-shadow(0 1rem 1.6rem var(--pack-shadow));
}
.deal__spar {
  position: absolute;
  top: var(--s-4); left: var(--s-4);
  padding: .5rem .85rem;
  border-radius: var(--r-voll);
  background: var(--accent);
  color: var(--bone);
  font-family: var(--f-mono);
  font-size: .66rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  line-height: 1;
  z-index: 2;
}
.deal__mini { display: flex; gap: var(--s-3); justify-content: center; }
.deal__mini-kachel {
  width: clamp(3.4rem, 7vw, 4.6rem);
  aspect-ratio: 1;
  border: 1px solid var(--line);
  border-radius: var(--r-2);
  background: var(--surface);
}
.deal__mini-kachel img { width: 100%; height: 100%; object-fit: contain; padding: 8%; }

.deal__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  align-items: flex-start;
  padding: clamp(1.5rem, 4vw, 2.75rem);
}
.deal__body .lead { max-width: 46ch; }

.deal__liste {
  width: 100%;
  border-top: 1px solid var(--line);
  margin-top: var(--s-2);
}
.deal__liste li {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr) auto;
  gap: var(--s-3);
  align-items: baseline;
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--line);
}
.deal__nr {
  font-family: var(--f-mono); font-size: .68rem;
  color: var(--fg-faint); letter-spacing: .1em;
}
.deal__was { display: flex; flex-direction: column; gap: .28rem; min-width: 0; }
.deal__was b { font-weight: 500; font-size: .98rem; line-height: 1.3; }
.deal__ep {
  font-family: var(--f-mono); font-size: .82rem;
  color: var(--fg-faint); font-variant-numeric: tabular-nums;
}

.deal__preis {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-4);
  width: 100%;
  padding-top: var(--s-2);
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
}
.deal__preis strong {
  font-family: var(--f-preis);
  font-size: clamp(1.9rem, 3.4vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -.025em;
  line-height: 1;
  order: -1;
}
.deal__alt { font-size: .74rem; letter-spacing: .08em; color: var(--fg-faint); text-transform: uppercase; }
.deal__alt s { color: var(--fg-mute); }
.deal__spar-txt {
  font-size: .68rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent-br);
}

.deal__cta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s-4);
  margin-top: var(--s-3);
}
.deal__note {
  font-family: var(--f-mono); font-size: .66rem;
  letter-spacing: .08em; color: var(--fg-faint);
}

/* --- Spezifikationsliste (Datenblatt) -----------------------------------
   Zwei Spalten: Bezeichnung links, Wert rechts. Das ist die Datenblatt-Logik
   der ganzen Website.

   **Ab hier nur noch, wenn Platz dafür ist** (6.9.2026). Im Größenberater
   steht dieselbe Liste in der klebenden rechten Spalte, und die ist auf
   23 rem begrenzt. Dort blieben für den Wert rund 140 px — „Sack und
   allgemeines Training bleiben bei der Grundstufe" fiel damit auf fünf
   Zeilen und die Zeile wurde 183 px hoch. Der Betreiber sah das als Text,
   der senkrecht heruntertropft.

   `container-type: inline-size` misst den Platz, den die Liste **tatsächlich
   hat** — nicht die Fensterbreite. Eine Medienabfrage hätte hier nichts
   geholfen: Das Fenster ist 1600 px breit, die Spalte trotzdem schmal. */
.spec {
  border-top: 1px solid var(--line);
  container-type: inline-size;
}
.spec__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-2);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--line);
}
/* Nebeneinander erst, wenn der Wert davon etwas hat. 26rem ist gemessen:
   Darunter bleiben für den Wert weniger als 200 px, und ab da bricht der
   längste Eintrag der Liste auf mehr als zwei Zeilen. */
@container (min-width: 26rem) {
  .spec__row {
    grid-template-columns: minmax(7rem, 12rem) 1fr;
    gap: var(--s-4);
    align-items: baseline;
  }
}
.spec__key {
  font-family: var(--f-mono);
  font-size: .7rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fg-faint);
}
.spec__val { color: var(--fg-mute); font-size: .95rem; }
.spec__val strong { color: var(--fg); font-weight: 500; }

/* --- Kennzahl ----------------------------------------------------------- */
.stat { display: flex; flex-direction: column; gap: var(--s-2); }
.stat__num {
  font-family: var(--f-display);
  font-weight: 800;
  font-stretch: 115%;
  font-size: clamp(2.4rem, 5vw, 3.8rem);
  line-height: .9;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.stat__num sup { font-size: .38em; vertical-align: super; color: var(--accent-br); letter-spacing: 0; }
.stat__cap { font-family: var(--f-mono); font-size: .68rem; letter-spacing: .13em; text-transform: uppercase; color: var(--fg-faint); }

/* --- Das Seil, nicht mehr als Trenner (1.10.2026) -----------------------
   Bis hierhin stand über jedem Abschnittskopf und über dem Zubehör ein Seil:
   drei Haarlinien, die mittlere rot. Rund 90 Mal auf 24 Seiten. Der
   Betreiber: „gefühlt überall, und das wirkt billig und nach einfach copy
   paste, ohne nachgedacht."

   Er hat recht. Ein Zeichen, das an jeder Kante steht, sagt an keiner mehr
   etwas — es war Gliederung, nicht Marke. Abschnitte trennt jetzt der
   Weißraum (padding der .section) und das Label links. Das Seil bleibt dort,
   wo es etwas bedeutet: einmal auf der Seite, auf dem Preisetikett im
   Auftakt (pages.css, „Der Anhänger") — am Angebot. */

/* --- Laufband (einmal, ruhig) ------------------------------------------ */
.marquee {
  --mq-speed: 42s;
  overflow: hidden;
  border-radius: var(--r-3);
  border-block: 1px solid var(--line);
  padding-block: var(--s-5);
  background: var(--surface);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

/* --- Bahn: das Foto in voller Breite ------------------------------------
   Die helle Seite braucht einen dunklen Anker, sonst liest sie sich über
   sieben Abschnitte als eine einzige Fläche. Die Bahn ist dieser Anker:
   dunkel in BEIDEN Fassungen, weil ein Foto aus einer abgedunkelten Halle
   nichts gewinnt, wenn man es aufhellt. Darüber läuft die Schrift — einmal
   voll, einmal als Kontur, in Gegenrichtung. */
/* Von Rand zu Rand — aber nicht bis in die Ecken. Auf breiten Bildschirmen
   rückt die Bahn um den halben Gutter ein und bekommt die größte Rundung
   der Website. Das ist der einzige Ort, an dem sie so groß sein darf: Eine
   Fläche über 1400 px braucht mehr Radius als eine Karte über 320, sonst
   sieht dieselbe Zahl an ihr aus wie ein Bearbeitungsfehler.

   Auf dem Handy bleibt sie randlos. Dort ist der Gutter die Hälfte der
   verfügbaren Ruhe, und eine eingerückte Bahn nähme dem Foto genau die
   Breite, für die es da ist. */
.band {
  position: relative;
  overflow: hidden;
  background: var(--night);
  isolation: isolate;
}
@media (min-width: 760px) {
  .band {
    border-radius: var(--r-5);
    margin-inline: calc(var(--gutter) * .5);
  }
}

/* --- Tiefe auch auf dem Telefon -----------------------------------------
   initParallax() steigt unter 900 px aus, und das aus gutem Grund: Der Takt
   liest Geometrie und schreibt danach Stile, und ein zweiter solcher Takt
   neben der Gewichtstafel zwingt den Browser in jedem Scrollbild zum
   erneuten Layout-Aufbau. Auf einem Telefon ist genau das der Ruckler.

   Eine Scroll-Zeitachse in CSS hat dieses Problem nicht: Sie wird einmal
   angelegt und läuft danach auf dem Compositor mit — kein Skript, keine
   Messung, kein Layout. Damit bekommt die schmale Fassung die Tiefe, die
   ihr bisher fehlte, ohne dafür zu zahlen.

   `@supports` ist keine Höflichkeit: Wo die Zeitachse fehlt, bleibt das
   Bild stehen, wie es ohnehin stand. Und wo initParallax() läuft (ab
   900 px), darf sie NICHT greifen — zwei Quellen auf demselben transform
   überschreiben einander in jedem Bild. */
@supports (animation-timeline: view()) {
  @media (max-width: 899px) {
    .band__bg img {
      animation: bandTiefe linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    @keyframes bandTiefe {
      from { transform: translate3d(0, -6%, 0) scale(1.2); }
      to   { transform: translate3d(0, 6%, 0) scale(1.2); }
    }
  }
}
.band__bg { position: absolute; inset: 0; z-index: 0; }
.band__bg img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 38%;
  filter: saturate(.6) contrast(1.08) brightness(.5);
  /* Den laufenden Wert schreibt initParallax() direkt hierher; hier steht
     nur der Zustand, mit dem das Bild ohne Skript dasteht. */
  transform: translate3d(0, 0, 0) scale(1.2);
  will-change: transform;
}
.band::after {
  content: '';
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(12,11,14,.55), rgba(12,11,14,.2) 50%, rgba(12,11,14,.6));
}
.band__inhalt {
  position: relative; z-index: 2;
  padding-block: clamp(4.5rem, 11vw, 8.5rem);
  display: flex;
  flex-direction: column;
  gap: clamp(.5rem, 1.4vw, 1.1rem);
}
/* Auf der Bahn liegt keine Fläche und keine Kante — das Foto trägt sie */
.band .marquee {
  border: 0;
  background: none;
  padding-block: 0;
}
.band .marquee__item { color: var(--bone); }
.marquee__track {
  display: flex;
  width: max-content;
  gap: var(--s-7);
  animation: mqScroll var(--mq-speed) linear infinite;
  animation-play-state: var(--mq-state, running);
}
.marquee__item {
  display: flex; align-items: center; gap: var(--s-7);
  font-family: var(--f-display);
  font-weight: 700;
  font-stretch: 108%;
  font-size: clamp(1.1rem, 2.1vw, 1.7rem);
  text-transform: uppercase;
  letter-spacing: -.01em;
  color: var(--fg-mute);
  white-space: nowrap;
}
.marquee__item::after {
  content: '';
  width: .42rem; height: .42rem;
  background: var(--accent);
  transform: rotate(45deg);
  flex-shrink: 0;
}
@keyframes mqScroll { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee__track { animation: none; } }

/* --- Formulare ---------------------------------------------------------- */
.field { position: relative; display: flex; flex-direction: column; }
.field input,
.field textarea,
.field select {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line-2);
  padding: 1.55rem 0 .65rem;
  font-size: 1rem;
  color: var(--fg);
  transition: border-color var(--t-med) var(--ease);
  border-radius: 0;
}
.field textarea { resize: vertical; min-height: 6.5rem; }
.field label {
  position: absolute;
  top: 1.5rem; left: 0;
  font-family: var(--f-mono);
  font-size: .8rem;
  letter-spacing: .08em;
  color: var(--fg-faint);
  pointer-events: none;
  transform-origin: left top;
  transition: transform var(--t-med) var(--ease-out), color var(--t-med) var(--ease);
}
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-1.45rem) scale(.78);
  color: var(--accent-br);
}
.field input:focus, .field textarea:focus { outline: 0; border-bottom-color: var(--accent-br); }
.field__req { color: var(--accent-br); }
.field__err {
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .06em;
  color: var(--accent-br); margin-top: .5rem;
  max-height: 0; overflow: hidden; opacity: 0;
  transition: max-height var(--t-med) var(--ease), opacity var(--t-med) var(--ease);
}
.field.is-bad .field__err { max-height: 3rem; opacity: 1; }
.field.is-bad input, .field.is-bad textarea { border-bottom-color: var(--accent); }

/* Newsletter-Zeile */
.inline-form { display: flex; gap: var(--s-3); align-items: flex-end; flex-wrap: wrap; }
.inline-form .field { flex: 1 1 15rem; }

/* Erfolgsmeldung */
.form-done {
  display: none;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5);
  border: 1px solid var(--ok);
  border-radius: var(--r-3);
  background: color-mix(in srgb, var(--ok) 10%, transparent);
}
.form-done.is-on { display: flex; animation: doneIn .55s var(--ease-out); }
@keyframes doneIn { from { opacity: 0; transform: translateY(10px); } }
.form-done svg { width: 1.5rem; height: 1.5rem; color: var(--ok); flex-shrink: 0; }

/* --- Aufklappbereich ---------------------------------------------------- */
.acc { border-top: 1px solid var(--line); }
.acc__item { border-bottom: 1px solid var(--line); }
.acc__btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding-block: var(--s-5);
  text-align: left;
  font-family: var(--f-display);
  font-weight: 600;
  font-stretch: 105%;
  font-size: 1.08rem;
  letter-spacing: -.01em;
  color: var(--fg);
  transition: color var(--t-fast) var(--ease);
}
.acc__btn:hover { color: var(--accent-br); }
.acc__sign { position: relative; width: .8rem; height: .8rem; flex-shrink: 0; }
.acc__sign::before, .acc__sign::after {
  content: ''; position: absolute; inset: 0; margin: auto;
  background: currentColor;
}
.acc__sign::before { width: 100%; height: 1px; }
.acc__sign::after  { width: 1px; height: 100%; transition: transform var(--t-med) var(--ease-out); }
.acc__item.is-open .acc__sign::after { transform: scaleY(0); }
/* Aufklappen ist die häufigste Handlung, die diese Seite auf einem Handy
   überhaupt anbietet — die Fragenliste hat zwölf Einträge. Entsprechend
   kurz: 420 ms waren für eine Antwort auf einen Tipp zu lang.

   Die Höhe selbst lässt sich nicht auf der Grafikeinheit bewegen, dafür
   gibt es keinen Weg (0fr → 1fr ist der sauberste, den CSS kennt). Was
   sich bewegen lässt, ist der Text darin: Er kommt mit Deckkraft und einem
   kleinen Weg nach, und das ist der Teil, den man tatsächlich ansieht. */
.acc__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .32s var(--ease-out);
}
.acc__item.is-open .acc__panel { grid-template-rows: 1fr; }
.acc__panel > div { overflow: hidden; }
.acc__panel p {
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .2s var(--ease), transform .28s var(--ease-out);
}
.acc__item.is-open .acc__panel p {
  opacity: 1; transform: none;
  transition-delay: .08s;
}
.acc__panel p { padding-bottom: var(--s-5); color: var(--fg-mute); max-width: 62ch; }

/* --- Bewertungssterne --------------------------------------------------- */
.stars { display: inline-flex; gap: .12rem; }
.stars svg { width: .85rem; height: .85rem; fill: var(--accent-br); }

/* --- Hinweis-Marker (Platzhalter-Inhalte) ------------------------------- */
.ph {
  display: inline-block;
  border-radius: var(--r-1);
  font-family: var(--f-mono);
  font-size: .58rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--warn);
  border: 1px dashed var(--warn);
  padding: .16rem .38rem;
  line-height: 1;
  vertical-align: middle;
  opacity: .85;
}

/* --- Angebotszeile am Kaufbereich --------------------------------------- */
.upsell {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--line-2);
  border-left: 2px solid var(--accent);
  border-radius: var(--r-2);
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.upsell:hover { background: color-mix(in srgb, var(--accent) 14%, transparent); border-color: var(--accent); border-left-color: var(--accent); }
.upsell__txt { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.upsell__txt b { font-size: .9rem; font-weight: 500; line-height: 1.3; }
.upsell__txt span { font-family: var(--f-mono); font-size: .66rem; letter-spacing: .05em; color: var(--fg-mute); }
.upsell__spar {
  flex-shrink: 0;
  font-family: var(--f-mono); font-size: .8rem; font-weight: 500;
  color: var(--accent-br); font-variant-numeric: tabular-nums;
}

/* --- Feste Kaufleiste (schmale Geräte) ---------------------------------- */
.buybar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 88;
  display: none;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-3) var(--gutter);
  background: var(--glass-2);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
  border-radius: var(--r-4) var(--r-4) 0 0;
  transform: translateY(100%);
  transition: transform .38s var(--ease-out);
}
@media (max-width: 979px) { .buybar { display: flex; } }
.buybar.is-on { transform: none; }
.buybar__info { display: flex; flex-direction: column; gap: .2rem; }
.buybar__info b {
  font-family: var(--f-preis); font-size: 1.1rem; font-weight: 600;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.buybar .btn { padding: .9rem 1.4rem; }

/* --- Formular zum Abschreiben (Muster-Widerruf) ------------------------- */
/* Ausfülllinien als Rahmen statt als Unterstrichkette: die bricht auf
   schmalen Geräten nicht um und schiebt die Seite seitlich auf. */
.formular {
  margin-top: var(--s-5);
  font-family: var(--f-mono);
  font-size: .86rem;
  line-height: 1.75;
  color: var(--fg-mute);
}
.formular p + p { margin-top: var(--s-4); }
.formular__linie {
  display: block;
  height: 1px;
  width: 100%;
  max-width: 32rem;
  background: var(--line-2);
  margin: .9rem 0;
}
.formular__linie--kurz { max-width: 16rem; }
.formular__fuss { color: var(--fg-faint); font-size: .9em; margin-top: var(--s-5); }

/* --- Overlay-Karte ------------------------------------------------------ */
.modal {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: grid;
  place-items: center;
  padding: var(--s-4);
  background: var(--scrim);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  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 die Karte
   unsichtbar über der ganzen Seite und schluckt jeden Klick. */
.modal[hidden] { display: none; }
/* Zweite Sicherung für den Moment zwischen hidden=false und is-on */
.modal:not(.is-on) { pointer-events: none; }
.modal.is-on { opacity: 1; pointer-events: auto; }
.modal__karte {
  width: min(38rem, 100%);
  max-height: min(86svh, 44rem);
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  padding: clamp(1.25rem, 3.5vw, 2.25rem);
  transform: translateY(12px);
  transition: transform .32s var(--ease-out);
}
.modal.is-on .modal__karte { transform: none; }
.modal__kopf {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); margin-bottom: var(--s-4);
}
.modal__fuss {
  font-family: var(--f-mono); font-size: .68rem;
  letter-spacing: .05em; color: var(--fg-faint);
  line-height: 1.6; margin-block: var(--s-4) var(--s-5);
}
@media (prefers-reduced-motion: reduce) {
  .modal, .modal__karte { transition: none; }
}

/* --- Bewertungen -------------------------------------------------------- */
.bewertung { display: grid; gap: var(--s-6); }
@media (min-width: 860px) {
  .bewertung { grid-template-columns: 15rem minmax(0, 1fr); gap: clamp(2rem, 4vw, 3.5rem); }
}
.bewertung__note {
  display: flex; flex-direction: column; gap: .5rem; align-items: flex-start;
  padding-right: var(--s-5);
}
.bewertung__zahl {
  display: flex; align-items: baseline; gap: .15rem;
  font-family: var(--f-display); font-weight: 800; font-stretch: 115%;
  font-size: clamp(3rem, 6vw, 4rem); line-height: .9; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.bewertung__zahl span { font-size: .3em; color: var(--fg-mute); letter-spacing: 0; }
.bewertung__note .stars svg { width: .95rem; height: .95rem; }
.bewertung__quelle {
  font-family: var(--f-mono); font-size: .62rem;
  letter-spacing: .05em; color: var(--fg-faint); line-height: 1.5;
}
.bewertung__zahl--leer { color: var(--fg-faint); }
.bewertung__inhalt { display: flex; flex-direction: column; gap: var(--s-5); min-width: 0; }
/* Die nicht vergebenen Sterne stehen als leere Form da, nicht als Lücke:
   „3 von 5" liest man erst, wenn man sieht, wovon. */
.stars__leer { display: inline-flex; gap: .12rem; opacity: .26; }

/* --- Selbst bewerten -----------------------------------------------------
   Bis zum 16.8.2026 gab es hier nur eine Note zum Ansehen. Ein Shop, in dem
   man nicht bewerten kann, sammelt auch keine Bewertungen — und die
   Gesamtnote, die oben steht, bliebe für immer die einzige Zahl.        */
.bew-form {
  padding-top: var(--s-5);
  border-top: 1px solid var(--line);
  display: flex; flex-direction: column; gap: var(--s-4);
}
.bew-form__feld { display: flex; flex-direction: column; gap: var(--s-5); align-items: flex-start; }
.bew-form__feld .field { width: 100%; max-width: 34rem; }
.bew-form__weg {
  font-family: var(--f-mono); font-size: .68rem; line-height: 1.6;
  letter-spacing: .04em; color: var(--fg-faint); max-width: 52ch;
}
.bew-form .form-done { margin-top: var(--s-2); }
.bew-form .form-done p { font-size: .92rem; line-height: 1.5; color: var(--fg-mute); }

/* Der Sternewähler.
   Fünf Radios, im Markup RÜCKWÄRTS (5 → 1) und visuell umgedreht. Nur so
   lässt sich „bis hierher gefüllt" ohne eine Zeile Skript ausdrücken: Die
   Geschwisterauswahl kennt nur das, was NACH einem Element kommt, und das
   sind hier die kleineren Werte. */
.bew-sterne { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.bew-sterne__legende {
  padding: 0;
  font-family: var(--f-mono); font-size: .7rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--fg-faint);
}
.bew-sterne__reihe {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: .25rem;
}
.bew-stern {
  display: grid; place-items: center;
  width: 2.6rem; height: 2.6rem;
  border-radius: var(--r-2);
  color: var(--line-2);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease), transform .12s var(--ease-out), background var(--t-fast) var(--ease);
}
.bew-stern svg { width: 1.5rem; height: 1.5rem; fill: currentColor; }
/* Gewählt: dieser Stern und alle kleineren. Im Markup stehen die kleineren
   dahinter, deshalb der Geschwister-Kombinator. */
.bew-sterne__reihe input:checked ~ .bew-stern { color: var(--accent); }
@media (hover: hover) and (pointer: fine) {
  .bew-sterne__reihe .bew-stern:hover,
  .bew-sterne__reihe .bew-stern:hover ~ .bew-stern { color: var(--accent-br); }
  .bew-stern:hover { transform: scale(1.12); }
}
.bew-stern:active { transform: scale(.9); }
/* Die Tastaturbedienung darf nicht unsichtbar sein: Das Radio selbst ist
   versteckt, also trägt sein Label den Fokusring. */
.bew-sterne__reihe input:focus-visible + .bew-stern {
  outline: 2px solid var(--accent-br);
  outline-offset: 2px;
}
.bew-sterne__wert {
  font-family: var(--f-mono); font-size: .72rem;
  letter-spacing: .06em; color: var(--fg-mute);
}
.bew-sterne__reihe.is-bad ~ .bew-sterne__wert,
.bew-sterne.is-bad .bew-sterne__wert { color: var(--accent-br); }
.bew-sterne__reihe.is-bad .bew-stern { color: color-mix(in srgb, var(--accent) 45%, var(--line-2)); }

/* --- Was schon geschrieben wurde ---------------------------------------- */
.bew-liste { display: flex; flex-direction: column; gap: var(--s-4); }
.bew-eintrag {
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
  background: var(--surface);
  display: flex; flex-direction: column; gap: .5rem;
}
.bew-eintrag__kopf { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem var(--s-3); }
.bew-eintrag__note,
.bew-eintrag__datum {
  font-family: var(--f-mono); font-size: .66rem;
  letter-spacing: .07em; color: var(--fg-faint);
}
.bew-eintrag__datum { margin-left: auto; }
.bew-eintrag__titel { font-size: 1.02rem; font-stretch: 105%; letter-spacing: -.01em; }
.bew-eintrag__text { color: var(--fg-mute); font-size: .95rem; line-height: 1.6; white-space: pre-line; }
.bew-eintrag__wer {
  font-family: var(--f-mono); font-size: .66rem;
  letter-spacing: .07em; color: var(--fg-faint);
}
/* Der Status ist keine Nebensache: Er ist der Unterschied zwischen „steht
   im Shop" und „liegt in deinem Browser". */
.bew-eintrag__status { color: var(--warn); }

/* --- Hinweisblock (Angaben stehen noch aus) ----------------------------- */
/* Größere Schwester des .ph-Markers: dort, wo nicht ein Wert fehlt,
   sondern ein ganzes Datenblatt. */
.hinweis {
  display: flex;
  gap: var(--s-4);
  align-items: flex-start;
  padding: var(--s-5);
  border: 1px dashed var(--warn);
  border-radius: var(--r-3);
  background: color-mix(in srgb, var(--warn) 8%, transparent);
}
.hinweis svg {
  width: 1.15rem; height: 1.15rem;
  color: var(--warn); flex-shrink: 0;
  stroke-width: 1.6; margin-top: .12rem;
}
.hinweis p { font-size: .89rem; line-height: 1.55; color: var(--fg-mute); max-width: 62ch; }
.hinweis b {
  display: block;
  font-family: var(--f-mono); font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--warn); font-weight: 500;
  margin-bottom: .4rem;
}

/* Die laute Fassung — für Hinweise, die zur Entscheidung gehören und
   deshalb gelesen werden müssen. Der gestrichelte Warnrahmen oben heißt in
   diesem Projekt „Angabe fehlt noch"; das trifft hier nicht zu. Also
   durchgezogene Kante, Akzentfarbe und ein Balken, der die Ecke hält. */
.hinweis--stark {
  border: 1px solid var(--accent);
  border-left-width: 3px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  padding: clamp(1.1rem, 2.5vw, 1.6rem);
}
.hinweis--stark svg { color: var(--accent-br); width: 1.3rem; height: 1.3rem; }
.hinweis--stark b { color: var(--accent-br); font-size: .74rem; letter-spacing: .16em; }
.hinweis--stark a { color: var(--accent-br); text-decoration: underline; text-underline-offset: .18em; }

/* --- Sparhinweis nach dem Hinzufügen ------------------------------------
   Ein Streifen, kein Dialog: Er nimmt keinen Fokus, sperrt nichts und geht
   von selbst wieder weg. Erscheint höchstens einmal je Sitzung — die
   Bedingungen stehen bei sparHinweis() in shop.js. */
.sparhint {
  position: fixed;
  z-index: 95;
  right: var(--s-4);
  bottom: var(--s-4);
  left: var(--s-4);
  max-width: 23rem;
  margin-left: auto;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5) var(--s-5) var(--s-4);
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-top: 2px solid var(--accent);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-l);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .34s var(--ease), transform .38s var(--ease-out);
}
.sparhint.is-on { opacity: 1; transform: none; }
/* Auf schmalen Geräten liegt auf Produktseiten die feste Kaufleiste unten */
@media (max-width: 979px) { .sparhint { bottom: 5.4rem; } }

.sparhint__zu {
  position: absolute; top: .4rem; right: .4rem;
  width: 2rem; height: 2rem;
  display: grid; place-items: center;
  color: var(--fg-faint);
  transition: color var(--t-fast) var(--ease);
}
.sparhint__zu:hover { color: var(--fg); }
.sparhint__zu svg { width: .9rem; height: .9rem; }

.sparhint__zeile { display: flex; align-items: center; gap: var(--s-4); }
.sparhint__bilder { display: flex; flex-shrink: 0; }
.sparhint__bilder img {
  width: 2.6rem; height: 2.6rem; object-fit: contain;
  background: var(--line);
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  padding: .2rem;
  filter: drop-shadow(0 0 1px rgba(237, 233, 227, calc(var(--rim, 0) * var(--rim-mul) * .9)));
}
.sparhint__bilder img + img { margin-left: -.55rem; }
.sparhint__txt { font-size: .86rem; line-height: 1.5; color: var(--fg-mute); }
.sparhint__txt b { color: var(--fg); font-weight: 500; }

.sparhint__cta {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
}
.sparhint__cta .btn { padding: .8rem 1.05rem; font-size: .7rem; }
.sparhint__cta .btn b { font-weight: 500; opacity: .8; }

@media (prefers-reduced-motion: reduce) {
  .sparhint { transition: opacity .2s linear; transform: none; }
}

/* --- Vertrauensleiste --------------------------------------------------- */
/* Die Leiste ragt in den Auftakt hinein, statt darunter zu warten.
   Zwei Gründe, und der zweite ist der wichtigere: Sie verzahnt die beiden
   Bereiche, statt sie stumpf aneinanderzusetzen — genau die Kante, die
   diese Seite über sieben Abschnitte hinweg zu oft hatte. Und auf einem
   Telefon steht damit am unteren Bildrand ein angeschnittener Block: der
   deutlichste Hinweis, dass es weitergeht, den eine Seite geben kann. */
.trust {
  position: relative;
  z-index: 3;
  margin-top: calc(var(--s-6) * -1);
  box-shadow: var(--shadow-m);
  /* Die Verzahnung mit dem Auftakt gilt nur am Schreibtisch — siehe die
     Regel am Ende dieses Blocks. */
  display: grid;
  gap: 1px;
  background: var(--line);
  /* Die Fugen bleiben, was sie sind — ein Raster mit Haarlinien, wie ein
     Datenblatt. Rund ist nur die Außenkante: Sie löst den Block vom
     Seitengrund, ohne dass die vier Kacheln zu vier Karten zerfallen. */
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  overflow: hidden;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 760px) { .trust { grid-template-columns: repeat(4, 1fr); } }
/* Seit dem 29.9.2026 steht die Leiste unter dem Sortiment und ragt nirgends
   mehr hinein. */
.trust--unten { margin-top: 0; margin-bottom: clamp(3rem, 7vw, 6rem); }
.trust__cell {
  background: var(--bg);
  padding: clamp(1.5rem, 3vw, 2.25rem) clamp(1.15rem, 2.5vw, 1.75rem);
  display: flex;
  flex-direction: column;
  gap: .7rem;
  align-items: flex-start;
  transition: background var(--t-med) var(--ease);
}
.trust__cell:hover { background: var(--surface); }
.trust__cell svg {
  width: 1.55rem; height: 1.55rem;
  color: var(--accent-br); stroke-width: 1.4;
  margin-bottom: .35rem;
}
.trust__t { font-size: 1rem; font-weight: 500; line-height: 1.3; }
.trust__d { font-family: var(--f-mono); font-size: .68rem; letter-spacing: .07em; color: var(--fg-faint); line-height: 1.4; }

/* Farbwahl ---------------------------------------------------------------
   Vier Punkte statt vier Karten. Der Auftakt zeigte bisher einen Handschuh
   und daneben den Satz „Vier Ausführungen" — man musste ihn glauben. Jetzt
   sieht man sie, indem man sie anfasst.

   Das Tippziel ist 44 px, der sichtbare Punkt 1.55rem. Die Differenz ist
   Absicht: Sichtbar bleibt der zurückhaltende Tupfer, getroffen wird die
   Fläche darum. Ohne das wäre der Punkt auf dem Telefon 25 px und damit
   unter jeder Empfehlung. */
.farbwahl {
  display: flex;
  gap: .15rem;
  border: 0; padding: 0; margin: 0;
}
.farbwahl__opt {
  position: relative;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* Das Eingabefeld bleibt bedienbar und fokussierbar — es ist nur unsichtbar.
   `appearance: none` statt display:none: Ein ausgeblendetes Feld nimmt keinen
   Fokus an, und damit wäre die Pfeiltastenbedienung weg. */
.farbwahl input {
  position: absolute; inset: 0;
  appearance: none; -webkit-appearance: none;
  margin: 0; border: 0; padding: 0;
  border-radius: var(--r-voll);
  cursor: pointer;
}
.farbwahl__punkt {
  width: 1.55rem; height: 1.55rem;
  border-radius: var(--r-voll);
  background: var(--fw);
  /* Weiß auf hellem Grund braucht eine Kante, sonst ist der Punkt ein Loch. */
  box-shadow: inset 0 0 0 1px var(--line-2);
  transition: transform .16s var(--ease-out), box-shadow .16s var(--ease-out);
  pointer-events: none;
}
/* Der Ring sitzt außen und nimmt die Grundfarbe als Fuge — so trägt er auf
   jedem Untergrund, ohne dass die Fassung davon wissen muss. */
.farbwahl input:checked ~ .farbwahl__punkt {
  transform: scale(1.12);
  box-shadow:
    inset 0 0 0 1px var(--line-2),
    0 0 0 3px var(--bg),
    0 0 0 4.5px var(--fg);
}
.farbwahl input:focus-visible ~ .farbwahl__punkt {
  box-shadow:
    inset 0 0 0 1px var(--line-2),
    0 0 0 3px var(--bg),
    0 0 0 5.5px var(--accent-br);
}
.farbwahl input:active ~ .farbwahl__punkt { transform: scale(.92); }
.farbwahl input:checked:active ~ .farbwahl__punkt { transform: scale(1.02); }

@media (hover: hover) and (pointer: fine) {
  .farbwahl input:not(:checked):hover ~ .farbwahl__punkt { transform: scale(1.1); }
}

/* Der Bildtausch --------------------------------------------------------
   Eine Überblendung zeigt zwei Handschuhe, die einander durchscheinen. Der
   kurze Weichzeichner zeigt einen, der sich verwandelt. Deshalb Unschärfe
   statt Kreuzblende.

   Asymmetrisch: 110 ms hinein (dort steht noch das alte Bild), 190 ms
   heraus (dort kommt das neue an). Die Zeiten stehen auch in shop.js —
   bilderTauschen() wartet die kurze ab, bevor es die Quelle setzt. */
.tausch {
  transition: filter .19s var(--ease-out), opacity .19s var(--ease-out);
}
.tausch.is-tauscht {
  filter: blur(5px);
  opacity: .4;
  transition-duration: .11s;
}
/* Unschärfe ist keine Bewegung und darf bleiben — sie erklärt den Wechsel.
   Verkürzt wird sie trotzdem: Wer Bewegung abbestellt, will keine Wartezeit. */
@media (prefers-reduced-motion: reduce) {
  .tausch, .tausch.is-tauscht { transition-duration: .08s; filter: none; }
}

/* --- Der Preisblock -----------------------------------------------------
   Bis zum 28.8.2026 stand hier eine Waage mit zwei Balken: oben der fremde
   Preis, unten der eigene. Sie ist entfallen, weil die Vergleichszahl nie
   erhoben war (siehe MARKT in data.js).

   Was bleibt, ist die Aussage, die trägt: eine Zahl für das ganze
   Sortiment. Sie steht groß und allein — ein Argument, das keinen Gegner
   braucht.

   Keine eigene Animation. Die Waage hatte einen Ablauf in zwei Schritten
   (erst der fremde Balken, dann der kurze eigene), und der war das
   Argument. Eine Zahl, die einläuft, wäre Dekoration — der Abschnitt
   blendet ohnehin als Ganzes ein. */
.preisblock {
  margin-top: var(--s-7);
  padding-block: var(--s-5);
  border-block: 1px solid var(--line);
  text-align: center;
}
.preisblock__zahl {
  font-family: var(--f-display);
  font-weight: 800; font-stretch: 115%;
  font-size: clamp(3rem, 11vw, 6rem);
  line-height: .95; letter-spacing: -.03em;
  color: var(--accent-br);
}
.preisblock__was {
  margin-top: var(--s-3);
  font-size: 1.05rem;
}
.preisblock__umfang {
  margin-top: .35rem;
  font-family: var(--f-mono);
  font-size: .72rem; letter-spacing: .06em;
  color: var(--fg-mute);
}

.waage__fuss {
  margin-top: var(--s-5);
  font-size: .88rem;
  line-height: 1.6;
  color: var(--fg-mute);
}

/* Der Konfigurator -------------------------------------------------------
   Zwei Schalter, mit denen das Paket zusammengestellt wird. Echte
   Kontrollkästchen, kein Knopfpaar: Das Formular kennt den Zustand dann
   selbst, die Tastatur bedient es ohne eine Zeile Skript, und eine
   Vorlesehilfe sagt „aktiviert" statt „gedrückt".

   Die Schalter sind absichtlich groß und tragen den Einzelpreis. Wer
   abwählt, soll sehen, was er wegnimmt — der Abschnitt lebt davon, dass
   der Paketrabatt beim Abwählen sichtbar verschwindet. */
.konf { display: grid; gap: var(--s-3); }
.konf__teil { cursor: pointer; }
.konf__teil input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.konf__box {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--line-2);
  border-radius: var(--r-3);
  background: var(--surface);
  transition: border-color .18s var(--ease-out), background .18s var(--ease-out),
              transform .16s var(--ease-out);
}
.konf__teil input:checked ~ .konf__box { border-color: var(--accent); }
.konf__teil input:focus-visible ~ .konf__box {
  outline: 2px solid var(--accent-br);
  outline-offset: 3px;
}
.konf__teil input:active ~ .konf__box { transform: scale(.985); }
@media (hover: hover) and (pointer: fine) {
  .konf__teil:hover .konf__box { border-color: var(--fg-faint); }
}

.konf__zeichen {
  display: grid; place-items: center;
  width: 2.4rem; height: 2.4rem;
  color: var(--fg-faint);
  transition: color .18s var(--ease-out), opacity .18s var(--ease-out);
  opacity: .55;
}
.konf__zeichen svg { width: 100%; height: 100%; }
.konf__teil input:checked ~ .konf__box .konf__zeichen { color: var(--accent); opacity: 1; }

.konf__text { display: grid; gap: .15rem; min-width: 0; }
.konf__text b { font-weight: 500; font-size: .98rem; }
.konf__text span {
  font-family: var(--f-mono);
  font-size: .7rem; letter-spacing: .05em;
  color: var(--fg-faint);
}

/* Der Haken ist der einzige Teil, der aus dem Nichts kommen darf — er ist
   kein Gegenstand, sondern eine Bestätigung. Trotzdem nicht aus scale(0):
   .6 mit Deckkraft liest sich als „schnappt ein", 0 als „erscheint". */
.konf__haken {
  display: grid; place-items: center;
  width: 1.5rem; height: 1.5rem;
  border-radius: var(--r-voll);
  background: var(--accent);
  color: #fff;
  transform: scale(.6);
  opacity: 0;
  transition: transform .2s var(--ease-back), opacity .2s var(--ease-out);
}
.konf__haken svg { width: .9rem; height: .9rem; }
.konf__teil input:checked ~ .konf__box .konf__haken { transform: scale(1); opacity: 1; }

/* Ein abgewähltes Teil verschwindet aus der Bühne, statt einfach zu fehlen.
   Ein Gegenstand, der ohne Übergang weg ist, wirkt wie ein Ladefehler. */
.pgruppe__teil.is-weg {
  opacity: 0 !important;
  transform: scale(.82) !important;
  transition: opacity .28s var(--ease-out), transform .28s var(--ease-out);
  pointer-events: none;
}

/* Ohne Paketrabatt ergibt die durchgestrichene Summe keinen Sinn — sie
   stünde als derselbe Betrag ein zweites Mal da, nur durchgestrichen. */
.pdp__price small.is-leer s,
.pdp__price small.is-leer { opacity: .0001; }
.pdp__price small.is-leer { visibility: hidden; }

.konf__warn { color: var(--accent-br); }

/* --- Athletenkarte -------------------------------------------------------
   Steht auf zwei Seiten (Startseite als Anriss, athleten.html in voll),
   deshalb hier und nicht in pages.css.

   Ein Porträt ist keine Produktkachel: Es steht hochkant (4:5), es trägt
   keinen Rahmen um das Bild, und der Text sitzt darunter statt in einem
   Kasten. Eine Karte mit Kante hätte hier die Wirkung eines Ausweises —
   der Mensch käme darin vor wie ein Artikel im Sortiment.                */
.ath { display: flex; flex-direction: column; gap: var(--s-4); }

/* Quadratisch ist für ein Porträt falsch, 4:5 richtig — dieselbe
   Überlegung wie bei der Produktgalerie, nur andersherum: Dort richtet
   sich der Rahmen nach den quadratischen Aufnahmen, hier gibt er dem
   Shooting das Format vor, das noch entsteht. Wer im Hochformat
   fotografiert, bekommt das ganze Bild; ein Querformat verlöre die Hälfte. */
.ath__media {
  position: relative;
  aspect-ratio: 4/5;
  background: var(--surface);
  border-radius: var(--r-4);
  overflow: hidden;
}
/* Nur das direkte Kind: Der Schakalkopf im leeren Platz liegt eine Ebene
   tiefer und ist 2,6 rem groß. Ohne den Kindselektor traf ihn diese Regel
   mit und blies ihn auf 307 px auf — er sprengte die Karte nach oben und
   drückte den Marker an die Unterkante. */
.ath__media > img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .9s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .ath:hover .ath__media > img { transform: scale(1.04); }
}

/* Der leere Platz. Markup statt Bilddatei, damit er die Fassung mitmacht:
   Der Warnton ist in Hell #7a5c0e und in Dunkel #c8a24a — eine SVG-Datei
   kann nur einen von beiden führen, und in der dunklen Fassung stand der
   Platzhalter damit in der falschen Farbe.

   Der Schakalkopf statt einer gezeichneten Figur: Er behauptet nichts über
   das Aussehen eines Menschen, den es geben wird, und er trägt über
   `class="marke"` dasselbe --logo-filter wie überall sonst. */
.ath__leerbild {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--s-4);
  width: 100%; height: 100%;
}
.ath__leerbild-marke { width: 3.2rem; height: auto; opacity: .34; }
/* Volle Deckkraft, anders als beim Marker sonst. `.ph` trägt projektweit
   opacity .85, weil er dort neben normalem Text steht und sich zurücknehmen
   soll. Hier ist er der einzige Text auf der Fläche, und die Deckkraft
   drückte den Kontrast auf **3,96** — bei 10 px Schrift unter die verlangten
   4,5. Ohne sie sind es 5,35.

   Nachgerechnet, nicht abgelesen: Die Designprüfung meldete an diesem Tag
   auch die Nummer als zu schwach, und das war ihr eigener Rechenfehler.
   Erst die Zahl von Hand hat auseinandergehalten, welche der beiden
   Meldungen stimmte. */
.ath__leerbild .ph { font-size: .62rem; opacity: 1; }

/* Der gestrichelte Rahmen sitzt an der Karte, nicht in der Zeichnung. Zwei
   gestrichelte Rechtecke ineinander — eins vom SVG, eins von der Karte —
   sahen aus wie ein Fehler beim Zusammenbauen. Ein Platzhalter, den man
   für kaputt hält, ist schlechter als gar keiner.
   Er hängt am fehlenden BILD, nicht am fehlenden Namen (seit 23.9.2026):
   Ein echtes Porträt in einem Platzhalterrahmen sieht aus wie ein Fehler. */
.ath__media--leer {
  background: color-mix(in srgb, var(--warn) 5%, var(--surface));
  border: 1px dashed color-mix(in srgb, var(--warn) 62%, transparent);
}

/* Die Nummer ist keine Rangfolge, sondern eine Position im Raster — sie
   macht vier gleich aussehende Platzhalter unterscheidbar und bleibt
   später als stiller Zähler stehen. */
.ath__nr {
  position: absolute;
  top: var(--s-4); left: var(--s-4);
  font-family: var(--f-mono);
  font-size: .68rem; letter-spacing: .14em;
  /* Die leiseste Ebene, und das ist hier richtig: Die Nummer ordnet, sie
     spricht nicht. Nachgerechnet kommt sie auf der Karte auf Kontrast 4,84
     — die Designprüfung meldete am 24.8.2026 zwar 3,55, das war aber ihr
     eigener Rechenfehler (siehe zuRGB() in _design.html). */
  color: var(--fg-faint);
  background: var(--glass);
  border: 1px solid var(--edge);
  border-radius: var(--r-voll);
  padding: .2rem .5rem;
  line-height: 1;
}

.ath__body { display: flex; flex-direction: column; gap: var(--s-2); }
.ath__name { font-size: clamp(1.05rem, 1.5vw, 1.22rem); line-height: 1.25; }
.ath__name--leer { font-weight: 400; }
.ath__klasse { font-family: var(--f-mono); font-size: .74rem; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-mute); }
.ath__klasse--leer { color: var(--fg-faint); text-transform: none; letter-spacing: .04em; font-style: italic; }
/* Der Verein in der Akzentfarbe: Er ist die Angabe, die jemand aus dem
   Sport wiedererkennt — und die einzige auf der Karte, die für sich steht. */
.ath__verein { font-size: .92rem; color: var(--accent-br); font-weight: 500; }
.ath__bilanz { font-size: .88rem; color: var(--fg-mute); }
.ath__satz { font-size: .95rem; line-height: 1.55; color: var(--fg-mute); max-width: 38ch; }

/* Die Zeile, die den Bereich rechtfertigt: vom Menschen zur Ware, ohne ein
   Verkaufswort. Der Punkt trägt die tatsächliche Farbe des Handschuhs. */
.ath__farbe {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-top: var(--s-2);
  font-size: .88rem;
  color: var(--fg);
  transition: color var(--t-fast) var(--ease);
}
.ath__farbe:hover { color: var(--accent-br); }
.ath__farbe-punkt {
  width: .72rem; height: .72rem;
  border-radius: var(--r-voll);
  background: var(--pkt);
  border: 1px solid var(--edge);
  flex-shrink: 0;
}

/* --- Athleten als Reihe (Anriss auf der Startseite) ---------------------
   Kein verkleinertes Raster, sondern ein eigener Baustein. Die Startseite
   verkauft; vier Porträts in voller Größe wären dort ein zweiter Abschnitt
   und, solange sie Platzhalter sind, vier leere Flächen an der Stelle, an
   der die Seite überzeugen soll.

   Die Reihe behauptet nichts — sie zeigt, dass Plätze da sind, und führt
   weiter. Sobald Porträts vorliegen, füllen sie dieselben Felder. */
.ath-reihe { margin-top: var(--s-5); }
/* Eine Reihe, die nicht umbricht. Mit fünf Plätzen passte sie auf 390 px
   nicht mehr in eine Zeile (5 × 66 px plus Abstände gegen 358 px), und
   eine Reihe, deren letzter Platz allein darunter steht, sieht aus wie
   einer, der nicht dazugehört. Die Spalten sind höchstens 5,2 rem breit
   und geben nach, wenn der Platz fehlt — die Zahl der Plätze rechnet
   niemand mit, das Raster tut es. */
.ath-reihe__plaetze {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 5.2rem);
  gap: var(--s-3);
}
.ath-reihe__fuss {
  margin-top: var(--s-3);
  font-size: .84rem;
  color: var(--fg-faint);
}
.ath-mini {
  position: relative;
  display: grid; place-items: center;
  width: 100%;
  aspect-ratio: 4/5;
  border-radius: var(--r-2);
  background: var(--surface);
  border: 1px solid var(--line);
  overflow: hidden;
  transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease);
}
.ath-mini img { width: 100%; height: 100%; object-fit: cover; }
/* Die Kante darf auf Touch mitgehen — sie ist Rückmeldung, keine Bewegung.
   Das Anheben nicht: Ein Bild, das beim Antippen springt, liest sich als
   Fehler. */
.ath-mini:hover { border-color: var(--line-2); }
@media (hover: hover) and (pointer: fine) {
  .ath-mini:hover { transform: translateY(-3px); }
}

/* Der leere Platz ist gestrichelt wie jeder Platzhalter dieser Website —
   und nicht grau gefüllt: Eine gefüllte Fläche liest sich als Inhalt, der
   nicht lädt, eine gestrichelte als Platz, der reserviert ist. */
.ath-mini--leer {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--warn) 60%, transparent);
  background: color-mix(in srgb, var(--warn) 7%, transparent);
}
.ath-mini__nr {
  font-family: var(--f-mono);
  font-size: .78rem; letter-spacing: .1em;
  color: var(--warn);
  opacity: .8;
}


/* --- Die Vertrauensleiste bleibt auf dem Handy unten -------------------
   Sie ragt mit -2 rem in den Auftakt hinein. Am Schreibtisch verzahnt das
   die beiden Bereiche, statt sie stumpf aneinanderzusetzen, und auf dem
   Telefon war der angeschnittene Block bewusst der Hinweis „es geht
   weiter".

   Seit dem 25.8.2026 ist genau das nicht mehr gewollt: Der Betreiber will
   den Auftakt als abgeschlossenen ersten Abschnitt — „sozusagen der
   Anfang sein, wenn man die Seite sieht". Ein Block, der von unten
   hineinragt, ist das Gegenteil davon. Gemessen stand die Leiste 32 px
   im Auftakt.

   Der Hinweis, dass es weitergeht, geht damit nicht verloren: Der Auftakt
   ist jetzt exakt einen Bildschirm hoch, und was genau an der Kante endet,
   liest sich ebenso als Fortsetzung. */
@media (max-width: 1019px) {
  .trust { margin-top: 0; }
}


/* Die Platzhalterzeile des Social-Blocks. Sie tritt an die Stelle der drei
   leeren Reel-Kacheln, die auf 390 px zusammen 2088 px hoch waren. */
.social__leer {
  margin-top: var(--s-5);
  padding: var(--s-5);
  border: 1px dashed var(--line-2);
  border-radius: var(--r-3);
  color: var(--fg-mute);
  font-size: .95rem;
  line-height: 1.6;
  max-width: 60ch;
}
.social__leer .ph { margin-right: .5rem; }


/* --- Die Karte in der schmalen Spalte ----------------------------------
   Seit dem 25.8.2026 stehen auf dem Telefon zwei Produkte nebeneinander
   (siehe .grid:has(> .card) in base.css). Damit ist die Karte dort 167 px
   breit statt 350 — und was für die volle Breite bemessen war, passt nicht
   mehr.

   Gemessen: Das Wort „BOXHANDSCHUH" braucht bei 18,4 px Schrift 136 px,
   das Titelfeld hatte nach 24 px Innenabstand nur noch 118. Der Titel
   stand abgeschnitten da — „BOXHANDSCH".

   Zwei Hebel, beide klein: weniger Innenabstand und eine Stufe kleinere
   Schrift. Dazu `hyphens: auto` als Netz — ein Wort, das trotzdem zu breit
   wird, bricht dann mit Trennstrich um, statt an der Kante abzureißen.
   Die Seite trägt `lang="de"`, die Trennung stimmt also. */
@media (max-width: 560px) {
  .grid:has(> .card) .card__body {
    padding: var(--s-4);
    gap: var(--s-2);
  }
  .grid:has(> .card) .card__title {
    font-size: .95rem;
    hyphens: auto;
  }
  /* Dieselbe Rechnung eine Zeile höher: „GRAU · LIEFERBAR" stand ebenfalls
     über die Kante — 168 px bei 134 px Feld.

     Das Wort „Lieferbar" verschwindet dort, der Punkt davor bleibt. Er
     trägt die Auskunft ohnehin: grün heißt da, rot heißt weg.

     `font-size: 0` und nicht `display: none`: Der Text bleibt im Baum und
     wird vorgelesen, gezeichnet wird er nicht. Der Punkt hat eigene Maße in
     rem und überlebt das — mit einer Clip-Technik wäre er mit verschwunden.

     **„Ausverkauft" bleibt sichtbar.** Ein fehlendes Wort, das gute
     Nachrichten trägt, kostet nichts; eines, das schlechte trägt, ist ein
     Fehler — wer nicht sieht, dass etwas weg ist, legt es in den Korb. */
  .grid:has(> .card) .card__kopf { font-size: .82em; gap: var(--s-2); }
  .grid:has(> .card) .card__lager:not(.is-out) {
    font-size: 0;
    letter-spacing: 0;
    gap: 0;
  }
  .grid:has(> .card) .card__lager:not(.is-out)::before {
    width: .4rem; height: .4rem;
  }
  /* Die Größenknöpfe der Schnellwahl liegen auf dem Bild. In 167 px passen
     drei nebeneinander nur, wenn sie enger stehen. */
  .grid:has(> .card) .card__quick { padding: var(--s-3); }
  .grid:has(> .card) .card__quick-btn { padding: .3rem .5rem; font-size: .7rem; }
}

/* --- Die Preis-Posten ----------------------------------------------------
   Drei Zeilen unter dem Sortiment, die den Preis erklären. Sie ersetzen seit
   dem 6.9.2026 einen ganzen Abschnitt („Die Rechnung", 988 px mit eigener
   Überschrift und Preisblock) — dieselbe Aussage, ein Zehntel der Fläche.

   Kein Kasten und kein Rahmen: Das sind Fußnoten zum Preis, keine dritte
   Kartenreihe. Die Haarlinie oben bindet sie an die Ware darüber. */
.posten {
  list-style: none;
  margin: var(--s-6) 0 0;
  padding: var(--s-5) 0 0;
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--s-4) var(--s-6);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.posten li {
  font-size: .93rem;
  line-height: 1.5;
  color: var(--fg-mute);
}

.posten b {
  display: block;
  color: var(--fg);
  font-weight: 600;
  margin-bottom: .15rem;
}

/* --- Bewertungen: der zugeklappte Teil -----------------------------------
   Das Formular stand bis zum 6.9.2026 auf jeder Produktseite offen und kostete
   rund 700 px. Es ist die einzige Handlung auf der Seite, die NACH dem Kauf
   kommt — sie darf warten. */
.bew-form__auf {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .3rem .7rem;
  cursor: pointer;
  padding: var(--s-4) 0;
  border-top: 1px solid var(--line);
  list-style: none;
}
.bew-form__auf::-webkit-details-marker { display: none; }

/* Das Dreieck zeichnen wir selbst — der Standardmarker springt zwischen den
   Browsern und lässt sich nicht am Text ausrichten. */
.bew-form__auf::after {
  content: "";
  width: .5rem; height: .5rem;
  margin-left: auto;
  border-right: 1.5px solid var(--fg-faint);
  border-bottom: 1.5px solid var(--fg-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--t-fast) var(--ease-out);
}
details[open] > .bew-form__auf::after {
  transform: rotate(-135deg) translate(-2px, -2px);
}

.bew-form__auf:focus-visible {
  outline: 2px solid var(--accent-br);
  outline-offset: 3px;
  border-radius: var(--r-1);
}

.bew-form__auf-hint {
  font-size: .85rem;
  color: var(--fg-faint);
}

/* Der Satz, der die fehlenden Kundentexte erklärt. Vorher ein Hinweiskasten
   mit vier Sätzen; die Aussage ist dieselbe, sie braucht nur keinen Rahmen. */
.bewertung__leer {
  font-size: .93rem;
  line-height: 1.55;
  color: var(--fg-mute);
  max-width: 52ch;
  margin-bottom: var(--s-5);
}

/* --- Die Preisnote auf der Produktseite ----------------------------------
   Ersetzt seit dem 6.9.2026 einen ganzen Abschnitt („Die Rechnung", 437 px
   mit Überschrift und Preisblock). Die Aussage stand wörtlich schon auf der
   Start- und der Paketseite; hier reicht die Bestätigung.

   Kein Kasten: Das ist eine Fußnote zum Preis, kein eigener Halt. Sie liegt
   auf derselben Bahn wie .wrap, damit sie mit dem Rest der Seite fluchtet. */
.preisnote {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: var(--s-5) var(--gutter);
  font-size: .93rem;
  line-height: 1.6;
  color: var(--fg-mute);
}

.preisnote b {
  color: var(--fg);
  font-weight: 600;
}

.preisnote a {
  color: var(--accent-br);
  text-underline-offset: 3px;
  white-space: nowrap;
}
