/* Egg-Tracker — /app/, die Produktseite (auch /en/app/, /es/app/, /fr/app/).
   Pilot fuer den Mobile-first-Umbau (TODO.md Etappe 1): Der Touch-Wert ist die
   Basisregel, `min-width` nur fuer echte Unterschiede, `clamp()` bevorzugt.
   Diese Datei gilt NUR fuer die /app/-Seiten — alle Selektoren tragen das
   `app-`-Praefix, bestehende Seiten bleiben unberuehrt. Paletten, Seitenraster,
   Header und Footer kommen weiterhin aus site.css.

   Gold als Zweitakzent (inszenierung.md §1/E8): Das gesamte Store-Material
   traegt Antikgold fuer alles rund ums Freischalten. Hier ist es bewusst auf
   die /app/-Seite begrenzt — Ribbon-Mitte, Preisblock, Hervorhebungen. */

.app-page {
  /* Die Lichtkraenze (::before-Verlaeufe) ragen bewusst ueber die Sektionen
     hinaus — ohne Clip wuerden sie zu Seitenscroll. `clip` statt `hidden`,
     damit main kein Scroll-Container wird; hidden bleibt als Rueckfall. */
  overflow-x: hidden;
  overflow-x: clip;

  --app-gold: #e8b660;
  --app-gold-strong: #f4d391;
  --app-gold-soft: rgba(232, 182, 96, 0.14);
  --app-gold-border: rgba(232, 182, 96, 0.38);
  --app-gold-glow: 0 0 24px rgba(232, 182, 96, 0.35);
  --app-preisfeld: rgba(8, 3, 18, 0.55);
}

/* Helle Palette: Gold ist dort ohnehin der Akzent — dieselben Werte wie
   site.css, zweimal notiert (Systemwahl + ausdrueckliche Wahl), Regel wie dort. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-page {
    --app-gold: #8a5a18;
    --app-gold-strong: #6f4712;
    --app-gold-soft: rgba(138, 90, 24, 0.10);
    --app-gold-border: rgba(138, 90, 24, 0.34);
    --app-gold-glow: 0 6px 20px -10px rgba(70, 52, 25, 0.45);
    --app-preisfeld: rgba(255, 252, 245, 0.75);
  }
}

:root[data-theme="light"] .app-page {
  --app-gold: #8a5a18;
  --app-gold-strong: #6f4712;
  --app-gold-soft: rgba(138, 90, 24, 0.10);
  --app-gold-border: rgba(138, 90, 24, 0.34);
  --app-gold-glow: 0 6px 20px -10px rgba(70, 52, 25, 0.45);
  --app-preisfeld: rgba(255, 252, 245, 0.75);
}

/* ---------- Skip-Link (Tastatur; unsichtbar bis fokussiert) ---------- */

.app-skip {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -150%);
  z-index: 200;
  padding: 0.6rem 1.2rem;
  border-radius: 0 0 0.75rem 0.75rem;
  background: var(--card);
  border: 1px solid var(--accent-40);
  color: var(--text-strong);
  font-weight: 700;
  text-decoration: none;
  transition: transform 0.15s ease;
}

.app-skip:focus-visible {
  transform: translate(-50%, 0);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Die Sprachwahl ist seit dem 2026-09-01 ein Aufklappmenue und liegt als
   .lang-menu in site.css — die frueheren .app-lang-switch-Regeln sind damit
   entfallen, /app/ nutzt dieselbe Bauform wie jede andere Seite. */

/* ---------- Scroll-Reveal ----------
   Nur mit JavaScript (body:not(.no-js)) und nur, wenn das System Bewegung
   erlaubt. Ohne beides steht jede Sektion sofort sichtbar da. */

body:not(.no-js) .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

body:not(.no-js) .reveal.in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  body:not(.no-js) .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------- Hero: Icon, Name, Untertitel, Status, Aufhaenger, Szene ---------- */

.app-hero {
  position: relative;
  text-align: center;
  padding-top: clamp(0.75rem, 3vw, 2rem);
}

/* Buehnenlicht hinter dem Kopfbereich — reine Verlaeufe, keine Ressourcen. */
.app-hero::before {
  content: '';
  position: absolute;
  inset: -4rem -20% auto;
  height: 30rem;
  background:
    radial-gradient(50% 60% at 50% 20%, var(--bg-glow-a), transparent 75%),
    radial-gradient(35% 45% at 68% 10%, var(--bg-glow-b), transparent 70%);
  filter: blur(10px);
  pointer-events: none;
  z-index: -1;
}

.app-head-icon {
  display: block;
  width: clamp(6rem, 18vw, 9.5rem);
  height: auto;
  margin: 0 auto clamp(0.85rem, 2.5vw, 1.2rem);
  border-radius: 22.5%;
  box-shadow: var(--shadow-lg), 0 0 30px var(--accent-15);
}

/* Wortmarke wie in der App (LayoutWrapper: <span class="accent-text">Egg</span>-Tracker):
   "Egg" in der Primaerfarbe der Palette, der Rest in der Textfarbe, kein
   Verlauf (Andreas, 2026-09-06). Der bis dahin gemalte Verlauf brauchte ein
   Polster gegen abgeschnittene Unterlaengen — mit echter Textfarbe entfaellt das. */
.app-hero h1 {
  font-size: clamp(2.4rem, 9vw, 3.6rem);
  line-height: 1.08;
  margin: 0 0 0.35rem;
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--text-strong);
}

.app-brand-egg {
  color: var(--accent);
}

/* Der Untertitel im Kopf ist seit dem 2026-09-06 eine gekuerzte Zeile
   („Zyklus-Tracking auch fuer Maenner – mit Style."), nicht mehr die
   Store-Kurzbeschreibung; die steht vollstaendig in meta/og/JSON-LD und wird
   dort vom Waechter check:store-mirror geprueft. "Style" traegt die Primaerfarbe
   wie das "Egg" darueber. */
.app-subtitle {
  margin: 0 auto clamp(0.9rem, 3vw, 1.25rem);
  max-width: 36rem;
  color: var(--text-muted);
  font-size: clamp(1rem, 3.2vw, 1.15rem);
  line-height: 1.55;
}

.app-subtitle em {
  font-style: normal;
  font-weight: 700;
  color: var(--accent);
}

.app-hero .status-badge {
  margin-bottom: 0;
}

/* Ueberschrift und Unterzeile zum Video (Andreas, 2026-09-06): nicht WIE man
   die App nutzt, sondern WARUM. Bis dahin standen hier Aufhaenger, Unterzeile
   und ein Textkasten mit den ersten drei Store-Absaetzen — ersatzlos weg, der
   Waechter check:store-mirror fuehrt sie als bewusste Luecke.

   Seit dem 2026-09-08 stehen beide Zeilen IM Element .app-szene-stage, also
   auf derselben Buehne wie das Video (Andreas: darueber wirkten sie verloren).
   Den Abstand nach oben traegt deshalb die Buehne, nicht mehr der Titel. */
.app-hook {
  /* 48rem statt 42: Bei 42rem hing ab 768px „sinnvoll." allein in der zweiten
     Zeile. text-wrap: balance verteilt die Zeilen in den laengeren Sprachen
     (ES/FR brechen ohnehin) gleichmaessig — Browser ohne Unterstuetzung
     brechen wie bisher. */
  max-width: 48rem;
  margin: 0 auto 0.5rem;
  /* Ueber dem Bodenlicht der Buehne (.app-szene-stage::before ist absolut
     positioniert und laege sonst als Schleier ueber der Schrift). */
  position: relative;
  font-size: clamp(1.5rem, 5.6vw, 2.3rem);
  line-height: 1.22;
  font-weight: 800;
  color: var(--text-strong);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

/* Der Lichthof haengt am Titel und ist in rem bemessen, damit er auf jedem
   Bildschirm dieselbe Schrift umfasst; er verlaeuft innerhalb seiner eigenen
   Flaeche vollstaendig ins Transparente und hat deshalb keine sichtbare Kante. */
.app-hook::before {
  content: '';
  position: absolute;
  z-index: -1;
  left: 50%;
  top: 50%;
  width: min(54rem, 128%);
  height: 20rem;
  transform: translate(-50%, -50%);
  background: radial-gradient(50% 50% at 50% 50%, var(--app-szene-textlicht), transparent 70%);
  pointer-events: none;
}

.app-hook em {
  font-style: normal;
  color: var(--accent);
}

.app-hook-sub {
  max-width: 40rem;
  /* Enger an das Video als frueher (2026-09-08): Titel, Unterzeile und Player
     sind eine Gruppe — der groesste Abstand der Gruppe liegt aussen, nicht
     zwischen ihren Teilen. */
  margin: 0 auto clamp(1.1rem, 3.2vw, 1.6rem);
  position: relative;
  font-size: clamp(1rem, 3.2vw, 1.15rem);
  line-height: 1.55;
  font-weight: 500;
  color: var(--text-muted);
  text-wrap: balance;
}

/* „Egg-Advisor" bricht nicht am Bindestrich — auf 360px stand „Egg-" allein
   am Zeilenende (Andreas' Screenshot vom 2026-09-08). */
.app-nowrap {
  white-space: nowrap;
}

/* ---------- Video-Buehne (2026-09-08) ----------
   Dieselbe Mechanik wie die Telefon-Buehne: Ein Bodenlicht in Primaerfarbe
   mit elliptischer Unterkante, darauf die Buehnenkante (.app-stage-edge mit
   negativem Abstand). Das Video steht auf dem Licht; das Bodenlicht ist
   zugleich der Lichtkranz hinter dem Player (bis dahin ein eigener Halo an
   .app-szene-figure::before, jetzt entfallen).

   Warum kein overflow: hidden wie an der Telefon-Buehne: Dort schneidet die
   Ellipse die Telefone, hier darf sie den Player nicht anschneiden (seine
   Bedienleiste liegt unten). Also traegt das Licht selbst die Ellipse
   (border-radius auf dem ::before), und die Buehne bleibt offen — der Schatten
   des Players laeuft frei aus. Das Licht ist so breit wie die Kante
   (max-width 62.5rem, wie die Telefon-Buehne), deshalb liegt der Strich auf
   jeder Breite genau auf der Ellipse.

   Der Sockel unter dem Video (padding-bottom) ist die Flaeche, auf der das
   Licht am hellsten ist: Kantentiefe plus eine knappe rem Luft. */
.app-szene-stage {
  position: relative;
  width: 100%;
  max-width: 62.5rem;
  /* Abstand zur Buehnenkante darueber — bis zum 2026-09-08 am .app-hook —
     und ein Polster nach innen, damit das Licht Luft ueber der Schrift hat. */
  margin: clamp(2.75rem, 8vw, 4rem) auto 0;
  padding: 1.25rem 0 calc(var(--app-stage-edge-depth) + 0.9rem);
}

.app-szene-stage::before {
  content: "";
  position: absolute;
  inset: -2rem 0 0;
  background: var(--app-szene-floor);
  border-bottom-left-radius: 50% var(--app-stage-edge-depth);
  border-bottom-right-radius: 50% var(--app-stage-edge-depth);
  pointer-events: none;
}

.app-szene-figure {
  position: relative;
  margin: 0 auto;
  max-width: 62rem;
}

/* ---------- Video im Kopf der Seite ----------
   Seit dem 2026-09-06 steht hier direkt ein <video>. Der Player bringt seinen
   Rahmen und seine Bedienleiste selbst mit und laeuft deshalb auch ohne
   JavaScript; mit Skript liegt vor dem ersten Abspielen ein transparenter
   Abspielknopf darauf (.app-szene-play, weiter unten). `preload="none"` sorgt dafuer, dass
   nur das Poster geladen wird; die 8 MB holt der Browser erst beim Abspielen.
   Kein YouTube/Vimeo: waere der erste externe Dienst auf der Domain und nach
   § 25 TDDDG einwilligungsbeduerftig (inszenierung.md §6). */

.app-szene-video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: clamp(1rem, 3vw, 1.6rem);
  border: 1px solid var(--panel-border);
  box-shadow: var(--shadow-hero);
  background: #0f0620;
}

/* Untertitel (2026-09-09, Andreas: "generell stoerend, ggfs. kleiner").
   Die Vorgabe der Browser ist eine tiefschwarze Box in rund 5 % der
   Videohoehe — auf der 1000-px-Buehne sind das ~28 px Schrift auf deckendem
   Schwarz, und die deckt in der Totalen das halbe Bild zu. Drei Stellschrauben:

   - font-size in Prozent ist relativ zur Browservorgabe und skaliert
     deshalb weiter mit der Spielergroesse mit — ein fester px-Wert waere auf
     dem Telefon zu gross und auf dem Tablet zu klein.
   - Der Kasten wird halbtransparent statt deckend; damit die Schrift auch
     ueber einer hellen Stelle steht, traegt sie zusaetzlich einen Schatten.
     Beides zusammen, nicht nur eins davon — ohne Kasten frisst die Barszene
     die Schrift, ohne Schatten der Lichtkegel im Intro.
   - Die Schriftart ist die der Seite statt der Systemvorgabe des Spielers.

   Was hier NICHT geht: Position und Zeilenumbruch. Die stehen im WebVTT und
   kaempfen sonst mit der Bedienleiste des Spielers. Safari ignoriert diese
   Regeln, sobald jemand in den Bedienungshilfen eine eigene Untertitel-
   Darstellung gesetzt hat — das ist Absicht des Systems und bleibt so. */
.app-szene-video::cue {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 80%;
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.96);
  background: rgba(11, 7, 16, 0.55);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.95);
}

/* Von der Tabletbreite an darf es kleiner sein. Nicht aus Geschmack: Chrome
   rechnet die Vorgabe aus der Videohoehe, faengt sie aber nach unten mit einem
   Mindestwert ab. Auf dem Telefon (Player rund 200 px hoch) greift dieser
   Boden — dieselbe Prozentzahl schneidet dort also in die Lesbarkeit, waehrend
   sie auf der 62-rem-Buehne nur von einem ohnehin reichlichen Wert abzieht.
   Am 2026-09-09 auf 390x844 und 1440x900 gegen die Vorgabe gemessen. */
@media (min-width: 48rem) {
  .app-szene-video::cue {
    font-size: 70%;
  }
}

/* ---------- Abspielknopf auf dem Video (2026-09-12, Andreas) ----------
   Ein sehr transparenter Knopf in der Mitte: Glas-Hauch, heller Rand,
   Dreieck. Durch ihn hindurch bleibt der Advisor im Standbild zu sehen —
   Andreas mochte den Advisor-Knopf vom Vortag (echter Kopf im Bullauge, §25),
   fand den echten Advisor an dieser Stelle aber schoener (hero-konzept.md
   §28). Deshalb auch kein backdrop-filter: Jede Unschaerfe nimmt dem Gesicht
   darunter die Zeichnung.

   Das Videolayout bleibt unangetastet: Die native Leiste steht ab dem ersten
   Bild, der Knopf ist nur ein Aufsatz. Das Markup baut app.js; ohne Skript
   gibt es ihn nicht. Groesse relativ zur Videobreite, gedeckelt: 80 px auf
   dem Telefon, 136 px auf der 62-rem-Buehne.

   Position (2026-09-12, Andreas: „direkt über dem Advisor"): Der Kopf des
   Advisors steht im Poster (1280x720) bei x 632 / y 360 — Ei von 283 bis 440,
   540 bis 725. Das sind 49,4 % / 50 %; weil das Video sein Seitenverhaeltnis
   haelt, treffen Prozentwerte ihn auf jeder Groesse. Auf dem Telefon bleibt
   die Hoehe bei 46 %: Bei 50 % laege die Unterkante des 80-px-Knopfs bei 133
   von 185 px, auf Hoehe der Bedienzeile, und der Knopf deckt dort ohnehin
   den ganzen Kopf. */
.app-szene-play {
  position: absolute;
  left: 49.4%;
  top: 46%;
  display: grid;
  place-items: center;
  width: clamp(5rem, 16%, 8.5rem);
  aspect-ratio: 1;
  margin: 0;
  padding: 0;
  border: 1.5px solid var(--app-play-border);
  border-radius: 50%;
  background: var(--app-play-bg);
  color: var(--app-play-icon);
  cursor: pointer;
  transform: translate(-50%, -50%);
  transition: transform 0.18s ease, background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
  -webkit-tap-highlight-color: transparent;
}

@media (min-width: 48rem) {
  .app-szene-play {
    top: 50%;
  }
}

.app-szene-play[hidden] {
  display: none;
}

.app-szene-play:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 4px;
}

.app-szene-play svg {
  width: 38%;
  height: 38%;
  /* Ein Dreieck sitzt optisch links, wenn es geometrisch mittig steht */
  transform: translateX(7%);
  filter: drop-shadow(0 1px 2px var(--app-play-schatten));
}

.app-szene-play:hover,
.app-szene-play:focus-visible {
  transform: translate(-50%, -50%) scale(1.05);
  background: var(--app-play-bg-hover);
  border-color: var(--app-play-border-hover);
  color: var(--app-play-icon-hover);
}

/* Den eigenen Abspielkreis mancher Player in der Bildmitte (Chrome auf
   Android, Safari auf iOS) ausblenden, solange der Advisor-Knopf dort steht —
   .hat-knopf setzt und nimmt app.js. Zwei getrennte Regeln: Ein Browser, der
   eines der beiden Pseudo-Elemente nicht kennt, verwirft sonst beide. Ohne
   Skript greift keine davon, der Player bleibt allein bedienbar. */
.app-szene-figure.hat-knopf .app-szene-video::-webkit-media-controls-overlay-play-button {
  display: none;
}

.app-szene-figure.hat-knopf .app-szene-video::-webkit-media-controls-start-playback-button {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .app-szene-play {
    transition: none;
  }
}

/* ---------- Sektionen: Titel ----------
   Die Nummern-Kicker ("01", "02") ueber den Ueberschriften sind am 2026-09-07
   ersatzlos entfallen (Andreas): Sie zaehlten eine Reihe von acht Sektionen ab
   — nach dem Umbau vom Vortag sind es zwei, und eine Aufzaehlung von zwei
   Punkten zaehlt nichts mehr. */

.app-section {
  max-width: var(--measure);
  margin-inline: auto;
  margin-top: clamp(3rem, 9vw, 4.5rem);
}

.app-section > h2 {
  font-size: clamp(1.5rem, 5vw, 2rem);
  font-weight: 800;
  color: var(--text-strong);
  letter-spacing: -0.015em;
  line-height: 1.2;
  margin: 0 0 clamp(0.85rem, 3vw, 1.2rem);
}

/* ---------- Zweispalter: "Deine Daten" neben "Was es kostet" ----------
   Seit dem 2026-09-06 sind das die einzigen beiden Inhaltssektionen der Seite
   (Andreas: Zyklusphasen, Egg-Advisor, "mit Style", "Sieh es dir an" und die
   Voraussetzungen sind raus, "Was ist neu" ist am 2026-09-09 ganz
   entfallen). Untereinander
   wirkten sie dadurch verloren.

   Erst ab 1000px zwei Spalten: Bei 76rem Inhaltsbreite bleiben je Spalte rund
   588px. Enger sollte keine der beiden Karten werden — das Bild der Datenkarte
   und die Betragsreihe der Preiskarte brauchen die Breite. */

.app-duo {
  display: block;
  /* Dieselbe Spaltenbreite wie Telefon- und Video-Buehne (2026-09-08): Bis
     dahin liefen die Karten auf 1280px 1216px breit, Buehne und Video 1000 —
     drei verschiedene Breiten untereinander. */
  max-width: 62.5rem;
  margin-inline: auto;
}

@media (min-width: 1000px) {
  .app-duo {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(1.5rem, 3.5vw, 2.75rem);
    /* Beide Karten gleich hoch (Andreas, 2026-09-07). Den Ueberschuss nimmt
       die Betragsreihe der Preiskarte auf (margin-block: auto weiter unten),
       nicht die Fusszeile — sonst haengt die Karte unten durch. */
    align-items: stretch;
  }
  .app-duo > .app-section {
    max-width: none;
    margin-inline: 0;
  }
}

/* ---------- Die beiden Inhaltskarten (Mockup vom 2026-09-07) ----------
   Beide Sektionen sind seit dem Umbau echte Karten: Chip-Marke, Ueberschrift
   mit farbigem zweiten Teil, Kurzzeile, Bild, Hakenliste, Fusszeile. Die
   Preiskarte traegt Gold — das Freischalt-Motiv des Store-Materials —, die
   Datenkarte das Violett der Seite.

   KEIN Kaufknopf (Andreas ausdruecklich, 2026-09-07): Die App ist nicht im
   Store, und die Seite fuehrt ueberhaupt keinen externen Link. Ein Knopf, der
   nirgendwohin fuehrt, ist schlimmer als keiner.

   site.css setzt auf aufeinanderfolgende <section> eine Haarlinie und
   Innenabstand (`section + section`, fuer die Textseiten). Die
   Kurzschreibweisen `padding` und `border` in .app-card haengen darueber und
   nehmen beides zurueck — deshalb braucht der Zweispalter dafuer keine
   Sonderregel mehr. */

.app-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.25rem, 4.5vw, 2rem);
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: clamp(1.1rem, 3vw, 1.75rem);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-md);
  overflow: hidden;
}

/* Lichtkranz in der oberen Ecke, wie am Kopf der Seite — nur viel ruhiger. */
.app-card::before {
  content: '';
  position: absolute;
  inset: -55% 45% 55% -45%;
  background: radial-gradient(circle, var(--accent-12), transparent 70%);
  pointer-events: none;
}

.app-card-preis {
  border-color: var(--app-gold-border);
}

.app-card-preis::before {
  background: radial-gradient(circle, var(--app-gold-soft), transparent 70%);
}

.app-card > * {
  position: relative;
}

/* Die Chip-Marke ueber der Ueberschrift */
.app-card-chip {
  display: inline-flex;
  /* Die Karte ist eine Flex-Spalte (fuer die gleiche Hoehe im Zweispalter);
     ohne align-self zoege der Chip sich ueber die ganze Kartenbreite. */
  align-self: flex-start;
  align-items: center;
  gap: 0.45rem;
  margin: 0 0 clamp(0.75rem, 2.5vw, 1.1rem);
  padding: 0.35rem 0.8rem 0.35rem 0.65rem;
  border: 1px solid var(--accent-30);
  border-radius: 999px;
  background: var(--accent-08);
  color: var(--accent);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.app-card-chip svg {
  width: 0.95rem;
  height: 0.95rem;
  flex: none;
}

.app-card-preis .app-card-chip {
  border-color: var(--app-gold-border);
  background: var(--app-gold-soft);
  color: var(--app-gold);
}

.app-card > h2 {
  margin: 0 0 0.5rem;
}

.app-card > h2 em {
  font-style: normal;
  color: var(--accent);
}

.app-card-preis > h2 em {
  color: var(--app-gold);
}

.app-card-lead {
  margin: 0 0 clamp(1rem, 3.5vw, 1.4rem);
  color: var(--text-muted);
  font-size: clamp(0.95rem, 2.9vw, 1.05rem);
  line-height: 1.6;
}

/* ---------- Datenkarte: das Bild traegt die Aussage ----------
   KEIN weicher Auslauf an den Kanten (Andreas' Frage vom 2026-09-05): Die drei
   durchgestrichenen Zeichen sitzen genau am linken und rechten Bildrand. Eine
   Maske, die nach aussen ausblendet, loescht damit das, was das Bild ueberhaupt
   sagt. Der Rahmen loest dieselbe Aufgabe. */

.app-data-figure {
  margin: 0 0 clamp(1rem, 3.5vw, 1.4rem);
}

.app-data-figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: clamp(0.9rem, 2.5vw, 1.25rem);
  border: 1px solid var(--card-border);
  box-shadow: var(--shadow-md);
}

/* Handschrift der Datenkarte (2026-09-11, Andreas): „Deine Daten bleiben
   privat. Versprochen." mit Schloss statt Herz, der Pfeil zeigt nach unten
   links ins Bild auf das Telefon. Schrift wie der Vermerk im Kopf (Caveat, §4),
   Farbe die der Karte (--accent), wie das Gold auf der Preiskarte: Dunkel ist
   das dasselbe Lila wie „Deine Daten.", hell dasselbe Braun. Das Violett des
   Kopf-Vermerks stand auf der hellen Karte als einziges kaltes Element — genau
   der Befund, der die Preis-Handschrift schon zu Gold gemacht hat.

   NICHT auf dem Bild: Die drei durchgestrichenen Zeichen sitzen genau an
   dessen linkem und rechtem Rand (siehe oben), und ein Vermerk darueber
   verdeckte auf dem Telefon eines davon. Nur der Pfeil ragt ins Bild hinein
   (z-index, weil das Bild spaeter im Fluss steht und sonst darueber malt).

   Neben der Kurzzeile, wo Platz ist, sonst darunter (Andreas, 2026-09-11,
   zweiter Anlauf): `.app-data-kopf` ist eine umbrechende Flexzeile. Die
   Kurzzeile behaelt mindestens 12rem — schmaler wurde sie auf 320/360 zu
   einer Fuenfzeilen-Spalte (FR/ES). Passt der Vermerk daneben nicht, rutscht
   er von selbst in die naechste Zeile, rechtsbuendig per `margin-left: auto`;
   das ist exakt die erste Fassung. Keine Breitengrenze, die an der laengsten
   Sprache haengt — dieselbe Mechanik wie das Preisschild (hero-konzept §26).

   Abstand zum Bild in beiden Lagen gleich: Die Kurzzeile haelt ihre Luft
   (--app-data-luft), der Vermerk zieht sich per negativem margin-bottom bis
   0.5rem ans Bild heran. Sonst reichte der Pfeil daneben weniger weit hinein
   als darunter. Der row-gap ist die Luft minus 0.35rem, wie vorher der
   Abstand zwischen Kurzzeile und Vermerk in eigener Zeile.

   Wohin der Pfeil zeigt, haengt an der Kartenbreite: Der Vermerk steht rechts,
   seine Spitze liegt links unter ihm. Rechtsbuendig allein landete sie auf
   der breiten Einzelkarte (560–999px) am rechten Schildrand ueber dem Auge.
   `max(0px, 45% - 12.5rem)` rueckt ihn dort so weit ein, dass die Spitze bei
   gut der halben Bildbreite liegt — auf dem Telefon und im Zweispalter ist der
   Wert null, dort reicht rechtsbuendig. Prozent im margin = Kartenbreite.

   Der Satz ist ein Versprechen ueber die Architektur (kein Server, kein Konto,
   kein Tracking). Kommt je ein Datenabfluss dazu, faellt er mit der
   Datenschutzerklaerung — nicht erst danach. */
.app-data-kopf {
  --app-data-luft: clamp(1rem, 3.5vw, 1.4rem);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  column-gap: 0.9rem;
  row-gap: calc(var(--app-data-luft) - 0.35rem);
  margin: 0 0 var(--app-data-luft);
}

/* „lokal" fett und in der Primaerfarbe (Andreas, 2026-09-15) — das eine Wort,
   das die Karte traegt. Der Store-Spiegel liest die Zeile ohne Tags. */
.app-data-lokal {
  font-weight: 800;
  color: var(--accent);
}

.app-data-kopf .app-card-lead {
  flex: 1 1 12rem;
  align-self: flex-start;
  margin: 0;
}

/* Mit dem Kopf als Vorsatz, nicht als nackte Klasse: Der Vermerk ist das
   letzte Kind im Kopf, und `p:last-child { margin-bottom: 0 }` aus site.css
   (0,1,1) schluege `.app-data-notiz` (0,1,0) — der negative margin-bottom
   fiele still weg, gemessen am 2026-09-11. */
.app-data-kopf > .app-data-notiz {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  max-width: 100%;
  margin: 0 max(0px, 45% - 12.5rem) calc(0.5rem - var(--app-data-luft)) auto;
  padding-right: 0.2rem;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.35rem, 4.4vw, 1.6rem);
  font-weight: 600;
  line-height: 0.95;
  color: var(--accent);
  transform: rotate(-5deg);
}

.app-data-notiz .app-schloss {
  display: inline-block;
  width: 0.8em;
  height: 0.8em;
  vertical-align: -0.06em;
  margin-left: 0.15em;
}

.app-data-notiz .app-arrow {
  position: absolute;
  right: 100%;
  bottom: -2rem;
  width: clamp(2.6rem, 8vw, 3.4rem);
  height: auto;
  aspect-ratio: 90 / 70;
  margin-right: -0.4rem;
}

/* ---------- Preiskarte: das Preisschild ----------
   Nach der Vision vom 2026-09-11 (Andreas, zwei Mockups fuer Telefon und
   Desktop): EIN Preisschild. Das Feld traegt Betrag, Einheit und Handschrift;
   das Freischalt-Bild sitzt auf seiner rechten Kante, greift ein Stueck hinein
   und steht oben und unten ueber, mit Goldrahmen und leicht gedreht. Kein
   Bogen mehr — die Handschrift steht im Feld, nicht daneben. Kein Herz
   (Andreas, 2026-09-07).

   Bis zum 2026-09-08 griff das Bild schon einmal ins Feld und deckte im
   Zweispalter den Betrag zu. Ursache war die erste Rasterspalte
   `minmax(0, 1fr)`: Das Feld schrumpfte unter seinen Inhalt, der Betrag
   (`nowrap`) lief unter das Bild. Jetzt ist die Reihe eine Flexzeile, und ein
   Flex-Element schrumpft nie unter seine Mindestbreite (`min-width: auto`) —
   Betrag plus Polster sind die Untergrenze des Felds. Das Polster rechts ist
   der Ueberhang plus Luft; der Inhalt endet damit auf jeder Breite vor dem
   Bild, auch vor dessen gedrehter Ecke.

   Das Feld ist nur so breit wie sein Inhalt (`flex: 0 1 auto`) und fuellt die
   Reihe erst, wenn der Platz knapp wird. Auf dem Tablet stuende sonst ein
   langes, leeres Feld mit dem Bild am anderen Ende. */
.app-price-row {
  --app-price-bild: clamp(112px, 34vw, 160px);
  --app-price-ueberhang: calc(var(--app-price-bild) * 0.24);
  display: flex;
  align-items: center;
  margin: 0 0 clamp(1rem, 3.5vw, 1.4rem);
}

.app-price-amount {
  flex: 0 1 auto;
  display: flex;
  flex-direction: column;
  padding: 0.95rem calc(var(--app-price-ueberhang) + 0.75rem) 0.95rem clamp(0.9rem, 3.5vw, 1.25rem);
  border: 1px solid var(--app-gold-border);
  border-radius: 1.1rem;
  background: var(--app-preisfeld);
  line-height: 1;
}

.app-price-amount strong {
  /* Kleiner als bis zum 2026-09-08 (3.1rem): Der Betrag steht nicht mehr unter
     dem Bild und muss deshalb nicht mehr durch Groesse dagegen ankommen
     (Andreas). Der untere Wert haelt "3,99 €*" auf 320px neben dem Bild. */
  font-size: clamp(1.75rem, 6vw, 2.6rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  white-space: nowrap;
  color: var(--app-gold);
}

/* Einheit und Handschrift stehen in einer umbrechenden Flexzeile. Wo die
   Handschrift landet, entscheidet der Platz, keine Breitengrenze: Passt sie
   neben „einmalig", steht sie dort, ihre erste Zeile auf dessen Grundlinie
   (`align-items: baseline`, Desktop-Mockup); sonst rutscht sie darunter und
   haengt sich mit `margin-left: auto` rechts ans Bild (Telefon-Mockup). Die
   Fassungen bis zum 2026-09-10 hingen an festen Grenzen (359px, 560px,
   Zweispalter), und jede Grenze hing an der laengsten Sprache — jetzt bricht
   Franzoesisch einfach frueher um als Deutsch. */
.app-price-unterzeile {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0.85rem;
  row-gap: 0.15rem;
  margin-top: 0.4rem;
}

.app-price-einheit {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-muted);
}

/* Der Stern verweist auf die Fusszeile der Karte (Pflichtangaben nach PAngV:
   Steuer, Abwicklung, Landespreise). `line-height: 0` haelt ihn aus der
   Zeilenhoehe des Betrags heraus, sonst waechst das Feld um seine Hochstellung.
   Fuer Vorlesewerkzeuge ist er `aria-hidden` — die Fusszeile steht ohnehin
   direkt darunter und wird vollstaendig vorgelesen. */
.app-price-stern {
  font-size: 0.42em;
  line-height: 0;
  vertical-align: super;
  margin-left: 0.06em;
}

/* Das Bild greift um den Ueberhang ins Feld (negativer Aussenabstand); das
   Feld haelt ihm mit seinem rechten Polster genau diesen Platz frei. Es malt
   ueber dem Feld, weil es spaeter im Fluss steht und die Drehung es auf eine
   eigene Ebene hebt. Es ist hoeher als das Feld und steht deshalb oben und
   unten ueber (`align-items: center` der Reihe). */
.app-price-visual {
  flex: none;
  margin: 0 0 0 calc(-1 * var(--app-price-ueberhang));
}

.app-price-visual img {
  display: block;
  width: var(--app-price-bild);
  height: auto;
  border-radius: 1rem;
  border: 2px solid var(--app-gold);
  box-shadow: 0 10px 22px rgba(0, 0, 0, 0.45), var(--app-gold-glow);
  transform: rotate(6deg);
}

/* Handschrift: dieselbe Schrift wie der Vermerk im Kopf (Caveat, §4), in Gold —
   Violett war auf der hellen Palette das einzige kalte Element in einer
   goldenen Karte. Eng gesetzt wie der Vermerk und rechtsbuendig, damit die
   kuerzere zweite Zeile einrueckt wie im Mockup. `max-width: 100%` laesst sie
   auf den schmalsten Geraeten im Feld umbrechen, statt unter das Bild zu laufen.

   Vom 2026-09-09 bis zum 2026-09-10 lief die Goldhaarlinie des Felds zwischen
   ihren beiden Zeilen hindurch, „Große Freiheit." stand ausserhalb; davor
   stand sie auf dem Tablet frei neben dem Bild, mit einem Bogen dorthin. Die
   Vision vom 2026-09-11 holt beide Zeilen ins Feld. */
.app-price-notiz {
  max-width: 100%;
  margin: 0 0 0 auto;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.15rem, 3.6vw, 1.3rem);
  font-weight: 600;
  line-height: 1.08;
  text-align: right;
  color: var(--app-gold);
  transform: rotate(-4deg);
}

/* ---------- Hakenliste ---------- */

.app-check-list {
  display: grid;
  gap: 0.5rem;
  margin: 0 0 clamp(1rem, 3.5vw, 1.4rem);
  padding: 0;
  list-style: none;
}

.app-check-list li {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--panel-border);
  border-radius: 0.8rem;
  background: var(--panel);
  color: var(--text);
  font-size: clamp(0.88rem, 2.6vw, 0.95rem);
  font-weight: 600;
  line-height: 1.3;
}

/* Die Datenkarte fuehrt seit dem 2026-09-08 drei Begriffe statt vier: "Lokale
   Speicherung" ist raus (Andreas), weil die Kurzzeile darueber genau das schon
   sagt — "Zyklusdaten bleiben lokal auf deinem Geraet."

   Drei Begriffe passen in kein Zweierraster, ohne dass unten einer allein
   stehenbleibt. Also keine Spalten, sondern eine mittige Reihe aus drei
   Pillen: Wo die Breite reicht, stehen sie nebeneinander; wo nicht, bricht die
   Reihe mittig um (auf 360px zwei plus eine). `flex: 0 0 auto` haelt jede
   Pille bei ihrer natuerlichen Breite — schrumpfen wuerde ihren Text umbrechen
   und die Reihe ungleich hoch machen. Die Preiskarte bleibt beim Raster, ihre
   Begriffe sind laenger. */
.app-card-daten .app-check-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
}

/* Knapp bemessen, damit die drei auch im Zweispalter (Karte ~394px) in EINE
   Reihe passen — mit dem Polster der Preiskarten-Haken waren es 407px und
   "Kein Tracking" fiel in die zweite Zeile. */
.app-card-daten .app-check-list li {
  flex: 0 0 auto;
  gap: 0.4rem;
  padding: 0.5rem 0.65rem;
  font-size: 0.8rem;
}

.app-card-daten .app-check-list svg {
  width: 1.05rem;
  height: 1.05rem;
}

.app-check-list svg {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
  padding: 0.15rem;
  border-radius: 999px;
  background: var(--accent-15);
  color: var(--accent);
}

.app-card-preis .app-check-list svg {
  background: var(--app-gold-soft);
  color: var(--app-gold);
}

.app-card-fuss {
  margin: 0;
  font-size: 0.84rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.app-card-fuss a {
  color: var(--accent-link);
  font-weight: 600;
}

/* Fusszeile mit haengendem Stern (2026-09-08, Andreas): Der Stern steht am
   Betrag, die Aufloesung hier — und zwar ausgerueckt, damit sie als Fussnote
   lesbar ist und nicht als weiterer Satz. */
.app-card-fuss-stern {
  display: flex;
  gap: 0.3rem;
}

/* Ab 560px stehen die Haken zu zweit nebeneinander — im Zweispalter ab 1000px
   ist die Karte dafuer wieder zu schmal, dort bleibt es einspaltig. */
@media (min-width: 560px) {
  .app-check-list {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Im Zweispalter ist eine Karte rund 410px breit. Die Preiskarte behaelt dort
   eine Spalte — "Keine automatische Verlaengerung" braucht die Zeile ganz. Die
   Datenkarte traegt ihre drei Pillen in einer mittigen Reihe (siehe oben) und
   braucht dafuer keine Sonderregel. */
@media (min-width: 1000px) {
  .app-duo .app-card-preis .app-check-list {
    grid-template-columns: 1fr;
  }
  /* Die Preiskarte ist kuerzer als die Datenkarte daneben; seit beide gleich
     hoch sind, verteilt sich die Differenz oberhalb und unterhalb der
     Betragsreihe. Sie ist das Element, dem Luft gut steht. */
  .app-duo .app-card-preis .app-price-row {
    margin-block: auto;
  }
  /* Keine eigene Anordnung mehr im Zweispalter, nur ein kleineres Bild: Bei
     160px blieben im Feld rund 211px, und die deutsche Handschrift brach auf
     1024px unter „einmalig" um, auf 1440px nicht — zwei Fassungen desselben
     Desktops. Mit 144px steht sie auf beiden daneben. Bis zum 2026-09-10
     standen hier eine zweite Rasterfassung und eine eigene Schriftgroesse. */
  .app-duo .app-price-row {
    --app-price-bild: 144px;
  }
}

/* ---------- Hinweis (Pflicht-Disclaimer, letzter Inhaltsblock) ---------- */

.app-notice {
  /* So breit wie die beiden Karten darueber (Andreas, 2026-09-08). .app-section
     setzt sonst die Lesebreite (--measure, 52rem) — der Kasten sass damit als
     einziger Block schmaler in der Spalte. */
  max-width: 62.5rem;
  background: var(--panel);
  border: 1px solid var(--panel-border);
  border-radius: 1.1rem;
  padding: clamp(1rem, 3.5vw, 1.35rem) clamp(1.1rem, 4vw, 1.5rem);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
}

.app-notice > h2 {
  font-size: 1.05rem;
  margin: 0 0 0.6rem;
  color: var(--accent);
  font-weight: 700;
}

.app-notice p {
  margin: 0 0 0.75rem;
  color: var(--text-muted);
  font-size: 0.92rem;
  line-height: 1.6;
}

.app-notice p:last-child {
  margin-bottom: 0;
}

/* Der Verweis auf die ausfuehrlichen Hinweise bleibt gut treffbar (Touchziel). */
.app-notice-link a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--accent-link);
  font-weight: 600;
}


/* ---------- Seitenkopf nach dem Mockup vom 2026-09-06 (docs/hero-konzept.md) ----------
   Unter Icon, Wortmarke und Untertitel: zwei Store-Knoepfe mit handschriftlichem
   Vermerk, darunter drei Telefone mit echten App-Renders (Display-Glas aus den
   Store-Bildern, `website-hero.mjs` im App-Repo). Der Kopf war am 2026-09-06
   zuerst auf der Landingpage gebaut worden — gemeint war /app/ (Andreas);
   die Landingpage ist unveraendert. Mobile-first: Basisregel ist das Telefon,
   `min-width` nur fuer Buehne und Vermerk. Tokens wie das Gold oben dreimal
   notiert (dunkel, Systemwahl hell, ausdrueckliche Wahl hell). */

.app-page,
.app-zoom {
  --app-shadow-phone: 0 40px 80px -30px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(0, 0, 0, 0.6);
  --app-hero-floor: radial-gradient(60% 45% at 50% 100%, rgba(168, 85, 247, 0.55), rgba(168, 85, 247, 0) 70%);
  --app-hero-note: #D8B4FE;
  --app-phone-frame: #15121c;
  --app-phone-rim: rgba(255, 255, 255, 0.28);
  --app-zoom-veil: rgba(9, 3, 20, 0.88);
  --app-store-badge-bg: #0b0710;
  --app-store-badge-border: rgba(255, 255, 255, 0.55);
  /* Bodenlicht der Video-Buehne: breiter als das der Telefon-Buehne, weil das
     Video die Mitte deckt und das Licht an den Seiten und unten sichtbar
     bleiben soll; dazu ein schwacher Kranz hinter dem ganzen Player. Seit dem
     2026-09-08 reicht es hoeher (78 % statt 60 % der Buehnenhoehe): Titel und
     Unterzeile stehen seither mit auf der Buehne und sollen im selben Licht
     liegen wie der Player. */
  --app-szene-floor:
    radial-gradient(85% 78% at 50% 100%, rgba(168, 85, 247, 0.6), rgba(168, 85, 247, 0) 70%),
    radial-gradient(70% 70% at 50% 60%, rgba(168, 85, 247, 0.22), rgba(168, 85, 247, 0) 70%);
  /* Lichthof hinter Titel und Unterzeile (2026-09-08). Er haengt am Text, nicht
     an der Buehne: Die Buehnenhoehe bestimmt das Video, ein prozentualer
     Verlauf auf der Buehne saesse je nach Bildschirm ueber oder unter der
     Schrift — und wo er an der Oberkante abgeschnitten wird, entsteht eine
     sichtbare gerade Kante quer ueber die Seite (am 2026-09-08 gemessen). */
  --app-szene-textlicht: rgba(168, 85, 247, 0.30);
  /* Abspielknopf (2026-09-12): sehr transparent, damit der Advisor im Standbild
     sichtbar bleibt. Er liegt auf dem dunklen Standbild, nicht auf der Seite —
     deshalb in allen drei Bloecken gleich. */
  --app-play-bg: rgba(255, 255, 255, 0.12);
  --app-play-bg-hover: rgba(255, 255, 255, 0.2);
  --app-play-border: rgba(255, 255, 255, 0.5);
  --app-play-border-hover: rgba(255, 255, 255, 0.75);
  --app-play-icon: rgba(255, 255, 255, 0.8);
  --app-play-icon-hover: #fff;
  --app-play-schatten: rgba(11, 7, 16, 0.45);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-page,
  :root:not([data-theme="dark"]) .app-zoom {
    --app-shadow-phone: 0 40px 70px -30px rgba(70, 52, 25, 0.55), 0 0 0 1px rgba(0, 0, 0, 0.35);
    --app-hero-floor: radial-gradient(60% 45% at 50% 100%, rgba(214, 160, 90, 0.55), rgba(214, 160, 90, 0) 70%);
    --app-hero-note: #7A4DE6;
    --app-phone-frame: #1b1720;
    --app-phone-rim: rgba(255, 255, 255, 0.22);
    --app-zoom-veil: rgba(241, 234, 217, 0.9);
    --app-store-badge-bg: #1a1322;
    --app-store-badge-border: rgba(0, 0, 0, 0.35);
    --app-szene-floor:
      radial-gradient(85% 78% at 50% 100%, rgba(214, 160, 90, 0.6), rgba(214, 160, 90, 0) 70%),
      radial-gradient(70% 70% at 50% 60%, rgba(214, 160, 90, 0.22), rgba(214, 160, 90, 0) 70%);
    --app-szene-textlicht: rgba(214, 160, 90, 0.34);
    --app-play-bg: rgba(255, 255, 255, 0.12);
    --app-play-bg-hover: rgba(255, 255, 255, 0.2);
    --app-play-border: rgba(255, 255, 255, 0.5);
    --app-play-border-hover: rgba(255, 255, 255, 0.75);
    --app-play-icon: rgba(255, 255, 255, 0.8);
    --app-play-icon-hover: #fff;
    --app-play-schatten: rgba(11, 7, 16, 0.45);
  }
}

:root[data-theme="light"] .app-page,
:root[data-theme="light"] .app-zoom {
  --app-shadow-phone: 0 40px 70px -30px rgba(70, 52, 25, 0.55), 0 0 0 1px rgba(0, 0, 0, 0.35);
  --app-hero-floor: radial-gradient(60% 45% at 50% 100%, rgba(214, 160, 90, 0.55), rgba(214, 160, 90, 0) 70%);
  --app-hero-note: #7A4DE6;
  --app-phone-frame: #1b1720;
  --app-phone-rim: rgba(255, 255, 255, 0.22);
  --app-zoom-veil: rgba(241, 234, 217, 0.9);
  --app-store-badge-bg: #1a1322;
  --app-store-badge-border: rgba(0, 0, 0, 0.35);
  --app-szene-floor:
    radial-gradient(85% 78% at 50% 100%, rgba(214, 160, 90, 0.6), rgba(214, 160, 90, 0) 70%),
    radial-gradient(70% 70% at 50% 60%, rgba(214, 160, 90, 0.22), rgba(214, 160, 90, 0) 70%);
  --app-szene-textlicht: rgba(214, 160, 90, 0.34);
  --app-play-bg: rgba(255, 255, 255, 0.12);
  --app-play-bg-hover: rgba(255, 255, 255, 0.2);
  --app-play-border: rgba(255, 255, 255, 0.5);
  --app-play-border-hover: rgba(255, 255, 255, 0.75);
  --app-play-icon: rgba(255, 255, 255, 0.8);
  --app-play-icon-hover: #fff;
  --app-play-schatten: rgba(11, 7, 16, 0.45);
}

/* Handschrift ohne externe Ressource: OFL-Subset, Lizenz liegt daneben
   (assets/fonts/OFL-Caveat.txt, hero-konzept.md §4). */
@font-face {
  font-family: "Caveat";
  src: url("../fonts/caveat-600-subset.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Knoepfe, Vermerk und Status-Badge als eine Gruppe; nur so breit wie die
   Knoepfe, damit der Vermerk ab 900px an ihrer Kante andocken kann. Der
   Deckel auf 100 % ist fuer den Vermerk darunter: Ohne feste Umbrueche waere
   seine Wunschbreite die ganze Zeile, und fit-content zoege die Gruppe damit
   ueber den Bildschirmrand. */
.app-hero-cta {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  width: fit-content;
  max-width: 100%;
  margin: 0.25rem auto 0;
}

.app-hero-cta .status-badge {
  margin-bottom: 0;
}

/* Store-Knoepfe: bis zum Launch Platzhalter in Badge-Geometrie, aber OHNE die
   Zeichen von Apple und Google (PLATZHALTER-Kommentar im HTML, Begruendung
   dort). Schwarz in beiden Paletten wie die Originale, nur der Rand wechselt.
   Seit dem 2026-09-08 tragen sie nur noch Text, deshalb symmetrisches Polster
   statt des linken Einzugs fuer die frueheren Glyphen. */
.app-store-badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
}

.app-store-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3.5rem;
  padding: 0.5rem 1.4rem;
  border-radius: 0.65rem;
  background: var(--app-store-badge-bg);
  color: #fff;
  border: 1.5px solid var(--app-store-badge-border);
  text-align: left;
  line-height: 1.05;
}

.app-store-badge small {
  display: block;
  font-size: 0.68rem;
  letter-spacing: 0.02em;
  opacity: 0.85;
}

.app-store-badge b {
  display: block;
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* Handschriftlicher Vermerk. Bis 899px steht er als LETZTES in der Gruppe —
   unter dem Status-Badge, rechts buendig, mit dem Pfeil nach unten links auf
   das mittlere Telefon (Andreas, 2026-09-08). Bis dahin stand er dreizeilig
   zwischen Knoepfen und Badge und der Pfeil fehlte; der Vermerk las sich so
   als Teil der Knopfgruppe statt als Hinweis auf die Bilder. Die drei festen
   Zeilen (<br>) bleiben auch hier — ein Zwischenstand mit freiem Umbruch ist
   auf Andreas' Wunsch zurueckgenommen (2026-09-08). */
.app-hero-note {
  order: 3;
  position: relative;
  align-self: flex-end;
  max-width: 100%;
  margin: 0.1rem 0 0;
  padding: 0 0.25rem 2.4rem 0;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: 1.7rem;
  font-weight: 600;
  line-height: 0.92;
  text-align: right;
  color: var(--app-hero-note);
  transform: rotate(-6deg);
}

.app-hero-note .app-heart {
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  vertical-align: -0.08em;
  margin-left: 0.15em;
}

/* Der Pfeil haengt unter dem Text und zeigt nach unten links auf die
   Oberkante des mittleren Telefons. Er ist von RECHTS gemessen: Die Gruppe
   ist so breit wie der Status-Badge (~300px) und mittig, der Vermerk schliesst
   rechts mit ihr ab — 6.5rem von dort liegt die Pfeilspitze auf jeder Breite
   ueber der Mitte der Buehne. Von links gemessen haette sie am Text gehangen,
   dessen Breite mit der Sprache wechselt. */
.app-hero-note .app-arrow {
  display: block;
  position: absolute;
  right: 6.5rem;
  bottom: 0;
  width: 3.4rem;
  height: 2.65rem;
}

/* Buehne: drei SICHTBARE Telefone, oben verankert, unten von der Buehne
   abgeschnitten (im Ring stehen seit dem 2026-09-10 abends sechs, drei davon
   verdeckt hinter der Mitte — siehe die Platz-Regeln weiter unten).
   Bis 760px skaliert sie mit ihrer Breite, damit alle drei Telefone
   vollstaendig im Bild stehen (Andreas, 2026-09-08 — vorher waren sie
   56vw breit, und auf 360px lief jedes aeussere Telefon rund 90px aus der
   Buehne). Rechnung: Telefon 36 % der Buehnenbreite, die aeusseren um 72 %
   versetzt und 7° gedreht; ihre obere Aussenecke liegt damit
   0,72 + 0,625 = 1,345 Telefonbreiten neben der Mitte, also bei 48,4 % —
   knapp innerhalb der Kante. Die Hoehe haelt das Verhaeltnis der grossen
   Fassung (Buehne ≈ 1,27 Telefonbreiten, 1000 : 457). Beide Deckel
   (max-height, Telefon 14.4rem) greifen gemeinsam ab 640px Buehnenbreite und
   treffen genau den Startwert des 761px-Blocks unten. */
.app-hero-stage {
  position: relative;
  width: 100%;
  max-width: 62.5rem;
  aspect-ratio: 1000 / 457;
  max-height: 18.3rem;
  margin: 1rem auto 0;
  overflow: hidden;
  /* Unterkante als flache Ellipse (Rx = halbe Breite, Ry = --app-stage-edge-depth):
     die Telefone werden entlang dieser Kurve abgeschnitten, und .app-stage-edge
     zeichnet dieselbe Ellipse als Linie genau darauf. */
  border-bottom-left-radius: 50% var(--app-stage-edge-depth);
  border-bottom-right-radius: 50% var(--app-stage-edge-depth);
}

.app-hero-stage::before {
  content: "";
  position: absolute;
  inset: auto -10% -10% -10%;
  height: 70%;
  background: var(--app-hero-floor);
  pointer-events: none;
}

.app-phone {
  position: absolute;
  top: 0;
  left: 50%;
  width: min(36%, 14.4rem);
  aspect-ratio: 9 / 19;
  transform: translateX(-50%) translateX(0%) translateY(0%) rotate(0deg);
  background: var(--app-phone-frame);
  border-radius: 14% / 6.6%;
  padding: 2.8%;
  box-shadow: var(--app-shadow-phone), inset 0 0 0 1.5px var(--app-phone-rim);
  transition: transform 0.55s cubic-bezier(0.22, 0.72, 0.24, 1),
              translate 0.55s cubic-bezier(0.22, 0.72, 0.24, 1),
              opacity 0.55s cubic-bezier(0.22, 0.72, 0.24, 1);
}

.app-phone-glass {
  width: 100%;
  height: 100%;
  border-radius: 11% / 5.2%;
  overflow: hidden;
  background: #000;
}

.app-phone img {
  display: block;
  width: 100%;
  height: auto;
}

/* Die Position haengt am PLATZ, nicht am Telefon (2026-09-10): app.js tauscht
   nur die data-slot-Werte, das CSS faehrt die Telefone dorthin. Ohne
   JavaScript bleibt der Ruhestand aus dem Markup stehen. */
.app-phone[data-slot="c"] { z-index: 3; }
.app-phone[data-slot="l"] { z-index: 2; transform: translateX(-50%) translateX(-72%) translateY(12%) rotate(-7deg); }
.app-phone[data-slot="r"] { z-index: 2; transform: translateX(-50%) translateX(72%) translateY(12%) rotate(7deg); }

/* Die VERDECKTEN Plaetze (2026-09-10 abends, hero-konzept.md §23/§24).
   Sichtbar bleiben drei Telefone; die uebrigen warten hinter der Mitte —
   kleiner, tiefer und unsichtbar. Sie liegen ALLE auf demselben Fleck, und
   das ist der eigentliche Trick: Jede Bewegung von einem verdeckten Platz zum
   naechsten geht ueber die Strecke null. Es gibt kein Telefon, das quer durchs
   Bild zurueckmuss — die Umleitung .faehrt-hinten von heute Nachmittag ist
   deshalb ersatzlos raus. Und weil sie sich nicht unterscheiden, kostet ein
   weiteres Motiv hier gar nichts: h4 traegt einfach der Attributselektor mit.

   z-index 1 haelt sie hinter allen drei sichtbaren Plaetzen, damit ein Telefon
   auf dem Weg nach hinten unter dem vorderen verschwindet statt davor.
   pointer-events: none, weil ein unsichtbares Telefon keinen Klick abfangen
   darf, der dem sichtbaren darunter gilt. */
.app-phone[data-slot^="h"] {
  z-index: 1;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateX(0%) translateY(9%) rotate(0deg) scale(0.8);
}

/* Wisch-Hinweis: ein Finger aus Glas (2026-09-16, Andreas; hero-konzept.md
   §37). Loest den Anstupser vom 2026-09-10 ab: Der kurze Schub war zu leise,
   man erkannte nicht sicher, dass sich die Buehne wischen laesst. Jetzt fuehrt
   eine Fingerkuppe die Geste vor (hoechstens zweimal, app.js) — sie setzt auf dem vorderen Telefon
   auf (Druckring), zieht mit Lichtspur nach links, die Telefone gehen ein
   Stueck mit, sie hebt ab, und die Telefone federn in den Ruhestand zurueck.
   Formensprache des Dreh-Hinweises „Quer halten!" (Glas, heller Rand,
   Lila-Glow), aber ohne Text: Ein zweiter handschriftlicher Vermerk im Kopf
   ist in §21 verworfen.

   Der Weg steht in Prozent der Buehne (60 % -> 32 %). Nachgemessen auf 320
   bis 1600 px liegt die Kuppe an beiden Enden 23–50 px innerhalb des
   vorderen Displays, auch waehrend es mitgezogen wird — sie laeuft also
   immer ueber das dunkle EggClipse-Display, in beiden Paletten, und die
   Farben stehen fest hell. Mit 64 % setzte sie auf 390 px halb auf dem
   schwarzen Rahmen auf.

   Das Markup baut app.js, ohne Skript gibt es keinen Hinweis. Die Zeiten
   dort (WISCH_MS, ZIEHEN_AB, LOSLASSEN, FEDERN_MS) gehoeren zu den Keyframes
   hier: 2,6 s, Zug von 18 % bis 52 %, Abheben ab 58 %.

   Die Telefone gehen ueber die EIGENE translate-Eigenschaft mit, nicht ueber
   transform: Das transform gehoert dem Platz und steht in zwei Fassungen da
   (Telefon und ab 761px). Ueber translate legt sich der Zug davor und kommt
   ohne eine zweite Wertetabelle aus — Prozente beziehen sich dabei auf die
   Telefonbreite, er skaliert also mit. Die Mitte laeuft weiter als die
   Aussenseiten: Bei einer echten Drehung legt sie auch den weitesten Weg
   zurueck, und die Staffelung liest sich als drehender Ring. */
.app-hero-stage.wird-gezogen .app-phone {
  transition: translate 0.88s cubic-bezier(0.45, 0, 0.3, 1);
  translate: -16% 0;
}
.app-hero-stage.wird-gezogen .app-phone[data-slot="c"] { translate: -26% 0; }

/* Zurueckfedern mit leichtem Ueberschwingen. transform und opacity stehen
   mit drin, damit eine Drehung waehrenddessen ihren Uebergang behaelt. */
.app-hero-stage.federt .app-phone {
  transition: transform 0.55s cubic-bezier(0.22, 0.72, 0.24, 1),
              translate 0.7s cubic-bezier(0.34, 1.5, 0.64, 1),
              opacity 0.55s cubic-bezier(0.22, 0.72, 0.24, 1);
}

.app-wisch {
  --wisch-kuppe: clamp(2.5rem, 7vw, 3.5rem);
  --wisch-von: 60%;
  --wisch-bis: 32%;
  --wisch-hoehe: 40%;
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

/* Jede Drehung und das Vergroessern beenden ihn sofort (app.js). */
.app-wisch.aus {
  opacity: 0;
}

.app-wisch > span {
  position: absolute;
  top: var(--wisch-hoehe);
  opacity: 0;
}

.app-wisch-kuppe,
.app-wisch-ring {
  left: var(--wisch-von);
  width: var(--wisch-kuppe);
  height: var(--wisch-kuppe);
  margin: calc(var(--wisch-kuppe) / -2) 0 0 calc(var(--wisch-kuppe) / -2);
  border-radius: 50%;
}

/* Klares Glas: leichter Schleier, Glanzlicht oben links, Rand und Lila-Glow
   tragen die Form. Ohne Weichzeichner — mit ihm wurde die Kuppe je nach
   Fuellung eine graue Mattscheibe oder eine dunkle Murmel (Standbilder
   2026-09-16). So bleibt das Display darunter lesbar, und der Kopf der
   Lichtspur leuchtet in der Mitte. */
.app-wisch-kuppe {
  border: 2px solid rgba(236, 226, 255, 0.95);
  background:
    radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.75) 0, rgba(255, 255, 255, 0.2) 14%, rgba(255, 255, 255, 0) 30%),
    radial-gradient(circle at 50% 50%, rgba(236, 226, 255, 0.14) 50%, rgba(196, 162, 255, 0.3) 100%);
  box-shadow: 0 0 0 1px rgba(196, 162, 255, 0.35), 0 0 22px 2px rgba(196, 162, 255, 0.7), inset 0 0 12px rgba(196, 162, 255, 0.4), 0 6px 18px rgba(8, 3, 22, 0.4);
}

/* Druckring: bleibt am Aufsetzpunkt, waehrend die Kuppe losfaehrt */
.app-wisch-ring {
  border: 2px solid rgba(236, 226, 255, 0.85);
  box-shadow: 0 0 14px rgba(196, 162, 255, 0.7);
}

/* Lichtspur: rechts am Aufsetzpunkt verankert, waechst mit derselben Kurve
   wie der Weg der Kuppe — ihr linkes Ende sitzt so immer unter dem Finger.
   Ein Kometenschweif: heller Kern in einer Lila-Huelle, per `screen` auf das
   dunkle Display gelegt, und die Maske laesst ihn zum Aufsetzpunkt hin
   auslaufen. Die erste Fassung (ein einfacher Verlauf von 60 % nach 0)
   war auf dem Display nicht zu sehen: Ihr heller Anfang lag unter der Kuppe,
   der Rest hatte 25–40 % Deckkraft (gemessen 2026-09-16). */
.app-wisch-spur {
  left: var(--wisch-bis);
  width: calc(var(--wisch-von) - var(--wisch-bis));
  height: calc(var(--wisch-kuppe) * 0.62);
  margin-top: calc(var(--wisch-kuppe) * -0.31);
  border-radius: 999px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0) 22%, rgba(255, 255, 255, 0.85) 50%, rgba(255, 255, 255, 0) 78%),
    rgba(196, 162, 255, 0.6);
  -webkit-mask-image: linear-gradient(90deg, #000 0, #000 30%, rgba(0, 0, 0, 0.45) 70%, transparent 100%);
  mask-image: linear-gradient(90deg, #000 0, #000 30%, rgba(0, 0, 0, 0.45) 70%, transparent 100%);
  mix-blend-mode: screen;
  filter: blur(2.5px);
  transform-origin: 100% 50%;
  transform: scaleX(0);
}

.app-wisch.spielt .app-wisch-kuppe { animation: app-wisch-kuppe 2.6s both; }
.app-wisch.spielt .app-wisch-ring { animation: app-wisch-ring 2.6s ease-out both; }
.app-wisch.spielt .app-wisch-spur { animation: app-wisch-spur 2.6s both; }

@keyframes app-wisch-kuppe {
  0% { left: var(--wisch-von); opacity: 0; transform: scale(1.35); }
  12% { left: var(--wisch-von); opacity: 1; transform: scale(1); }
  18% { left: var(--wisch-von); opacity: 1; transform: scale(0.92); animation-timing-function: cubic-bezier(0.45, 0, 0.3, 1); }
  52%, 58% { left: var(--wisch-bis); opacity: 1; transform: scale(0.92); }
  74%, 100% { left: var(--wisch-bis); opacity: 0; transform: scale(1.3); }
}

@keyframes app-wisch-ring {
  0%, 11% { opacity: 0; transform: scale(0.8); }
  13% { opacity: 0.9; transform: scale(1); }
  34%, 100% { opacity: 0; transform: scale(2.2); }
}

@keyframes app-wisch-spur {
  0%, 18% { opacity: 1; transform: scaleX(0); animation-timing-function: cubic-bezier(0.45, 0, 0.3, 1); }
  52% { opacity: 1; transform: scaleX(1); }
  74%, 100% { opacity: 0; transform: scaleX(1); }
}

@media (prefers-reduced-motion: reduce) {
  .app-wisch { display: none; }
}

/* Der Wisch funktioniert auf dem Finger NUR mit dieser Zeile (2026-09-10).
   Ohne sie darf der Browser die Beruehrung jederzeit als Seitenschwenk an sich
   ziehen — und tut es: Auf Android kam nach dem pointerdown sofort ein
   pointercancel, der Wisch war tot, bevor er gemessen werden konnte. Mit der
   Maus fiel das nie auf, weil es dort keine Gestenerkennung gibt; die Messung
   in §21 lief ueber Maus-Ereignisse und ging deshalb gruen durch.

   pan-y laesst das senkrechte Scrollen der Seite unangetastet (nachgemessen:
   die Seite scrollt weiter genauso), pinch-zoom bleibt ausdruecklich erlaubt —
   niemandem soll auf der Buehne der Zoom abgeschaltet werden. Verboten ist
   allein der waagerechte Schwenk, und den gibt es hier ohnehin nicht.

   Sie haengt an .ist-karussell, weil sie nur gilt, solange das Skript die
   Buehne bedient — ohne JavaScript nimmt die Seite dem Finger nichts weg.

   Bedienbarkeit nur, wenn app.js die Buehne uebernommen hat — ohne Skript soll
   kein Zeiger etwas versprechen, was nicht passiert. Das mittlere Telefon steht
   schon vorn und tut nichts. */
.app-hero-stage.ist-karussell {
  touch-action: pan-y pinch-zoom;
}
.app-hero-stage.ist-karussell .app-phone {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
/* Sonst startet der Zeiger auf dem Display den nativen Bild-Zug (Desktop) und
   der Wisch bricht mittendrin ab. */
.app-hero-stage.ist-karussell .app-phone img {
  -webkit-user-drag: none;
  user-select: none;
}
.app-hero-stage.ist-karussell .app-phone[data-slot="c"] { cursor: default; }
.app-hero-stage.ist-karussell .app-phone:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 6px;
}

/* Die Buehne stand bis zum 2026-09-10 bewusst still (§10). Bewegung gibt es
   jetzt als ANTWORT auf eine Geste — und dazu den Wisch-Hinweis oben
   (Glasfinger, §37, hoechstens zweimal), der dort endet, wo er angefangen hat. Kein Autoplay, kein Dauerloop, kein
   Einschweben. */
@media (prefers-reduced-motion: reduce) {
  .app-phone { transition: none; }
}

/* ---------- Buehnenkante: Linie in Primaerfarbe, das lila Ei in der Mitte ----------
   Der Uebergang von der Telefon-Buehne zum Video (Mockup vom 2026-09-06 abends,
   docs/hero-konzept.md §10). Der Kasten liegt exakt ueber den unteren
   --app-stage-edge-depth der Buehne; das SVG streckt eine Halbellipse
   (viewBox 1000x40, preserveAspectRatio none) auf Kastenbreite — dieselbe Form
   wie der border-radius der Buehne, darum trifft der Strich die Schnittkante
   bei jeder Breite. Der Strich selbst skaliert nicht mit
   (vector-effect: non-scaling-stroke). Die Hell-Palette faerbt Linie und Glow
   gold.

   In der Mitte hing bis zum 2026-09-07 das lila Ei der App (das Favicon-Motiv),
   zur Haelfte unter der Linie und mit ruhigem Puls. Andreas hat es wieder
   herausgenommen: Die Kante fuehrt jetzt allein, ohne Blickfang in der Mitte.
   Die Bilder dazu liegen weiter unter assets/img/egg-mark*. */
.app-page {
  --app-stage-edge-depth: 2.5rem;
  --app-stage-edge-glow: rgba(196, 162, 255, 0.55);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-page {
    --app-stage-edge-glow: rgba(138, 90, 24, 0.40);
  }
}

:root[data-theme="light"] .app-page {
  --app-stage-edge-glow: rgba(138, 90, 24, 0.40);
}

.app-stage-edge {
  position: relative;
  z-index: 4;
  width: 100%;
  max-width: 62.5rem;
  height: var(--app-stage-edge-depth);
  margin: calc(-1 * var(--app-stage-edge-depth)) auto 0;
  pointer-events: none;
}

/* Die zweite Kante unter dem Video hing vom 2026-09-07 bis zum 2026-09-08
   frei (.app-stage-edge-frei, eigener Abstand statt des negativen). Seit dem
   2026-09-08 sitzt sie mit demselben negativen Abstand auf der Video-Buehne
   (.app-szene-stage) — zwei Objekte auf zwei Buehnen, dieselbe Kante. */

.app-stage-edge-line {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  /* Statt hart an den Raendern abzubrechen, laeuft die Kante an beiden Enden
     aus. Auf schmalen Geraeten liegt ihr Ende sonst genau auf der Seitenkante
     und sieht abgeschnitten aus; die Maske nimmt Strich UND Glow gemeinsam
     zurueck, weil sie auf dem SVG sitzt und nicht auf einem einzelnen Pfad. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 13%, #000 87%, transparent 100%);
}

.app-stage-edge-glow {
  fill: none;
  stroke: var(--app-stage-edge-glow);
  stroke-width: 7;
  stroke-linecap: round;
  filter: blur(5px);
}

.app-stage-edge-stroke {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
}


/* Die Buehne steht still — bewusst, in zwei Schritten (Andreas, 2026-09-06
   abends). Zuerst waren hier zwei Bewegungen: ein Lichtpunkt lief alle 7 s ueber
   die Kante (dritter SVG-Pfad mit wanderndem Dash), und die drei Telefone
   schwebten ein paar Pixel in eigenem Takt (`translate` je Telefon). Beide sind
   auf seine Ansage wieder entfernt. Was der Kante Feinschliff gibt, ist jetzt
   rein statisch: die Maske an .app-stage-edge-line. Die einzige verbliebene
   Bewegung im Kopf ist der ruhige Puls des Eis (app-stage-egg-glow), der von
   der ersten Runde stehen geblieben ist. Nichts davon ohne Auftrag
   zurueckholen.

   Seit dem 2026-09-10 gilt das mit einer Grenze: Die Buehne bewegt sich, wenn
   der Besucher sie bewegt (Karussell, oben in diesem Abschnitt). Von selbst
   passiert genau eines — der Wisch-Hinweis (Glasfinger, §37; hoechstens zwei
   Durchgaenge), der zeigt, DASS sie sich bewegen laesst, und im Ruhestand
   endet. Kein Autoplay, kein Dauerloop, kein
   Lichtpunkt. */

/* Der Vermerk rueckt erst ab 900px neben die Knoepfe: Auf 768px (Tablet hoch)
   lief die franzoesische Fassung („Ensemble, au fil du cycle") rechts aus dem
   Bild — gemessen am 2026-09-06, rund 80px Ueberlauf, vom overflow-clip der
   Seite abgeschnitten. Die Buehne behaelt ihren 761px-Block darunter. */
@media (min-width: 900px) {
  .app-hero-note {
    position: absolute;
    left: calc(100% + 4rem);
    /* unterhalb der Untertitel-Zeile ansetzen — bei einzeiligem Untertitel (EN)
       ragt er sonst in die Zeile hinein */
    top: 0.35rem;
    max-width: none;
    margin: 0;
    padding: 0;
    font-size: 1.95rem;
    text-align: right;
    white-space: nowrap;
    transform: rotate(-12deg);
  }
  /* Der Pfeil haengt frei unter dem Vermerk, nicht an ihm: Bis zum 2026-09-06
     abends setzte er dicht unter „behalten" an und las sich wie eine vierte
     Zeile (Andreas). Seit dem 2026-09-08 zeigt er wie die schmale Fassung auf
     ein Telefon, nicht mehr auf die Knoepfe: Er begann UNTER den Knoepfen und
     endete 20–32 px ueber der Ecke des rechten Telefons — weder das eine noch
     das andere (gemessen in allen vier Sprachen bei 900/1100/1280/1600).
     Jetzt 3rem weiter rechts und 1.4rem tiefer; die Spitze liegt damit
     2–14 px ueber der Oberkante des rechten Telefons, rund 90 px von dessen
     linker Ecke. Der Vermerk selbst bleibt, wo er ist — nach rechts verschoben
     liefe EN/FR bei 900 px aus dem Bild. */
  .app-hero-note .app-arrow {
    display: block;
    position: absolute;
    left: -0.9rem;
    right: auto;
    top: 7.5rem;
    bottom: auto;
    width: 5.8rem;
    height: 4.55rem;
  }
}

@media (min-width: 761px) {
  .app-hero-stage {
    aspect-ratio: auto;
    height: clamp(15rem, 36vw, 25rem);
    max-height: none;
    margin-top: 2.5rem;
  }
  .app-phone {
    width: clamp(14.4rem, 29vw, 18.75rem);
  }
  .app-phone[data-slot="l"] { transform: translateX(-50%) translateX(-84%) translateY(11%) rotate(-7deg); }
  .app-phone[data-slot="r"] { transform: translateX(-50%) translateX(84%) translateY(11%) rotate(7deg); }
}

/* ---------- Vollbild-Ansicht der Buehne (2026-09-10, Andreas; §22) ----------
   „Auf der egg-tracker-website in dem Screenshot-Karussell soll es zudem
   moeglich sein, einen Screenshot zu vergroessern." Das vordere Telefon oeffnet
   die Ansicht, die aeusseren drehen weiter wie bisher (app.js).

   Sie ist KEINE generische Lightbox: Dasselbe Telefon steht auf demselben
   Bodenlicht wie auf der Buehne (--app-hero-floor, --app-phone-frame,
   --app-shadow-phone), nur gross und ohne Nachbarn. Der Grund ist derselbe wie
   gegen die Karussell-Punkte in §21 — die Seite hat eine eigene Formensprache,
   und ein schwarzer Kasten mit weissem Kreuz gehoert nicht dazu.

   Das Markup baut app.js beim ersten Oeffnen und haengt es an <body>: Ohne
   JavaScript gibt es die Ansicht nicht (progressive enhancement wie der Rest
   der Seite), und in .app-page haenge koennte sie nicht — dort steht
   `overflow-x: clip`, das ein `position: fixed` darin beschneiden darf. Die
   Telefon-Tokens gelten deshalb oben ausdruecklich auch fuer .app-zoom. */
.app-zoom {
  position: fixed;
  inset: 0;
  z-index: 300; /* ueber der Kopfzeile (100) und dem Skip-Link (200) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: clamp(0.5rem, 2vh, 1.25rem) clamp(0.75rem, 3vw, 2rem);
  background: var(--app-zoom-veil);
  -webkit-backdrop-filter: blur(18px) saturate(115%);
  backdrop-filter: blur(18px) saturate(115%);
  overscroll-behavior: contain;
  /* Wischen dreht weiter (app.js) — waagerechte Schwenks des Browsers wuerden
     die Geste sonst abfangen, genau wie auf der Buehne (§21). */
  touch-action: pan-y pinch-zoom;
}

/* Das Bodenlicht der Buehne, hier hinter dem grossen Telefon. Als eigene
   Ebene statt als zweiter background-Layer: --app-hero-floor ist selbst ein
   Verlauf und braucht eine Flaeche, auf der er sitzt. */
.app-zoom::before {
  content: "";
  position: absolute;
  inset: auto 0 -8% 0;
  height: 62%;
  background: var(--app-hero-floor);
  pointer-events: none;
}

/* Breite und Rand haengen an EINER Zahl. Das muss so, weil ein Prozent-Padding
   sich auf die BREITE DES ELTERNTEILS bezieht, nicht auf die eigene: Mit
   `padding: 2.8%` wie auf der Buehne bekam das grosse Telefon auf 1440px einen
   38 px dicken Rahmen (2,8 % von 1376) statt der 10 px, die zur Zeichnung
   gehoeren — gemessen am 2026-09-10. Ueber die Variable rechnet der Rand mit
   der Telefonbreite.

   Kein aspect-ratio: Die Hoehe kommt aus dem Bild selbst (778x1748) plus dem
   Rand. Ein 9/19-Kasten wie auf der Buehne ist etwas flacher als das Display
   und liesse unten einen schwarzen Streifen stehen — auf der Buehne faellt das
   bei 141 px Breite nicht auf, in der Vollbild-Ansicht sofort.

   Der Abzug von 6.5rem deckt Polster, Abstand und Bildunterschrift (bis zu drei
   Zeilen auf 320px); 2.177 ist die Hoehe eines Telefons in Telefonbreiten
   (1748/778 auf 94,4 % der Breite, plus zweimal Rand). */
.app-zoom-phone {
  position: relative;
  --zoom-breite: min(88vw, (100svh - 6.5rem) / 2.177, 30rem);
  width: var(--zoom-breite);
  background: var(--app-phone-frame);
  border-radius: 14% / 6.6%;
  padding: calc(var(--zoom-breite) * 0.028);
  box-shadow: var(--app-shadow-phone), inset 0 0 0 1.5px var(--app-phone-rim);
}

.app-zoom-phone .app-phone-glass {
  position: relative;
  width: 100%;
  height: auto;
}

.app-zoom-phone img {
  display: block;
  width: 100%;
  height: auto;
  -webkit-user-drag: none;
  user-select: none;
}

/* Die Bildunterschrift ist der alt-Text des Displays — er steht je Sprache
   schon im Markup, die Ansicht braucht dafuer keine neue Textstelle. */
.app-zoom-caption {
  position: relative;
  margin: 0;
  max-width: 28rem;
  text-align: center;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--text-muted);
}

.app-zoom-close {
  position: absolute;
  top: clamp(0.5rem, 2vw, 1.25rem);
  right: clamp(0.5rem, 2vw, 1.25rem);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--accent-40);
  background: var(--card);
  color: var(--text-strong);
  cursor: pointer;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

.app-zoom-close svg {
  width: 18px;
  height: 18px;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  fill: none;
}

.app-zoom-close:hover { border-color: var(--accent); }
.app-zoom-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Der Aufschlag: kurzes Aufziehen aus der Buehne heraus. Er antwortet auf die
   Geste, ist also keine Bewegung von selbst (§10/§21). */
@media (prefers-reduced-motion: no-preference) {
  .app-zoom { animation: app-zoom-auf 0.22s ease-out; }
  .app-zoom-phone { animation: app-zoom-phone-auf 0.28s cubic-bezier(0.22, 0.72, 0.24, 1); }
}

@keyframes app-zoom-auf {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes app-zoom-phone-auf {
  from { transform: scale(0.88); }
  to { transform: none; }
}

/* Das vordere Telefon vergroessert; die aeusseren drehen (Zeiger aus §21). */
.app-hero-stage.ist-karussell .app-phone[data-slot="c"] { cursor: zoom-in; }

/* Solange die Ansicht offen ist, scrollt die Seite dahinter nicht mit. */
html.app-zoom-offen,
html.app-zoom-offen body { overflow: hidden; }


/* ---------- Ribbon-Ansicht: Muster erkennen (2026-09-14, Andreas) ----------
   Der USP gegenueber dem Monatskalender, als Karte in der Bauform der beiden
   Karten darunter (Chip, Ueberschrift mit farbigem Teil, Kurzzeile, Bild mit
   Handschriften darueber und darunter) und so breit wie ihr Zweispalter — die drei
   Karten lesen sich als eine Reihe von Vorteilen. Ersetzt die SVG-Karte
   "Zyklusband" vom 2026-09-13; Konzept docs/hero-konzept.md §31.

   Die Grafik ist ein Querformat (1540 x 736) mit kleiner Schrift. In voller
   Kartenbreite (58.5rem) ist sie lesbar, auf dem Telefon waere sie es nicht
   (288 px, Ziffern um 5 px). Deshalb ist sie dort ein WISCHSTREIFEN: 48rem
   breit (Massstab ~0,5, Ziffern um 10 px), bis an die Kartenkanten gezogen,
   mit zwei Rastpunkten (Kalender, Ribbon), einer Wischpille und einem
   einmaligen Anstupsen aus app.js. Ab 700px steht sie in voller Breite.

   Farben: Das Bild ist in beiden Paletten dunkel (wie das mittlere Telefon
   der Buehne, das immer EggClipse zeigt). Die Pille liegt auf dem Bild und
   ist deshalb in beiden Paletten gleich; Periodenrosa und Lichtpunkt folgen
   der Grafik. Paletten-Tokens dreimal notiert wie das Gold. */

.app-card-ribbon {
  max-width: 62.5rem;
  /* derselbe Innenabstand wie .app-card — der Wischstreifen zieht sich um
     genau diesen Wert an die Kartenkanten */
  --app-ribbon-pad: clamp(1.25rem, 4.5vw, 2rem);
  /* Telefon: Raum des Streifens unter dem Bild — Schatten und die beiden
     Vermerke. Wischpille und Knopf stehen um genau diesen Wert hoeher. */
  --app-ribbon-unten: 4rem;
  --app-ribbon-periode: #ff6fae;
  --app-ribbon-periode-soft: rgba(255, 111, 174, 0.14);
  --app-ribbon-periode-glow: 0 0 18px rgba(255, 111, 174, 0.35);
  --app-ribbon-pille-bg: rgba(12, 5, 26, 0.74);
  --app-ribbon-pille-fg: #f3eeff;
  --app-ribbon-pille-rand: rgba(196, 162, 255, 0.45);
  --app-ribbon-schatten: drop-shadow(0 14px 22px rgba(8, 3, 22, 0.55));
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-card-ribbon {
    --app-ribbon-periode: #b3306b;
    --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
    --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
    --app-ribbon-schatten: drop-shadow(0 14px 22px rgba(60, 40, 20, 0.32));
  }
}

:root[data-theme="light"] .app-card-ribbon {
  --app-ribbon-periode: #b3306b;
  --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
  --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
  --app-ribbon-schatten: drop-shadow(0 14px 22px rgba(60, 40, 20, 0.32));
}

/* Kopfzeile: die Kurzzeile allein. Die Handschriften stehen seit dem
   2026-09-14 als Paar in der Notizenzeile darunter (.app-ribbon-notizen). */
.app-ribbon-kopf {
  --app-ribbon-luft: clamp(1.1rem, 3.5vw, 1.5rem);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  column-gap: 1.2rem;
  row-gap: calc(var(--app-ribbon-luft) - 0.35rem);
  margin: 0 0 var(--app-ribbon-luft);
}

.app-ribbon-kopf .app-card-lead {
  flex: 1 1 16rem;
  /* Breit genug, dass die beiden Definitionen auf dem Desktop in EINER Zeile
     stehen (FR ist die laengste); die Ueberleitung beginnt immer auf einer
     eigenen Zeile. Die fruehere Grenze 36rem stammte aus der Zeit, als die
     Handschrift daneben stand, und brach mitten in der Definition um. */
  max-width: 54rem;
  align-self: flex-start;
  margin: 0;
  text-wrap: pretty;
}

.app-ribbon-ueberleitung {
  display: block;
}

/* Zwei Handschriften als Paar ueber der Grafik (Andreas, 2026-09-14): links
   "Kalendertag 13, 9, 12, …???", rechts "Zyklustag 13? Schon wieder!" —
   beide in der Primaerfarbe wie jede Handschrift der Seite (Andreas: "nicht
   bunt"; Koralle und Gold bleiben der Grafik vorbehalten). Beide
   Pfeile zeigen nach unten links in ihre Haelfte: links Richtung
   Januar-Ring (6 % der Bildbreite), rechts auf die Sprechblase ueber der
   Ribbon-Linie (82 %). Die Zeile ist so breit wie die Grafik, der linke
   Innenabstand setzt die Kalender-Notiz ueber die Kalenderhaelfte. */
.app-ribbon-notizen {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-end;
  gap: 0.9rem 1.5rem;
  margin: 0 0 clamp(1.5rem, 4vw, 2rem);
  /* Links kein Einzug der Zeile: Den traegt die Kalender-Notiz selbst (Platz
     fuer ihren Pfeil), so hat die Zyklus-Notiz auf dem Telefon die volle Breite. */
  padding-inline: 0 clamp(0.5rem, 5vw, 3.5rem);
}

.app-ribbon-notiz {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  max-width: 100%;
  margin: 0;
  padding-right: 0.2rem;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.4rem, 4.6vw, 1.7rem);
  font-weight: 600;
  line-height: 0.95;
  color: var(--accent);
  transform: rotate(-5deg);
}

.app-ribbon-notiz-kalender {
  margin-left: 3.3rem;
  transform: rotate(-3deg);
}

.app-ribbon-notiz-zyklus {
  margin-left: auto;
}

.app-ribbon-notiz .app-arrow {
  position: absolute;
  right: 100%;
  bottom: -2.1rem;
  width: clamp(2.6rem, 8vw, 3.4rem);
  height: auto;
  aspect-ratio: 90 / 70;
  margin-right: -0.35rem;
}

/* Ab 700px: Kalender-Notiz ueber der Kalenderhaelfte (Pfeil landet nahe dem
   Januar-Ring), Zyklus-Notiz ueber der Ribbon-Linie. */
@media (min-width: 700px) {
  .app-ribbon-notizen {
    padding-left: 11%;
  }
  .app-ribbon-notiz-kalender {
    margin-left: 0;
  }
}

/* Telefon: Die Grafik ist ein Wischstreifen, zu Beginn ist nur der Kalender
   im Bild. Der Pfeil der Zyklus-Notiz zeigt deshalb nach unten RECHTS — dorthin,
   wo die Ribbon-Haelfte liegt, zugleich ein Hinweis zum Wischen. */
@media (max-width: 699px) {
  /* Reihenfolge getauscht: oben die Zyklus-Notiz (Pfeil nach rechts unten),
     darunter die Kalender-Notiz - so zeigt ihr Pfeil ungehindert in den
     Kalender, statt zwischen den beiden Notizen zu landen. */
  .app-ribbon-notiz-zyklus {
    order: -1;
    margin-right: 3.2rem;
  }
  .app-ribbon-notiz-zyklus .app-arrow {
    right: auto;
    left: 100%;
    margin-right: 0;
    margin-left: -0.35rem;
    transform: scaleX(-1);
  }
}

/* ---------- Symbol „Nochmal abspielen" (2026-09-15, Andreas, §36) ----------
   Ein rundes Glas-Symbol unten rechts an Takt, Ribbon-Grafik und
   Partner-Szene (die Style-Grafik bewusst ohne, §36) statt der Pille „Nochmal abspielen" — in der
   Formensprache des Dreh-Hinweises „Quer halten!" (Glas, heller Rand,
   Lila-Leuchten). Auf der Ribbon-Grafik fest in beiden Paletten
   wie der Dreh-Hinweis — der rauchige Grund haelt es auf hellen und dunklen
   Bildstellen lesbar; auf der Karte (Takt, Partner) in der hellen Palette
   helles Glas mit der Akzentfarbe (Tokens --app-nochmal-*). Ein echter <button> mit aria-label und title je Sprache. app.js
   blendet es ein — ohne JavaScript und bei „Bewegung reduzieren" bleibt es
   verborgen, dann gibt es nichts abzuspielen. Beim Antippen dreht sich der
   Pfeil einmal (.dreht). Klick oder Tipp auf die Grafik selbst spielt
   ebenfalls ab. */
.app-nochmal {
  --app-nochmal-rand: rgba(236, 226, 255, 0.7);
  --app-nochmal-rand-aktiv: rgba(236, 226, 255, 0.95);
  --app-nochmal-grund: linear-gradient(150deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.05) 45%, rgba(196, 162, 255, 0.12)), rgba(14, 6, 30, 0.34);
  --app-nochmal-schein: 0 0 0 1px rgba(196, 162, 255, 0.28), 0 0 18px rgba(196, 162, 255, 0.45), inset 0 0 10px rgba(255, 255, 255, 0.12);
  --app-nochmal-schein-aktiv: 0 0 0 1px rgba(196, 162, 255, 0.4), 0 0 26px rgba(196, 162, 255, 0.65), inset 0 0 10px rgba(255, 255, 255, 0.16);
  --app-nochmal-farbe: rgba(236, 226, 255, 0.95);
  --app-nochmal-leuchten: drop-shadow(0 0 4px rgba(196, 162, 255, 0.7));
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin: 0;
  padding: 0;
  border: 1.5px solid var(--app-nochmal-rand);
  border-radius: 50%;
  background: var(--app-nochmal-grund);
  -webkit-backdrop-filter: blur(3px) saturate(1.3);
  backdrop-filter: blur(3px) saturate(1.3);
  box-shadow: var(--app-nochmal-schein);
  color: var(--app-nochmal-farbe);
  cursor: pointer;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
}

.app-nochmal[hidden] {
  display: none;
}

.app-nochmal svg {
  width: 1.2rem;
  height: 1.2rem;
  filter: var(--app-nochmal-leuchten);
}

.app-nochmal:hover {
  border-color: var(--app-nochmal-rand-aktiv);
  box-shadow: var(--app-nochmal-schein-aktiv);
}

.app-nochmal:active {
  transform: scale(0.94);
}

.app-nochmal:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Der Pfeil dreht sich einmal gegen den Uhrzeigersinn — in seine Richtung. */
.app-nochmal.dreht svg {
  animation: app-nochmal-dreh 0.6s cubic-bezier(0.3, 0.7, 0.3, 1);
}

@keyframes app-nochmal-dreh {
  from { transform: rotate(0deg); }
  to { transform: rotate(-360deg); }
}

/* Takt und Partner: unten rechts in der Karte, unter der Grafik. Die Karte
   ist der Bezug (.app-card > * setzt sonst position: relative); die Grafiken
   selbst sind role="img" und duerfen keinen Knopf enthalten. */
.app-card > .app-nochmal {
  position: absolute;
  right: clamp(1.25rem, 4.5vw, 2rem);
  bottom: clamp(1.25rem, 4.5vw, 2rem);
  z-index: 3;
}

/* Takt: in der Luecke unter dem Feld, rechts neben der haengenden
   Handschrift. */
.app-card-einfach > .app-nochmal {
  bottom: 1rem;
}

/* Helle Palette, nur auf der Karte (Takt, Partner): Das rauchige Lila war
   auf Pergament zu blass (gesehen 2026-09-15). Dort helles Glas mit der
   Akzentfarbe; auf den Grafiken bleibt es fest. Zweimal notiert wie jedes
   Token (Systemwahl, ausdrueckliche Wahl). */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-card > .app-nochmal {
    --app-nochmal-rand: var(--accent-40);
    --app-nochmal-rand-aktiv: var(--accent);
    --app-nochmal-grund: linear-gradient(150deg, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.45) 45%, rgba(138, 90, 24, 0.08)), rgba(255, 252, 245, 0.35);
    --app-nochmal-schein: 0 0 0 1px rgba(138, 90, 24, 0.12), 0 8px 20px -10px rgba(70, 52, 25, 0.45), inset 0 0 10px rgba(255, 255, 255, 0.7);
    --app-nochmal-schein-aktiv: 0 0 0 1px rgba(138, 90, 24, 0.22), 0 10px 24px -10px rgba(70, 52, 25, 0.55), inset 0 0 10px rgba(255, 255, 255, 0.8);
    --app-nochmal-farbe: var(--accent);
    --app-nochmal-leuchten: none;
  }
}

:root[data-theme="light"] .app-card > .app-nochmal {
  --app-nochmal-rand: var(--accent-40);
  --app-nochmal-rand-aktiv: var(--accent);
  --app-nochmal-grund: linear-gradient(150deg, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.45) 45%, rgba(138, 90, 24, 0.08)), rgba(255, 252, 245, 0.35);
  --app-nochmal-schein: 0 0 0 1px rgba(138, 90, 24, 0.12), 0 8px 20px -10px rgba(70, 52, 25, 0.45), inset 0 0 10px rgba(255, 255, 255, 0.7);
  --app-nochmal-schein-aktiv: 0 0 0 1px rgba(138, 90, 24, 0.22), 0 10px 24px -10px rgba(70, 52, 25, 0.55), inset 0 0 10px rgba(255, 255, 255, 0.8);
  --app-nochmal-farbe: var(--accent);
  --app-nochmal-leuchten: none;
}

/* Ribbon: dort, wo bis zum 2026-09-15 die Pille stand. Ab 700px unten rechts
   auf der Grafik, auf dem Telefon an der Stelle der Pille „Wischen", sobald
   gewischt wurde. Nach einem automatischen Durchgang pulsieren zweimal Ringe
   um das Symbol (.lockt), bis jemand selbst abgespielt hat. */
.app-ribbon-abspielen {
  position: absolute;
  z-index: 3;
  right: calc(var(--app-ribbon-pad) + 0.6rem);
  bottom: calc(var(--app-ribbon-unten) + 0.7rem);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
}

.ist-gewischt .app-ribbon-abspielen {
  opacity: 1;
  pointer-events: auto;
}

.app-ribbon-abspielen.lockt {
  animation: app-ribbon-lockt 1.1s ease-out 2;
}

@keyframes app-ribbon-lockt {
  0% { box-shadow: 0 0 0 0 rgba(255, 214, 120, 0.75); }
  100% { box-shadow: 0 0 0 16px rgba(255, 214, 120, 0); }
}

@media (min-width: 700px) {
  /* Ab 700px waechst das Symbol mit der Grafik (Groesse und Abstand in cqw
     der Buehne, 35 bis 44 px): In fester Groesse verdeckte die Pille auf
     768 px die Legende „Symptom". Die erste Zeile je Eigenschaft ist der
     Rueckfall fuer Browser ohne Container-Einheiten. */
  .app-ribbon-buehne {
    container-type: inline-size;
  }
  .app-ribbon-abspielen {
    right: 1.1rem;
    right: 1.2cqw;
    bottom: 1.1rem;
    bottom: 2cqw;
    width: 2.75rem;
    width: clamp(2.2rem, 4.7cqw, 2.75rem);
    height: 2.75rem;
    height: clamp(2.2rem, 4.7cqw, 2.75rem);
    opacity: 1;
    pointer-events: auto;
  }
  .app-ribbon-abspielen svg {
    width: clamp(0.95rem, 2.3cqw, 1.2rem);
    height: clamp(0.95rem, 2.3cqw, 1.2rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .app-ribbon-abspielen.lockt {
    animation: none;
  }
}

/* ---------- Die Grafik ---------- */

/* Seit dem 2026-09-14 schliesst die Grafik die Karte (die drei Vorteile
   darunter sind raus). Den Raum ihrer Vermerke haelt auf dem Telefon der
   Streifen, ab 700px der untere Abstand (siehe dort). */
.app-ribbon-figure {
  position: relative;
  margin: 0;
}

/* Buehnenlicht hinter dem Bild — dieselbe Idee wie das Bodenlicht unter
   Telefonen und Video, nur als ruhiger Kranz. */
.app-ribbon-figure::before {
  content: '';
  position: absolute;
  inset: 6% 4% 10%;
  background: radial-gradient(60% 60% at 50% 50%, var(--accent-22), transparent 72%);
  filter: blur(22px);
  pointer-events: none;
}

.app-ribbon-buehne {
  position: relative;
  /* Telefon: bis an die Kartenkanten. Unten zieht der negative Abstand den
     Teil des Streifenraums (siehe dort), den die Vermerke nicht brauchen,
     wieder aus dem Layout. */
  margin-inline: calc(var(--app-ribbon-pad) * -1);
  margin-bottom: -0.4rem;
}

/* Der Streifen ist ein Raster, kein Block: Nur so zaehlt der Innenabstand am
   Ende mit zur Scrollbreite, und das Bild endet nicht an der Kartenkante.
   Oben und unten fasst der Innenabstand den Schatten des Bilds — ein
   Scrollbereich schneidet alles ab, was ueber ihn hinausragt, und in der
   hellen Palette stand der Schatten sonst als grauer Balken mit harter Kante
   ueber der Kartenbreite (gemessen 2026-09-14). Unten traegt er ausserdem
   die beiden Vermerke unter der Grafik (--app-ribbon-unten). */
.app-ribbon-strip {
  position: relative;
  display: grid;
  grid-auto-flow: column;
  justify-content: start;
  padding: 0.6rem var(--app-ribbon-pad) var(--app-ribbon-unten);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--app-ribbon-pad);
  scrollbar-width: none;
}

.app-ribbon-strip::-webkit-scrollbar {
  display: none;
}

.app-ribbon-strip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
  border-radius: 0.75rem;
}

/* Container fuer die Vermerke: Ihre Pfeile und ihre Schrift wachsen in cqw
   mit der Grafik (Telefon 48rem, darueber die Kartenbreite). */
.app-ribbon-leinwand {
  position: relative;
  width: 48rem;
  container-type: inline-size;
}

.app-ribbon-leinwand img {
  display: block;
  width: 100%;
  height: auto;
  filter: var(--app-ribbon-schatten);
}

/* Rastpunkte: Anfang (Kalender) und Beginn der Ribbon-Haelfte der Grafik. */
.app-ribbon-snap {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  scroll-snap-align: start;
}

.app-ribbon-snap-band {
  left: 29.6%;
}

/* Wischpille: liegt auf dem Bild (also immer auf dunklem Grund) und geht,
   sobald jemand wischt (.ist-gewischt aus app.js). Ohne JavaScript bleibt
   sie stehen — der Streifen laesst sich trotzdem wischen. */
.app-ribbon-wischen {
  position: absolute;
  right: calc(var(--app-ribbon-pad) + 0.6rem);
  bottom: calc(var(--app-ribbon-unten) + 0.85rem);
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  margin: 0;
  padding: 0.3rem 0.45rem 0.3rem 0.8rem;
  border: 1px solid var(--app-ribbon-pille-rand);
  border-radius: 999px;
  background: var(--app-ribbon-pille-bg);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: var(--app-ribbon-pille-fg);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  pointer-events: none;
  transition: opacity 0.35s ease;
}

.app-ribbon-wischen svg {
  width: 1rem;
  height: 1rem;
  animation: app-ribbon-wisch 1.6s ease-in-out infinite;
}

@keyframes app-ribbon-wisch {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(3px); }
}

.ist-gewischt .app-ribbon-wischen {
  opacity: 0;
}

/* Hinweis zum Querhalten (2026-09-15, Andreas): Quer gehalten ist ein
   Telefon breiter als 700 px, und dann steht die ganze Grafik in voller
   Breite da, so gut lesbar wie im Streifen (docs/hero-konzept.md §31). Im
   Hochformat nennt die Pille deshalb beide Wege, mit Dreh-Symbol; im
   Querformat unter 700 px (sehr kleine Telefone) bleibt es beim Wischen.
   Die laengere Pille reicht nach links bis unter den Maerz-Ring (Tag 13 bei
   12,1 | 85,1 % der Grafik) und steht deshalb tiefer als die kurze. */
.app-ribbon-wischen .app-ribbon-drehen-icon,
.app-ribbon-wischen-quer {
  display: none;
}

.app-ribbon-wischen .app-ribbon-drehen-icon {
  width: 1.05rem;
  height: 1.05rem;
  margin-right: 0.15rem;
  animation: none;
}

@media (orientation: portrait) {
  .app-ribbon-wischen {
    bottom: calc(var(--app-ribbon-unten) + 0.35rem);
    padding-left: 0.6rem;
  }
  .app-ribbon-wischen .app-ribbon-drehen-icon,
  .app-ribbon-wischen-quer {
    display: block;
  }
  .app-ribbon-wischen-nur {
    display: none;
  }
}

/* Dreh-Hinweis ueber der Grafik (2026-09-15, Andreas: "ein transparentes
   Smartphone, das sich ins Querformat dreht"). Ersetzt auf dem Telefon im
   Hochformat die Pille, sobald app.js ihn freischaltet (.hat-dreh an der
   figure; nicht bei "Bewegung reduzieren"). Spielt einmal, wenn der Streifen
   ins Bild kommt: Das Glas-Telefon blendet ein, der Bogen zeichnet die
   Richtung, das Telefon kippt mit leichtem Ueberschwingen quer, ein
   Lichtreflex streicht darueber, dann blendet alles aus; danach stupst der
   Streifen an. Jede Beruehrung beendet ihn sofort (.aus). Ohne JavaScript
   bleibt die Pille. Farben fest hell: Er liegt immer auf der dunklen Grafik. */
.app-ribbon-dreh {
  display: none;
}

@media (max-width: 699px) and (orientation: portrait) {
  .hat-dreh .app-ribbon-wischen {
    display: none;
  }
  .hat-dreh .app-ribbon-dreh {
    display: block;
    position: absolute;
    inset: 0.6rem 0 var(--app-ribbon-unten);
    z-index: 2;
    pointer-events: none;
    transition: opacity 0.25s ease;
  }
}

.app-ribbon-dreh.aus {
  opacity: 0;
}

/* Schleier hinter dem Telefon: hebt es vom unruhigen Kalender ab */
.app-ribbon-dreh::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(closest-side, rgba(8, 3, 22, 0.66), rgba(8, 3, 22, 0));
  opacity: 0;
}

.app-ribbon-dreh-telefon {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 4.6rem;
  height: 8.4rem;
  margin: -4.2rem 0 0 -2.3rem;
  border: 2px solid rgba(236, 226, 255, 0.92);
  border-radius: 1.05rem;
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.05) 45%, rgba(196, 162, 255, 0.12));
  -webkit-backdrop-filter: blur(3px) saturate(1.3);
  backdrop-filter: blur(3px) saturate(1.3);
  box-shadow: 0 0 0 1px rgba(196, 162, 255, 0.28), 0 0 28px rgba(196, 162, 255, 0.55), inset 0 0 16px rgba(255, 255, 255, 0.14);
  overflow: hidden;
  opacity: 0;
}

/* Lautsprecher */
.app-ribbon-dreh-telefon::before {
  content: '';
  position: absolute;
  top: 0.45rem;
  left: 50%;
  width: 1.3rem;
  height: 0.26rem;
  margin-left: -0.65rem;
  border-radius: 999px;
  background: rgba(236, 226, 255, 0.75);
}

/* Lichtreflex, der nach dem Kippen einmal ueber das Glas streicht */
.app-ribbon-dreh-telefon::after {
  content: '';
  position: absolute;
  inset: -30%;
  background: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, 0.4) 50%, transparent 58%);
  transform: translateX(-75%);
}

.app-ribbon-dreh-bogen {
  position: absolute;
  left: 50%;
  top: 46%;
  width: 12rem;
  height: 12rem;
  margin: -6rem 0 0 -6rem;
  overflow: visible;
  color: rgba(236, 226, 255, 0.95);
  filter: drop-shadow(0 0 6px rgba(196, 162, 255, 0.7));
}

.app-ribbon-dreh-bahn {
  stroke-dasharray: 80;
  stroke-dashoffset: 80;
}

.app-ribbon-dreh-spitze {
  opacity: 0;
}

.app-ribbon-dreh-text {
  position: absolute;
  left: 50%;
  top: calc(46% + 5.4rem);
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: 1.7rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  color: #ece2ff;
  text-shadow: 0 0 10px rgba(8, 3, 22, 0.95), 0 0 18px rgba(8, 3, 22, 0.8);
  transform: translateX(-50%) rotate(-4deg);
  opacity: 0;
}

.app-ribbon-dreh.spielt::before {
  animation: app-dreh-schleier 4.4s ease both;
}

.app-ribbon-dreh.spielt .app-ribbon-dreh-telefon {
  animation: app-dreh-telefon 4.4s both;
}

.app-ribbon-dreh.spielt .app-ribbon-dreh-telefon::after {
  animation: app-dreh-reflex 4.4s ease both;
}

.app-ribbon-dreh.spielt .app-ribbon-dreh-bahn {
  animation: app-dreh-bahn 4.4s both;
}

.app-ribbon-dreh.spielt .app-ribbon-dreh-spitze {
  animation: app-dreh-spitze 4.4s both;
}

.app-ribbon-dreh.spielt .app-ribbon-dreh-text {
  animation: app-dreh-text 4.4s ease both;
}

@keyframes app-dreh-schleier {
  0% { opacity: 0; }
  8%, 84% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes app-dreh-telefon {
  0% { opacity: 0; transform: scale(0.8) rotate(0deg); animation-timing-function: cubic-bezier(0.2, 0.8, 0.3, 1); }
  9% { opacity: 1; transform: scale(1) rotate(0deg); }
  30% { transform: scale(1) rotate(0deg); animation-timing-function: cubic-bezier(0.6, 0, 0.3, 1); }
  48% { transform: scale(1) rotate(97deg); animation-timing-function: ease-out; }
  55% { transform: scale(1) rotate(90deg); }
  84% { opacity: 1; transform: scale(1) rotate(90deg); animation-timing-function: ease-in; }
  100% { opacity: 0; transform: scale(0.94) rotate(90deg); }
}

@keyframes app-dreh-reflex {
  0%, 55% { transform: translateX(-75%); }
  76%, 100% { transform: translateX(75%); }
}

@keyframes app-dreh-bahn {
  0%, 10% { stroke-dashoffset: 80; opacity: 1; animation-timing-function: ease-in-out; }
  28%, 48% { stroke-dashoffset: 0; opacity: 1; }
  58%, 100% { stroke-dashoffset: 0; opacity: 0; }
}

@keyframes app-dreh-spitze {
  0%, 25% { opacity: 0; }
  29%, 48% { opacity: 1; }
  58%, 100% { opacity: 0; }
}

@keyframes app-dreh-text {
  0%, 6% { opacity: 0; transform: translateX(-50%) translateY(0.3rem) rotate(-4deg); }
  16%, 84% { opacity: 1; transform: translateX(-50%) translateY(0) rotate(-4deg); }
  100% { opacity: 0; transform: translateX(-50%) translateY(0) rotate(-4deg); }
}

/* Lichtpunkt: laeuft beim Einblenden der Karte einmal die gestrichelte Linie
   der Grafik hinunter und haelt kurz auf jedem der drei Tage 13 — genau dort,
   wo die Aussage sitzt. Lage in Prozent der Grafik (Linie bei 81,6 % der
   Breite, Tage 13 bei 29,4 / 53,7 / 77,9 % der Hoehe - die korrigierten
   Grafiken, seit dem 2026-09-14 in allen vier Sprachen); die Grafiken sind
   deckungsgleich. */
.app-ribbon-puls {
  position: absolute;
  left: 81.6%;
  top: 20%;
  width: 4.6%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255, 236, 170, 0.95) 0%, rgba(255, 200, 90, 0.55) 32%, transparent 70%);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
}

/* Abgespielt wird er ueber .spielt, die app.js setzt: einmal, wenn die Grafik
   ins Bild kommt, auf dem Telefon noch einmal, sobald man zur Ribbon-Haelfte
   wischt (dort liegt die Linie beim Laden ausserhalb des Streifens), und bei
   jedem Klick auf die Grafik (Andreas, 2026-09-14). Ohne JavaScript bleibt
   der Punkt aus — die Grafik sagt dasselbe ohne ihn. */
.app-ribbon-puls.spielt {
  animation: app-ribbon-puls 2.4s cubic-bezier(0.45, 0, 0.3, 1) 0.1s 1 both;
}

body:not(.no-js) .app-ribbon-leinwand {
  cursor: pointer;
}

/* Suchpunkt im Kalender (Variante A, Andreas 2026-09-14): Bevor der goldene
   Punkt die Ribbon-Linie ruhig hinuntergleitet, springt ein korallroter Punkt
   den Zickzack der Kalenderseite ab — 13. Januar, 9. Februar, 12. Maerz. Links
   wird gesucht, rechts gefunden. Nur wo die Grafik den Zickzack traegt: Die
   figure bekommt dafuer .app-ribbon-mit-suche (seit 2026-09-14 nur DE; EN/ES/FR
   folgen mit ihren korrigierten Grafiken). Lage in Prozent der Bildflaeche:
   Ringe bei 6,1|31,1 — 24,2|54,8 — 12,1|85,1. Wer die Grafik austauscht,
   prueft sie. */
.app-ribbon-suche {
  position: absolute;
  left: 6.1%;
  top: 31.1%;
  width: 3.8%;
  aspect-ratio: 1;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255, 214, 206, 0.95) 0%, rgba(255, 110, 100, 0.6) 34%, transparent 70%);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
}

.app-ribbon-suche.spielt {
  animation: app-ribbon-suche 1.9s ease-in-out 0.1s 1 both;
}

/* Mit Suchpunkt startet der goldene Punkt erst, wenn die Suche vorbei ist —
   ausser nach dem Wischen auf dem Telefon (.sofort), dann ist nur er im Bild. */
.app-ribbon-mit-suche .app-ribbon-puls.spielt {
  animation-delay: 2.05s;
}

.app-ribbon-mit-suche .app-ribbon-puls.spielt.sofort {
  animation-delay: 0.1s;
}

@keyframes app-ribbon-suche {
  0% { left: 6.1%; top: 31.1%; opacity: 0; }
  10% { opacity: 1; }
  24% { left: 6.1%; top: 31.1%; }
  48% { left: 24.2%; top: 54.8%; }
  60% { left: 24.2%; top: 54.8%; }
  84% { left: 12.1%; top: 85.1%; }
  92% { left: 12.1%; top: 85.1%; opacity: 1; }
  100% { left: 12.1%; top: 85.1%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .app-ribbon-suche {
    display: none;
  }
}

/* Die beiden Begriffe in der Kurzzeile (Andreas, 2026-09-14): fett und
   beide in der Primaerfarbe - "nicht bunt". Koralle und Gold bleiben der
   Grafik vorbehalten. */
.app-ribbon-begriff {
  font-weight: 700;
  white-space: nowrap;
  color: var(--accent);
}

@keyframes app-ribbon-puls {
  0% { top: 20%; opacity: 0; }
  12% { opacity: 1; }
  30% { top: 29.4%; }
  36% { top: 29.4%; }
  60% { top: 53.7%; }
  66% { top: 53.7%; }
  90% { top: 77.9%; opacity: 1; }
  100% { top: 77.9%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .app-ribbon-puls {
    display: none;
  }
  .app-ribbon-wischen svg {
    animation: none;
  }
}

/* Ab 700px: volle Breite, kein Streifen. Den Raum der Vermerke haelt der
   untere Abstand der figure. Prozent im margin sind Prozent der
   Kartenbreite, und die ist hier die Breite der Grafik: Der Raum waechst mit
   ihr wie die Vermerke selbst. */
@media (min-width: 700px) {
  .app-ribbon-figure {
    margin-bottom: 7.5%;
  }
  .app-ribbon-buehne {
    margin: 0;
  }
  .app-ribbon-strip {
    display: block;
    padding: 0;
    overflow: visible;
  }
  .app-ribbon-leinwand {
    width: auto;
  }
  .app-ribbon-snap,
  .app-ribbon-wischen {
    display: none;
  }
}

/* ---------- Zwei Vermerke unter der Grafik (Andreas, 2026-09-14) ----------
   Ersetzen die drei Vorteils-Kacheln: „Tag 1 steht immer vorn" mit Pfeil auf
   die 1 von Zyklus 3, „Wiederholungen fallen auf" unter der Spalte der Tage
   13. Handschrift in der Primaerfarbe wie die beiden Notizen ueber der Grafik.

   Sie liegen IN der Leinwand, damit sie auf dem Telefon mit dem
   Wischstreifen mitwandern, und sind wie Licht- und Suchpunkt in Prozent der
   Bildflaeche verankert: left/right und top sind die Pfeilspitze. Pfeil und
   Schrift wachsen in cqw der Leinwand mit, die Komposition skaliert als
   Ganzes. Die Box sitzt mit einer oberen Ecke auf der Spitze, Pfeil und
   Schrift haengen darunter, und die Drehung um genau diese Ecke laesst die
   Spitze stehen.

   Jeder Pfeil beschreibt sich in Vielfachen seiner Breite P (aus der
   viewBox): --app-vermerk-spitze-x/-y = Abstand der Spitze von der Seite der
   SVG, an der die Schrift NICHT steht, und von oben; --app-vermerk-schwanz-x/-y
   = Weg von der Spitze zum Schwanz. Daraus folgen Lage der SVG und
   Innenabstand der Schrift.

   Der Pfeil liegt zum groessten Teil auf der immer dunklen Grafik; der
   Lichthof in Seitenfarbe traegt ihn dort auch in der hellen Palette. */
.app-ribbon-vermerk {
  position: absolute;
  display: block;
  width: max-content;
  padding: calc(var(--app-vermerk-p) * var(--app-vermerk-schwanz-y) - 0.3em) calc(var(--app-vermerk-p) * var(--app-vermerk-schwanz-x) + 0.2em) 0 0;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: 1.4rem;
  font-size: clamp(1.2rem, 2.9cqw, 1.7rem);
  font-weight: 600;
  line-height: 0.95;
  text-align: right;
  color: var(--accent);
  transform: rotate(-4deg);
  transform-origin: 100% 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}

.app-ribbon-vermerk-pfeil {
  position: absolute;
  top: calc(var(--app-vermerk-p) * var(--app-vermerk-spitze-y) * -1);
  right: calc(var(--app-vermerk-p) * var(--app-vermerk-spitze-x) * -1);
  width: var(--app-vermerk-p);
  height: auto;
  overflow: visible;
  filter: drop-shadow(0 0 1.2px var(--bg)) drop-shadow(0 0 1.2px var(--bg));
}

/* „Tag 1 steht immer vorn": Pfeil 80 x 90, Spitze (70|8), Schwanz (8|84) —
   ein weiter Bogen von links unten, die Schrift steht unter dem Kalender.
   Spitze an der unteren linken Ecke der Kachel 1 von Zyklus 3 (32,4 | 82,5). */
.app-ribbon-vermerk-eins {
  --app-vermerk-p: 9.7cqw;
  --app-vermerk-spitze-x: 0.125;
  --app-vermerk-spitze-y: 0.1;
  --app-vermerk-schwanz-x: 0.775;
  --app-vermerk-schwanz-y: 0.95;
  right: 67.6%;
  top: 82.5%;
}

.app-ribbon-vermerk-eins .app-ribbon-vermerk-pfeil {
  aspect-ratio: 80 / 90;
}

/* „Wiederholungen fallen auf": ohne Pfeil, mittig unter der Spalte der
   Tage 13 (81,6 %, wie die gestrichelte Linie). Ein Pfeil in diese Spalte
   fand keinen Weg: Unten in der Grafik liegen die Legende „Symptom" (bis
   76,4 %) und der Knopf „Nochmal abspielen", der auf Deutsch ab etwa 77 %
   beginnt. Auf dem Telefon am Ende des Streifens blieb zwischen beiden keine
   Gasse (gemessen 2026-09-14: Pfeil 16 px im Knopf, auf 768 px 7 px). */
.app-ribbon-vermerk-wiederholung {
  left: 81.6%;
  top: 101%;
  padding: 0;
  text-align: center;
  transform: translateX(-50%) rotate(-4deg);
  transform-origin: 50% 0;
}

/* Browser ohne Container-Einheiten: Mass des Telefon-Streifens (48rem). */
@supports not (width: 1cqw) {
  .app-ribbon-vermerk-eins {
    --app-vermerk-p: 4.65rem;
  }
}

/* Telefon: Zu Beginn zeigt der Streifen den Kalender, und die Wischpille
   liegt je nach Breite irgendwo zwischen 24 und 80 % der Bildbreite — genau
   in der Zone, durch die jeder Pfeil von unten ins Bild muss. Die Vermerke
   kommen deshalb erst mit dem ersten Wischen (.ist-gewischt, wie der Knopf
   „Nochmal abspielen"), und „Tag 1" steht rechts von seiner Kachel: Nach
   dem Wischen zur Ribbon-Haelfte ist genau dieser Teil im Bild, der Kalender
   nicht mehr. Der Pfeil ist dafuer gespiegelt, die Spitze sitzt unter der
   Kachel (34,7 | 84). Ohne JavaScript stehen beide von Anfang an. */
@media (max-width: 699px) {
  body:not(.no-js) .app-ribbon-figure:not(.ist-gewischt) .app-ribbon-vermerk {
    opacity: 0;
  }
  .app-ribbon-vermerk-eins {
    right: auto;
    left: 34.7%;
    top: 84%;
    padding: calc(var(--app-vermerk-p) * var(--app-vermerk-schwanz-y) - 0.3em) 0 0 calc(var(--app-vermerk-p) * var(--app-vermerk-schwanz-x) + 0.2em);
    text-align: left;
    transform-origin: 0 0;
  }
  .app-ribbon-vermerk-eins .app-ribbon-vermerk-pfeil {
    right: auto;
    left: calc(var(--app-vermerk-p) * var(--app-vermerk-spitze-x) * -1);
    transform: scaleX(-1);
  }
}

/* ---------- Kacheln in der Bildsprache der Grafik ----------
   Tag 1 als Periodenkachel. Seit die Vorteile raus sind (2026-09-14), nutzen
   sie nur noch der Takt der Karte „Ein Eintrag pro Monat reicht.". Ihre
   Farben (--app-ribbon-periode) sind dort ein zweites Mal notiert. */
.app-ribbon-kachel {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 1.5px solid var(--accent-40);
  border-radius: 0.75rem;
  background: var(--accent-12);
  color: var(--accent);
  font-size: 1.1rem;
  font-weight: 800;
  line-height: 1;
}

.app-ribbon-kachel-start {
  border-color: var(--app-ribbon-periode);
  background: var(--app-ribbon-periode-soft);
  color: var(--app-ribbon-periode);
  box-shadow: var(--app-ribbon-periode-glow);
}

/* ---------- Style-Karte: „Nicht nur in Pink" (2026-09-14, Andreas) ----------
   Unter dem Seitenkopf, vor der Ribbon-Karte. Eine Aussage, eine Grafik:
   derselbe Bildschirm der App in vier diagonalen Streifen, einer je Theme.
   Einer davon ist pink, das ist die Pointe der Ueberschrift.
   Der Takt (28 Tage: jeden Tag gegen einmal) war bis zum 2026-09-15 die
   zweite Aussage dieser Karte und ist in die eigene Karte direkt darunter
   umgezogen — seine Regeln stehen dort (app-einfach-takt-*).
   Konzept und Messungen: docs/hero-konzept.md §32 (erste Fassung mit Faecher),
   §33 (zweite Runde: Streifen, Zwischenueberschrift, ohne Vorteile) und §34
   (Umzug des Takts).

   Das Rosa ist dasselbe Periodenrosa wie auf der Ribbon-Karte
   (--app-ribbon-periode), hier als --app-style-pink dreimal notiert wie
   jedes Token. */

.app-card-style {
  max-width: 62.5rem;
  --app-style-pink: #ff6fae;
  --app-style-pink-soft: rgba(255, 111, 174, 0.12);
  --app-style-pink-border: rgba(255, 111, 174, 0.45);
  --app-style-rand: rgba(255, 255, 255, 0.16);
  --app-style-schatten: 0 22px 36px -16px rgba(0, 0, 0, 0.7);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-card-style {
    --app-style-pink: #b3306b;
    --app-style-pink-soft: rgba(179, 48, 107, 0.09);
    --app-style-pink-border: rgba(179, 48, 107, 0.42);
    --app-style-rand: rgba(92, 70, 40, 0.28);
    --app-style-schatten: 0 22px 36px -18px rgba(60, 40, 20, 0.45);
  }
}

:root[data-theme="light"] .app-card-style {
  --app-style-pink: #b3306b;
  --app-style-pink-soft: rgba(179, 48, 107, 0.09);
  --app-style-pink-border: rgba(179, 48, 107, 0.42);
  --app-style-rand: rgba(92, 70, 40, 0.28);
  --app-style-schatten: 0 22px 36px -18px rgba(60, 40, 20, 0.45);
}

.app-card-style > .app-card-lead {
  max-width: 54rem;
  text-wrap: pretty;
}

/* ---------- Vier Streifen, ein Bildschirm ----------
   Zweite Runde (Andreas, 2026-09-14): Der Faecher aus vier gedrehten Kacheln
   wirkte „komisch". Jetzt ist es EIN Bildschirm, diagonal in vier Streifen
   geteilt — das uebliche Bild, um Themes oder Hell/Dunkel zu zeigen. Die
   vier Bilder sind deckungsgleich (theme-faecher.mjs richtet sie an der
   ersten Tageskarte aus), deshalb laufen Datum, „Zyklus 1" und Kartenreihe
   ueber die Naehte weiter, und nur die Farbe wechselt.

   Jede Ebene reicht von ihrer linken Naht bis zum rechten Rand und liegt
   ueber der vorigen. Sichtbar bleibt so von jeder genau ihr Streifen, und
   beim Einblenden schieben sich die drei hinteren wie Vorhaenge von rechts
   herein, ohne dass je eine Luecke entsteht. Naehte bei 29|21, 54|46 und
   79|71 % (oben|unten). Auf dem Telefon ist es dieselbe Grafik — kein
   eigener Umbau, das war die Schwachstelle des Faechers.

   Verworfen nach Prototyp (Screenshots 1280/360): Kartenhand (drei der vier
   Themes nur als Randstreifen, auf dem Telefon verdeckte Namen) und eine
   gerade Reihe bzw. 2x2 (sauber, aber sagt nicht „dieselbe App"). */
.app-style-figur {
  position: relative;
  /* width: 100 %, weil die Karte eine Flex-Spalte ist: Mit auto-Rand allein
     schrumpfte die Figur auf die Breite der Handschrift (gemessen: 178 px). */
  width: 100%;
  max-width: 44rem;
  /* Unten der Platz fuer die Namenspillen, die zur Haelfte unter der Grafik
     haengen — seit dem Umzug des Takts (2026-09-15) ist die Figur das letzte
     Kind der Karte; mit 0,4–0,8 rem standen die Pillen 23 px vor der Kante. */
  margin: 0 auto clamp(0.9rem, 2.5vw, 1.2rem);
}

/* Buehnenlicht hinter der Grafik, wie hinter der Ribbon-Grafik. */
.app-style-figur::before {
  content: '';
  position: absolute;
  inset: 14% 2% 4%;
  background: radial-gradient(60% 60% at 50% 50%, var(--accent-22), transparent 72%);
  filter: blur(22px);
  pointer-events: none;
}

.app-style-streifen {
  position: relative;
  aspect-ratio: 412 / 248;
  overflow: hidden;
  border: 1px solid var(--app-style-rand);
  border-radius: clamp(0.9rem, 2.6vw, 1.25rem);
  background: #14092a;
  box-shadow: var(--app-style-schatten);
}

/* Tempo (Andreas, 2026-09-14): etwas langsamer als die erste Fassung
   (0,9 s je Streifen, 0,2 s Abstand) — jetzt 1,4 s und 0,3 s. */
.app-style-theme {
  position: absolute;
  inset: 0;
  transition: clip-path 1.4s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.app-style-theme img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}

.app-style-theme:nth-child(2) {
  clip-path: polygon(29% 0, 100% 0, 100% 100%, 21% 100%);
  transition-delay: 0.4s;
}

.app-style-theme:nth-child(3) {
  clip-path: polygon(54% 0, 100% 0, 100% 100%, 46% 100%);
  transition-delay: 0.7s;
}

.app-style-theme:nth-child(4) {
  clip-path: polygon(79% 0, 100% 0, 100% 100%, 71% 100%);
  transition-delay: 1s;
}

.app-style-naehte {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55));
  transition: opacity 0.5s ease 2.2s;
}

.app-style-naehte line {
  stroke: rgba(255, 255, 255, 0.9);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

/* Vor dem Einblenden (.in aus dem Scroll-Reveal der Sektion) liegen die drei
   hinteren Ebenen rechts ausserhalb, zu sehen ist nur EggClipse. Nur mit
   JavaScript und nur, wenn Bewegung erlaubt ist — sonst steht die Grafik
   sofort fertig da.
   Ein Klick auf die Grafik spielt das Einschieben noch einmal ab (Andreas,
   2026-09-14): app.js setzt kurz .von-vorn, das die Ebenen ohne Uebergang
   zuruecklegt, und nimmt es nach einem Reflow wieder ab. Bewusst ohne Knopf
   — nur der Zeiger zeigt es an (.abspielbar setzt app.js nur, wo es etwas
   abzuspielen gibt). Das Glas-Symbol der anderen Grafiken (§36) stand hier
   am 2026-09-15 kurz und ist wieder raus: Auf dem Telefon verdeckte es zu
   viel von der kompakten Grafik (Andreas).
   .laedt haelt das Einschieben zurueck, bis alle vier Bilder dekodiert sind
   (app.js, hoechstens 4 s) — sonst glitt nach einem Refresh eine leere Ebene
   herein und Rose Sunset sprang am Ende fertig ins Bild. */
@media (prefers-reduced-motion: no-preference) {
  body:not(.no-js) .reveal:not(.in) .app-style-theme:nth-child(n + 2),
  .app-style-streifen.laedt .app-style-theme:nth-child(n + 2),
  .app-style-streifen.von-vorn .app-style-theme:nth-child(n + 2) {
    clip-path: polygon(108% 0, 108% 0, 108% 100%, 100% 100%);
    transition: none;
  }
  body:not(.no-js) .reveal:not(.in) .app-style-naehte,
  .app-style-streifen.laedt .app-style-naehte,
  .app-style-streifen.von-vorn .app-style-naehte {
    opacity: 0;
    transition: none;
  }
  .app-style-streifen.abspielbar {
    cursor: pointer;
  }
}

@media (prefers-reduced-motion: reduce) {
  .app-style-theme,
  .app-style-naehte {
    transition: none;
  }
}

/* Namen der Themes (Andreas: „ins jeweilige Theme rutschen"): je eine Pille
   in den Farben ihres Themes, mittig unter ihrem Streifen und halb in ihn
   hineingeschoben. Die Farben stehen fest — sie zeigen das Theme der App,
   nicht die Palette der Seite. Mitten der Streifen an der Unterkante:
   10,5 | 33,5 | 58,5 | 85,5 %. Die Tonzeile der ersten Fassung („Dunkel ·
   Lila") ist raus: Die Farbe sagt sie selbst, und auf dem Telefon passten
   die Namen sonst nicht unter ihre Streifen. */
.app-style-namen {
  position: relative;
  height: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.app-style-name {
  position: absolute;
  top: 0;
  z-index: 1;
  display: inline-flex;
  padding: 0.28rem 0.75rem;
  border: 1px solid;
  border-radius: 999px;
  font-size: clamp(0.6rem, 1.9vw, 0.78rem);
  font-weight: 800;
  letter-spacing: 0.02em;
  line-height: 1.2;
  white-space: nowrap;
  transform: translate(-50%, -55%);
}

.app-style-name-eggclipse {
  left: 10.5%;
  border-color: rgba(165, 162, 249, 0.6);
  background: #140a2e;
  color: #cfc9ff;
  box-shadow: 0 0 14px rgba(139, 92, 246, 0.5);
}

.app-style-name-eggsposure {
  left: 33.5%;
  border-color: #c9a25a;
  background: #fbf4e4;
  color: #6f4712;
  box-shadow: 0 4px 12px -4px rgba(70, 52, 25, 0.5);
}

.app-style-name-beer {
  left: 58.5%;
  border-color: #e8b54a;
  background: linear-gradient(#3d2609, #1c1105);
  color: #f4cd72;
  box-shadow: 0 0 14px rgba(232, 181, 74, 0.35);
}

.app-style-name-rose {
  left: 85.5%;
  border-color: #eea0bd;
  background: #fde7ee;
  color: #b3306b;
  box-shadow: 0 4px 12px -4px rgba(179, 48, 107, 0.5);
}

/* Telefon: kleiner und die ersten beiden Namen etwas auseinander — auf 360 px
   beruehrten sich EggClipse und EggSposure (gemessen 2026-09-14). 35,5 % liegt
   noch im zweiten Streifen (unten 21–46 %). */
@media (max-width: 699px) {
  .app-style-name {
    padding: 0.2rem 0.45rem;
    font-size: 0.56rem;
  }
  .app-style-name-eggclipse {
    left: 11%;
  }
  .app-style-name-eggsposure {
    left: 35.5%;
  }
}

/* ---------- Handschriften ----------
   Dieselbe Caveat wie ueberall auf der Seite, in der Primaerfarbe. */
.app-style-notiz {
  position: relative;
  z-index: 2;
  margin: 0;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.4rem, 4.6vw, 1.7rem);
  font-weight: 600;
  line-height: 0.95;
  color: var(--accent);
}

.app-style-notiz .app-arrow {
  position: absolute;
  width: clamp(2.6rem, 8vw, 3.4rem);
  height: auto;
  aspect-ratio: 90 / 70;
}

/* „Pink gibt’s auch." steht ueber der Grafik rechts, der Pfeil zeigt nach
   rechts unten in den pinken Streifen, neben dessen Menueknopf (Andreas:
   „sollte tatsaechlich auf das Pinke zeigen" — in der ersten Fassung landete
   er zwischen Beer und Rosé). Dieselbe Mechanik wie die Zyklus-Notiz der
   Ribbon-Karte auf dem Telefon: Der rechte Abstand ist der Platz fuer den
   Pfeil plus 6 % der Grafikbreite (Prozent im margin = Breite der Figur). Die
   Spitze landet damit bei rund 90–93 % der Breite auf dem Menueknopf des
   pinken Streifens, der oben bei 79 % beginnt. Ohne die 6 % traf sie auf dem
   Desktop die rechte obere Ecke der Grafik (gemessen 2026-09-14).
   Die Notiz steht 1 rem ueber der Grafik (Andreas: „etwas nach oben
   absetzen", vorher 0,35 rem). Den Abstand ueberbrueckt ein laengerer Pfeil:
   Er beginnt an der Unterkante der Notiz (translateY um die eigene Hoehe)
   und ist so breit wie --app-style-pfeil, das auch den rechten Abstand
   bestimmt — Groesse und Lage haengen damit an einer Zahl. */
.app-style-notiz-pink {
  --app-style-pfeil: clamp(3.4rem, 9vw, 4.2rem);
  width: fit-content;
  max-width: calc(100% - 4rem);
  margin: 0 calc(var(--app-style-pfeil) - 0.1rem + 6%) 1rem auto;
  text-align: right;
  transform: rotate(-4deg);
}

.app-style-notiz-pink .app-arrow {
  left: 100%;
  bottom: 0;
  width: var(--app-style-pfeil);
  margin-left: -0.3rem;
  /* + 0,1 rem: Die Drehung der Notiz hebt die rechte Seite an, sonst ragte
     die Spitze auf dem Telefon nur 5 px in die Grafik (gemessen). */
  transform: translateY(calc(100% + 0.1rem)) scaleX(-1);
}

/* ---------- Karte „Ein Eintrag pro Monat reicht." (2026-09-15, Andreas) ----------
   Direkt hinter der Style-Karte, bewusst kurz: Chip, Ueberschrift, eine
   Zeile und der Takt — 28 Tage im Vergleich, oben fragt ein typischer Tracker
   jeden Tag, unten traegt man bei Egg-Tracker nur Tag 1 ein. Bis zum
   2026-09-15 die zweite Haelfte der Style-Karte (§32/§33), als eigene Karte
   herausgezogen; die Takt-Regeln sind dieselben, nur umbenannt
   (app-style-takt → app-einfach-takt). Eine Fassung mit zweiter Aussage
   (Partner-Chat) war zu lang; sie steht in der Git-Historie (Commit
   5364c99). Die Partner-Karte ist seither eine eigene Szene.
   Konzept: docs/hero-konzept.md §34/§35.

   Das Rosa ist das Periodenrosa der Ribbon-Karte, hier als --app-einfach-pink
   dreimal notiert wie jedes Token. --app-ribbon-periode braucht die Kachel „1"
   — in der Style-Karte war es nie gesetzt, die Kachel stand dort bis zum Umzug
   ohne Rosa, mit Textfarbe und leerem Grund. */
.app-card-einfach {
  max-width: 62.5rem;
  --app-einfach-pink: #ff6fae;
  --app-einfach-pink-soft: rgba(255, 111, 174, 0.12);
  --app-einfach-pink-border: rgba(255, 111, 174, 0.45);
  --app-ribbon-periode: #ff6fae;
  --app-ribbon-periode-soft: rgba(255, 111, 174, 0.14);
  --app-ribbon-periode-glow: 0 0 18px rgba(255, 111, 174, 0.35);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-card-einfach {
    --app-einfach-pink: #b3306b;
    --app-einfach-pink-soft: rgba(179, 48, 107, 0.09);
    --app-einfach-pink-border: rgba(179, 48, 107, 0.42);
    --app-ribbon-periode: #b3306b;
    --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
    --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
  }
}

:root[data-theme="light"] .app-card-einfach {
  --app-einfach-pink: #b3306b;
  --app-einfach-pink-soft: rgba(179, 48, 107, 0.09);
  --app-einfach-pink-border: rgba(179, 48, 107, 0.42);
  --app-ribbon-periode: #b3306b;
  --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
  --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
}

.app-card-einfach > .app-card-lead {
  max-width: 54rem;
  text-wrap: pretty;
}

/* Die Handschrift unter der Kachel „1": dieselbe Caveat wie ueberall. */
.app-einfach-notiz {
  position: relative;
  z-index: 2;
  margin: 0;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.4rem, 4.6vw, 1.7rem);
  font-weight: 600;
  line-height: 0.95;
  color: var(--accent);
}

.app-einfach-notiz .app-arrow {
  position: absolute;
  width: clamp(2.6rem, 8vw, 3.4rem);
  height: auto;
  aspect-ratio: 90 / 70;
}

/* ---------- Der Takt: jeden Tag gegen einmal ----------
   Zwei Zeilen: wer fragt, was gefragt wird, 28 Tage, wie oft. Die Tage sind
   kein Markup, sondern ein sich wiederholender Verlauf (28 Kacheln je Zeile,
   ein Kreis je Kachel) — 224 Spans in vier Sprachen waeren fuer Punkte zu
   viel. Oben alle voll in Rosa, unten die Periodenkachel „1" der Ribbon-Karte
   und 27 leere Ringe. Der Kreisdurchmesser haengt an der Breite des Takts
   (Container-Einheiten), damit 28 Kacheln auch auf 288 px Platz haben.

   Unten reserviert der Aussenabstand den Platz fuer die Handschrift, die an
   der Kachel „1" haengt (siehe dort) — auf dem Telefon zweizeilig. */
.app-einfach-takt {
  container-type: inline-size;
  display: grid;
  gap: 0.75rem;
  /* Unten der Platz fuer die haengende Handschrift (zweizeilig auf dem
     Telefon); die Haarlinie der naechsten Zwischenueberschrift folgt direkt. */
  margin: 0 0 3.4rem;
  padding: 0.9rem 1rem 1rem;
  border: 1px solid var(--panel-border);
  border-radius: 1rem;
  background: var(--panel);
}

.app-einfach-takt-zeile {
  --app-takt-punkt: clamp(0.5rem, 2.7cqw, 0.95rem);
  --app-takt-farbe: var(--app-einfach-pink);
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    "wer zahl"
    "frage frage"
    "tage tage";
  align-items: center;
  gap: 0.45rem 0.75rem;
}

.app-einfach-takt-egg {
  --app-takt-farbe: var(--accent);
}

.app-einfach-takt-wer {
  grid-area: wer;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.app-einfach-takt-egg .app-einfach-takt-wer {
  color: var(--accent);
}

.app-einfach-takt-frage {
  grid-area: frage;
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 100%;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--app-einfach-pink-border);
  border-radius: 999px 999px 999px 0.35rem;
  background: var(--app-einfach-pink-soft);
  color: var(--text);
  font-size: clamp(0.82rem, 2.6vw, 0.92rem);
  font-weight: 600;
  line-height: 1.3;
}

.app-einfach-takt-egg .app-einfach-takt-frage {
  border-color: var(--accent-40);
  background: var(--accent-12);
  font-weight: 700;
}

.app-einfach-takt-frage svg {
  flex: none;
  height: 1.1rem;
  width: auto;
  color: var(--app-takt-farbe);
}

.app-einfach-takt-tage {
  grid-area: tage;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
}

/* Die 28 (bzw. 27) Tage: ein Streifen mit sich wiederholendem Verlauf.
   `circle closest-side` haelt den Kreis in der Kachel, auch wenn sie
   schmaler ist als hoch. */
.app-einfach-takt-punkte {
  flex: 1 1 auto;
  min-width: 0;
  height: var(--app-takt-punkt);
  --app-takt-n: 28;
  background-image: radial-gradient(circle closest-side at center, var(--app-takt-farbe) 0 78%, transparent 84%);
  background-size: calc(100% / var(--app-takt-n)) 100%;
  background-repeat: repeat-x;
}

.app-einfach-takt-egg .app-einfach-takt-punkte {
  --app-takt-n: 27;
  background-image: radial-gradient(circle closest-side at center, transparent 0 58%, var(--app-takt-farbe) 66% 78%, transparent 84%);
  opacity: 0.55;
}

/* Die Periodenkachel „1" — dieselbe wie auf der Ribbon-Karte, nur so gross
   wie der Punktestreifen hoch ist (plus etwas Luft). */
.app-einfach-takt-tage .app-ribbon-kachel {
  width: calc(var(--app-takt-punkt) + 0.9rem);
  height: calc(var(--app-takt-punkt) + 0.9rem);
  border-radius: 0.45rem;
  font-size: calc(var(--app-takt-punkt) * 0.9 + 0.1rem);
}

.app-einfach-takt-zahl {
  grid-area: zahl;
  justify-self: end;
  font-size: 0.82rem;
  font-weight: 800;
  white-space: nowrap;
  color: var(--app-takt-farbe);
}

/* „Beginn der Periode reicht." haengt an der Kachel „1": unter ihr, nach
   rechts versetzt, der Pfeil zeigt nach links oben auf sie. Weil die Notiz
   an der Kachel sitzt und nicht an der Zeile, trifft der Pfeil auf jeder
   Breite — auf dem Telefon steht die „1" am linken Rand, auf dem Desktop
   hinter der Frage. Die Breite ist an den Takt gebunden (cqw), damit sie
   auf dem Telefon umbricht statt aus der Karte zu laufen. */
.app-einfach-eins {
  position: relative;
  flex: none;
  display: inline-grid;
}

/* Lage nach Andreas' Sichtung weiter rechts unten (vorher 2,7 rem / 1,25 rem).
   Der Pfeil ist dafuer fest 3,3 rem breit und so gesetzt, dass seine Spitze
   0,3 rem unter der Kachel und auf ihrer Mitte liegt, unabhaengig von deren
   Groesse (Telefon 22 px, Desktop 30 px): Spitze x = left + 0,15 rem −
   0,867 × Breite, Spitze y = top + Pfeil-top + 0,229 × Hoehe. */
.app-einfach-notiz-eins {
  position: absolute;
  top: calc(100% + 1.8rem);
  left: 3.6rem;
  width: max-content;
  max-width: calc(100cqw - 8rem);
  transform: rotate(-3deg);
  transform-origin: left top;
}

.app-einfach-notiz-eins .app-arrow {
  right: 100%;
  top: -2.1rem;
  width: 3.3rem;
  margin-right: -0.15rem;
  transform: scaleY(-1);
}

/* Ab 700px: Absender links, „wie oft" rechts, dazwischen Frage ueber den
   Tagen — so bekommen die 28 Tage die ganze Mitte (auf 768 px rund 430 px,
   in EINER Reihe mit der Frage blieben ihnen 137 px, keine 5 px je Tag).
   Ab 1000px eine Reihe: wer | Frage | Tage | wie oft. */
@media (min-width: 700px) {
  .app-einfach-takt {
    gap: 1rem;
    margin-bottom: 2.2rem;
    padding: 1.1rem 1.25rem;
  }
  .app-einfach-takt-zeile {
    grid-template-columns: 8.5rem minmax(0, 1fr) auto;
    grid-template-areas:
      "wer frage zahl"
      "wer tage zahl";
    gap: 0.5rem 0.9rem;
  }
}

@media (min-width: 1000px) {
  .app-einfach-takt-zeile {
    grid-template-columns: 9.5rem auto minmax(0, 1fr) auto;
    grid-template-areas: "wer frage tage zahl";
    gap: 0.9rem;
  }
  /* 20 rem: "How are you feeling today?" und "Comment te sens-tu aujourd’hui ?"
     brachen bei 17 rem in zwei Zeilen (gemessen 2026-09-14). */
  .app-einfach-takt-frage {
    max-width: 20rem;
  }
}

/* Beim Einblenden laufen die Tage von links nach rechts durch: oben fuellt
   sich die Zeile Tag fuer Tag (1,4 s), unten springt danach nur die „1" auf.
   Ohne JavaScript und bei „Bewegung reduzieren" steht alles sofort.
   Seit dem 2026-09-14 (Andreas) haelt .app-einfach-takt:not(.spielt) beide
   Animationen an ihrem Anfang an — leere Punkte, keine „1" —, bis app.js das
   Feld zu drei Vierteln im Bild sieht. (In der Style-Karte wartete es
   zusaetzlich auf die Streifen darueber; seit dem Umzug am 2026-09-15 steht
   der Takt in seiner eigenen Karte, die Kopplung ist entfallen.) */
body:not(.no-js) .reveal.in .app-einfach-takt-typisch .app-einfach-takt-punkte {
  animation: app-einfach-takt-fuellen 1.4s steps(28, end) 0.4s both;
}

body:not(.no-js) .reveal.in .app-einfach-takt-egg .app-ribbon-kachel {
  animation: app-einfach-takt-eins 0.5s cubic-bezier(0.2, 0.9, 0.3, 1.4) 1.9s both;
}

body:not(.no-js) .reveal.in .app-einfach-takt:not(.spielt) .app-einfach-takt-punkte,
body:not(.no-js) .reveal.in .app-einfach-takt:not(.spielt) .app-ribbon-kachel {
  animation-play-state: paused;
}

/* Nochmal abspielen (2026-09-15, Andreas, §36): app.js setzt kurz .von-vorn,
   das die Animationen abnimmt; nach dem Reflow laufen sie von vorn. */
body:not(.no-js) .reveal.in .app-einfach-takt.von-vorn .app-einfach-takt-punkte,
body:not(.no-js) .reveal.in .app-einfach-takt.von-vorn .app-ribbon-kachel {
  animation: none;
}

@keyframes app-einfach-takt-fuellen {
  from { clip-path: inset(0 100% 0 0); }
  to { clip-path: inset(0 0 0 0); }
}

@keyframes app-einfach-takt-eins {
  from { transform: scale(0.4); opacity: 0; }
  to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  body:not(.no-js) .reveal.in .app-einfach-takt-typisch .app-einfach-takt-punkte,
  body:not(.no-js) .reveal.in .app-einfach-takt-egg .app-ribbon-kachel {
    animation: none;
  }
}

/* ---------- Partner-Karte: „Einfach gemeinsam informiert." (2026-09-15, Andreas) ----------
   Zwischen der Karte „Einfach" und der Ribbon-Karte. Eine Szene in der
   Formensprache des Seitenkopfs: zwei Glas-Telefone (Rahmen-Tokens der
   Telefon-Buehne) mit echten Renders der Band-Ansicht, hinter jedem sein
   Symbol (Venus, Mars) in den Farben des Anhaengers an der Kette des
   Egg-Advisors, darueber der Bogen, auf dem die Periodenkachel „1" von ihrem
   Telefon auf seines fliegt. Darunter zwei Handschriften, eine je Telefon.
   Das Nachfragen kommt weder in der Szene noch im Text vor, und die drei
   Haken-Pillen sind ersatzlos entfallen (Andreas, 2026-09-15).
   Konzept: docs/hero-konzept.md §35 (Vorfassungen §34).

   Aufbau: .app-partner-szene ist Container (Breite = cqw). Die Buehne haelt
   ihr Seitenverhaeltnis, alle Lagen darin sind Prozent. Jedes Telefon steht
   in einem .app-partner-platz (Lage, Groesse, Drehung); darin liegt das
   Symbol hinter dem Telefon. Die Symbole sind in Telefon-Einheiten gezeichnet
   (Telefon = 100 × 211), ihre Lage in Prozent folgt aus der viewBox:
   left = x, top = y / 211, width = Breite, height = Hoehe / 211.
   Die Kachel-Ziele (.app-partner-ziel) sitzen per Prozent auf der Kachel „1"
   der Renders (480 × 1078: Kachel x 40–118, y 258–340) — wer die Renders
   austauscht, prueft diese vier Werte.

   Das Rosa ist das Periodenrosa der Ribbon-Karte; --app-ribbon-periode
   braucht die Kachel „1" (Flieger). Tokens dreimal notiert wie jedes Token. */
.app-card-partner {
  max-width: 62.5rem;
  --app-partner-flieger-bg: #3a1530;
  --app-partner-toast-bg: rgba(18, 10, 32, 0.9);
  --app-partner-glow: rgba(255, 111, 174, 0.55);
  --app-partner-boden: rgba(168, 85, 247, 0.34);
  --app-partner-symbol-deckkraft: 0.38;
  --app-ribbon-periode: #ff6fae;
  --app-ribbon-periode-soft: rgba(255, 111, 174, 0.14);
  --app-ribbon-periode-glow: 0 0 18px rgba(255, 111, 174, 0.35);
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .app-card-partner {
    --app-partner-flieger-bg: #fbe3ee;
    --app-partner-toast-bg: rgba(255, 252, 245, 0.95);
    --app-partner-glow: rgba(179, 48, 107, 0.4);
    --app-partner-boden: rgba(160, 110, 40, 0.16);
    --app-partner-symbol-deckkraft: 0.45;
    --app-ribbon-periode: #b3306b;
    --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
    --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
  }
}

:root[data-theme="light"] .app-card-partner {
  --app-partner-flieger-bg: #fbe3ee;
  --app-partner-toast-bg: rgba(255, 252, 245, 0.95);
  --app-partner-glow: rgba(179, 48, 107, 0.4);
  --app-partner-boden: rgba(160, 110, 40, 0.16);
  --app-partner-symbol-deckkraft: 0.45;
  --app-ribbon-periode: #b3306b;
  --app-ribbon-periode-soft: rgba(179, 48, 107, 0.09);
  --app-ribbon-periode-glow: 0 6px 16px -8px rgba(179, 48, 107, 0.5);
}

.app-card-partner > .app-card-lead {
  max-width: 54rem;
  text-wrap: pretty;
}

/* Der Produktname bricht nicht am Bindestrich um (auf 360 px stand
   „Egg-“ am Zeilenende, gesehen 2026-09-15). */
.app-partner-marke {
  white-space: nowrap;
}

/* Die Hervorhebung der Ueberschrift trennt nicht: Auf 360 px trennte die
   automatische Silbentrennung „in-/formiert" (DE) und „infor-/més" (FR).
   Lieber rutscht das ganze Akzentwort in die naechste Zeile. */
.app-card-partner > h2 em {
  white-space: nowrap;
}

/* ---------- Die Szene ---------- */
.app-partner-szene {
  --app-partner-lauf: paused;
  container-type: inline-size;
  position: relative;
  display: grid;
  width: 100%;
  max-width: 48rem;
  margin: 0 auto;
}

.app-partner-szene.spielt {
  --app-partner-lauf: running;
}

/* Auf dem Telefon schmalere Telefone mit mehr Rand: Die Symbole ragen nach
   aussen und wurden bei 38 % / 6 % Rand an der Kartenkante abgeschnitten. */
.app-partner-buehne {
  --app-partner-telefon: 34%;
  --app-partner-symbol-skala: 0.8;
  position: relative;
  aspect-ratio: 1 / 1.02;
}

/* Licht unter den Telefonen: eine Ellipse, die nach allen Seiten auslaeuft.
   Das Bodenlicht des Seitenkopfs (--app-hero-floor) ist am unteren Rand am
   hellsten und endet an der Buehnenkante — hier stehen die Handschriften
   darunter, und diese Kante zeichnete eine Linie quer durch die Karte
   (gesehen 2026-09-15). */
.app-partner-buehne::before {
  content: '';
  position: absolute;
  inset: 35% -12% -18% -12%;
  background: radial-gradient(50% 50% at 50% 50%, var(--app-partner-boden), transparent 72%);
  pointer-events: none;
}

.app-partner-platz {
  position: absolute;
  top: 12%;
  width: var(--app-partner-telefon);
  aspect-ratio: 9 / 19;
}

.app-partner-sie {
  left: 11%;
  transform: rotate(-5deg);
}

.app-partner-er {
  right: 11%;
  transform: rotate(5deg);
}

/* Das Symbol hinter dem Telefon — der Platz ist durch die Drehung ein eigener
   Stapelkontext, das Telefon liegt mit z-index 1 darueber. Skaliert wird um
   den Mittelpunkt des Rings (transform-origin aus der viewBox). */
.app-partner-symbol {
  position: absolute;
  z-index: 0;
  overflow: visible;
  opacity: var(--app-partner-symbol-deckkraft);
  transform: scale(var(--app-partner-symbol-skala));
  pointer-events: none;
}

.app-partner-symbol-sie {
  left: -65%;
  top: 2.37%;
  width: 205%;
  height: 127.96%;
  transform-origin: 56.1% 33.3%;
  filter: drop-shadow(0 0 14px rgba(255, 92, 158, 0.55));
}

.app-partner-symbol-er {
  left: -30%;
  top: -4.74%;
  width: 200%;
  height: 94.79%;
  transform-origin: 40% 60%;
  filter: drop-shadow(0 0 14px rgba(59, 149, 255, 0.55));
}

.app-partner-telefon {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  /* Prozent im Padding beziehen sich auf die Breite des Platzes, also des
     Telefons: derselbe Rand wie am Telefon des Seitenkopfs. */
  padding: 7.8%;
  border-radius: 14% / 6.6%;
  background: var(--app-phone-frame);
  box-shadow: var(--app-shadow-phone), inset 0 0 0 1.5px var(--app-phone-rim);
}

.app-partner-glas {
  width: 100%;
  height: 100%;
  border-radius: 11% / 5.2%;
  overflow: hidden;
  background: #000;
}

.app-partner-bild {
  position: relative;
  display: block;
}

.app-partner-bild img {
  display: block;
  width: 100%;
  height: auto;
}

/* Die Kachel „1" im Render — Start und Ziel des Flugs. */
.app-partner-ziel {
  position: absolute;
  left: 8.3%;
  top: 23.9%;
  width: 16.3%;
  height: 7.6%;
  border-radius: 22% / 20%;
}

/* Ihr Tipp und seine Landung: ein Ring, der einmal aufgeht. */
.app-partner-ziel::after {
  content: '';
  position: absolute;
  inset: -12%;
  border: 2px solid var(--app-ribbon-periode);
  border-radius: inherit;
  opacity: 0;
}

/* Im Endstand leuchtet seine Kachel: Die „1" ist angekommen. */
.app-partner-er .app-partner-ziel {
  box-shadow: 0 0 0 2px var(--app-ribbon-periode), 0 0 16px 3px var(--app-partner-glow);
}

/* Die Erfolgsmeldung der App, als Hinweis ueber seinem Bildschirm. Sie darf
   breiter sein als das Telefon — sie ist ein Vermerk, kein Teil des Renders. */
.app-partner-toast {
  position: absolute;
  z-index: 2;
  top: 10%;
  left: 50%;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.3rem 0.65rem 0.3rem 0.5rem;
  border: 1px solid var(--accent-40);
  border-radius: 999px;
  background: var(--app-partner-toast-bg);
  color: var(--text-strong);
  font-size: 0.66rem;
  font-weight: 800;
  white-space: nowrap;
  box-shadow: 0 10px 22px -10px rgba(0, 0, 0, 0.6);
  transform: translateX(-50%);
}

.app-partner-toast svg {
  width: 0.85rem;
  height: 0.85rem;
  flex: none;
  color: var(--accent);
}

/* Der Bogen: app.js setzt viewBox und Pfad aus der gemessenen Lage beider
   Kacheln. Ohne JavaScript bleibt er leer. */
.app-partner-bogen {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.app-partner-bogen path {
  fill: none;
  stroke: var(--app-ribbon-periode);
  stroke-width: 2;
  stroke-dasharray: 2 8;
  stroke-linecap: round;
  opacity: 0.6;
}

/* Die fliegende Kachel: dieselbe wie im Takt, deckend, mit Leuchten. Sie
   sitzt oben links in der Buehne; app.js faehrt sie per transform. */
.app-partner-flieger {
  position: absolute;
  z-index: 4;
  left: 0;
  top: 0;
  width: 2.2rem;
  height: 2.2rem;
  margin: -1.1rem 0 0 -1.1rem;
  border-radius: 0.6rem;
  background: var(--app-partner-flieger-bg);
  font-size: 1.05rem;
  box-shadow: var(--app-ribbon-periode-glow), 0 0 24px 6px var(--app-partner-glow);
  opacity: 0;
  pointer-events: none;
}

/* ---------- Die Handschriften ----------
   Eine je Telefon, der Pfeil zeigt nach oben auf das Telefon. Auf dem
   Telefon mittig unter ihrem Telefon (Container-Block vor dem Ablauf),
   darueber versetzt in einer Reihe. */
.app-partner-notizen {
  display: grid;
  gap: 0.2rem;
  padding-top: 1.4rem;
}

.app-partner-notiz {
  position: relative;
  z-index: 2;
  width: fit-content;
  margin: 0;
  font-family: "Caveat", "Segoe Script", "Bradley Hand", cursive;
  font-size: clamp(1.35rem, 4.4vw, 1.65rem);
  font-weight: 600;
  line-height: 0.95;
  color: var(--accent);
}

.app-partner-notiz .app-arrow {
  position: absolute;
  top: -1.9rem;
  width: 2.8rem;
  height: auto;
  aspect-ratio: 90 / 70;
}

.app-partner-notiz-sie {
  justify-self: start;
  margin-left: 24cqw;
  transform: rotate(-3deg);
}

.app-partner-notiz-sie .app-arrow {
  right: 100%;
  margin-right: -0.2rem;
  transform: scaleY(-1);
}

.app-partner-notiz-er {
  justify-self: end;
  margin-right: 24cqw;
  text-align: right;
  transform: rotate(3deg);
}

/* Unter dem Telefon zweizeilig und eine Zeile tiefer als ihre Notiz: Der
   Pfeil muss weiter hinauf. */
.app-partner-notiz-er .app-arrow {
  left: 100%;
  top: -3rem;
  width: 3.2rem;
  margin-left: -0.2rem;
  transform: scale(-1, -1);
}

/* Ab 34 rem Szenenbreite: Buehne breiter als hoch, Telefone naeher an der
   Mitte (die Symbole brauchen aussen Platz), Handschriften in einer Reihe. */
@container (min-width: 34rem) {
  .app-partner-buehne {
    --app-partner-telefon: 27%;
    /* 0,8: In voller Groesse drueckten die Symbole die Telefone an die Wand,
       und das Kreuz lief unten aus der Karte (gesehen 2026-09-15). */
    --app-partner-symbol-skala: 0.8;
    aspect-ratio: 16 / 11;
  }
  .app-partner-platz {
    top: 11%;
  }
  .app-partner-sie {
    left: 13%;
    transform: rotate(-6deg);
  }
  .app-partner-er {
    right: 13%;
    transform: rotate(6deg);
  }
  .app-partner-toast {
    font-size: 0.74rem;
  }
  .app-partner-flieger {
    width: 2.6rem;
    height: 2.6rem;
    margin: -1.3rem 0 0 -1.3rem;
    font-size: 1.2rem;
  }
  .app-partner-notizen {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    padding-top: 0.6rem;
  }
  .app-partner-notiz-sie {
    margin-left: 27cqw;
  }
  .app-partner-notiz-er {
    margin-right: 27cqw;
  }
  .app-partner-notiz-er .app-arrow {
    top: -1.9rem;
    width: 2.8rem;
  }
}

/* Auf dem Telefon (Szene unter 34 rem; Andreas, 2026-09-15: „die Pfeile
   sind nicht korrekt auf die Handys ausgerichtet"): Beide Handschriften
   stehen in EINER Reihe, jede mittig unter ihrem Telefon (28 / 72 % der
   Breite), und ihr Pfeil zeigt senkrecht nach oben auf dessen Unterkante.
   Vorher standen sie untereinander mit seitlichen Pfeilen, die 40–50 px
   neben die Telefone zielten (gemessen auf 320–600 px).
   Der Pfeil ist der Seitenpfeil, um 126° gedreht: Dann liegen Schwanz und
   Spitze senkrecht uebereinander, 0,91 × Pfeilbreite auseinander (bei
   2,6 rem also 38 px). Die Reihe rueckt so weit hoch, dass die Spitze knapp
   unter dem Telefon endet: Telefon-Unterkante = 85,3 % der Szenenbreite
   (gemessen, alle Breiten), Notiz-Oberkante = Unterkante + 2,9 rem; die
   Buehne ist 102 % hoch, also margin-top = 2,9 rem − 16,7 cqw. Hoechstens
   42 cqw breit, damit sich die Notizen nicht beruehren (FR und ES brechen
   dann um). Unten 3,2 rem Platz fuer das Symbol „Nochmal abspielen". */
@container (max-width: 33.99rem) {
  .app-partner-notizen {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 0;
    margin-top: calc(2.9rem - 16.7cqw);
    padding: 0 0 3.2rem;
  }
  .app-partner-notiz-sie,
  .app-partner-notiz-er {
    justify-self: center;
    max-width: 42cqw;
    margin: 0;
    text-align: center;
  }
  .app-partner-notiz-sie {
    translate: 3cqw 0;
  }
  .app-partner-notiz-er {
    translate: -3cqw 0;
  }
  .app-partner-notiz-sie .app-arrow,
  .app-partner-notiz-er .app-arrow {
    top: -2.55rem;
    left: calc(50% - 1.42rem);
    right: auto;
    width: 2.6rem;
    margin: 0;
    transform: rotate(126deg);
  }
  .app-partner-notiz-er .app-arrow {
    transform: scaleX(-1) rotate(126deg);
  }
}

/* ---------- Der Ablauf ----------
   Ruhig (Andreas: „etwas langsamer"). Alles laeuft ueber CSS-Verzoegerungen
   ab dem Moment, in dem app.js .spielt setzt; bis dahin haelt
   --app-partner-lauf jede Animation an ihrem Anfang (fill both = der erste
   Schluessel gilt schon vorher). Den Flug selbst faehrt app.js (Web
   Animations, 1,3 s Verzoegerung, 2 s Flug).
   0,5 s        ihr Tipp (Ring) und „Einmal teilen."
   0,8 s        der Bogen
   1,3–3,3 s    der Flug
   3,3 s        Landung (Ring, Leuchten)
   3,6 s        Erfolgsmeldung
   4,3 s        „Zweimal tippen. Fertig."
   Ohne JavaScript und bei „Bewegung reduzieren" steht der Endstand. */
body:not(.no-js) .app-partner-sie .app-partner-ziel::after {
  animation: app-partner-ring 1s ease-out 0.5s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-er .app-partner-ziel::after {
  animation: app-partner-ring 1s ease-out 3.3s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-er .app-partner-ziel {
  animation: app-partner-leuchten 0.7s ease-out 3.3s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-bogen path {
  animation: app-partner-bogen 0.7s ease 0.8s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-toast {
  animation: app-partner-toast 0.6s cubic-bezier(0.2, 0.9, 0.3, 1.2) 3.6s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-notiz-sie {
  animation: app-partner-notiz 0.7s ease 0.5s both;
  animation-play-state: var(--app-partner-lauf);
}

body:not(.no-js) .app-partner-notiz-er {
  --app-partner-notiz-dreh: 3deg;
  animation: app-partner-notiz 0.7s ease 4.3s both;
  animation-play-state: var(--app-partner-lauf);
}

@keyframes app-partner-ring {
  0% { opacity: 0; transform: scale(0.8); }
  20% { opacity: 1; }
  100% { opacity: 0; transform: scale(1.7); }
}

@keyframes app-partner-leuchten {
  from { box-shadow: 0 0 0 0 transparent, 0 0 0 0 transparent; }
  to { box-shadow: 0 0 0 2px var(--app-ribbon-periode), 0 0 16px 3px var(--app-partner-glow); }
}

@keyframes app-partner-bogen {
  from { opacity: 0; }
  to { opacity: 0.6; }
}

@keyframes app-partner-toast {
  from { opacity: 0; transform: translateX(-50%) translateY(-0.6rem) scale(0.9); }
  to { opacity: 1; transform: translateX(-50%); }
}

/* Die Notizen tragen ihre Drehung im transform — die Keyframes nehmen sie mit. */
@keyframes app-partner-notiz {
  from { opacity: 0; transform: rotate(var(--app-partner-notiz-dreh, -3deg)) translateY(0.4rem); }
  to { opacity: 1; transform: rotate(var(--app-partner-notiz-dreh, -3deg)); }
}

/* Nochmal abspielen (§36): .von-vorn nimmt alle Animationen ab, nach dem
   Reflow laufen sie von vorn; den Flug startet app.js neu. Steht hinter den
   Ablauf-Regeln, damit es bei gleicher Spezifitaet gewinnt. */
body:not(.no-js) .app-partner-szene.von-vorn *,
body:not(.no-js) .app-partner-szene.von-vorn *::after {
  animation: none;
}

@media (prefers-reduced-motion: no-preference) {
  .app-partner-buehne.abspielbar,
  .app-einfach-takt.abspielbar {
    cursor: pointer;
  }
}

@media (prefers-reduced-motion: reduce) {
  body:not(.no-js) .app-partner-szene *,
  body:not(.no-js) .app-partner-szene *::after {
    animation: none;
  }
}
