/* ============================================================
   shop.css — die Uebersicht: Markenreihe, Raster, Kacheln

   Setzt brand.css (Tokens) und layout.css (Reset, .container, Kopf,
   Fuss, Knoepfe) voraus. Was bis 06.09.2026 hier doppelt zu
   produkt.css stand — Reset, .container, .kopf, .fuss — ist dorthin
   umgezogen.

   Die Kachel ist das Stueck, an dem eine Uebersicht als Shop gelesen
   wird oder nicht. Sie traegt fuenf Dinge, und zwar in dieser
   Rangfolge: Bild, Preis, Titel, Marke, Verkaufszahl. Der Preis steht
   VOR dem Titel, weil auf einer Uebersicht danach gesucht wird.
   ============================================================ */

/* ============================================================
   DIE BREITE DES SHOPS

   --maxw (1120px) ist eine LESEBREITE: sie sorgt dafuer, dass eine
   Zeile Fliesstext nicht ueber den halben Schirm laeuft. Der Shop
   besteht aber nicht aus Zeilen, sondern aus Bildern — und die waren
   auf einem 1900px-Schirm eine schmale Spalte in sehr viel Schwarz.

   Erster Anlauf war, nur Kopfbank und Raster breiter zu machen. Das
   war falsch: die Kopfzeile blieb dabei auf 1120 stehen, das Logo
   begann 125px weiter rechts als die Ueberschrift darunter, und die
   Seite sah aus, als sei ihr Kopf verrutscht.

   Also die GANZE Startseite. Das geht ohne Nebenwirkung, weil
   shop.css und start.css ausschliesslich von index.html geladen
   werden — die Bestell-, Produkt- und Kassenseiten behalten ihre
   1120er Lesebreite. Fliesstext bleibt trotzdem lesbar: die Absaetze
   darunter tragen ihre eigenen max-widths (620px, 62ch), sie waren
   nie an --maxw gebunden.

   1360 ist nicht gerundet, sondern gerechnet: bei 1312px Innenmass
   passen drei Kacheln zu je 421px (3x336+48 = 1056 passt, vier
   brauchten 1416). Der Shop bleibt damit dreispaltig und die Kachel
   waechst von 341 auf 421px. Wer die Zahl aendert, prueft nach, ob
   auto-fill immer noch drei Spalten ergibt. */
:root { --maxw: 1360px; }

/* ---- Kopfbereich: Ueberschrift und Marken auf EINER Bank ----
   Bis 08.09.2026 standen Ueberschrift, Markenreihe und Werkzeugzeile
   uebereinander. Gemessen bei 1440x900: 531px, bevor das erste Produkt
   anfing — 59 % des Fensters. Die PREISZEILE der ersten Kachel lag
   danach 12px unter der Falz. Man sah das Bild und musste scrollen, um
   zu erfahren, was es kostet; auf einer Uebersicht ist der Preis der
   Grund, warum man hinsieht.

   Jetzt teilen sich beide das obere Feld: Ueberschrift links, die
   Marken als Gegengewicht rechts auf derselben Grundlinie. Das spart
   die volle Hoehe der Markenreihe und macht aus einem Stapel eine
   Komposition. Erst ab 1240px — darunter braucht die Ueberschrift die
   ganze Breite, sonst bricht sie auf drei Zeilen und frisst die
   Ersparnis wieder auf. */
.shop-kopf { padding: var(--s-7) 0 var(--s-4); }
.shop-kopf-band { display: grid; gap: var(--s-5); }
/* Ab 1024 statt 1240: dazwischen liegt der haeufigste Laptop, und dort
   stand der Kopf noch gestapelt — 507px, bevor das erste Produkt kam.
   Die Ueberschrift braucht in dieser Spanne drei Zeilen statt zwei, die
   Bank spart trotzdem rund 80px gegenueber dem Stapel. Die groesseren
   Ringe bleiben der breiten Stufe vorbehalten (unten). */
@media (min-width: 1024px) {
  .shop-kopf-band {
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--s-6);
    align-items: end;
  }
  /* Die SPALTE begrenzt die Zeile hier, nicht mehr das max-width der
     Ueberschrift — beide zusammen kosteten dem englischen Text eine
     dritte Zeile ("On your own / account."), waehrend das deutsche
     Original mit zweien auskam. Eine Ueberschrift, die je nach Sprache
     unterschiedlich hoch ist, verschiebt das ganze Feld darunter. */
  .shop-kopf-band h1 { max-width: none; }
  .shop-kopf-band .marken { padding-bottom: 6px; gap: var(--s-4); }
}
/* Neben einer 74px-Ueberschrift waren 72px-Ringe zu leise, um als
   Gegengewicht zu taugen — sie sahen aus wie hingestellt, nicht wie
   gesetzt. 92px halten die rechte Seite der Bank. Erst ab 1240: in der
   Spanne darunter ist die Textspalte schmaler, dort wuerden die
   groesseren Ringe ihr die Breite nehmen. */
@media (min-width: 1240px) {
  .shop-kopf-band .marken-ring { width: 92px; height: 92px; }
  .shop-kopf-band .marken-ring.alle svg { width: 26px; height: 26px; }
  .shop-kopf-band .marken-kachel { width: 108px; }
}
/* Groesser als jede andere Zeile der Seite — die Ueberschrift ist der
   einzige Auftritt, den der Shop sich erlaubt. Zwei Zeilen bei voller
   Breite (max-width bricht nach "Ihrem"), eine Stufe ueber --t-4xl,
   weil die Skala fuer Fliesstext-Kapitel gebaut ist, nicht fuer eine
   Buehne. Wortweise Einblendung ueber data-wortfade im Generator. */
.shop-kopf h1 {
  font-size: clamp(2.6rem, 1.6rem + 5vw, 4.6rem); font-weight: 700;
  letter-spacing: -0.04em; line-height: 0.98; max-width: 20ch;
}
/* Die Ueberschrift ist zwei Saetze, nicht einer: "Echte Abos." ist die
   Behauptung, "Auf Ihrem eigenen Konto." der Beleg. Vorher standen
   beide in derselben Lautstaerke da — 35 Zeichen gleichmaessiges Weiss,
   in denen nichts zuerst gelesen wird. Die zweite Stufe ist genau das
   Mittel, das brand.css dafuer vorsieht: Rangfolge ueber HELLIGKEIT,
   nicht ueber Farbe oder Groesse. Bei 74px reicht --muted (7,9:1) weit
   ueber die 3:1, die grosse Schrift braucht.

   sprache.js tauscht data-en per innerHTML, deshalb traegt der
   englische Text dieselbe Struktur; motion.js zerlegt nur Textknoten
   und laesst den Span stehen. */
.h1-leise { color: var(--muted); }

.shop-kopf .lede {
  color: var(--muted); font-size: var(--t-md);
  margin-top: var(--s-3); max-width: 54ch;
}
.etikett {
  display: inline-block;
  font-family: var(--mono); font-size: var(--t-xs);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint); margin-bottom: var(--s-3);
}

/* ============================================================
   MARKENREIHE

   Die Marken stehen als Ringe da, nicht als Text — bei zwei Marken
   waere eine Textliste schneller zu bauen, aber der Ring ist das, was
   man auf einer Uebersicht wiedererkennt, ohne zu lesen.
   ============================================================ */

.marken {
  display: flex; gap: var(--s-5);
  overflow-x: auto; scrollbar-width: none;
  padding: var(--s-2) 0 var(--s-4);
  scroll-snap-type: x proximity;
}
.marken::-webkit-scrollbar { display: none; }

.marken-kachel {
  flex: none; scroll-snap-align: start;
  display: flex; flex-direction: column; align-items: center; gap: var(--s-3);
  width: 92px; padding: 0; border: 0; background: none; cursor: pointer;
  font: inherit; color: var(--muted);
  transition: color 0.18s;
}
.marken-kachel:hover { color: var(--text); }

.marken-ring {
  position: relative; width: 72px; height: 72px;
  border-radius: 50%; overflow: hidden;
  border: 1px solid var(--line-2);
  transition: border-color 0.2s, transform 0.2s var(--e1, ease);
}
.marken-ring img { width: 100%; height: 100%; object-fit: cover; display: block; }
.marken-kachel:hover .marken-ring { transform: translateY(-2px); border-color: var(--ic, var(--brand)); }
.marken-kachel.ist-an .marken-ring { border-color: var(--ic, var(--brand)); }

/* Der Zustand liegt auf dem Ring und auf der Schrift, nie als Strich
   UNTER der Zeile — dort waere er die Oberkante des naechsten
   Elements. */
.marken-kachel.ist-an { color: var(--text); }
.marken-name {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.1em; text-transform: uppercase;
  white-space: nowrap;
}
.marken-kachel:focus-visible { outline: 2px solid var(--text); outline-offset: 4px; border-radius: var(--r); }

/* Der "Alle"-Knopf hat kein Bild, sondern ein Zeichen. */
.marken-ring.alle {
  display: grid; place-items: center;
  background: var(--e1);
}
.marken-ring.alle svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 1.5; }

/* ============================================================
   WERKZEUGZEILE: Zahl der Treffer + Sortierung
   ============================================================ */

.werkzeuge {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
  padding: var(--s-4) 0;
  border-top: 1px solid var(--line);
}
.treffer {
  font-family: var(--mono); font-size: var(--t-xs);
  letter-spacing: 0.08em; color: var(--faint);
}
.sortierung {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--t-xs); color: var(--faint);
}
.sortierung select {
  background: none; border: 0; border-bottom: 1px solid var(--line-2);
  color: var(--text); font-family: var(--mono); font-size: 11.5px;
  letter-spacing: 0.06em; padding: 4px 2px; cursor: pointer;
}
.sortierung select:focus-visible { outline: none; border-bottom-color: var(--brand); }

/* ============================================================
   RASTER

   auto-fill statt fester Spaltenzahl: bei drei Produkten stehen sie
   nebeneinander, bei fuenfzehn bricht das Raster von selbst um. Der
   Shop skaliert damit ohne CSS-Aenderung.

   Das Mindestmass ist so gewaehlt, dass bei voller Containerbreite
   GENAU drei Spalten entstehen: 1120 − 2·24 = 1072 Innenmass, und
   3·336 + 2·24 = 1056 passt, 4·336 + 3·24 = 1416 nicht. Bei 232px
   (bis 08.09.2026) ergab auto-fill vier Spalten — drei Kacheln zu
   je 250px und rechts eine leere vierte. Das Produktbild ist das
   einzige Farbige auf der Seite; es verdient die Breite. */

.raster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 336px), 1fr));
  gap: var(--s-5);
  /* Unten nur --s-6: darunter folgt der Ablaufstreifen ("kaufen, Link
     oeffnen, Abo laeuft"), und der beantwortet die Frage, die genau
     hier aufkommt — nachdem man den Preis gesehen hat. Mit --s-8 plus
     der Polsterung des Abschnitts standen 96px Nichts dazwischen, und
     der Streifen las sich wie ein eigenes Kapitel statt wie die
     Antwort. */
  padding: var(--s-2) 0 var(--s-6);
}

/* ---- Die Kachel ----
   Kein Rahmen: eine Flaeche, die sich um eine Spur aufhellt. Rahmen
   waeren sieben Kaesten nebeneinander. */
.kachel {
  position: relative;
  /* isolation macht die Kachel zum Stapelkontext. Damit kann das Licht
     (::before) auf z-index -1 liegen: ueber der Flaeche der Kachel, unter
     ALLEM Inhalt — ohne dass die Kinder positioniert werden muessten.
     Genau das war am 08.09.2026 der Fehler: `.kachel > * { position:
     relative }` machte .kachel-koerper zum Bezug fuer den Flaechenlink
     (.kachel-titel a::after, inset: 0), und der deckte danach nur noch
     den Textkoerper ab. Das Produktbild — die groesste Flaeche der
     Kachel und die, auf die man zuerst zeigt — war nicht mehr anklickbar. */
  isolation: isolate;
  display: flex; flex-direction: column;
  background: var(--e1);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: var(--kante);
  transition: background 0.2s ease, transform 0.2s var(--e1, ease);
}
/* PFLICHT: .kachel ist display:flex, und eine Autorenregel schlaegt
   das display:none des hidden-Attributs. Ohne diese Zeile filtert der
   Shop sichtbar nichts. Die Falle hat schon zweimal zugeschlagen. */
.kachel[hidden] { display: none; }

.kachel:has(a:hover),
.kachel:has(a:focus-visible) { background: var(--e2); transform: translateY(-2px); }

.kachel-bild {
  display: block; aspect-ratio: 1 / 1;
  background: var(--lack-tief);
  border-bottom: 1px solid var(--line);
}
.kachel-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }

.kachel-koerper {
  display: flex; flex-direction: column; gap: 7px;
  padding: var(--s-4);
  flex: 1;
}

/* Die Marke als kleines Zeichen plus Wort — hier darf die
   Produktfarbe auftreten, sonst nirgends auf der Kachel. */
.kachel-marke {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--faint);
}
.kachel-marke::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--ic, var(--faint));
}

/* Preis vor Titel: auf einer Uebersicht wird nach dem Preis gesucht. */
.kachel-preis {
  display: flex; align-items: baseline; gap: var(--s-2);
  font-family: var(--mono);
}
.kachel-preis b {
  font-size: 1.35rem; font-weight: 700; letter-spacing: -0.02em;
  color: var(--text);
  /* Der Betrag darf nie zwischen Zahl und Waehrung brechen — "14,99"
     ueber "€" liest sich als zwei Angaben. */
  white-space: nowrap;
}
/* Eigene Zeile statt dritter Teil der Preiszeile: zu dritt passten sie
   auf schmalen Kacheln nicht nebeneinander und brachen mitten im
   Betrag um. */
.kachel-monat {
  font-family: var(--mono); font-size: var(--t-xs); color: var(--faint);
  margin-top: -3px;
}

/* Der Produktname stand in --t-sm (14px) unter einem 421px-Bild und war
   damit kleiner als der Preis darueber — auf einer Uebersicht ist er
   aber das, wonach man das Produkt WIEDERERKENNT. 17px stellt die
   Rangfolge her, ohne dem Preis seinen Platz streitig zu machen: der
   ist Mono und tiefer gestellt, die beiden konkurrieren nicht. */
.kachel-titel {
  font-size: 17px; font-weight: 600; line-height: 1.35;
  letter-spacing: -0.015em;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Ein Link, der die ganze Kachel anfassbar macht — Bild eingeschlossen —
   statt sieben ueberlappender Trefferflaechen. Der Bezug ist .kachel
   (position: relative); nichts dazwischen darf positioniert werden, sonst
   schrumpft die Flaeche stillschweigend auf diesen Kasten. */
.kachel-titel a::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
}

.kachel-fuss {
  margin-top: auto; padding-top: var(--s-3);
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3);
  border-top: 1px solid var(--line);
}
.kachel-laufzeit {
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.06em; color: var(--faint);
}
.kachel-weiter {
  font-size: var(--t-xs); font-weight: 600; color: var(--muted);
  display: inline-flex; align-items: center; gap: 5px;
  transition: color 0.18s;
}
.kachel:has(a:hover) .kachel-weiter { color: var(--text); }
/* Der Pfeil laeuft ein Stueck los — die kleinste Zusage, die eine
   Kachel geben kann: hier geht es weiter. Nur der Pfeil bewegt sich,
   nicht das Wort davor, sonst wackelt die Zeile. */
.kachel-weiter svg { transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1); }
.kachel:has(a:hover) .kachel-weiter svg,
.kachel:has(a:focus-visible) .kachel-weiter svg { transform: translateX(4px); }
@media (prefers-reduced-motion: reduce) {
  .kachel-weiter svg { transition: none; }
  .kachel:has(a:hover) .kachel-weiter svg { transform: none; }
}
.kachel-weiter svg { width: 13px; height: 13px; stroke: currentColor; fill: none; stroke-width: 1.8; }

/* ---- Leerzustand ---- */
.leer {
  padding: var(--s-8) 0; text-align: center; color: var(--muted);
  font-size: var(--t-sm);
}
.alszlink {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: var(--text); text-decoration: underline;
  text-underline-offset: 3px;
}

/* 160px war das Mindestmass, solange die Kachel nur Bild und zwei
   Zeilen trug. Mit dem 17px-Titel, der Fusszeile und dem Korbknopf
   ergaben sich daraus bei 560px DREI Kacheln zu je 160px nebeneinander
   — gequetscht, und das Produktbild als Briefmarke. 240 gibt bei 560px
   zwei brauchbare Karten und bleibt darunter einspaltig. */
@media (max-width: 560px) {
  .raster { grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: var(--s-4); }
  .kachel-titel { -webkit-line-clamp: 2; }
}

@media (prefers-reduced-motion: reduce) {
  .kachel, .marken-ring { transition: background 0.2s ease, border-color 0.2s ease; }
  .kachel:has(a:hover), .marken-kachel:hover .marken-ring { transform: none; }
}

/* ---- "In den Warenkorb" auf der Kachel ----
   z-index 2, weil der Flaechenlink der Kachel auf 1 liegt und den Klick
   sonst abfaengt. */
.kachel-korb {
  position: relative; z-index: 2;
  margin-top: var(--s-3);
  width: 100%; padding: 9px 12px;
  background: none; border: 1px solid var(--line-2); border-radius: 9px;
  /* --text statt --muted: der Knopf war das einzige Bedienelement der
     Kachel und zugleich ihr leisestes Element. Er bleibt zweitrangig
     (Umriss statt Flaeche — die ganze Kachel fuehrt zum Produkt), aber
     lesbar. */
  color: var(--text); cursor: pointer;
  font-family: inherit; font-size: var(--t-sm); font-weight: 600;
  transition: color 0.18s, border-color 0.18s, background 0.18s;
}
.kachel-korb:hover {
  color: var(--text); border-color: rgba(255, 255, 255, 0.34);
  background: rgba(255, 255, 255, 0.04);
}
.kachel-korb:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
/* Bestaetigung ohne Layoutwechsel: die Breite bleibt, nur Text und
   Helligkeit aendern sich. Ein wachsender Knopf schoebe das Raster. */
.kachel-korb.drin { color: var(--bg); background: var(--brand); border-color: var(--brand); }

/* ============================================================
   ANKOMMEN UND ANTWORTEN

   Bewegung sitzt hier dort, wo sie ANTWORTET: beim Ankommen eines
   Abschnitts, unter dem Zeiger, nach einem Klick. Nichts davon laeuft
   von allein weiter — eine Seite, auf der dauernd etwas wackelt, ist
   nicht lebendig, sondern unruhig.
   ============================================================ */

/* ---- Die Kacheln kommen nacheinander ----
   .reveal am Raster ist nur der AUSLOESER; sichtbar wird das Raster
   selbst sofort, sonst blendete erst der Container und dann noch
   einmal jede Kachel ein. Gestaffelt werden die Kinder, ueber das --i,
   das js/motion.js aus data-staffel setzt. */
.js .raster.reveal { opacity: 1; transform: none; }
.js .raster.reveal .kachel {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 0.5s ease calc(var(--i, 0) * 70ms),
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) calc(var(--i, 0) * 70ms),
    background 0.2s ease;
}
.js .raster.reveal.in .kachel { opacity: 1; transform: none; }

/* ---- Licht aus dem Bild ----
   Unter dem Zeiger wirft das Produktbild sein eigenes Licht in den
   Kachelkoerper: eine stark verwischte Kopie des Bildes liegt hinter
   allem und wird von der Kachel selbst beschnitten (overflow: hidden)
   — nichts leuchtet nach aussen. Keine neue Farbe, kein Leuchtschatten:
   das Bild ist die einzige Lichtquelle der Seite, und es leuchtet nur,
   solange man hinsieht. Die Adresse kommt als --bild aus dem Generator.

   z-index: -1 statt positionierter Kinder — siehe .kachel oben. */
.kachel::before {
  content: ""; position: absolute; inset: -30%; z-index: -1;
  background: var(--bild) center / cover no-repeat;
  filter: blur(56px) saturate(1.3);
  opacity: 0; transition: opacity 0.5s ease;
  pointer-events: none;
}
.kachel:has(a:hover)::before,
.kachel:has(a:focus-visible)::before { opacity: 0.32; }

/* ---- Unter dem Zeiger ----
   Das Bild waechst INNERHALB seines Rahmens: overflow versteckt den
   Ueberstand, die Kachel bleibt exakt gleich gross. Ein Zustand, der
   das Layout aendert, schoebe das Raster unter der Hand weg. */
.kachel-bild { overflow: hidden; }
/* Dasselbe Kippen wie auf der Produktseite (js/kippen.js), aber
   schwaecher: drei Kacheln nebeneinander, die alle kraeftig kippen,
   waeren Unruhe statt Antwort. Vier Grad, und der Zeiger steht ohnehin
   nur auf einer. */
.kachel-bild {
  transform: perspective(800px)
             rotateX(calc(var(--ky, 0) * -4deg))
             rotateY(calc(var(--kx, 0) * 4deg));
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.kachel:has(a:hover) .kachel-bild { transition-duration: 0.1s; }
@media (prefers-reduced-motion: reduce) {
  .kachel-bild { transform: none; transition: none; }
}
.kachel-bild img { transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1); }
.kachel:has(a:hover) .kachel-bild img,
.kachel:has(a:focus-visible) .kachel-bild img { transform: scale(1.06); }

/* Der Markenpunkt geht unter dem Zeiger an — das kleine Zeichen ist die
   einzige Stelle, an der die Produktfarbe auftreten darf. */
.kachel-marke::before { transition: box-shadow 0.25s ease; }
.kachel:has(a:hover) .kachel-marke::before {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ic) 22%, transparent);
}

/* ---- Die Kachel, die gerade in den Korb ging ----
   Eine kurze Lichtkante laeuft aussen herum. Kein Rahmen, der bleibt:
   die Kante ist der Vorgang, nicht ein Zustand. */
@keyframes korbQuittung {
  from { box-shadow: var(--kante), 0 0 0 1px var(--brand); }
  to   { box-shadow: var(--kante), 0 0 0 1px transparent; }
}
.kachel.quittiert { animation: korbQuittung 0.9s ease-out both; }

@media (prefers-reduced-motion: reduce) {
  .js .raster.reveal .kachel { opacity: 1; transform: none; transition: none; }
  .kachel-bild img { transition: none; }
  .kachel:has(a:hover) .kachel-bild img { transform: none; }
  .kachel.quittiert { animation: none; }
}

/* Der Browser braucht je Kachel einen eigenen Namen, sonst behandelt er
   das Raster als EIN Bild und blendet nur ueber, statt die Kacheln
   einzeln gleiten zu lassen. Der Name kommt aus dem Produktschluessel,
   den der Generator ohnehin schon in data-korb schreibt. */
@supports (view-transition-name: none) {
  .kachel { view-transition-name: var(--vt); }
}
