/* ============================================================
   produkt.css — die Produktseiten

   Eigenes Stylesheet, kein Anfassen der Startseite: deren Layout
   steckt in einem 1.100-Zeilen-<style> im Kopf von index.html und
   laesst sich nicht gefahrlos herausloesen. Alle Werte kommen aus
   den Tokens von brand.css (--s-*, --t-*, --maxw, --r, --e*), damit
   die Seiten trotzdem aus derselben Familie stammen.

   Die Produktfarbe setzt jede Seite selbst als --ic (--duo / --max /
   --nitro aus brand.css). Sie faerbt genau drei Dinge: das Zeichen im
   Kopf, die Zahl im Preis und die Schrittnummern. Nirgends Flaeche —
   brand.css: "Farbe bedeutet etwas."
   ============================================================ */

/* Reset, .container, Kopfzeile, Sprachschalter und Knoepfe stehen in
   css/layout.css — bis 06.09.2026 standen sie hier UND in shop.css
   woertlich doppelt. Diese Datei traegt nur noch, was der
   Produktseite eigen ist. */


/* ---- Der Grund traegt das Produkt ----
   Die Seite stand auf reinem Schwarz, waehrend das Kopfbild in seiner
   eigenen Farbwelt sass — Bild und Seite wirkten wie zwei Sachen
   nebeneinander statt wie eine. Der Grund kommt jetzt aus dem
   Thumbnail selbst (--raum, je Seite gemessen und im Kopf der Seite
   dokumentiert) und verlaeuft ueber 880px in den Seitengrund.

   Warum das hier erlaubt ist und in der Bestellstrecke nicht: "Kein
   Violett" gilt order.css. Eine Produktseite wird von Google betreten,
   nicht aus einem Angebot heraus, und traegt ihre eigene Produktwelt —
   so steht es seit dem 06.09.2026 im Kopf jeder der drei Seiten. Auf
   der UEBERSICHT gilt das ausdruecklich nicht: drei Gruende
   nebeneinander waeren der Regenbogen, den CLAUDE.md verbietet.

   Auf dem body, nicht auf .held: sonst risse zwischen Kopfzeile und
   Held eine Kante auf. 880px, damit der Ton im Kopfbereich (720px)
   traegt und vor "Was Sie bekommen" ausgelaufen ist. */
body {
  background: linear-gradient(180deg, var(--raum, var(--bg)) 0, var(--bg) 880px) no-repeat,
              var(--bg);
}
/* Die Kopfzeile ist sticky und liegt mit rgba(10,10,11,0.78) darueber —
   auf dem getoenten Grund ergab das eine sichtbare schwarze Bank ueber
   einer violetten Seite. Dieselbe Deckung, nur im Ton der Seite. */
.kopf { background: color-mix(in srgb, var(--raum, var(--bg)) 78%, transparent); }

/* ---- Die Seitenbreite ----
   Dieselben 1360 wie die Startseite (shop.css). Ohne das hatte die Site
   ZWEI Breiten: man kam von einer 1360er Uebersicht auf eine 1120er
   Produktseite, und der ganze Inhalt sprang beim Klick um 120px nach
   innen. produkt.css laedt nur diese drei Seiten, die Kasse behaelt
   ihre eigenen 760 (Fokus auf einer Handlung). Fliesstext bleibt
   lesbar: die Absaetze tragen ihre max-widths selbst (46ch, 62ch,
   64ch), sie haengen nicht an --maxw. */
:root { --maxw: 1360px; }

/* ---- Kopfbereich ---- */
/* 64px Polster sind auf einem 375px-Schirm ein Sechstel des Fensters,
   bevor irgendetwas beginnt. Waechst mit der Breite mit. */
.held { padding: clamp(24px, 4.5vw, 64px) 0 var(--s-7); }
.krumen {
  font-size: var(--t-xs); color: var(--faint);
  margin-bottom: var(--s-5); display: flex; gap: 8px; flex-wrap: wrap;
}
.krumen a:hover { color: var(--text); }
/* .held-zeichen entfaellt, siehe .held-titel. */
/* Ohne fill zeichnet ein SVG-Pfad SCHWARZ. Der Funke stand damit
   unsichtbar auf #131315 — im Screenshot vom 05.09.2026 sah man an der
   Stelle nichts. */
.held h1 {
  font-size: var(--t-4xl); line-height: 1.08;
  letter-spacing: -0.035em; font-weight: 700;
}
.held-unter {
  font-size: var(--t-lg); color: var(--muted); line-height: 1.5;
  max-width: 46ch;
}

/* Preis + Handlung */
/* Preisleiste und Laufzeit sind seit dem 05.09.2026 EIN Kasten: der
   Screenshot zeigte zwei Objekte auf verschiedenen Hoehen mit einem Loch
   dazwischen. Rahmen und Abstaende traegt jetzt .held-angebot. */
.angebot-oben {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4) var(--s-6);
  flex-wrap: wrap;
  padding: var(--s-5) var(--s-6);
}

.held-angebot {
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--e1);
  box-shadow: var(--kante), var(--tiefe);
  overflow: hidden;
  max-width: 780px;
}

.angebot-laufzeit {
  padding: var(--s-5) var(--s-6);
  border-top: 1px solid var(--line);
  display: grid;
  gap: var(--s-4);
}
.preis-zahl {
  font-family: var(--mono); font-size: var(--t-3xl);
  font-weight: 600; letter-spacing: -0.03em; color: var(--text);
  line-height: 1;
}
.preis-fuss { font-size: var(--t-xs); color: var(--faint); }
/* Bis 08.09.2026 stand hier margin-left: auto — die Knoepfe wurden an
   die rechte Kante geschoben, und bei 1900px lagen zwischen Preis und
   "Hier kaufen" 437px Nichts. Das waren zwei Inseln, keine Zeile; das
   Fundament sagt "alles linksbuendig, keine mittigen Inseln". Jetzt
   stehen Preis und Handlung als EINE Gruppe zusammen, der Rest der
   Breite bleibt schlicht leer — so, wie jede andere Zeile der Seite
   auch endet. */
.preisleiste-handlung { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.angebot-oben { justify-content: flex-start; column-gap: var(--s-7); }
@media (max-width: 620px) {
  .preisleiste-handlung { margin-left: 0; width: 100%; }
  .preisleiste-handlung .btn { flex: 1 1 100%; }
}

/* ---- Abschnitte ---- */
.abschnitt { padding: var(--s-7) 0; border-top: 1px solid var(--line); }
.abschnitt h2 {
  font-size: var(--t-2xl); letter-spacing: -0.025em; font-weight: 700;
  margin-bottom: var(--s-5);
}
.abschnitt h3 {
  font-size: var(--t-md); font-weight: 600; margin-bottom: 6px;
}
.fliess { color: var(--muted); max-width: 62ch; }
.fliess + .fliess { margin-top: var(--s-3); }
.fliess strong { color: var(--text); font-weight: 600; }
.fliess a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--line-2); }
.fliess a:hover { text-decoration-color: var(--text); }

/* Leistungen */
.punkte { list-style: none; display: grid; gap: var(--s-4); margin-top: var(--s-2); }
@media (min-width: 720px) { .punkte { grid-template-columns: 1fr 1fr; gap: var(--s-4) var(--s-6); } }
.punkte li { display: flex; gap: var(--s-3); align-items: flex-start; }
/* --ok heisst in dieser Marke "bezahlt/verfuegbar". Hier sind es
   Listenpunkte, keine Zustaende — also die Produktfarbe. */
.punkte svg {
  width: 17px; height: 17px; flex: none; margin-top: 4px;
  stroke: var(--ic); fill: none; stroke-width: 2.6;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ---- Die Haken zeichnen sich ----
   Dieselbe Geste wie der Lichtbogen auf der Erfolgsseite, nur klein und
   sechsmal nacheinander: das Zeichen ENTSTEHT, statt da zu sein. Der
   versteckte Anfangszustand haengt an html.js-reveal — ohne JS waeren
   die Haken sonst fuer immer weg. */
html.js-reveal .punkte svg path { stroke-dasharray: 30; stroke-dashoffset: 30; }
html.js-reveal .punkte.in svg path { animation: hakenZieht 0.5s cubic-bezier(0.65, 0, 0.35, 1) forwards; }
html.js-reveal .punkte.in li:nth-child(1) svg path { animation-delay: 0.06s; }
html.js-reveal .punkte.in li:nth-child(2) svg path { animation-delay: 0.14s; }
html.js-reveal .punkte.in li:nth-child(3) svg path { animation-delay: 0.22s; }
html.js-reveal .punkte.in li:nth-child(4) svg path { animation-delay: 0.30s; }
html.js-reveal .punkte.in li:nth-child(5) svg path { animation-delay: 0.38s; }
html.js-reveal .punkte.in li:nth-child(6) svg path { animation-delay: 0.46s; }
@keyframes hakenZieht { to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .punkte svg path { stroke-dashoffset: 0; }
  html.js-reveal .punkte.in svg path { animation: none; }
}
.punkte span { color: var(--muted); }
.punkte b { color: var(--text); font-weight: 600; }

/* Bedingungen. Drei Dinge, drei Zeilen — als Absatz musste man sie
   suchen, und genau an diesen dreien scheitern Bestellungen: Anzeigename
   statt Benutzername, privates Profil, noch laufendes Abo. Der Punkt
   traegt die Produktfarbe: es ist das, was DIESES Produkt braucht. */
.bedarf { list-style: none; display: grid; gap: var(--s-4); max-width: 64ch; }
.bedarf li { display: flex; gap: var(--s-3); align-items: flex-start; color: var(--muted); }
.bedarf li::before {
  content: "";
  flex: none; width: 6px; height: 6px; margin-top: 9px;
  border-radius: 50%; background: var(--ic, var(--muted));
}
.bedarf b { color: var(--text); font-weight: 600; }

/* Ablauf */
.schritte { list-style: none; counter-reset: s; display: grid; gap: var(--s-5); }
.schritte li { display: flex; gap: var(--s-4); align-items: flex-start; counter-increment: s; }
.schritte li::before {
  content: counter(s);
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 12.5px; font-weight: 700;
  color: var(--ic, var(--text));
  border: 1px solid var(--line-2); background: var(--e1);
}

/* Jede Nummer zuendet einmal, wenn der Abschnitt ankommt: der Rand geht
   kurz auf die Produktfarbe und laesst einen Ring auslaufen. Dieselbe
   Mechanik wie markeAn auf der Startseite — einmal, dann Ruhe. */
html.js-reveal .schritte.in li::before { animation: nummerZuendet 0.9s cubic-bezier(0.22, 1, 0.36, 1) both; }
html.js-reveal .schritte.in li:nth-child(1)::before { animation-delay: 0.05s; }
html.js-reveal .schritte.in li:nth-child(2)::before { animation-delay: 0.20s; }
html.js-reveal .schritte.in li:nth-child(3)::before { animation-delay: 0.35s; }
@keyframes nummerZuendet {
  0%   { border-color: var(--ic); box-shadow: 0 0 0 0 color-mix(in srgb, var(--ic) 55%, transparent); }
  100% { border-color: var(--line-2); box-shadow: 0 0 0 10px transparent; }
}
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .schritte.in li::before { animation: none; }
}

/* Fragen */
.frage {
  border-top: 1px solid var(--line);
  padding: var(--s-4) 0;
}
.frage:last-of-type { border-bottom: 1px solid var(--line); }
.frage > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  font-weight: 600; font-size: var(--t-md);
}
.frage > summary::-webkit-details-marker { display: none; }
.frage > summary::after {
  content: ""; flex: none; width: 10px; height: 10px;
  border-right: 1.8px solid var(--faint); border-bottom: 1.8px solid var(--faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.22s var(--e1, ease);
}
.frage[open] > summary::after { transform: rotate(225deg) translate(-2px, -2px); }
.frage > summary:hover { color: var(--text); }
.frage-inhalt { padding-top: var(--s-3); color: var(--muted); max-width: 62ch; }
.frage-inhalt p + p { margin-top: var(--s-3); }

/* Abschluss */
.abschluss {
  margin: var(--s-7) 0 var(--s-8);
  padding: var(--s-6); border-radius: 16px;
  border: 1px solid var(--line); background: var(--e1);
  box-shadow: var(--kante), var(--tiefe);
  text-align: center;
}
.abschluss h2 { font-size: var(--t-xl); margin-bottom: var(--s-3); letter-spacing: -0.02em; }
.abschluss p { color: var(--muted); max-width: 52ch; margin: 0 auto var(--s-5); }
.abschluss-handlung { display: flex; gap: var(--s-3); justify-content: center; flex-wrap: wrap; }

/* ---- Fuss ---- */
/* .fuss steht in css/layout.css. */


/* ---- Der Kopf wird zweispaltig: Text links, Schluesselkarte rechts ----
   Die Karte ist das Identitaetselement der Marke. Auf der Einloeseseite
   wirkte sie ueber dem Passwortfeld fehl am Platz (ausprobiert und
   zurueckgenommen, 20.08.2026) — eine Produktseite ist aber genau die
   Marketingflaeche, fuer die sie gedacht ist. Ohne Preis darauf: der
   steht in der Leiste darunter, zweimal waere es eine Behauptung zu viel. */
/* ---- Der Kopf: drei Bereiche, EINE Kante ----
   Vorher ein Stapel aus Bloecken mit vier verschiedenen Breiten (656,
   46, 613, 400) und den Abstaenden 24/16/12/32/8 — die Karte klebte
   8px unter der Preisleiste, war 400 breit wo alles andere 656 war und
   liess 280px Leere rechts stehen. Gemessen am 05.09.2026, nachdem der
   Nutzer sagte, es sehe durcheinander aus. Er hatte recht, und es war
   keine Geschmacksfrage.

   Jetzt drei benannte Bereiche, alle auf der Kante des Containers.

   Schmal: Text, PREIS, Karte. Erst war die Karte in der Mitte — sie ist
   bei voller Breite 414px hoch und schob den Kaufknopf damit unter die
   Falz. Der Preis mit dem Knopf ist das Ziel der Seite und gehoert nach
   oben; die Karte siegelt den Kopf danach ab.

   Breit: Text und Preis links untereinander, die Karte rechts ueber
   beide Zeilen. */
.held-inhalt { display: grid; gap: var(--s-5); }

/* ---- Das Produktbild im Kopf (08.09.2026) ----
   Weiter unten steht seit dem 06.09. "Kein Bild. Ein Produkt aus
   Laufzeit, Frist und Konto hat kein Foto". Das galt dem Datenblatt —
   aber die Kachel, von der man kommt, ZEIGT das Produkt, und die Seite
   danach zeigte nur Text. Jetzt dasselbe Bild wie auf der Kachel, damit
   Uebersicht und Seite dasselbe Produkt behaupten. Es ist die einzige
   Farbe auf der Seite und bekommt deshalb keinen Rahmen und kein
   Leuchten: Kante und Tiefe wie das Angebot, sonst nichts.

   Schmal sitzt es als 72px-Marke rechts in der Krumenzeile, wie das
   Zeichen einer App ueber ihrem Namen. Erster Versuch war ein 90px-Bild
   NEBEN Ueberschrift und Unterzeile: das drueckte die Ueberschrift bei
   375px auf drei Zeilen, die Unterzeile auf vier, und der Kaufknopf
   rutschte von ~726 auf 798px — unter die Falz. Gemessen, dann
   verworfen. So kostet es 28px, und alles unterhalb laeuft voll. */
.held-bild {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  border-radius: 14px; background: var(--lack-tief);
  box-shadow: var(--kante), var(--tiefe);
}
.held-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ---- Das Bild kippt zum Zeiger (js/kippen.js) ----
   Die einzige Bewegung der Seite, die nicht beim Ankommen passiert.
   6 Grad, mehr nicht: darueber sieht ein Quadrat aus wie ein Deckel,
   der aufgeht. Perspektive 900px haelt die Verzerrung flach.

   Das Zurueckfallen dauert laenger als das Folgen (0,5s gegen 0,1s) —
   ein Gegenstand, der genauso schnell zurueckschnappt, wie er folgt,
   wirkt wie ein Gummiband, nicht wie Masse. */
/* Der Doppelselektor ist Absicht, kein Spezifitaets-Trick ins Blaue:
   das Einblende-System besitzt `transform` auf jedem .reveal-Element
   (`html.js-reveal .reveal.in { transform: none }`, Spezifitaet 0-3-1).
   Ein einfaches `.held-bild` verliert dagegen und hat genau nichts
   getan. Die Aufteilung ist jetzt sauber: der EINTRITT gehoert weiter
   dem Reveal (es schiebt das Bild von unten herein), der RUHEZUSTAND
   danach dem Kippen. */
.held-bild,
html.js-reveal .held-bild.reveal.in {
  transform: perspective(900px)
             rotateX(calc(var(--ky, 0) * -6deg))
             rotateY(calc(var(--kx, 0) * 6deg));
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.held-bild:hover { transition-duration: 0.1s; }
@media (prefers-reduced-motion: reduce) {
  .held-bild { transform: none; transition: none; }
}
.held-inhalt { grid-template-columns: minmax(0, 1fr) 72px; align-items: start; }
.held-inhalt > .krumen { grid-column: 1; grid-row: 1; align-self: center; }
.held-inhalt > .held-bild { grid-column: 2; grid-row: 1; }
.held-inhalt > h1,
.held-inhalt > .held-unter,
.held-inhalt > .held-spez,
.held-inhalt > .held-angebot { grid-column: 1 / -1; }


/* ---- Das Kopfbild ist die LAUFZEIT ----
   Hier stand bis 05.09.2026 die Schluesselkarte. Der Nutzer hat den
   Fehler gesehen: ihr Seitenverhaeltnis ist 1.586 — die ISO-Norm fuer
   Kreditkarten —, sie traegt einen Chip und einen Code-Platzhalter.
   Neben einem Preis liest das als Zahlungsmittel, nicht als Produkt. Und
   vor dem Kauf gibt es gar keinen Code; CLAUDE.md haelt genau das fuer
   die Regal-Karten schon fest. Auf der Startseite darf sie bleiben: dort
   ist sie das Identitaetselement in einer Auswahl, nicht die Aussage
   neben einem Preis.

   Stattdessen das, was man tatsaechlich kauft: zwoelf Monate. Das Band
   fuellt sich beim Ankommen von links, Monat fuer Monat, und HOERT dann
   sichtbar auf — es verlaengert sich nicht. Damit beantwortet das Bild
   nebenbei die Frage auf Platz 5 der eBay-Auswertung ("was passiert nach
   dem Jahr?"): es laeuft aus, es wird nichts abgebucht.

   Die Farbe bleibt eine LINIE, keine Flaeche: 10px hoch. Ein
   vollflaechig eingefaerbter Kasten waere Farbe als Dekor, und die
   Marke sagt, Hierarchie kommt aus Helligkeit. */
/* Der Rahmen liegt jetzt aussen, am .held-angebot. */

.laufzeit-kopf,
.laufzeit-fuss {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  font-size: var(--t-xs);
  line-height: 1.4;
}
.laufzeit-kopf { color: var(--text); font-weight: 600; }
.laufzeit-fuss { color: var(--faint); }
.laufzeit-kopf span:last-child,
.laufzeit-fuss span:last-child { text-align: right; }

.laufzeit-band {
  position: relative;
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 3px;
  height: 10px;
}

/* ---- Der gefuellte Monat traegt den Schriftzug-Verlauf ----
   Bis 08.09.2026 war jeder Monat eine flache Mischung aus --ic. Jetzt
   liegt der Verlauf des THUMBNAIL-SCHRIFTZUGS (--band, je Seite
   gemessen) ueber dem ganzen Band — und jeder Monat zeigt genau sein
   Zwoelftel davon.

   Der Trick dabei: das Bild ist 1200 % breit, und jeder Monat schiebt
   es um sein Zwoelftel weiter (--i mal 100 % / 11). Zusammengesetzt
   ergeben die zwoelf Kaesten wieder den ganzen Verlauf. Die 3px-Luecken
   zaehlt die Rechnung nicht mit — auf ein 1000px-Band sind das 33px
   Stauchung, rund 3 %, und die sieht auf 10px Hoehe niemand.

   Der Verlauf sitzt auf einem Pseudoelement, nicht auf dem Kasten
   selbst: background-image laesst sich nicht animieren, opacity schon.
   Der leere Kasten (--e3) bleibt darunter die Spur.

   ::BEFORE, nicht ::after — das war der erste Anlauf und er war falsch:
   `nth-child(3n)::after` traegt seit dem 06.09.2026 die Achsenzahlen
   (03, 06, 09, 12). Jeder dritte Monat blieb dadurch grau, und zwar
   lautlos: kein Fehler, nur ein Band mit vier Luecken.

   Ebenso kein `overflow: hidden` zum Runden der Ecken — die Zahlen
   haengen mit `top: calc(100% + 7px)` UNTER dem Kasten und waeren
   damit abgeschnitten. Das Pseudoelement erbt stattdessen den Radius. */
.laufzeit-monat {
  position: relative;
  border-radius: 2px;
  background: var(--e3);
}
.laufzeit-monat::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  background-image: var(--band, linear-gradient(90deg, var(--ic), var(--ic)));
  background-size: 1200% 100%;
  background-position-x: calc(var(--i, 0) * 100% / 11);
  opacity: 0;
}
.laufzeit-monat:nth-child(1)  { --i:  0; }
.laufzeit-monat:nth-child(2)  { --i:  1; }
.laufzeit-monat:nth-child(3)  { --i:  2; }
.laufzeit-monat:nth-child(4)  { --i:  3; }
.laufzeit-monat:nth-child(5)  { --i:  4; }
.laufzeit-monat:nth-child(6)  { --i:  5; }
.laufzeit-monat:nth-child(7)  { --i:  6; }
.laufzeit-monat:nth-child(8)  { --i:  7; }
.laufzeit-monat:nth-child(9)  { --i:  8; }
.laufzeit-monat:nth-child(10) { --i:  9; }
.laufzeit-monat:nth-child(11) { --i: 10; }
.laufzeit-monat:nth-child(12) { --i: 11; }
.laufzeit-monat:first-child { border-top-left-radius: 6px; border-bottom-left-radius: 6px; }
.laufzeit-monat:last-child { border-top-right-radius: 6px; border-bottom-right-radius: 6px; }

/* Der Schlussstrich: hier ist Ende. Kein Pfeil, keine Fortsetzung.

   Er kommt zuletzt — nach dem zwoelften Monat (0,655s Versatz plus
   0,4s Lauf), und zwar aus der Mitte heraus in die volle Hoehe. Das
   Fuellen der zwoelf Monate hatte bis dahin keinen Schluss: es hoerte
   einfach auf. Jetzt setzt der Strich den Punkt. */
.laufzeit-schluss {
  position: absolute;
  right: -1px; top: -5px; bottom: -5px;
  width: 2px;
  border-radius: 1px;
  background: var(--text);
}
html.js-reveal .held-angebot .laufzeit-schluss { transform: scaleY(0); }
html.js-reveal .held-angebot.in .laufzeit-schluss {
  animation: schlussSetzt 0.34s cubic-bezier(0.34, 1.56, 0.64, 1) 1.06s both;
}
@keyframes schlussSetzt {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .held-angebot .laufzeit-schluss,
  html.js-reveal .held-angebot.in .laufzeit-schluss {
    animation: none; transform: none;
  }
}

/* Zwoelf Monate fuellen sich nacheinander — 55ms Versatz, zusammen knapp
   eine Sekunde. Der Anfangszustand haengt bewusst NICHT an js-reveal: ein
   ungefuelltes Band ist eine gueltige Darstellung, kein Fehler. */
html.js-reveal .held-angebot.in .laufzeit-monat::before {
  animation: monatFuellt 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes monatFuellt {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .held-angebot.in .laufzeit-monat::before {
    animation: none;
    opacity: 1;
  }
}

/* ---- Zeichen und Ueberschrift sind EIN Block ----
   Ein 46px-Kaestchen allein in einer Spalte aus vollbreiten Bloecken war
   die vierte Breite. Als Zeile davor beschriftet es die Ueberschrift,
   statt ueber ihr zu schweben. */
/* Das eingefaerbte Markenzeichen ist am 05.09.2026 entfallen. Zwei
   Gruende, der zweite wiegt schwerer: neben dem Namen war es redundant —
   die Kopfzeile traegt die Marke schon —, und CLAUDE.md sagt "Das Logo
   nimmt nie eine Farbe an: es ist der Absender, kein Signal". In der
   Produktfarbe getaucht war es genau das Gegenteil. */
.held-titel { margin: 0; }

/* ---- Einblenden: dieselbe Sprache wie auf der Startseite ----
   Versteckt wird NUR, wenn JS laeuft (html.js-reveal, gesetzt von einem
   Inline-Skript im Kopf). Andersherum waere es ein schlechtes Geschaeft:
   loest der Beobachter nicht aus — versteckter Tab, kein
   IntersectionObserver, ein Crawler, der anders rendert —, bliebe die
   Seite auf opacity 0 stehen. Bei einer Seite, deren einziger Zweck das
   Gefundenwerden ist, waere das der teuerste denkbare Fehler. */
html.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s var(--e1, ease), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
html.js-reveal .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js-reveal .reveal { opacity: 1; transform: none; transition: none; }
}


/* ---- Die Produktfarbe traegt die Seite, nicht nur die Zahl ----
   Vorher tauchte sie an genau EINER Stelle auf (dem Preis). Auf einer
   Produktseite ist die Farbe aber die Aussage: sie sagt, wo man ist.
   Trotzdem nirgends als Flaeche — brand.css: Hierarchie kommt aus
   Helligkeit, Farbe bedeutet etwas. */
::selection { background: color-mix(in srgb, var(--ic) 32%, transparent); color: var(--text); }

a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2px solid var(--ic);
  outline-offset: 3px;
  border-radius: 4px;
}

/* Die aufgeklappte Frage bekommt eine Kante in der Produktfarbe — die
   einzige Stelle, an der die Seite auf eine Handlung antwortet. */
.frage[open] > summary { color: var(--text); }
.frage[open] > summary::after { border-color: var(--ic); }
.frage[open] .frage-inhalt {
  border-left: 2px solid color-mix(in srgb, var(--ic) 45%, transparent);
  padding-left: var(--s-4);
  margin-left: 1px;
}

/* Der Kopf traegt einen Faden in der Produktfarbe. Ein Pixel, ganz
   unten — genug, damit die Seite ihre Zugehoerigkeit zeigt, ohne dass
   irgendwo eine farbige Flaeche entsteht. */
.kopf { border-bottom-color: color-mix(in srgb, var(--ic) 22%, var(--line)); }

html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(1)::before { animation-delay: 0.050s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(2)::before { animation-delay: 0.105s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(3)::before { animation-delay: 0.160s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(4)::before { animation-delay: 0.215s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(5)::before { animation-delay: 0.270s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(6)::before { animation-delay: 0.325s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(7)::before { animation-delay: 0.380s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(8)::before { animation-delay: 0.435s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(9)::before { animation-delay: 0.490s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(10)::before { animation-delay: 0.545s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(11)::before { animation-delay: 0.600s; }
html.js-reveal .held-angebot.in .laufzeit-monat:nth-child(12)::before { animation-delay: 0.655s; }


/* ============================================================
   WERKZEUG — die Produktseite liest sich wie ein Messinstrument
   Richtung vom Nutzer gewaehlt am 06.09.2026, nachdem er sagte, die
   Produktseiten saehen mies aus. Diesmal habe ich die Seite vorher
   angesehen statt darueber zu raten. Drei Befunde:

   1. Vier .abschnitt-Bloecke hintereinander, alle dieselbe Schablone:
      linksbuendige Liste, gleiche Breite, gleicher flacher Grund. Nach
      dem Kopf passierte 1.400px lang nichts Neues.
   2. Der Kopf war 578px hoch und rechts leer.
   3. JetBrains Mono wurde geladen und NIE benutzt — null Mono-Regeln in
      dieser Datei. brand.css sagt selbst, die Mono gehoere dorthin, "wo
      der Zugangscode SELBST das Produkt ist". Ein Abo, das aus einer
      Laufzeit, einer Frist und einem Konto besteht, ist genau das.

   Die Regel dieses Blocks: ZAHLEN sind Mono, TEXT ist Instrument Sans.
   Und Gruen meldet nur noch einen Zustand — "dieser Monat ist bezahlt".
   Schrittnummern und Bedarfspunkte geben es zurueck; sie beschreiben
   einen Ablauf und eine Bedingung, keinen Zustand.

   KEINE neuen Kaesten. CLAUDE.md: "Hervorhebung laeuft ueber Licht und
   Linien, nicht ueber Rahmen" — ein erster Entwurf dieses Blocks hatte
   Datenblatt und Bedarf gerahmt und war damit falsch.
   ============================================================ */

/* ---- Das Datenblatt: was vorher rechts fehlte ----
   Kein Bild. Ein Produkt aus Laufzeit, Frist und Konto hat kein Foto —
   es hat Werte. Sie stehen jetzt dort, wo 280px Leere waren, und zwar
   als Haarlinienliste wie auf der Startseite, nicht als Kasten. */
.held-spez { display: grid; border-top: 1px solid var(--line); }
/* Ab 560px zweispaltig — einspaltig zog es die Zeile ueber die volle
   Breite, und bei 960px standen "LAUFZEIT" und "12 Monate" 912px
   auseinander. Eine Zeile, deren Etikett und Wert man mit den Augen
   verbinden muss, ist keine Liste mehr. Der zweispaltige Fall stand
   bis 08.09.2026 erst ab 980px zur Verfuegung, also genau dort, wo der
   Kopf ohnehin umbrach. */
@media (min-width: 560px) {
  .held-spez { grid-template-columns: 1fr 1fr; column-gap: var(--s-6); }
}

/* ---- Die Mittelstrecke (620-879px) ----
   Hier war die groesste Luecke: der Kopf ist noch nicht zweispaltig,
   das Bild klebte aber weiter als 72px-Marke in der Krumenzeile — bei
   768px Fenster eine Briefmarke am rechten Rand einer 720px-Zeile, mit
   einer 20px-Zeile daneben und viel Nichts darunter. Auf Tablets und
   geteilten Fenstern ist das der haeufigste Fall.

   Jetzt rueckt es neben Ueberschrift und Unterzeile und waechst mit.
   Untergrenze 620 und nicht 560: darunter bliebe der Textspalte zu
   wenig, die Ueberschrift braeche auf drei Zeilen und schoebe den
   Kaufknopf weiter nach unten, als das Bild wert ist. */
@media (min-width: 620px) and (max-width: 879px) {
  .held-inhalt { grid-template-columns: minmax(0, 1fr) clamp(132px, 21vw, 190px); }
  .held-inhalt > .krumen { grid-column: 1 / -1; grid-row: 1; }
  .held-inhalt > h1,
  .held-inhalt > .held-unter { grid-column: 1; }
  .held-inhalt > .held-bild { grid-column: 2; grid-row: 2 / span 2; align-self: start; }
  .held-inhalt > .held-spez,
  .held-inhalt > .held-angebot { grid-column: 1 / -1; }
}
.held-spez > div {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-4); padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.held-spez dt {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--faint);
  white-space: nowrap;
}
.held-spez dd {
  font-family: var(--mono); font-size: 13px; font-weight: 600;
  color: var(--text); text-align: right; letter-spacing: -0.01em;
}

/* ---- Kein Piktogramm im Kopf, dritter und letzter Anlauf ----
   Am 06.09.2026 dreimal versucht: als Kaestchen ueber der Ueberschrift
   (schwebte), am Preis mittig ueber beide Zeilen (sass schief), am Preis
   auf der Zahl (sass richtig — und wirkte trotzdem falsch).

   Dass die Position dreimal nicht half, war die Antwort: nicht der Platz
   war das Problem, sondern das Element.

   1. Ein Herz neben einem Preis heisst im Handel "merken". Es liest sich
      als Bedienelement und ist Dekoration.
   2. Diese Seite spricht Zahlen und Linien — Mono-Ziffern, Haarlinien,
      ein Band mit Achse, gezaehlte Kapitel. Ein weiches Piktogramm ist
      darin das einzige niedliche Element.
   3. Der Block ueber diesem sagt "Gruen meldet nur noch einen Zustand".
      Ein gruenes Herz direkt ueber dem gruenen Band teilt genau dieses
      Signal in zwei.

   Die Seite hat ihr Produktzeichen ohnehin: das gefuellte Band. Gruen,
   blau, violett — schon farbig, schon in der Sprache der Seite, und es
   sagt zusaetzlich, was man kauft. Ein Piktogramm daneben ist die
   vierte Identitaetsangabe nach Ueberschrift, Grund und Band.

   Auf den REGAL-KARTEN bleibt das Set (Herz/Sprechblase/Blitz): dort
   unterscheidet es drei Produkte auf einen Blick und sitzt auf einer
   Kartenflaeche, die ein Piktogramm traegt. Hier weiss man laengst, wo
   man ist — die Ueberschrift sagt es in 60px. */
.preis { display: flex; flex-direction: column; gap: 2px; }

/* Breit: Text und Datenblatt links, das Bild rechts ueber alle vier
   Zeilen, das Angebot darunter ueber beide Spalten. Bis 08.09.2026
   stand das Datenblatt rechts (296px); jetzt rueckt es unter die
   Unterzeile und wird zweispaltig, damit Etikett und Wert nicht 660px
   auseinanderstehen. :has() bindet das an die Bedingung, dass es ein
   Datenblatt GIBT — eine Seite ohne eines behaelt die schmale
   Anordnung, statt eine leere Spalte aufzureissen. */
/* Bis 08.09.2026 gab es genau EINEN Umbruch (980px). Zwischen 375 und
   979 passierte nichts: das Bild blieb 72px, auch bei 960px Fenster,
   wo es als Briefmarke am rechten Rand einer 912px-Zeile klebte. Jetzt
   drei Stufen — 880 (Kopf wird zweispaltig, Bild 240), 1080 (320),
   1240 (440). */
@media (min-width: 880px) {
  .held-inhalt:has(.held-spez) {
    grid-template-columns: minmax(0, 1fr) 240px;
    column-gap: var(--s-7);
    align-items: start;
  }
  .held-inhalt:has(.held-spez) > .krumen     { grid-column: 1; grid-row: 1; }
  .held-inhalt:has(.held-spez) > h1          { grid-column: 1; grid-row: 2; }
  .held-inhalt:has(.held-spez) > .held-unter { grid-column: 1; grid-row: 3; }
  .held-inhalt:has(.held-spez) > .held-spez  {
    grid-column: 1; grid-row: 4;
    grid-template-columns: 1fr 1fr; column-gap: var(--s-6);
  }
  .held-inhalt:has(.held-spez) > .held-bild  { grid-column: 2; grid-row: 1 / span 4; border-radius: 18px; }
}
@media (min-width: 1080px) {
  .held-inhalt:has(.held-spez) { grid-template-columns: minmax(0, 1fr) 320px; }
}
/* Auf der breiten Seite darf das Bild mitwachsen: 360px waren neben
   einer 49px-Ueberschrift und 1312px Innenmass ein Vorschaubild, kein
   Produktbild. */
@media (min-width: 1240px) {
  .held-inhalt:has(.held-spez) { grid-template-columns: minmax(0, 1fr) 440px; }
  .held-inhalt:has(.held-spez) > .held-angebot {
    grid-column: 1 / -1; grid-row: 5; max-width: none;
  }
}

/* ---- Die Laufzeit bekommt eine Achse ----
   Ein Balken ohne Skala ist ein Ladebalken — genau so las sich das Band
   im Screenshot. Mit einer Teilung alle drei Monate ist es eine Messung.
   Die Ziffern kommen aus einem Zaehler: die Monate stehen im HTML schon
   zwoelfmal, ein dreizehnter Satz Markup waere Verschwendung. */
.laufzeit-band { counter-reset: monat; margin-bottom: 22px; }
.laufzeit-monat { counter-increment: monat; position: relative; }
.laufzeit-monat:nth-child(3n)::after {
  content: counter(monat, decimal-leading-zero);
  position: absolute; top: calc(100% + 7px); right: 0;
  font-family: var(--mono); font-size: 9.5px; font-weight: 500;
  letter-spacing: 0.08em; color: var(--faint);
}
.laufzeit-kopf span {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase;
}

/* ---- Die Abschnitte zaehlen sich selbst ----
   Dasselbe Idiom wie auf der Startseite (dort .sec-head::after): die
   Nummer haengt zweistellig RECHTS an der Haarlinie und stanzt sie mit
   dem Seitengrund aus. Damit werden aus vier gleich aussehenden Bloecken
   vier Kapitel — man sieht, wo man ist und wie viel noch kommt.

   Nicht unter die Ueberschrift: "Eine Markierung gehoert nie unter die
   Zeile" — dort laege sie auf der Trennlinie zum naechsten Abschnitt. */
main { counter-reset: kap; }
.abschnitt > .container { position: relative; }
.abschnitt > .container::before {
  counter-increment: kap;
  content: counter(kap, decimal-leading-zero);
  position: absolute; right: var(--s-5); top: calc(-1 * var(--s-7));
  transform: translateY(-50%);
  padding: 0 9px; background: var(--bg);
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: 0.16em; color: var(--faint);
}

/* ---- Der Ablauf laeuft quer ----
   Drei Schritte untereinander lasen sich wie eine weitere Liste. Als
   Schiene nebeneinander liest derselbe Inhalt sich als Vorgang: eine
   Haarlinie auf Nummernhoehe verbindet sie zu einer Zeitachse. */
@media (min-width: 860px) {
  .schritte { grid-template-columns: repeat(3, 1fr); gap: var(--s-6); position: relative; }
  .schritte li { flex-direction: column; gap: var(--s-4); }
  /* KEIN z-index: -1. .abschnitt hat keinen eigenen Grund, also laege die
     Achse hinter dem Seitenhintergrund und waere unsichtbar. Sie braucht
     das auch nicht: ein ::before der Liste wird VOR den <li> gezeichnet,
     und jede Nummer stanzt sich mit ihrem eigenen var(--bg) darueber. */
  .schritte::before {
    content: ""; position: absolute; left: 0; right: 0; top: 15px;
    height: 1px; background: var(--line);
  }
}
/* Die Nummer ist ab hier weiss und steht auf dem Seitengrund, damit die
   Achse hinter ihr sauber ausgestanzt wird. Sie zaehlt einen Ablauf; sie
   meldet keinen Zustand, also traegt sie keine Produktfarbe. */
.schritte li::before { color: var(--text); background: var(--bg); }
/* Dasselbe fuer die Bedingungen: was man BRAUCHT, ist kein Zustand. */
.bedarf li::before { background: var(--line-2); }
