/*
  Die Startseite - und NUR sie.

  stil.css bleibt, was es war: die Gestaltung der Rechtsseiten, eine Spalte
  Fliesstext auf 42rem. Diese Datei liegt daneben und traegt die Landingpage.
  Bewusst getrennt und nicht in stil.css hineingeschrieben: Datenschutz,
  Impressum, AGB und der Loeschweg haengen an denselben Klassen (.kopf, .inhalt,
  .kacheln), und eine Startseite, die dort mitmischt, aendert vier Rechtstexte
  mit, ohne dass es jemand merkt.

  Die Tokens kommen aus stil.css, das die Startseite VOR dieser Datei laedt -
  Farben, Radien, Abstaende und @font-face stehen dort einmal. Wer eine Farbe
  aendert, aendert sie in ui/theme/Color.kt und in stil.css, nie hier.

  Kein Build-Schritt, keine Abhaengigkeit, keine Anfrage nach draussen.

  KEINE GEWICHTE UEBER 600 IM FLIESSTEXT. Inter liegt hier als woff2-Subset mit
  einer wght-Achse von 400 bis 600 (tools/web_schrift_subset.py) - genau die
  zwei Gewichte, die auch die App kennt (ui/theme/Type.kt: bodyFamily()). Vier
  kleine Labels standen auf 700 und haetten den Browser synthetisch faelschen
  lassen: .schritte .nr, .store-status, .plan-liste b, .takt-sparen. Sie stehen
  jetzt auf 600 - die Rolle, die die App dafuer hat (labelLarge). Ueber 600 geht
  nur Nunito, und Nunito traegt ausschliesslich Ueberschriften und Titel.

  KEINE SCHLAGSCHATTEN. Die Seite hatte welche - unter den Knoepfen, unter dem
  Telefon, unter der Rezeptkarte, unter der Premium-Karte - und sie sahen nach
  Bauteilen aus, die ueber dem Grund schweben, statt nach einer Flaeche.
  Getrennt wird ueber Rand und Flaechenton, nicht ueber Tiefe. Wer hier ein
  `box-shadow` ergaenzt, nimmt es wieder heraus; die einzige Ausnahme ist die
  Lichtkante INNEN am Telefonrahmen (`inset`), und die ist kein Schatten.
*/

/* --- Was diese Seite zusaetzlich braucht --------------------------------- */

:root {
  /*
    Die gesaettigten Enden derselben Achse. Sie stehen in Color.kt als
    ClayGradientStart/End und tragen in der App die Verlaufskarte des
    Abo-Screens; hier tragen sie die Preisflaeche.

    Beide am 10.10.2026 mit der Palette nachgezogen (#7A2F1A -> #642514 und
    #E8A176 -> #E9AA98). ClayGradientMid braucht hier keinen eigenen Token mehr:
    Er IST --clay-500.
  */
  --clay-tief: #642514;
  --clay-warm: #E9AA98;

  /*
    Text auf dunklem Grund wird NICHT grau. Ink900 ist ein warmer Ton, und ein
    neutrales Grau darauf sieht schmutzig aus - dieselbe Begruendung wie bei
    ShadowTint in Color.kt. Das hier ist Sand200, in die Tiefe gezogen.
  */
  --auf-dunkel:       #F3EBE2;
  --auf-dunkel-leise: #C4B2A4;
  --auf-clay-leise:   #FADFCF;

  --sp-4xl: 72px;
  --sp-5xl: 112px;

  /*
    Zwei Kurven, und der Unterschied ist Absicht. `--kurve` geht schnell los
    und laeuft weich aus (expo): das Richtige fuer alles, was unter dem Zeiger
    passiert - ein Knopf soll auf den Griff sofort antworten.

    `--kurve-auftritt` ist die gleichmaessigere (ease-out-cubic) und traegt
    alles, was von selbst hereinkommt. Auf der Expo-Kurve hat ein Absatz nach
    einem Sechstel der Zeit schon die Haelfte des Weges hinter sich - er ist
    damit fast sofort da und danach nur noch am Auslaufen. Das liest sich als
    Schnappen, nicht als Gleiten.
  */
  --kurve: cubic-bezier(0.16, 1, 0.3, 1);
  --kurve-auftritt: cubic-bezier(0.33, 1, 0.68, 1);
}

/*
  Fokusring, Auswahlfarbe und die Sprungmarke stehen in stil.css - sie gelten
  fuer den ganzen Auftritt. Hier bleibt nur, was die beiden gesaettigten Bahnen
  dieser Seite zusaetzlich brauchen: Clay600 kommt auf Ink900 auf 2,7:1 und auf
  dem Clay-Verlauf auf 1,2:1, der Ring waere dort also nicht zu sehen.
*/
.band-dunkel :focus-visible { outline-color: var(--clay-warm); }

.band-clay :focus-visible { outline-color: var(--sand-50); }

.start {
  /* Der Fliesstext der Startseite steht dunkler als auf den Rechtsseiten. */
  color: var(--ink-700);
  overflow-x: hidden;
}

/*
  `main { padding: 32px 0 48px }` in stil.css gilt dem FLIESSTEXT der
  Rechtsseiten. Auf der Startseite trug es zwei sandfarbene Balken ein, die wie
  ein Fehler aussahen und einer waren: einen 32px hohen zwischen Kopfzeile und
  dem Verlauf des ersten Bildes, einen 48px hohen zwischen der Clay-Bahn und dem
  dunklen Fuss. Hier bringt jede Bahn ihre Polsterung selbst mit.
*/
.start main { padding: 0; }

/* --- Raster -------------------------------------------------------------- */
/*
  Ein Mass fuer die ganze Seite. Die Rechtsseiten stehen auf 42rem, weil sie
  gelesen werden; hier wird geschaut, und ein Telefon neben einer Textspalte
  braucht Platz.
*/
.bahn {
  width: min(100% - 2 * var(--sp-xl), 74rem);
  margin-inline: auto;
}

.band { padding: var(--sp-5xl) 0; }

/* Die beiden gesaettigten Flaechen der Seite. */
.band-dunkel {
  background: var(--ink-900);
  color: var(--auf-dunkel);
}

.band-clay {
  /*
    Von oben warm nach unten dunkel - dieselbe Achse wie die Verlaufskarte des
    Abo-Screens in der App (`verticalGradient(Clay500, ClayGradientStart)`).

    Bis zum 10.10.2026 fing sie erst bei Clay600 an und endete auf einem
    Literal (#6F2712), weil das flache Clay500 von damals (#B54A2E) mit
    16px-Text nur 4,4:1 hielt. Dieser Grund ist weg: Das tiefere #A7482E traegt
    --sand-50 mit 5,24:1, das dunkelste Ende mit 10,41:1. Damit stehen hier drei
    echte Tokens und kein gerundeter Zwischenwert mehr.
  */
  background: linear-gradient(160deg, var(--clay-500) 0%, var(--clay-600) 55%, var(--clay-tief) 100%);
  color: var(--sand-50);
}

/* --- Ueberschriften ------------------------------------------------------ */

.start h1,
.start h2,
.start h3 {
  font-family: "Nunito", system-ui, "Segoe UI", sans-serif;
  color: var(--ink-900);
  text-wrap: balance;
  margin: 0;
}

/*
  Die drei Groessen standen vorher auf 68 / 45.6 / 20.8px (Desktop) und damit
  auf einem Verhaeltnis von 3,3 : 2,2 : 1. Das ist zu eng: Eine h2 auf zwei
  Dritteln der h1 liest sich nicht als naechste Ebene, sondern als zweite
  Hauptzeile - die Seite hatte damit sechs gleich laute Ueberschriften und
  keine Spitze. Jetzt 84 / 40 / 19.2px, also 4,4 : 2,1 : 1.
*/
.start h1 {
  font-weight: 600;
  font-size: clamp(2.6rem, 1.4rem + 5.2vw, 5.25rem);
  /*
    1.03 sass auf dem Desktop sauber, drueckte die Zeilen aber zusammen, sobald
    die Ueberschrift auf dem Telefon dreizeilig umbricht - dort steht sie bei
    42px, und Oberlaenge und Unterlaenge kamen sich ins Gehege.
  */
  line-height: 1.05;
  letter-spacing: -0.03em;
}

.start h2 {
  font-weight: 600;
  font-size: clamp(1.7rem, 1.25rem + 1.9vw, 2.5rem);
  line-height: 1.14;
  letter-spacing: -0.02em;
  scroll-margin-top: 88px;
}

.start h3 {
  font-weight: 600;
  font-size: 1.2rem;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

/*
  Die Bahnen sind selbst Sprungziele (#staerken, #funktionen, #holen), nicht nur
  ihre Ueberschriften: Ohne eigenen Abstand verschwindet die erste Zeile hinter
  dem klebenden Kopf.
*/
.start section[id] { scroll-margin-top: 76px; }

.band-dunkel h2,
.band-dunkel h3 { color: var(--auf-dunkel); }

.band-clay h2,
.band-clay h3 { color: var(--sand-50); }

.start p { margin: 0; }

.gross {
  font-size: clamp(1.05rem, 0.98rem + 0.35vw, 1.2rem);
  line-height: 1.55;
  color: var(--ink-700);
  max-width: 34rem;
}

.band-dunkel .gross { color: var(--auf-dunkel-leise); }
.band-clay .gross { color: var(--auf-clay-leise); }

/* --- Kopf ---------------------------------------------------------------- */

/*
  Der Kopf steht vollstaendig in stil.css - er ist auf jeder Seite derselbe.
  Verschieden ist nur der Container darin: hier `.bahn` mit 74rem, auf den
  Rechtsseiten `.kopf-inhalt` mit 42rem.
*/

/*
  Der Sprachumschalter selbst steht in stil.css (`.sprachen`) - er ist auf jeder
  Seite derselbe. Hier bleibt nur der Trenner, den es nur im Kopf gibt.
*/
.sprachen .teiler { color: var(--sand-200); min-width: 0; min-height: 0; }

/* --- Knoepfe ------------------------------------------------------------- */

.knopf-reihe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-md);
}

.knopf {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-sm);
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 14px var(--sp-xl);
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  line-height: 1;
  cursor: pointer;
  /*
    Der Ruhezustand traegt eine Verschiebung um NULL, und das ist kein
    Versehen: Sie haelt den Knopf auf einer eigenen Ebene, sodass seine
    Beschriftung beim Loslassen des Zeigers nicht neu gerastert wird. Ohne sie
    zuckt die Schrift am Ende jedes Hovers - derselbe Grund wie bei den
    Auftritten, siehe den Abschnitt "Bewegung".
  */
  transform: translate3d(0, 0, 0);
  will-change: transform;
  transition: transform 0.25s var(--kurve), background-color 0.2s ease,
              border-color 0.2s ease;
}

/*
  **Jetzt Clay500, der Markenton** - und das ist der sichtbarste Gewinn der
  Palette vom 10.10.2026. Hier stand Clay600, weil die helle Schrift auf dem
  alten #B54A2E nur 4,4:1 hielt und damit unter der Schwelle lag: Der wichtigste
  Knopf der Startseite trug deshalb nicht die Farbe des Produkts, sondern eine
  Notloesung. Das tiefere #A7482E haelt 5,24:1, genau wie der Kochen-Knopf in
  der App - der Knopf hier und der Knopf dort sind endlich derselbe Ton.
*/
.knopf-voll {
  background: var(--clay-500);
  color: var(--sand-50);
}

.knopf-voll:hover {
  background: var(--clay-600);
  color: var(--sand-50);
  transform: translate3d(0, -2px, 0);
}

/*
  Der zweite Knopf im ersten Bild. Er war ein Umriss auf durchsichtigem Grund -
  auf dem alten Sandverlauf ging das, auf der Holzplatte des Fotos nicht: Die
  Maserung lief mitten durch die Schrift, und der Knopf sah aus wie ein Rahmen
  um nichts. Jetzt volle Flaeche in Sand100 - derselbe Ton wie die Karten der
  App.

  **Hiess bis zum 10.10.2026 `.knopf-weiss`.** Sand100 war Weiss, der Name war
  also richtig; mit dem Sandgrund waere er eine Luege geworden. Umbenannt und
  nicht nur umkommentiert, weil ein Klassenname, der die falsche Farbe nennt,
  beim naechsten Palettenwechsel genau die Stelle ist, die man uebersieht.
*/
.knopf-sand {
  background: var(--sand-100);
  color: var(--ink-900);
  border-color: var(--sand-200);
}

.knopf-sand:hover { background: var(--sand-50); color: var(--ink-900); transform: translate3d(0, -2px, 0); }

.band-clay .knopf-voll {
  background: var(--sand-50);
  color: var(--clay-600);
}

.band-clay .knopf-voll:hover { background: #fff; color: var(--clay-600); }

.knopf svg { display: block; transform: translate3d(0, 0, 0); will-change: transform; }

/*
  Der Knopf im Kopf. Er ist kleiner als die Knoepfe im Inhalt, aber bewusst
  gefuellt und nicht als vierter Anker geschrieben: Die Seite hatte oben gar
  keine Handlung, nur drei Sprungmarken - wer nach dem dritten Abschnitt kaufen
  wollte, musste bis ganz nach unten scrollen. Er bleibt auf schmalen
  Bildschirmen stehen, waehrend die Anker (.nur-breit) wegfallen.
*/
/*
  Zwei Klassen, und das ist Pflicht: `.kopf-nav a` in stil.css ist mit
  Element-Selektor spezifischer als `.knopf-voll` und gewinnt trotz spaeterer
  Datei. Mit einer Klasse allein bekam der Knopf die Farbe der Kopfzeilen-Anker
  (dunkel auf Terracotta) UND deren Polsterung `4px 0` - die Schrift stand
  daraufhin links und rechts ueber die Pille hinaus.
*/
.kopf-nav .knopf-kopf {
  padding: 9px var(--sp-lg);
  font-size: 0.92rem;
  color: var(--sand-50);
  border-bottom: 1px solid transparent;
  flex: none;
}

/*
  Und derselbe Grund noch einmal: `.kopf-nav a:hover` zoege sonst einen
  Clay-Strich unter die Pille.
*/
.kopf-nav .knopf-kopf:hover {
  color: var(--sand-50);
  border-bottom-color: transparent;
}

/* --- Held ---------------------------------------------------------------- */

/*
  Das erste Bild ist seit dem 17.08.2026 ein Foto: Arbeitsplatte, das Telefon
  mit der echten Rezeptliste darauf, Zutaten daneben. Der Text liegt links auf
  der freien Holzflaeche - die Aufnahme ist dafuer angelegt.

  Vorher standen hier zwei sehr weiche Farbkreise als Grund und daneben ein
  gekippter Telefonrahmen; beides ist im Foto aufgegangen.
*/
.held-start {
  position: relative;
  isolation: isolate;
  display: grid;
  align-items: center;
  min-height: clamp(28rem, 42vw, 40rem);
  padding: var(--sp-4xl) 0;
  background: var(--sand-100);
}

/*
  `cover` fuellt die Bahn immer ganz und schneidet den Ueberschuss symmetrisch
  ab - leere Balken kann es damit auf keinem Seitenverhaeltnis geben. Der Preis
  dafuer: Beschnitten wird auf BEIDEN Achsen, je nachdem welche knapper ist. Auf
  einem Telefon hochkant bleiben von der Breite rund 40 Prozent uebrig. Alles,
  was man erkennen koennen muss, gehoert deshalb in die Bildmitte.
*/
.held-foto {
  position: absolute;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/*
  Hier lag ein Sand50-Verlauf als Schleier hinter dem Text, und er ist wieder
  raus: Auf dieser Platte kommt Ink900 in der linken Bildhaelfte im Mittel auf
  9,9:1 und im dunkelsten Punkt auf 7,3:1 - gemessen ueber 30.000 Punkte, kein
  einziger unter 4,5:1. Ein Schleier haette die Maserung zugedeckt, ohne etwas
  zu gewinnen. Bei einem dunkleren Foto gehoert er zurueck; die erste Fassung
  dieses Bildes kam in den Schattenstreifen auf 2,5:1.
*/

.held-raster { display: grid; }

.held-text > * + * { margin-top: var(--sp-2xl); }
/* Die Displayzeile traegt am meisten Gewicht und braucht entsprechend Luft. */
.held-text h1 + * { margin-top: var(--sp-3xl); }
.held-text .held-preis { margin-top: var(--sp-xl); }
.held-text .stand-zeile { margin-top: var(--sp-sm); }

/*
  Die Textspalte deckelt sich selbst auf die linke Haelfte. Ein Grid mit zweiter
  Spalte waere die Alternative gewesen - nur steht in der zweiten Spalte nichts,
  was das Raster halten muesste: rechts liegt das Foto, und das haengt an der
  Bahn, nicht an der Spalte.

  30rem waren zu wenig, und das sah man an der Displayzeile: Bei 84px Schrift
  passen dort keine sieben Zeichen in eine Zeile, jedes zweite Wort bekam eine
  eigene. Die freie Holzflaeche links im Foto reicht bis knapp vor das Telefon,
  also rund 60 Prozent der Bahn - die Spalte hoerte deutlich davor auf und liess
  den Platz ungenutzt.

  38rem / 54 Prozent, und beide Werte haben einen Grund: Der Prozentwert haelt
  Abstand zum Telefon (bei 1440px sind das 640px Text, das Geraet im Ausschnitt
  beginnt bei rund 890px), die rem-Grenze deckelt die Zeilenlaenge auf breiten
  Schirmen, wo 54 Prozent von 74rem sonst ueber 90 Zeichen je Fliesstextzeile
  ergaeben. Wer hier weiter aufdreht, prueft beides: den Umbruch der Headline
  UND den Abstand zum Telefon (1024, 1280, 1440, 1920px).
*/
.held-text { max-width: min(38rem, 54%); }
.held-text .gross { max-width: 34rem; }

/*
  Der Preis im ersten Bild. Er steht bewusst hier und nicht erst am Knopf ganz
  unten: Wer nach drei Bahnen Begeisterung zum ersten Mal von einem Abo erfaehrt,
  erlebt es als Falle - dieselbe Ueberlegung wie im WelcomeOverlay der App, wo
  die 2,99 EUR vor dem ersten Import stehen und nicht erst an der Sperre.
*/
.held-preis {
  font-size: 0.98rem;
  color: var(--ink-700);
}

.held-preis b {
  font-weight: 600;
  color: var(--ink-900);
  border-bottom: 2px solid var(--clay-100);
}

/* Die ehrliche Zeile unter den Knoepfen: kein Store-Abzeichen, das es nicht gibt. */
.stand-zeile {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-sm);
  font-size: 0.9rem;
  color: var(--ink-500);
}

.punkt {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--sage-500);
  flex: none;
}

/*
  Schmal wird aus dem Grund ein Bild DARUEBER. Der Grund ist der Beschnitt: Bei
  390px Fensterbreite zeigt `cover` von einem 21:9-Bild die mittleren rund 40
  Prozent - die freie Holzflaeche links waere weg, der Text laege auf dem
  Telefon. Als eigener Streifen bleibt das Bild ganz, und der Text steht darunter
  auf Sand.
*/
@media (max-width: 62rem) {
  .held-start {
    display: block;
    min-height: 0;
    padding: 0 0 var(--sp-3xl);
  }

  .held-foto {
    position: static;
    height: clamp(13rem, 46vw, 20rem);
    /* Etwas nach rechts gerueckt, damit das Telefon im Ausschnitt bleibt. */
    object-position: 62% center;
  }

  .held-raster { padding-top: var(--sp-2xl); }

  .held-text { max-width: none; }
  .held-text .gross { max-width: none; }
}

/* --- Das Telefon --------------------------------------------------------- */
/*
  Im Rahmen stehen echte Screenshots vom Geraet (Pixel 9, 1080x2424). Vorher
  war der Bildschirminhalt HTML in der Gestaltung der App - hundert Zeilen
  Nachbau, die bei jeder Aenderung an der echten App still veralteten.

  Das Seitenverhaeltnis bringt das Bild selbst mit (width/height am <img>);
  der Rahmen richtet sich danach. Ein aspect-ratio am Rahmen waere falsch:
  Das Polster von 10px zaehlt mit, das Bild sasse dann leicht verzerrt darin.
*/

.telefon {
  width: 100%;
  max-width: 320px;
  margin-inline: auto;
  background: var(--ink-900);
  border-radius: 44px;
  padding: 10px;
  /*
    Was hier steht, ist KEIN Schatten, sondern eine Lichtkante INNEN: die eine
    helle Linie an der Oberkante, die den schwarzen Rahmen als Geraet lesbar
    macht statt als schwarzes Rechteck. Die beiden geworfenen Schatten, die
    frueher darunter standen, sind raus - siehe der Hinweis im Kopf der Datei.
  */
  box-shadow: 0 2px 0 rgba(255, 255, 255, 0.12) inset;
}

.schirm-bild {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1080 / 2424;
  object-fit: cover;
  border-radius: 35px;
  background: var(--sand-100);
}

/* --- Die Verwandlung ----------------------------------------------------- */

/*
  Zentriert wie der Kopf der Gruende-Bahn. Er stand als einziger Bahnenkopf
  linksbuendig, und das Paar darunter ist symmetrisch - die Ueberschrift zog die
  ganze Bahn nach links, obwohl unter ihr zwei gleich schwere Blaetter stehen.
*/
.verwandlung-kopf {
  display: grid;
  gap: var(--sp-md);
  justify-items: center;
  text-align: center;
  max-width: 44rem;
  margin: 0 auto var(--sp-4xl);
}

/*
  `stretch` statt `start`: Die beiden Blaetter sind unterschiedlich hoch, und
  der Pfeil sitzt in der Mitte der ZEILE - also in der Mitte des hoeheren. Er
  zeigte damit auf halber Hoehe des Rezepts los, waehrend das linke Blatt
  darueber schon zu Ende war. Gleich hohe Blaetter loesen das, ohne dass der
  Pfeil einen gerechneten Abstand braucht.
*/
.verwandlung {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: stretch;
  gap: var(--sp-xl);
}

.blatt {
  border-radius: var(--r-xxl);
  padding: var(--sp-xl);
  display: flex;
  flex-direction: column;
  gap: var(--sp-md);
}

/*
  Dieselbe Kopfzeile auf beiden Blaettern - Marke, darunter ein Haarstrich.
  Ohne sie war links ein grauer Textblock und rechts eine gebaute Karte: zwei
  Dinge, die nichts miteinander zu tun zu haben schienen. Die gemeinsame Zeile
  macht aus ihnen ein Vorher und ein Nachher.
*/
.blatt-kopf {
  padding-bottom: var(--sp-md);
  border-bottom: 1px solid rgba(243, 235, 226, 0.16);
}

.blatt-rezept .blatt-kopf { border-bottom-color: var(--sand-200); }

/* Links: was aus der App geteilt wird. Rohtext, Zeilenumbrueche wie im Original. */
.blatt-roh {
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid rgba(243, 235, 226, 0.14);
}

.blatt-marke {
  font-size: 0.78rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--auf-dunkel-leise);
}

.band-clay .blatt-marke { color: var(--auf-clay-leise); }

.roh-text {
  font-size: 0.9rem;
  line-height: 1.65;
  color: var(--auf-dunkel-leise);
  white-space: pre-line;
  margin: 0;
}

/*
  Blasser als der Rohtext, aber nicht unter die Schwelle: Das fruehere #8C7C6E
  kam auf 3,97:1 und lag damit unter den 4,5:1 fuer Text dieser Groesse.
*/
.roh-text .hash { color: #9C8C7E; }

/* Rechts: das fertige Rezept, in der Flaeche der App (Sand100). */
.blatt-rezept {
  background: var(--sand-100);
  color: var(--ink-700);
  border: 1px solid var(--sand-200);
}

.blatt-rezept .blatt-marke { color: var(--ink-500); }

.rezept-titel {
  font-family: "Nunito", system-ui, "Segoe UI", sans-serif;
  font-weight: 700;
  font-size: 1.35rem;
  line-height: 1.15;
  color: var(--ink-900);
}

.rezept-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-sm);
  font-size: 0.85rem;
  color: var(--ink-500);
}

.marke-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--clay-100);
  color: var(--clay-600);
  font-size: 0.78rem;
  font-weight: 600;
}

.rezept-spalten {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: var(--sp-xl);
}

/*
  Eigene Regel, obwohl es ein h3 ist: Das Blatt ist hell, liegt aber INNERHALB
  der dunklen Bahn - `.band-dunkel h3` faerbt sonst auch diese beiden Zeilen
  hell, und sie stehen dann fast unsichtbar auf Sand. Vorher war es ein h4 und
  entging der Regel; das war aber eine Stufe zu tief (h2 -> h4) und fuer einen
  Screenreader ein Loch in der Gliederung.
*/
.rezept-spalten h3 {
  margin: 0 0 var(--sp-sm);
  font-family: "Nunito", system-ui, "Segoe UI", sans-serif;
  font-size: 0.95rem;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--ink-900);
}

.zutaten,
.schritte { margin: 0; padding: 0; list-style: none; font-size: 0.88rem; }

.zutaten li {
  display: flex;
  gap: var(--sp-sm);
  padding: 5px 0;
  border-bottom: 1px solid var(--sand-200);
  color: var(--ink-700);
}

.zutaten li:last-child { border-bottom: 0; }
.zutaten .menge { color: var(--ink-900); font-weight: 600; flex: none; min-width: 3.4rem; }

/*
  Die Gruppenzeile. In der App steht sie als "##Fuer den Teig" in derselben
  Zutatenliste (siehe IngredientGroups) - hier bekommt sie dieselbe Rolle:
  Ueberschrift statt Zutat.
*/
.zutaten .gruppe {
  border-bottom: 0;
  padding-top: var(--sp-md);
  font-family: "Nunito", system-ui, "Segoe UI", sans-serif;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.zutaten .gruppe:first-child { padding-top: 0; }

.schritte li {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: var(--sp-sm);
  padding: 6px 0;
  color: var(--ink-700);
  line-height: 1.5;
}

.schritte .nr {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--clay-600);
  background: var(--clay-100);
  border-radius: 50%;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  margin-top: 2px;
}

/*
  Der Pfeil zwischen den beiden Blaettern, mit einem Haarstrich nach links und
  rechts: Er soll nicht zwischen den Blaettern schweben, sondern das eine ins
  andere fuehren.
*/
.pfeil {
  position: relative;
  align-self: center;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  color: var(--clay-warm);
  background: rgba(167, 72, 46, 0.18);
  border: 1px solid rgba(233, 170, 152, 0.35);
}

.pfeil::before,
.pfeil::after {
  content: "";
  position: absolute;
  top: 50%;
  width: var(--sp-xl);
  height: 1px;
  background: rgba(233, 170, 152, 0.3);
}

.pfeil::before { right: 100%; }
.pfeil::after { left: 100%; }

.pfeil svg { width: 24px; height: 24px; }


@media (max-width: 62rem) {
  .verwandlung { grid-template-columns: 1fr; }
  /*
    Untereinander zeigt der Pfeil nach unten. Die Drehung nimmt die beiden
    Haarstriche mit - sie sitzen am Pfeil, nicht an der Bahn.
  */
  .pfeil { transform: rotate(90deg); justify-self: center; }
  .rezept-spalten { grid-template-columns: 1fr; gap: var(--sp-lg); }
}

/* --- Die vier Gruende ---------------------------------------------------- */
/*
  Diese Bahn ersetzt die frueheren vier Kleinzeilen unter den Funktionen. Sie
  liegt VOR den Funktionen, nicht dahinter: Erst die Behauptung, dann der Beleg
  mit Bildschirmfoto - andersherum stand der Grund erst da, nachdem der Besucher
  sich schon entschieden hatte, weiterzublaettern.

  Vier gleiche Spalten, zentriert, ohne Karte: kein Rahmen, keine Flaeche, keine
  Ordnungsziffer. Ein erster Anlauf hatte Kacheln mit Rand, Fuellfarbe, Kreis
  hinter dem Symbol und einer grossen "01" daneben - vier Behauptungen, die um
  Aufmerksamkeit rangen und keine gewann. Hier traegt jede Spalte nur das
  Symbol, eine Zeile und zwei Saetze; was heraussticht, ist der Inhalt.

  Bewusst KEINE hervorgehobene erste Kachel mehr: Das verknuepfte Kochbuch ist
  der wichtigste Punkt und bekommt sein Gewicht ueber die Reihenfolge - es steht
  vorn, und der ausfuehrliche Beleg mit Bildschirmfoto folgt direkt darunter als
  erster Zug.
*/

.staerken-kopf {
  display: grid;
  gap: var(--sp-md);
  justify-items: center;
  text-align: center;
  max-width: 42rem;
  margin: 0 auto var(--sp-4xl);
}

/*
  Die kleine Zeile ueber der Ueberschrift. Sie ist der einzige Ort auf der
  Seite, an dem Clay als Textfarbe steht - deshalb Clay600 und nicht Clay500:
  Letzteres haelt auf Sand nur 4,25:1.
*/
.augenbraue {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--clay-600);
}

.staerken-raster {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-3xl) var(--sp-2xl);
}

.staerke {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--sp-lg);
  text-align: center;
}

/*
  Das Symbol traegt die Bahn und steht deshalb doppelt so gross wie sonst auf
  der Seite - ohne Kreis, ohne Flaeche dahinter. Die Strichstaerke bleibt 1.6
  wie ueberall; auf 44px wirkt sie zeichnerisch statt fett.
*/
.staerke-zeichen { display: block; color: var(--clay-500); }

.staerke h3 { color: var(--ink-900); }

.staerke p {
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--ink-500);
  max-width: 20rem;
}

/*
  Zwei Spalten statt vier, bevor die Zeilen auf zwei Woerter schrumpfen: Bei
  vier Spalten unter 62rem stand in jeder Spalte noch etwa ein Drittel Wort je
  Zeile.
*/
@media (max-width: 62rem) {
  .staerken-raster { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .staerken-kopf { margin-bottom: var(--sp-3xl); }
}

/* --- Die Funktionen ------------------------------------------------------ */

.zug {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-4xl);
  padding: var(--sp-4xl) 0;
}

.zug + .zug { border-top: 1px solid var(--sand-200); }

/* Jeder zweite Zug dreht die Seiten. */
.zug-gedreht .zug-bild { order: -1; }

/*
  Nach einer Ueberschrift mehr Luft als zwischen zwei Absaetzen: Mit einheitlich
  16px stand eine 45px-Zeile direkt auf ihrem Vorspann, und die Ueberschrift
  wirkte wie die erste Zeile des Absatzes statt wie sein Titel.
*/
.zug-text > * + * { margin-top: var(--sp-lg); }
.zug-text h2 + * { margin-top: var(--sp-xl); }
.zug-text .gross + .zug-punkte { margin-top: var(--sp-xl); }

.zug-punkte {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-sm);
  font-size: 0.98rem;
}

.zug-punkte li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: var(--sp-md);
  align-items: start;
  color: var(--ink-700);
}

.zug-punkte svg { color: var(--clay-500); margin-top: 3px; }

.zug-bild { display: grid; place-items: center; }

.zug-bild .telefon { max-width: 272px; }

@media (max-width: 62rem) {
  .zug { grid-template-columns: 1fr; gap: var(--sp-2xl); padding: var(--sp-3xl) 0; }
  .zug-gedreht .zug-bild { order: 0; }
}

/*
  Hier stand eine Leiste aus vier, zuletzt drei Kleinzeilen: sechs Sprachen,
  Kategorien und Favoriten, Suche ueber alles. Sie ist ersatzlos entfallen -
  das sind Selbstverstaendlichkeiten, die jede Rezept-App hat, und die
  Bildschirmfotos darueber zeigen sie ohnehin. Was wirklich unterscheidet,
  steht als eigene Bahn weiter oben (.staerke).
*/

/* --- Holen und Preis ----------------------------------------------------- */
/*
  Frueher zwei Dinge an zwei Orten: eine Preisbahn ohne Handlung und gar kein
  Holen-Block. Wer am Ende der Preisbahn stand, konnte nichts tun; der einzige
  Knopf der Seite stand ganz oben im ersten Bild. Jetzt tragen beide dieselbe
  Bahn - links das Angebot mit den beiden Store-Zeilen, rechts die zwei Tarife.

  Die Bahn steht seit dem 17.08.2026 an DRITTER Stelle, direkt hinter den vier
  Gruenden: Was etwas kostet, gehoert vor die Ausfuehrlichkeit und nicht dahinter.

  .preis-zahl, .preis-zusatz, .tarif und .bleibt sind mit diesem Umbau
  entfallen - drei Preiszeilen untereinander und eine Kasten-Liste "Was ohne Abo
  bleibt" beantworteten dieselbe Frage zweimal und keine davon vergleichend.
*/

.holen-raster {
  display: grid;
  /*
    Die rechte Spalte ist die breitere, und das ist gerechnet: Zwei Tarifkarten
    nebeneinander brauchen je rund 300px, sonst bricht in der Liste jede zweite
    Zeile um ("Unbegrenzt Kochbuecher / verknuepfen"). Der Steg ist aus dem
    gleichen Grund 48px statt der 72px der uebrigen Bahnen.
  */
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: var(--sp-3xl);
  align-items: start;
}

/*
  `min-width: 0` auf beiden Spalten, und das ist kein Zierrat: Ein Grid-Track
  aus `1fr` hat als automatisches Minimum die MIN-CONTENT-Breite seines Inhalts.
  Die Store-Kacheln (`auto-fit, minmax(15rem, 1fr)`) melden dort zwei Spuren zu
  je 240px an - der Track wuchs damit auf 492px und schob die ganze Bahn auf
  einem 390er-Telefon aus dem Bild (gemessen: scrollWidth 516 bei clientWidth
  390). Sichtbar war davon nichts, weil `.start` `overflow-x: hidden` traegt;
  die Seite liess sich nur seitlich schieben.
*/
.holen-haupt,
.plan-paar { min-width: 0; }

/*
  Die offiziellen Abzeichen von Google und Apple. Vorher standen hier zwei
  selbst gezeichnete Zeilen aus Symbol, Wort und Statuswort - richtig, solange
  es die Store-Eintraege nicht gibt, aber ein Eigenbau bleibt ein Eigenbau.
  Jetzt sind es die Originaldateien aus den Markenportalen der beiden.

  Sie sind weiterhin KEINE Links, und deshalb steht neben jedem Abzeichen, woran
  es gerade ist: Beide Richtlinien setzen voraus, dass das Abzeichen auf den
  Eintrag zeigt - ohne Statuswort behauptet es Verfuegbarkeit.

  44px Hoehe fuer beide, und das ist gerechnet: Die Play-Dateien sind auf ihre
  sichtbare Flaeche zugeschnitten (die eine trug ringsum Rand, die andere nur
  oben und unten - bei gleicher CSS-Hoehe waeren die Sprachfassungen
  verschieden gross gewesen). Der von Google verlangte Freiraum ist damit
  Aufgabe des Layouts: Er betraegt ein Viertel der Abzeichenhoehe, bei Apple
  ein Zehntel - beides deckt der Steg von 16px.

  Untereinander, nicht nebeneinander: In der halben Bahn blieben je 150px, und
  die beiden Abzeichen brauchen mit ihren Statuswoertern das Doppelte.
*/
.store-liste {
  display: grid;
  gap: var(--sp-lg);
  margin-top: var(--sp-2xl);
  justify-items: start;
}

.store-badge {
  display: flex;
  align-items: center;
  gap: var(--sp-md);
}

.store-badge img {
  display: block;
  height: 44px;
  width: auto;
}

.store-status {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid rgba(249, 242, 233, 0.35);
  color: var(--auf-clay-leise);
  white-space: nowrap;
}

/* --- Die zwei Tarife ------------------------------------------------------ */

.plan-paar {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-lg);
  align-items: start;
}

.plan {
  display: grid;
  align-content: start;
  gap: var(--sp-md);
  padding: var(--sp-xl);
  border-radius: var(--r-xxl);
  background: rgba(42, 26, 19, 0.18);
  border: 1px solid rgba(249, 242, 233, 0.16);
}

/*
  Die bezahlte Karte ist die hellere, nicht die dunklere: Auf einer Clay-Bahn
  ist Naehe zum Sand der Seite das Signal "das hier ist gemeint". Sie traegt
  ausserdem als einzige einen vollen Rand und einen Schatten.
*/
.plan-voll {
  background: rgba(249, 242, 233, 0.12);
  border-color: rgba(249, 242, 233, 0.42);
}

.plan h3 {
  color: var(--sand-50);
  font-size: 1.35rem;
}

.plan-satz {
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--auf-clay-leise);
}

.plan-preis {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-sm);
}

.plan-preis b {
  font-family: "Nunito", system-ui, "Segoe UI", sans-serif;
  font-size: 2.6rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--sand-50);
}

.plan-preis span { font-size: 0.9rem; color: var(--auf-clay-leise); }

.plan-liste {
  margin: var(--sp-sm) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--sp-sm);
}

.plan-liste li {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: var(--sp-md);
  align-items: start;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--sand-50);
}

.plan-liste b { font-weight: 600; }

.plan-liste svg { margin-top: 3px; color: var(--auf-clay-leise); }

/* Nur die bezahlte Karte bekommt die Haken in voller Helligkeit. */
.plan-voll .plan-liste svg { color: var(--sand-50); }

/* --- Monatlich oder jaehrlich -------------------------------------------- */
/*
  Ein Paar Radio-Knoepfe, umgeschaltet mit `:has()` - ohne eine Zeile
  JavaScript. Die Eingaben bleiben im Dokument und nur optisch verborgen
  (`opacity: 0`, nicht `display: none`): Ein `display: none` naehme sie aus der
  Tabreihenfolge, und der Umschalter waere mit der Tastatur nicht mehr zu
  bedienen.
*/
.takt-schalter {
  display: inline-flex;
  align-self: start;
  padding: 3px;
  border-radius: 999px;
  background: rgba(42, 26, 19, 0.28);
  border: 1px solid rgba(249, 242, 233, 0.2);
  margin-bottom: var(--sp-xs);
}

.takt-eingabe {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.takt-schalter label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--auf-clay-leise);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.takt-eingabe:checked + label {
  background: var(--sand-100);
  color: var(--clay-600);
}

/* Der Fokusring haengt am Label, weil die Eingabe selbst unsichtbar ist. */
.takt-eingabe:focus-visible + label {
  outline: 2px solid var(--sand-50);
  outline-offset: 2px;
}

.takt-sparen {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  padding: 2px 6px;
  border-radius: 999px;
  background: rgba(249, 242, 233, 0.22);
}

.takt-eingabe:checked + label .takt-sparen {
  background: var(--clay-100);
  color: var(--clay-600);
}

/*
  Beide Preise stehen im HTML, einer wird ausgeblendet. Der Grundzustand zeigt
  den MONATSPREIS - wo `:has()` fehlt, steht damit der hoehere Preis da. Eine
  Anzeige, die zu niedrig faellt, waere die falsche Richtung (PAngV).
*/
.nur-jahr { display: none; }

.plan-voll:has(#takt-jahr:checked) .nur-monat { display: none; }
.plan-voll:has(#takt-jahr:checked) .nur-jahr { display: revert; }

@media (max-width: 62rem) {
  .holen-raster { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2xl); }
}

/* --- Die Stimmen --------------------------------------------------------- */
/*
  Die letzte Bahn vor dem Fuss. Sie steht auf Sand100 statt auf dem Sand50 der
  Seite - zwei helle Bahnen hintereinander (Funktionen, Stimmen) waeren sonst
  eine einzige lange Flaeche.

  Die Saetze darin sind ERFUNDEN. Der sichtbare Hinweis darueber ist auf Wunsch
  entfallen; was daran haengt, steht im Kommentar im HTML.
*/

.band-sand { background: var(--sand-50); }

.stimmen-raster {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-lg);
}

.stimme {
  display: grid;
  align-content: start;
  gap: var(--sp-md);
  margin: 0;
  padding: var(--sp-xl);
  border-radius: var(--r-xxl);
  background: var(--sand-100);
  border: 1px solid var(--sand-200);
}

/*
  Die Sterne sind gefuellt (i-stern-voll), nicht die offene Kontur aus der
  Symbolliste: Ein Umriss-Stern liest sich als "nicht vergeben".
*/
.sterne {
  display: flex;
  gap: 3px;
  color: var(--clay-500);
}

.sterne svg { display: block; }

/*
  Ohne Anfuehrungszeichen im Text - `blockquote` sagt schon, was es ist, und
  ein getipptes Zitatzeichen stuende in sechs Sprachen verschieden.
*/
.stimme blockquote {
  margin: 0;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ink-700);
}

.stimme figcaption {
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink-500);
}

@media (max-width: 62rem) {
  .stimmen-raster { grid-template-columns: 1fr; }
}

/* --- Fuss ---------------------------------------------------------------- */
/*
  Der Fuss steht seit der Angleichung der Rechtsseiten in stil.css
  (`.seitenfuss`) - er ist auf jeder Seite derselbe. Hier bleibt nur, was die
  breitere Bahn der Startseite braucht.
*/

/* --- Bewegung ------------------------------------------------------------ */
/*
  Vier Regungen, mehr nicht - und jede hat einen Anlass im Inhalt: der Auftakt
  im ersten Bild, der Auftritt jeder Bahn beim Hereinscrollen, die Choreografie
  der Verwandlung und der Pfeil im Holen-Knopf.

  Es bewegen sich AUSSCHLIESSLICH `opacity` und `transform`. Beide kann der
  Browser ohne neues Layout auf die Grafikkarte legen; eine Animation auf
  `height`, `top` oder `width` laesst die Seite bei jedem einzelnen Bild neu
  rechnen, und genau daran ruckelt eine Startseite auf einem mittleren Telefon.

  ZWEI KURVEN, und der Unterschied ist der Grund fuer die zweite: `--kurve`
  (expo, 0.16/1/0.3/1) hat nach einem Sechstel der Zeit schon die Haelfte des
  Weges hinter sich. Fuer einen Knopf unter dem Zeiger ist das richtig - er
  soll auf den Griff sofort antworten. Ein ganzer Absatz, der so hereinkommt,
  ist im selben Moment fast da und danach nur noch am Auslaufen: Er schnappt,
  statt zu gleiten. Die Auftritte laufen deshalb auf `--kurve-auftritt`
  (0.33/1/0.68/1) und in laengeren Dauern - rund eine Sekunde statt einer
  halben.

  Wer eine fuenfte Regung ergaenzen will, prueft zuerst, ob eine der vier sie
  schon traegt: Effekte an jedem Abschnitt heben sich gegenseitig auf.

  ZWEI SICHERUNGEN, und beide sind wichtiger als der Effekt:

  1. Was JAVASCRIPT ausblendet, blendet auch JavaScript wieder ein. Die Klasse
     `.auftritt-an` steht auf <html> und wird vom Skript selbst gesetzt, erst
     nachdem feststeht, dass es animieren darf. Ohne JS, ohne
     IntersectionObserver und bei abbestellter Bewegung steht die ganze Seite
     einfach da - was ein fehlgeschlagenes Skript ausblendet, sieht niemand
     wieder.
  2. Was CSS ausblendet, steht in `prefers-reduced-motion: no-preference` und
     laeuft ueber `animation ... backwards` statt ueber einen gesetzten
     Grundzustand: Der Auftakt im ersten Bild braucht kein Skript, und wo die
     Animation nicht laeuft, ist der Text sichtbar.
*/

/* 1. Der Auftakt im ersten Bild ------------------------------------------- */
/*
  Ohne Beobachter und ohne Skript: Das erste Bild ist beim Laden immer
  sichtbar, ein IntersectionObserver haette hier nichts zu beobachten. Die
  Reihenfolge ist die Leserichtung - Zeile, Vorspann, Knoepfe.

  DREI ZEITEN, und keine davon ist rund: 200ms Vorlauf, damit die Seite erst
  steht, bevor etwas losgeht (bei 0 laeuft der Auftakt in den Bildaufbau
  hinein und ist halb vorbei, bevor jemand hinsieht). Dann die Zeile ALLEIN -
  450ms, bis der Vorspann nachkommt, und das ist der eigentliche Punkt: Bei
  150ms lief alles praktisch gemeinsam, und ein Auftakt, bei dem alles
  gleichzeitig kommt, ist keiner. Die Knoepfe folgen dem Vorspann nach 200ms;
  sie gehoeren zu ihm, nicht zur Zeile.

  DAS FOTO BEWEGT SICH NICHT. Hier lag eine Kamerafahrt (`scale(1.06)` auf 1
  ueber 1,6s), und sie ist wieder raus: Das Foto IST das erste Bild, nicht
  seine Verzierung - ein Grund, der sich beim Laden noch zurechtrueckt, macht
  aus dem ruhigen Aufmacher eine Diashow. Mit ihr ging das `overflow: hidden`,
  das nur sie gebraucht hat: Ein groesser gezeichnetes Bild ragte waehrend der
  Fahrt ueber die Kanten seiner Bahn.
*/
@media (prefers-reduced-motion: no-preference) {
  @keyframes auftakt {
    from { opacity: 0; transform: translate3d(0, 20px, 0); }
    to   { opacity: 1; transform: translate3d(0, 0, 0); }
  }

  .held-text > h1,
  .held-text > .gross,
  .held-text > .knopf-reihe {
    animation: auftakt 1.2s var(--kurve-auftritt) backwards;
    will-change: transform, opacity;
  }

  .held-text > h1           { animation-delay: 200ms; }
  .held-text > .gross       { animation-delay: 650ms; }
  .held-text > .knopf-reihe { animation-delay: 850ms; }
}

/* 2. Der Auftritt der Bahnen ---------------------------------------------- */
/*
  EIN Mechanismus fuer die ganze Seite statt eines Sondereffekts je Abschnitt:
  `data-auftritt` im HTML, `--i` fuer die Reihenfolge innerhalb einer Gruppe.
  Wer eine Bahn ergaenzt, haengt das Attribut daran und ist fertig; wer einen
  eigenen Effekt dafuer schreibt, hat den zweiten Stil der Seite.

  24px, nicht 60: Der Weg soll die Zeile begleiten, nicht sie herbeifliegen
  lassen. Er ist zugleich der Grund, warum die Dauer allein es nicht macht -
  ein kurzer Weg ueber eine lange Zeit sieht nicht ruhig aus, sondern zaeh.

  AUSGELOEST WIRD DIE GRUPPE, NICHT DAS EINZELTEIL. `data-auftritt-gruppe`
  steht am Container, `data-auftritt` an dem, was sich bewegt; beobachtet wird
  nur der Container. Vorher hing jedes Teil an einem eigenen Beobachter, und
  damit entschied seine Hoehe im Fenster ueber den Zeitpunkt: Der Kopf einer
  Bahn stand fertig da, waehrend die Spalten darunter noch gar nicht angefangen
  hatten - die Bahn zerfiel in zwei Ereignisse. Ueber die Gruppe faengt sie als
  eine an.

  Daraus folgt die Regel fuer `--i`:

  - Kopf UEBER Inhalt (Gruende, Stimmen): zeitgleich, also ueberall --i:0. Eine
    Ueberschrift, die vor ihrem Block kommt, liest sich als eigene Bahn.
  - Spalten NEBENEINANDER (Text | Geraet, Angebot | Tarife): ein Takt Versatz.
    Sie stehen ohnehin nebeneinander im Blick, und der Versatz sagt, was zuerst
    gelesen werden will.

  110ms je Takt, nicht 300: Drei Takte mit 300ms brauchen fast eine Sekunde,
  bis der letzte anfaengt, und so lange sieht niemand zu.
*/
/*
  `will-change` STEHT HIER DAUERHAFT, und das ist der Unterschied zwischen
  sauber und ruckelnd am Ende jeder Bewegung.

  Solange eine Verschiebung oder eine Deckkraft laeuft, zeichnet der Browser
  das Stueck auf einer eigenen Ebene: Text bekommt dort Graustufen-Glaettung
  und darf um Bruchteile eines Pixels versetzt liegen. Ist die Animation
  vorbei, faellt die Ebene weg - der Text wird noch einmal neu gerastert, auf
  ganze Geraetepixel und mit der Subpixel-Glaettung des normalen Textes. Genau
  das ist der Ruck am Schluss, und er trifft ALLE Texte, nicht nur die
  Ueberschriften; dort faellt er nur am meisten auf. Die Bahnen der Seite
  stehen ueberdies auf krummen Positionen (gemessen: 894,31px), weil Hoehen und
  Abstaende aus `clamp()` und `vw` kommen - der Sprung ist damit nicht nur eine
  Frage der Glaettung, sondern auch der Rundung.

  `will-change` haelt die Ebene ueber das Ende hinaus, und deshalb steht es im
  GRUNDZUSTAND und nicht in der `.ist-da`-Regel: Wer es erst zum Auftritt
  setzt, baut die Ebene mitten in der Bewegung auf und hat den Ruck nur an den
  Anfang verschoben. Ein `translate3d(0, 0, 0)` als Endwert taete es nicht -
  Chrome rechnet die Matrix zu einer 2D-Matrix zurueck (nachgemessen:
  `matrix(1, 0, ...)`), und die Ebene entfaellt.

  Der Preis ist Speicher auf der Grafikkarte, je Element eine Ebene. Bei den
  rund zwanzig Textbloecken dieser Seite ist das vertretbar; wer die Regel auf
  Listen mit vielen Eintraegen ausweitet, prueft das neu.
*/
.auftritt-an [data-auftritt] {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  will-change: transform, opacity;
}

.auftritt-an [data-auftritt].ist-da,
.auftritt-an .ist-da [data-auftritt] {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  /*
    Beide Eigenschaften brauchen DIESELBE Dauer. Standen sie auf 1s und 1,1s,
    lief die Verschiebung noch ein Zehntel weiter, nachdem der Text schon voll
    dastand - auf einer ease-out-Kurve sind das die letzten Bruchteile eines
    Pixels, also genau die Bewegung, die man als Nachzucken sieht.
  */
  transition: opacity 1s var(--kurve-auftritt), transform 1s var(--kurve-auftritt);
  transition-delay: calc(var(--i, 0) * 110ms);
}

/*
  Die Bahn, die beim Laden schon angeschnitten im Bild steht, laeuft mit dem
  ersten Bild los statt auf den Beobachter zu warten - sonst steht unter dem
  Foto ein leerer Streifen, bis der Nutzer scrollt. Sie kommt ZULETZT: 1000ms,
  also hinter den Knoepfen (850ms). Die Reihenfolge auf dem Schirm ist damit
  auch die der Bewegung - Zeile, Vorspann, Knoepfe, und dann, was darunter
  angeschnitten ist. Gesetzt wird die Klasse vom Skript, das dafuer misst; ein
  fester Wert im HTML waere auf dem naechsten Fenster falsch.
*/
.auftritt-an [data-auftritt].ist-da.im-ersten-bild,
.auftritt-an .ist-da.im-ersten-bild [data-auftritt] {
  transition-delay: calc(1000ms + var(--i, 0) * 110ms);
}

/*
  Die Geraete kommen zusaetzlich einen Hauch naeher. Der Text daneben steigt
  nur auf; laufen beide gleich, liest sich die Bahn als eine Flaeche, die
  hochrutscht, statt als Text und Beleg dazu.
*/
.auftritt-an .zug-bild[data-auftritt] { transform: translate3d(0, 28px, 0) scale(0.96); }

.auftritt-an .zug-bild[data-auftritt].ist-da,
.auftritt-an .ist-da .zug-bild[data-auftritt] { transform: translate3d(0, 0, 0) scale(1); }

/* 3. Die Verwandlung ------------------------------------------------------ */
/*
  Der orchestrierte Moment der Seite, und der einzige Abschnitt mit einer
  eigenen Reihenfolge: Erst liegt die geteilte Caption da (0ms), dann ziehen
  die beiden Haarstriche den Pfeil heran (200ms) und schieben ihn nach rechts,
  dann laeuft das fertige Rezept Zeile fuer Zeile ein (ab 420ms) - in
  derselben Reihenfolge, in der die App es erzeugt.

  Der Vorlauf der Stufen ist der Punkt: Ohne ihn liefen Pfeil und Rezept
  gleichzeitig, und damit sagte die Bahn "hier sind zwei Blaetter" statt "aus
  dem einen wird das andere".

  Der Pfeil selbst bekommt KEIN `transform` - unter 62rem traegt er
  `rotate(90deg)`, und ein zweiter Wert an derselben Eigenschaft loescht die
  Drehung. Bewegt wird stattdessen das SVG darin; hochkant zeigt sein Vorschub
  dadurch von selbst nach unten.
*/
.laeuft .blatt-roh {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
  will-change: transform, opacity;
}

.laeuft.ist-da .blatt-roh {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition: opacity 1s var(--kurve-auftritt), transform 1s var(--kurve-auftritt);
}

.laeuft .pfeil { opacity: 0; will-change: opacity; }
.laeuft .pfeil svg { transform: translate3d(-10px, 0, 0); will-change: transform; }

/* Die beiden Haarstriche wachsen zum Pfeil hin, nicht von ihm weg. */
.laeuft .pfeil::before,
.laeuft .pfeil::after { transform: scale3d(0, 1, 1); }
.laeuft .pfeil::before { transform-origin: right center; }
.laeuft .pfeil::after  { transform-origin: left center; }

.laeuft.ist-da .pfeil {
  opacity: 1;
  transition: opacity 0.8s var(--kurve-auftritt) 200ms;
}

.laeuft.ist-da .pfeil svg {
  transform: translate3d(0, 0, 0);
  transition: transform 0.8s var(--kurve-auftritt) 200ms;
}

.laeuft.ist-da .pfeil::before,
.laeuft.ist-da .pfeil::after {
  transform: scale3d(1, 1, 1);
  transition: transform 0.8s var(--kurve-auftritt) 200ms;
}

.laeuft .stufe {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  will-change: transform, opacity;
}

.laeuft.ist-da .stufe {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition: opacity 0.85s var(--kurve-auftritt), transform 0.85s var(--kurve-auftritt);
  transition-delay: calc(420ms + var(--i, 0) * 95ms);
}

/* 4. Der Pfeil im Knopf --------------------------------------------------- */
/*
  Die einzige Regung auf Zuruf, und die einzige, die weiterhin auf `--kurve`
  laeuft: Was unter dem Zeiger passiert, darf nicht nachlaufen. Sie sitzt am
  einzigen Knopf der Seite, der ein Symbol traegt - bewusst NICHT an den
  Store-Zeilen und nicht an den Karten: Was sich unter dem Zeiger bewegt,
  sieht aus, als koenne man es anklicken, und die Store-Abzeichen kann man
  nicht (siehe .store-liste).
*/
.knopf-voll svg { transition: transform 0.3s var(--kurve); }

.knopf-voll:hover svg,
.knopf-voll:focus-visible svg { transform: translate3d(3px, 0, 0); }

/*
  Der Rueckfall fuer alle, die Bewegung abbestellt haben. Das Skript setzt
  `.auftritt-an` und `.laeuft` in diesem Fall gar nicht erst - die Regeln hier
  sind die zweite Reihe, falls die Klassen doch einmal von woanders kommen.
*/
@media (prefers-reduced-motion: reduce) {
  .auftritt-an [data-auftritt],
  .auftritt-an [data-auftritt].ist-da,
  .auftritt-an .ist-da [data-auftritt],
  .auftritt-an .zug-bild[data-auftritt],
  .auftritt-an .ist-da .zug-bild[data-auftritt],
  .laeuft .blatt-roh,
  .laeuft .pfeil,
  .laeuft .stufe,
  .laeuft.ist-da .blatt-roh,
  .laeuft.ist-da .stufe { opacity: 1; transform: none; transition: none; }

  .laeuft .pfeil svg,
  .laeuft .pfeil::before,
  .laeuft .pfeil::after { transform: none; transition: none; }

  .knopf,
  .knopf-voll svg { transition: none; }

  /*
    Ohne Bewegung braucht auch niemand eine Ebene: `will-change` kostet dann
    nur Speicher, ohne einen Ruck zu verhindern, den es gar nicht gibt.
  */
  .held-text > h1,
  .held-text > .gross,
  .held-text > .knopf-reihe,
  .auftritt-an [data-auftritt],
  .laeuft .blatt-roh,
  .laeuft .pfeil,
  .laeuft .pfeil svg,
  .laeuft .stufe,
  .knopf,
  .knopf svg { will-change: auto; }
}

/* --- Ganz schmal --------------------------------------------------------- */

@media (max-width: 34rem) {
  /*
    Die zwei Tarife untereinander. Nebeneinander blieben je 150px - der Preis
    stand dann zweizeilig, "2,99" ueber "EUR".
  */
  .plan-paar { grid-template-columns: minmax(0, 1fr); }

  .band { padding: var(--sp-3xl) 0; }
  .held-start { padding: var(--sp-2xl) 0 var(--sp-3xl); }
  .blatt { padding: var(--sp-lg); }
  .knopf { width: 100%; justify-content: center; }
  .knopf-reihe { gap: var(--sp-sm); }

  /*
    Ausgenommen der Knopf im Kopf: Auf voller Breite schoebe er die Marke aus der
    Kopfzeile. Er ist der einzige Knopf, der neben etwas anderem steht.
  */
  .kopf-nav .knopf-kopf { width: auto; padding: 8px var(--sp-md); font-size: 0.88rem; }

  /*
    Erst hier eine Spalte, nicht schon bei 62rem: Zwei Spalten mit je zwei
    Saetzen sind auf einem 390er-Telefon noch lesbar, und untereinander waere die
    Bahn viermal so hoch.
  */
  .staerken-raster { grid-template-columns: 1fr; gap: var(--sp-2xl); }

}
