/* ═══════════════════════════════════════════════════════════════════════
   Entwurf einer neuen Startseite, nach einer Skizze auf Papier.
   Gleiche Grundlage wie die veröffentlichte Seite (Schrift, Farbwelt,
   Bewegung nur über die native Scroll-Zeitleiste, kein JavaScript),
   mit einem eigenen Motiv: eine Ablauf-Strecke mit fester Mittellinie
   und ein Übergang, der aus dem letzten Punkt der Strecke die große
   Ergebnis-Fläche werden lässt.
   ═══════════════════════════════════════════════════════════════════════ */

@font-face { font-family:"PlexSans"; src:url("schriften/plexsans-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap; }
@font-face { font-family:"PlexSans"; src:url("schriften/plexsans-600.woff2") format("woff2");
  font-weight:600; font-style:normal; font-display:swap; }
@font-face { font-family:"Zahl"; src:url("schriften/plexmono-400.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap; }

:root {
  --grund:   oklch(15.5% 0.028 265);
  --grund-2: oklch(20%   0.03 265);
  --grund-3: oklch(25%   0.03 265);
  --text:    oklch(96.5% 0.008 265);
  --text-2:  oklch(79%   0.022 262);
  --leise:   oklch(67%   0.024 262);
  --linie:   oklch(30%   0.03 265);
  --linie-2: oklch(24%   0.028 265);

  --akzent:   oklch(71% 0.16 266);
  /* Kobalt in zwei Rollen: hell für Schrift, Linien und Punkte auf dem
     dunklen Grund, kräftig für Flächen mit weißer Schrift darauf. */
  --flaeche:  oklch(53% 0.215 266);
  --akzent-2: oklch(47% 0.2 266);
  --auf-akzent: oklch(100% 0 0);

  /* Seitlicher Versatz, mit dem die Ablauf-Karten hereingleiten. Steht hier,
     weil zwei Dinge ihn kennen müssen: die Bewegung selbst und die Länge der
     Verbindungslinie, die die Karte auch im Anflug noch erreichen soll. */
  --karte-versatz: 32px;

  --grotesk: "PlexSans", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --zahl:    "Zahl", ui-monospace, "SF Mono", Menlo, monospace;

  --t-xs: 0.8rem; --t-sm: 0.92rem; --t-base: 1.03rem; --t-lg: 1.22rem;
  --t-xl: 1.5rem; --t-2xl: 1.9rem; --t-h1: clamp(2.1rem, 4.4vw, 3.4rem);

  --s-3xs: .25rem; --s-2xs: .5rem; --s-xs: .75rem; --s-sm: 1rem;
  --s-md: 1.5rem; --s-lg: 2.25rem; --s-xl: 3.25rem; --s-2xl: 4.75rem;
  --rand: clamp(1.25rem, 4.5vw, 3.25rem);
  --mass: 36rem;

  --schnell: 140ms; --normal: 420ms;
  --raus: cubic-bezier(0.23, 1, 0.32, 1);
}

*, *::before, *::after { box-sizing: border-box; }
html, body { overflow-x: clip; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* Lenis übernimmt das Scrollen selbst (Sprungmarken inklusive) — die
   native CSS-Glättung würde ihr sonst ins Gehege kommen. Ohne Lenis
   (kein JavaScript, reduzierte Bewegung) bleibt die native Glättung von
   oben aktiv, weil dieser Klasse dann niemand hinzufügt. */
html.lenis { scroll-behavior: auto; }
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

body { margin: 0; background: var(--grund); color: var(--text);
  font-family: var(--grotesk); font-size: var(--t-base); line-height: 1.65;
  font-feature-settings: "kern" 1, "liga" 1; }

h1, h2, h3, h4 { font-family: var(--grotesk); font-weight: 600; margin: 0;
  letter-spacing: -0.026em; line-height: 1.14; overflow-wrap: anywhere; min-width: 0; }
p { margin: 0 0 var(--s-sm); max-width: var(--mass); }
ul, ol, dl { margin: 0; padding: 0; }
a { color: inherit; }
mark { background: none; color: var(--akzent); font-weight: 600; }
.zahl { font-family: var(--zahl); font-variant-numeric: tabular-nums;
  font-size: 0.92em; letter-spacing: -0.01em; }

.mitte { width: 100%; max-width: 74rem; margin-inline: auto; padding-inline: var(--rand); }
:where(a, button):focus-visible { outline: 2px solid var(--akzent); outline-offset: 3px; border-radius: 1px; }

.spring { position: absolute; left: var(--s-sm); top: var(--s-sm); z-index: 900;
  background: var(--text); color: var(--grund); padding: var(--s-xs) var(--s-sm);
  text-decoration: none; clip-path: inset(50%); }
.spring:focus { clip-path: none; }

/* ─────────────── Kopf ─────────────── */
.leiste { position: relative; border-bottom: 1px solid var(--linie); z-index: 30;
  background: var(--grund); }
.leiste-innen { display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--s-sm) var(--s-xl); padding-block: var(--s-sm); }
.marke { position: relative; display: inline-flex; align-items: center; gap: var(--s-2xs);
  text-decoration: none; font-weight: 600; font-size: var(--t-base);
  letter-spacing: -0.01em; white-space: nowrap; min-height: 46px; flex: none; }
.marke img { width: 22px; height: 22px; display: block; }
.haupt { margin-left: auto; display: flex; align-items: center; gap: var(--s-md); flex-wrap: wrap; }
.haupt a { position: relative; display: inline-flex; align-items: center; min-height: 46px;
  text-decoration: none; font-size: var(--t-sm); color: var(--text-2);
  transition: color var(--schnell) var(--raus); }
.haupt a:hover { color: var(--text); }
.leiste-tel { position: relative; display: inline-flex; align-items: center; min-height: 46px;
  margin-left: var(--s-md); font-family: var(--zahl); font-size: var(--t-sm);
  white-space: nowrap; text-decoration: none; color: var(--text-2); flex: none; }
.leiste-tel:hover { color: var(--text); }
@media (max-width: 30rem) { .leiste-tel { display: none; } }

/* ─────────────── Abschnitte ─────────────── */
.abschnitt { padding-block: var(--s-2xl); border-top: 1px solid var(--linie); }
.kopfzeile { font-size: var(--t-xs); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--leise); margin: 0 0 var(--s-sm); }
.h2 { font-size: var(--t-2xl); }
.blei { color: var(--text-2); max-width: 34rem; }

/* ─────────────── Hero ─────────────── */
.hero { border-top: 0; overflow: clip; position: relative; }
.hero-innen { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: var(--s-2xl); align-items: center; padding-block: var(--s-2xl); position: relative; z-index: 1; }
.hero h1 { font-size: var(--t-h1); max-width: 15ch; }
.hero-blei { margin-top: var(--s-md); color: var(--text-2); max-width: 30rem; font-size: var(--t-lg); }

.wege { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-sm) var(--s-md);
  margin-top: var(--s-lg); }
.knopf { position: relative; display: inline-flex; align-items: center; min-height: 50px;
  padding-inline: var(--s-lg); font-weight: 600; font-size: var(--t-sm); text-decoration: none;
  white-space: nowrap; background: var(--flaeche); color: var(--auf-akzent);
  border: 1px solid var(--flaeche); border-radius: 2px;
  transition: background var(--schnell) var(--raus), transform var(--schnell) var(--raus); }
.knopf:hover { background: var(--akzent-2); border-color: var(--akzent-2); transform: translateY(-1px); }
.anruf { position: relative; display: inline-flex; align-items: center; min-height: 44px;
  font-family: var(--zahl); font-size: var(--t-sm); color: var(--text-2); text-decoration: none;
  border-bottom: 1px solid var(--linie);
  transition: color var(--schnell) var(--raus), border-color var(--schnell) var(--raus); }
.anruf:hover { color: var(--text); border-color: var(--text-2); }

.hero-bild-feld { position: relative; display: grid; place-items: center; }
.hero-blob { position: absolute; inset: -12% -8%; z-index: 0;
  background: radial-gradient(closest-side, oklch(55% 0.2 266 / 0.32), transparent 72%); }
.hero-foto { position: relative; z-index: 1; margin: 0; max-width: 22rem; width: 100%; }

/* Parallax: driftet beim Scrollen minimal langsamer/schneller als der Rest
   der Seite (app.js schreibt --parallax-y). Rein dekorativ, deshalb bewusst
   nicht an die einmalige Text-Einblendung gekoppelt — hier darf es beim
   Zurückscrollen ruhig wieder zurücklaufen, das erzählt keine Geschichte,
   sondern nur Tiefe. */
@media (prefers-reduced-motion: no-preference) {
  [data-parallax] { transform: translateY(var(--parallax-y, 0px)); will-change: transform; }
}
.hero-foto img { width: 100%; height: auto; display: block; border-radius: 10px;
  box-shadow: 0 30px 60px -30px oklch(0% 0 0 / 0.6); }

@media (prefers-reduced-motion: no-preference) {
  .hero-blob { animation: schweben-blob 12s ease-in-out infinite alternate; }
}
@keyframes schweben-blob { from { transform: translateY(0) scale(1); } to { transform: translateY(-14px) scale(1.04); } }


@media (max-width: 60rem) {
  .hero-innen { grid-template-columns: minmax(0,1fr); text-align: left; }
  .hero-foto { max-width: 15rem; margin-inline: auto; }
}

/* ─────────────── Leistungen: drei Zeilen, abwechselnd ───────────────
   Je Zeile eine Überschrift mit ihrem Absatz und gegenüber die Abbildung,
   die genau das zeigt, wovon der Absatz spricht. Zeile zwei kehrt die
   Seiten um — der Blick läuft im Zickzack nach unten statt in einer
   Spalte geradeaus, und jede Abbildung bekommt die halbe Breite, statt
   sich mit dem Text um dieselbe Spalte zu streiten. */
.zeilen { display: grid; gap: var(--s-2xl); margin-top: var(--s-2xl); }
.zeile { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--s-lg) var(--s-2xl); align-items: center; }
.zeile + .zeile { padding-top: var(--s-2xl); border-top: 1px solid var(--linie-2); }
.zeile-text h3 { font-size: clamp(1.4rem, 2.5vw, 1.95rem); margin-bottom: var(--s-sm); }
.zeile-text p { color: var(--text-2); max-width: 32rem; margin: 0; }
.zeile-bild { margin: 0; display: flex; flex-direction: column; align-items: center;
  gap: var(--s-xs); min-width: 0; }

/* Jede zweite Zeile spiegelt sich: Überschrift rechts, Abbildung links.
   Der Absatz bleibt linksbündig gesetzt — rechtsbündiger Fließtext liest
   sich im Deutschen schlecht —, rückt als Block aber an die rechte Kante. */
.zeile:nth-child(even) .zeile-text { order: 2; text-align: right; }
.zeile:nth-child(even) .zeile-text p { text-align: left; margin-left: auto; }

@media (max-width: 52rem) {
  .zeile { grid-template-columns: minmax(0, 1fr); gap: var(--s-lg); }
  .zeile + .zeile { padding-top: var(--s-xl); }
  .zeile:nth-child(even) .zeile-text { order: 0; text-align: left; }
  .zeile:nth-child(even) .zeile-text p { margin-left: 0; }
  .zeile-bild { align-items: flex-start; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .zeile-text, .zeile-bild { animation: hoch linear both;
      animation-timeline: view(); animation-range: cover 2% cover 30%; }
  }
}

/* Mini-Gerätewand: dieselben echten Apple-Rahmengrafiken wie im Ergebnis-
   Bildschirm, nur klein. Das Gerät ist der Vordergrund — die Rahmengrafik
   liegt über allem und gibt die Rundung vor. Die Seite dahinter ist deshalb
   eine schlichte, kantige Fläche — bei Tablet und Laptop ohne eigene
   Ecken-Rundung, denn deren Bildschirmecken sind so großzügig, dass die
   Rahmengrafik sie ohnehin vollständig verdeckt. Beim Telefon dagegen ist
   die Ecke eng genug, dass eine rechtwinklige Fläche an der Kurve der
   Rahmengrafik vorbeiblitzt — dort rundet die Fläche deshalb leicht mit
   (grob geschätzt, nicht ausgemessen; die Kurve der Rahmengrafik selbst
   folgt keiner einfachen Formel).

   Die Ränder unten sind kein Augenmaß, sondern das ausgemessene durch-
   sichtige Fenster jeder Rahmendatei. Beim Telefon reicht es bis ganz nach
   oben: Die Insel („Notch") ist Teil der Rahmengrafik und liegt über der
   Seite — die Seite muss also darunter durchlaufen, sonst steht dort ein
   schwarzer Streifen. */
/* Bewusst nowrap: Alle drei sollen immer in einer Reihe bleiben, nie eines
   davon in eine zweite Zeile umbrechen. Die Mindestbreiten unten sind so
   knapp gewählt, dass die Summe selbst auf sehr schmalen Telefonen
   (320px Breite, davon 40px Seitenrand) noch hineinpasst; flex-shrink
   bleibt trotzdem erlaubt (kein flex:none mehr) als Sicherheitsnetz für
   noch schmalere Fälle — dann schrumpfen alle drei gemeinsam, statt dass
   eines umbricht oder über den Rand hinausragt. */
.mini-geraete { display: flex; align-items: flex-end; justify-content: center;
  gap: clamp(0.5rem, 2.5vw, 1.6rem); flex-wrap: nowrap; }
.mini-geraet { position: relative; flex: 0 1 auto; min-width: 0; }
.mini-geraet > img { position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none; z-index: 1; }
.mini-telefon  { width: clamp(42px, 5.8vw, 70px);   aspect-ratio: 620 / 1265; }
.mini-tablet   { width: clamp(70px, 9.6vw, 118px);  aspect-ratio: 1200 / 1687; }
.mini-laptop   { width: clamp(132px, 19vw, 240px);  aspect-ratio: 1600 / 965; }

.mini-bildschirm { position: absolute; overflow: clip; background: #f1f3f7; }
/* Radius aus dem echten Foto ausgemessen (Flood-Fill der transparenten
   Bildschirm-Aussparung in geraet-iphone.webp, 620×1265px): Der Ausschnitt
   ist 556×1209px groß, die Eckenrundung passt auf einen Kreis mit Radius
   ≈80px (an mehreren Punkten der Kurve gegengeprüft, Abweichung < 1px).
   80/556 = 14.39 % (horizontal), 80/1209 = 6.62 % (vertikal) — als
   "X% / Y%" ergibt das denselben echten Kreis, obwohl das Element selbst
   kein Quadrat ist. Ohne dieses Radius (0 %, "das Foto schneidet schon
   passend zu") blieben die rechteckigen Ecken der Fläche dahinter sichtbar,
   weil die Rundung im Foto selbst liegt, nicht am Rand des Ausschnitts;
   mit einem geschätzten Radius (vorher 12 %, kreisrund) lag die Kurve nie
   exakt auf der des Fotos. Erst dieser gemessene, elliptisch skalierte
   Wert deckt sich mit der echten Kurve. */
.mini-telefon  .mini-bildschirm { inset: 2.21% 5.16%  2.21%  5.16%;
  border-radius: 14.39% / 6.62%; }
.mini-tablet   .mini-bildschirm { inset: 3.68% 5.17%  3.50%  4.92%; }
.mini-laptop   .mini-bildschirm { inset: 2.49% 10.31% 12.12% 10.31%; }

/* ── Drei Seitenentwürfe, keiner gestaucht ──
   Vorher war es dreimal dasselbe Baukasten-Gerüst, das sich in drei völlig
   verschiedene Seitenverhältnisse pressen musste — dabei wird dieselbe
   Fläche einmal lang gezogen und einmal gequetscht, und genau so sah es
   auch aus. Jetzt zeichnet jedes Gerät seine eigene kleine Seite als SVG,
   und zwar in einem Koordinatensystem, das exakt das Seitenverhältnis
   seines Bildschirmfensters hat (1 Einheit ≈ 1 Bildpunkt bei voller
   Größe). Dadurch ist nichts verzerrt, die Strichstärken wirken auf allen
   drei Geräten gleich schwer, und jedes Gerät zeigt den Aufbau, den es im
   Echtbetrieb hätte: Telefon einspaltig mit Bild über die volle Breite und
   Menüzeichen, Tablet hochkant mit Kopfnavigation, breitem Bild und zwei
   Karten, Laptop im Browserfenster mit Zweispalter und drei Karten. */
.mini-schirm { display: block; width: 100%; height: 100%; }

/* ── Abbildung: Suchtreffer ──
   Eine Ergebnisliste, wie eine Suchmaschine sie zeigt. Der markierte
   Treffer steht bewusst nicht ganz oben: Diese Seite verspricht nirgends
   eine Platzierung (die kontrolliert niemand). Gefunden werden heißt,
   überhaupt vorzukommen — genau das zeigt die Abbildung. */
.abb-suche { width: min(100%, 27rem); background: #f1f3f7; color: #252b38;
  padding: clamp(0.85rem, 1.8vw, 1.25rem);
  box-shadow: 0 26px 50px -30px oklch(0% 0 0 / 0.8); }
.such-feld { display: flex; align-items: center; gap: 0.55rem;
  background: #fff; border: 1px solid #d5dae4; padding: 0.45rem 0.6rem; }
.such-feld svg { width: 13px; height: 13px; flex: none; color: #8a92a2; }
.such-eingabe { display: block; height: 6px; width: 44%; background: #c5ccd8; }
.such-treffer { list-style: none; margin: 0.95rem 0 0; padding: 0; display: grid; gap: 0.8rem; }
.such-treffer li { position: relative; display: grid; gap: 4px; padding-left: 0.7rem; }
.treffer-url   { display: block; height: 4px; width: 32%; background: #d5dae4; }
.treffer-titel { display: block; height: 8px; width: 70%; background: #b1b9c9; }
.treffer-text  { display: block; height: 4px; width: 92%; background: #dde2ec; }
.treffer-text.kurz { width: 58%; }
.such-treffer .ihre { background: #e1e8f8; margin-inline: -0.55rem;
  padding: 0.5rem 0.55rem 0.5rem 1.25rem; }
.such-treffer .ihre::before { content: ""; position: absolute; left: 0.55rem;
  top: 0.5rem; bottom: 0.5rem; width: 3px; background: #3160f0; }
.such-treffer .ihre .treffer-url   { background: #3160f0; width: 36%; }
.such-treffer .ihre .treffer-titel { background: #3a4a6e; width: 74%; }
.such-treffer .ihre .treffer-text  { background: #c7d2ec; }
.treffer-name { position: absolute; right: 0.55rem; top: 0.4rem; font-family: var(--zahl);
  font-size: 0.6rem; letter-spacing: 0.04em; color: #2f5ae0; }

/* ── Abbildung: Ladevorgang ──
   Vorher stand hier ein Wasserfall-Diagramm aus den Entwicklerwerkzeugen:
   fachlich richtig, für jemanden ohne Werkzeugkasten aber nicht lesbar.
   Jetzt steht dort das, was jeder schon einmal gesehen hat — eine Seite,
   die sich aufbaut, und ein Balken, der vollläuft. Keine Zahl und kein
   Vergleich mit anderen, weil für diesen Entwurf nichts gemessen ist; die
   Aussage macht allein das Tempo, in dem der Balken durchläuft. */
.abb-laden { width: min(100%, 26rem); display: grid; gap: 0.85rem;
  background: oklch(18.5% 0.028 265); border: 1px solid var(--linie-2);
  padding: clamp(0.9rem, 1.8vw, 1.25rem); }

.laden-fenster { background: #f1f3f7; }
.laden-leiste { display: flex; align-items: center; gap: 4px;
  background: #e2e6ee; padding: 0.4rem 0.55rem; }
.laden-punkt { flex: none; width: 5px; height: 5px; border-radius: 50%; background: #b9c0cd; }
.laden-pille { flex: 1; height: 7px; margin-left: 0.4rem; background: #f1f3f7; }

.laden-seite { display: grid; gap: 0.5rem; padding: 0.85rem 0.85rem 1rem; }
.laden-teil { display: block; background: #d8dde7; }
.laden-teil.t1 { height: 11px; width: 62%; background: #b1b9c9; }
.laden-teil.t2 { height: 6px;  width: 88%; }
.laden-teil.t3 { height: 52px; width: 100%; background: #c9d6f5; margin-top: 0.2rem; }
.laden-reihe { display: flex; gap: 0.5rem; }
.laden-reihe .laden-teil { height: 26px; flex: 1; background: #e8ecf5; border: 1px solid #dde2ec; }

.laden-spur { position: relative; height: 9px; background: var(--grund-3); overflow: clip; }
.laden-fuellung { position: absolute; inset: 0; background: var(--akzent);
  transform-origin: left center; }
.laden-fuss { display: flex; justify-content: space-between;
  font-family: var(--zahl); font-size: var(--t-xs); color: var(--leise); }
.laden-fertig { color: var(--akzent); }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .such-treffer li { animation: hoch-kurz linear both; animation-timeline: view(); }
    .such-treffer li:nth-child(1) { animation-range: cover 10% cover 26%; }
    .such-treffer li:nth-child(2) { animation-range: cover 13% cover 29%; }
    .such-treffer li:nth-child(3) { animation-range: cover 16% cover 32%; }
    .such-treffer li:nth-child(4) { animation-range: cover 19% cover 35%; }

    .laden-teil { animation: hoch-kurz linear both; animation-timeline: view(); }
    .laden-teil.t1 { animation-range: cover 10% cover 18%; }
    .laden-teil.t2 { animation-range: cover 13% cover 21%; }
    .laden-teil.t3 { animation-range: cover 16% cover 24%; }
    .laden-reihe .laden-teil { animation-range: cover 19% cover 27%; }
    .laden-fuellung { animation: balken-auf linear both; animation-timeline: view();
      animation-range: cover 10% cover 28%; }
    .laden-fertig { animation: marke-auf linear both; animation-timeline: view();
      animation-range: cover 28% cover 34%; }
  }
}
@keyframes hoch-kurz  { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes balken-auf { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes marke-auf  { from { opacity: 0; } to { opacity: 1; } }

/* Gestaffelt wird über versetzte Bereiche, nicht über animation-delay:
   Eine Animation an der Scroll-Zeitleiste hat keine Zeitachse, auf die
   eine Verzögerung wirken könnte — der Versatz muss in den Bereich. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .mini-geraet { transform-origin: bottom; animation: geraet-wachsen linear both;
      animation-timeline: view(); animation-range: cover 10% cover 30%; }
    .mini-tablet { animation-range: cover 14% cover 34%; }
    .mini-laptop { animation-range: cover 18% cover 38%; }

    /* Das Telefon dreht sich beim Ankommen leicht ein, statt nur zu wachsen
       — perspective() steht direkt in der eigenen transform-Kette (nicht
       am Elternelement .mini-geraete), damit nur dieses eine Gerät die
       Tiefe bekommt und Tablet/Laptop unangetastet bleiben. Bewusst kein
       voller Umlauf: Es ist eine flache Mockup-Grafik, kein echtes
       3D-Modell — bei 90° stünde sie unsichtbar auf der Kante, bei 180°
       zeigte sie rückwärts. Ein kurzer Schwenk aus 35° in die Frontale
       reicht, um Tiefe zu zeigen, ohne diese Grenze zu berühren. */
    .mini-telefon { animation-name: telefon-drehen; }
  }
}
@keyframes geraet-wachsen { from { transform: scaleY(0.7); opacity: 0; } to { transform: scaleY(1); opacity: 1; } }
@keyframes telefon-drehen {
  from { transform: perspective(700px) scaleY(0.7) rotateY(-35deg); opacity: 0; }
  to   { transform: perspective(700px) scaleY(1) rotateY(0deg); opacity: 1; } }

/* Sanftes Einblenden für Textblöcke, wenn sie in den sichtbaren Bereich
   laufen. Ohne Unterstützung der Zeitleiste steht alles von Anfang an da —
   es wird nichts dauerhaft verborgen. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .auftauchen { animation: hoch linear both; animation-timeline: view();
      animation-range: cover 0% cover 26%; }
  }
}
@keyframes hoch { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: none; } }

/* ─────────────── Über mich: Foto + Text, wie der Hero gespiegelt ─────────────── */
.ueber-innen { display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: var(--s-2xl); align-items: center; }
.ueber-mich .blei + .blei { margin-top: var(--s-sm); }
@media (max-width: 56rem) {
  .ueber-innen { grid-template-columns: minmax(0,1fr); text-align: left; }
  .ueber-innen .hero-foto { max-width: 15rem; margin-inline: auto; }
}

/* ─────────────── Ablauf: Strecke mit fester Mittellinie ─────────────── */
.ablauf-szene { position: relative; margin-top: var(--s-2xl);
  timeline-scope: --punkt-lauf; }
.ablauf-spur { position: absolute; left: 50%; top: 0; bottom: 0; width: 2px;
  background: linear-gradient(to bottom, var(--linie), var(--linie) 88%, transparent);
  transform: translateX(-50%); pointer-events: none; }
/* Kein z-index mehr: Der Punkt gehört in die Schichtung seines eigenen
   Abschnitts. Lag er darüber, legte sich die gewachsene Fläche auch über
   alles Nachfolgende — der Kontaktteil stand dann auf Gold statt auf
   Dunkel. So übermalen die späteren Abschnitte sie ganz normal. */
.ablauf-punkt-huelle { position: sticky; top: 50vh; height: 0; pointer-events: none; }

/* Die Fläche, die aus dem Punkt wird: exakt ein Bildschirm groß (100vw ×
   100vh, um den festgehaltenen Punkt zentriert) und deshalb von Natur aus
   begrenzt — sie kann gar nicht über den Bildschirm hinauswachsen. Sichtbar
   wird sie über einen Kreis, der von der Punktgröße (10px Radius = die 20px
   des Punkts) aufgeht, bis er größer als die Fläche ist: Aus dem Punkt wird
   der Kreis, aus dem Kreis das Rechteck, und das Rechteck ist die Seite.
   Vorher wuchs stattdessen der Punkt selbst auf das 216-fache — also weit
   über den Bildschirm hinaus, mit genau dem Ergebnis, dass danach alles
   gelb war. */
/* --punkt-x: wo der Punkt (und damit der Kreis-Mittelpunkt) sitzt — als
   Default die Bildschirmmitte. Die Fläche selbst bleibt IMMER exakt über
   dem Bildschirm zentriert (left: 50%; translate(-50%)) und deckt ihn so
   sicher komplett ab; nur der Kreis-Ursprung im clip-path wandert per
   --punkt-x an die Position des sichtbaren Punkts. Würde man stattdessen
   die Fläche selbst verschieben (links: mobil versucht), reicht ihr
   rechter Rand nicht mehr bis zum Bildschirmrand — genau das ließ zuvor
   ein schwarzes Stück stehenbleiben, das nie goldfarben wurde. */
.ablauf-punkt-flaeche { --punkt-x: 50%; --punkt-radius-max: 75vmax;
  position: absolute; left: 50%; top: 0;
  width: 100vw; height: 100vh; transform: translate(-50%, -50%);
  background: var(--flaeche); clip-path: circle(10px at var(--punkt-x) 50%); }
.ablauf-punkt { --punkt-x: 50%; position: absolute; left: var(--punkt-x); top: 0;
  width: 20px; height: 20px;
  transform: translate(-50%, -50%); border-radius: 50%; background: var(--flaeche);
  box-shadow: 0 0 0 7px oklch(62% 0.2 266 / 0.2), 0 0 24px oklch(62% 0.2 266 / 0.45); }
@media (prefers-reduced-motion: no-preference) {
  .ablauf-punkt { animation: puls 2.6s ease-in-out infinite; }
}
@keyframes puls { 0%,100% { transform: translate(-50%,-50%) scale(1); }
  50% { transform: translate(-50%,-50%) scale(1.18); } }

.ablauf-liste { list-style: none; margin: 0; padding: 6vh 0 4vh; }
.ablauf-schritt { position: relative; display: flex; min-height: 42vh; align-items: center; }
.ablauf-karte { position: relative; max-width: 21rem; background: var(--grund-2);
  border: 1px solid var(--linie); border-radius: 4px; padding: var(--s-lg); }
.ablauf-links { justify-content: flex-end; padding-right: calc(50% + var(--s-2xl)); }
.ablauf-rechts { justify-content: flex-start; padding-left: calc(50% + var(--s-2xl)); }
.schritt-nr { display: block; font-family: var(--zahl); font-size: var(--t-sm);
  color: var(--akzent); margin-bottom: var(--s-2xs); }
.ablauf-karte h3 { font-size: var(--t-lg); color: var(--text); }
.ablauf-karte p { margin: var(--s-2xs) 0 0; font-size: var(--t-sm); color: var(--text-2); }

/* Die Verbindungslinie ist um genau den Betrag länger, um den die Karte
   beim Einfliegen seitlich versetzt ist (--karte-versatz). Sonst endete
   sie im Leeren, solange die Karte noch unterwegs war — die Linie stand
   fest, die Karte kam erst von außen herangeglitten. Jetzt reicht sie
   immer bis an die Karte heran; ist diese angekommen, verschwindet das
   überstehende Stück hinter ihr (die Karte wird nach der Linie gezeichnet
   und deckt sie ab). */
.ablauf-verbinder { position: absolute; top: 50%; height: 1px;
  width: calc(var(--s-2xl) - 4px + var(--karte-versatz)); background: var(--linie); }
.ablauf-links .ablauf-verbinder { right: calc(50% + 2px); }
.ablauf-rechts .ablauf-verbinder { left: calc(50% + 2px); }

/* Leerstrecke nach Schritt 04: keine Karte, nur die Linie und der Punkt.
   Eine Weile bleibt nur er übrig, bevor er zur Ergebnis-Fläche wird — der
   Übergang entwickelt sich sichtbar aus dem Punkt: Die Leerstrecke liefert
   per view-timeline-name nur den Scroll-Fortschritt, animiert wird damit
   ein ganz anderes Element weiter oben (.ablauf-punkt-flaeche, über
   timeline-scope an .ablauf-szene sichtbar gemacht) — der Punkt bleibt
   dabei die ganze Zeit mittig fixiert (sticky) stehen und wächst an Ort
   und Stelle, statt dass irgendwo anders im Layout etwas aufreißt. */
/* 180vh statt 120vh: Die Strecke ist das Zeitfenster für das Wachstum, und
   das muss zwischen zwei festen Ereignissen Platz haben — die letzte Karte
   ist draußen (36 %), die echte Goldfläche schiebt sich von unten ins Bild
   (69 %). Bei 120vh blieben dafür nur 249px, der Kreis wuchs noch, während
   schon die Kante der echten Fläche von unten hereinfuhr und ihn abschnitt.
   Bei 180vh sind es 681px. Weil die Höhe in vh angegeben ist, bleiben diese
   Prozentwerte auf jeder Bildschirmhöhe gleich. */
.ablauf-leerlauf { display: block; min-height: 180vh;
  view-timeline-name: --punkt-lauf; }

/* 75vmax Endradius: Die Fläche misst höchstens 100vw × 100vh, ihre halbe
   Diagonale also höchstens rund 71vmax — der Kreis deckt sie damit sicher
   vollständig ab, ohne dass irgendetwas über den Bildschirm hinausragt.

   Die beiden Grenzen sind nicht geschätzt, sondern am laufenden Entwurf
   ausgemessen: Bei 36 % hat die letzte Karte den Bildschirm gerade
   verlassen — vorher ginge der Kreis hinter ihr auf. Bei 69 % schiebt sich
   die echte Ergebnis-Fläche von unten ins Bild; ist der Kreis bis dahin
   nicht fertig, schneidet ihre gerade Oberkante ihn sichtbar ab. Dazwischen
   liegt das Wachstum. Der Kreis hält sich anfangs zurück und öffnet sich
   dann zügig, bleibt dabei aber durchgehend am Scrollen hängen: keine
   Zeitkurve, die eigenmächtig losläuft. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .ablauf-punkt-flaeche { animation: flaeche-auf 1s both;
      animation-timing-function: cubic-bezier(0.55, 0, 0.85, 0.5);
      animation-timeline: --punkt-lauf; animation-range: cover 36% cover 68%; }
  }
}
@keyframes flaeche-auf { from { clip-path: circle(10px at var(--punkt-x) 50%); }
  to { clip-path: circle(var(--punkt-radius-max) at var(--punkt-x) 50%); } }

/* Zwei Animationen je Karte, die sich nicht ins Gehege kommen, weil sie
   verschiedene Eigenschaften bewegen: das Hereingleiten (Deckkraft und
   Position) und das Aufleuchten des Rahmens. Beide hängen an der eigenen
   Sichtbarkeit der Karte, brauchen aber verschiedene Abschnitte davon —
   deshalb zwei Werte in animation-range, in derselben Reihenfolge wie die
   Animationen selbst.

   Die Markierung sitzt um 50 % herum, weil genau dort die Karte die
   Bildschirmmitte passiert — und dort steht der festgehaltene Punkt. Die
   Ränder (38 % / 62 %) entsprechen dem Moment, in dem Ober- bzw. Unterkante
   der Karte diese Mitte kreuzen; bei anderer Bildschirmhöhe verschieben
   sie sich nur um wenige Prozent, die Markierung bleibt also mittig. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .ablauf-links .ablauf-karte { animation: von-links 520ms ease-out both,
      karte-markieren 1s linear both;
      animation-timeline: view(), view();
      animation-range: cover 28% cover 55%, cover 30% cover 70%; }
    .ablauf-rechts .ablauf-karte { animation: von-rechts 520ms ease-out both,
      karte-markieren 1s linear both;
      animation-timeline: view(), view();
      animation-range: cover 28% cover 55%, cover 30% cover 70%; }
    .ablauf-verbinder { animation: linie-markieren 1s linear both;
      animation-timeline: view(); animation-range: cover 30% cover 70%; }
  }
}
@keyframes von-links  { from { opacity: 0; transform: translateX(calc(-1 * var(--karte-versatz))); }
  to { opacity: 1; transform: none; } }
@keyframes von-rechts { from { opacity: 0; transform: translateX(var(--karte-versatz)); }
  to { opacity: 1; transform: none; } }

/* Prozentwerte innerhalb des Bereichs 30–70 %: 0 % entspricht cover 30 %,
   100 % entspricht cover 70 %. Die Karte steht also bei 50 % mittig. */
@keyframes karte-markieren {
  0%, 20%    { border-color: var(--linie); }
  30%, 70%   { border-color: var(--akzent); }
  80%, 100%  { border-color: var(--linie); } }
@keyframes linie-markieren {
  0%, 30%    { background: var(--linie); }
  45%, 55%   { background: var(--akzent); }
  70%, 100%  { background: var(--linie); } }

@media (max-width: 56rem) {
  .ablauf-spur { left: 10px; }
  /* Der Punkt bleibt sticky und poppt am Ende zur Goldfläche auf wie am
     Desktop — nur eben nicht mittig, sondern auf der Randlinie, damit er
     nicht über den linksbündigen Karten schwebt. Fläche und Punkt sitzen
     beide in der 2px schmalen Spur (.ablauf-spur, jetzt selbst auf
     left: 10px verschoben, ihr Rand-zu-Rand-Versatz dadurch 9px — die
     halbe Spurbreite abzüglich ihrer eigenen 10px), brauchen deshalb aber
     UNTERSCHIEDLICHE Korrekturen, weil eine der --punkt-x-Wert relativ zur
     Spur liest (Punkt) und die andere relativ zu ihrer eigenen, neu
     zentrierten Box (Fläche) — ohne Anpassung landen beide zwar nah
     beieinander, aber sichtbar versetzt (der "Doppelpunkt"-Effekt):
     - Die Fläche (100vw × 100vh) hebt den Spur-Versatz per
       calc(50vw - 9px) exakt auf und sitzt wieder echt bildschirmzentriert
       — sonst reicht ihr rechter Rand nicht mehr bis zur rechten
       Bildschirmkante (siehe Kommentar weiter oben). Der clip-path-Kreis
       darin (--punkt-x) ist danach relativ zu DIESER Box gemeint, landet
       also bei genau 10px echtem Bildschirmabstand.
     - Der sichtbare Punkt bleibt dagegen relativ zur Spur positioniert
       (kein left-Fix nötig), braucht aber den umgekehrten Ausgleich: 1px
       statt 10px, damit sein Mittelpunkt (Spur-Versatz 9px + 1px) auf
       dieselben echten 10px trifft wie der Kreis-Ursprung der Fläche. */
  .ablauf-punkt-flaeche { left: calc(50vw - 9px); --punkt-x: 10px; }
  .ablauf-punkt { --punkt-x: 1px; }
  /* 150vmax statt 75vmax: Bei den breiten, aber flachen Fenstern, die
     dieser Breakpoint auch abdeckt (Tablets quer, kurze Browserfenster),
     reicht ein Radius von 75vmax nicht mehr bis in die vom Rand
     entferntesten Ecken — sichtbar als Kante, an der das Gold aufhört,
     bevor der Bildschirm wirklich voll ist. 150vmax deckt auch diese
     Fälle sicher ab; bei der zentrierten Desktop-Variante wächst der
     Kreis dadurch nur unsichtbar etwas über den ohnehin schon vollen
     Bildschirm hinaus. */
  .ablauf-punkt-flaeche { --punkt-radius-max: 150vmax; }
  /* Rechts derselbe Seitenabstand wie überall sonst auf der Seite: vorher
     stand die Karte bündig an der Bildschirmkante, ihr rechter Rahmen fiel
     mit dem Rand des Fensters zusammen. */
  .ablauf-schritt, .ablauf-links, .ablauf-rechts { justify-content: flex-start;
    padding-left: calc(10px + var(--s-lg)); padding-right: var(--rand); min-height: 0;
    margin-bottom: var(--s-lg); }
  .ablauf-verbinder { display: none; }
  .ablauf-karte { max-width: none; }
}

/* ─────────────── Ergebnis: die große Fläche ─────────────── */
/* Kein eigener Aufreiß-Effekt mehr an dieser Stelle: Die Fläche ist die
   Fortsetzung des Punkts, der weiter oben in der Leerstrecke bereits zur
   vollen Bildschirmgröße gewachsen ist (siehe .ablauf-punkt-flaeche) —
   in derselben Goldfarbe, sodass der Übergang nahtlos ist, sobald der
   fixierte Punkt sich löst und die echte Fläche darunter durchscrollt. */
/* Die Sektion ist deutlich höher als der Bildschirm (min-height: 230vh) und
   der eigentliche Inhalt sitzt in .ergebnis-buehne, die sticky oben bleibt,
   solange die Sektion durchscrollt wird. Dadurch bleibt man auf dieser
   Seite optisch "hängen", während phone-scroll.js die zusätzliche
   Scroll-Strecke nutzt, um das iPhone einmal ganz um sich selbst zu
   drehen — erst wenn die Drehung fertig ist und die Sektion zu Ende
   gescrollt, gibt sie den Weg zu Kontakt frei. Kein scroll-snap mehr hier:
   Das kollidierte mit Lenis' eigener Glättung (app.js, ergebnisPolster) und
   fühlte sich wie ein zweites, hartes Einrasten obendrauf an. Dass man
   nicht einfach durchscrollen kann, übernimmt jetzt allein die spürbare
   Reaktionsträgheit dort. */
.ergebnis { position: relative; background: var(--flaeche); color: var(--auf-akzent);
  border-top: 0; overflow: clip; min-height: 230vh; }
.ergebnis-buehne { position: sticky; top: 0; min-height: 100vh; min-height: 100svh;
  display: flex; align-items: center; }
.ergebnis-innen { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1.15fr);
  gap: var(--s-2xl); align-items: center; padding-block: var(--s-2xl); width: 100%; }
.ergebnis .kopfzeile { color: oklch(100% 0 0 / 0.72); }
.ergebnis h2 { font-size: var(--t-2xl); }
.ergebnis p:not(.kopfzeile) { color: oklch(100% 0 0 / 0.9); font-size: var(--t-lg); max-width: 28rem; }
.ergebnis .knopf { background: var(--auf-akzent); color: var(--grund); border-color: var(--auf-akzent); }
.ergebnis .knopf:hover { background: oklch(94% 0.025 266); border-color: oklch(94% 0.025 266); }

/* iPhone-Szene (3D, scroll-gekoppelt) mit Platzhalter-Bildschirm */
.geraet-iphone-buehne { position: relative; width: min(100%, 22rem); aspect-ratio: 3 / 4;
  margin-inline: auto; }
.geraet-iphone { position: absolute; inset: 0; width: 100%; height: 100%; --poster-color: transparent; }

@media (max-width: 56rem) {
  .ergebnis-innen { grid-template-columns: minmax(0,1fr); text-align: center; }
  .ergebnis p:not(.kopfzeile) { margin-inline: auto; }
}

/* ─────────────── Kontakt ─────────────── */
.kontakt { background: var(--grund-2); }
.kontakt-innen { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: var(--s-xl); align-items: start; }
.kontakt-weg + .kontakt-weg { margin-top: var(--s-lg); }
.gross { display: inline-block; font-family: var(--zahl); font-size: var(--t-xl);
  letter-spacing: -0.02em; color: var(--akzent); text-decoration: none;
  transition: color var(--schnell) var(--raus); }
.gross:hover { color: var(--text); }
.kontakt-weg p { font-size: var(--t-sm); color: var(--text-2); margin-top: var(--s-2xs); }
@media (max-width: 56rem) { .kontakt-innen { grid-template-columns: minmax(0,1fr); } }

/* ─────────────── Fuß ─────────────── */
.fuss { border-top: 1px solid var(--linie); padding-block: var(--s-xl) var(--s-lg); }
.fuss-oben { display: flex; flex-wrap: wrap; justify-content: space-between;
  align-items: center; gap: var(--s-md); }
.fuss-marke { display: inline-flex; align-items: center; gap: var(--s-2xs); font-weight: 600; }
.fuss-marke img { width: 20px; height: 20px; }
.fuss-links { display: flex; gap: var(--s-md); flex-wrap: wrap; }
.fuss-links a { text-decoration: none; font-size: var(--t-sm); color: var(--text-2);
  transition: color var(--schnell) var(--raus); }
.fuss-links a:hover { color: var(--text); }
.fuss-hinweis { margin-top: var(--s-lg); padding-top: var(--s-md); border-top: 1px solid var(--linie-2); }
.fuss-hinweis p { font-size: var(--t-xs); color: var(--leise); margin: 0; max-width: none; }

@media (max-width: 40rem) {
  .abschnitt { padding-block: var(--s-xl); }
}

/* ─────────────── Einfache Unterseiten: Impressum, Datenschutz ─────────────── */
.seiten-kopf { border-top: 0; padding-block: var(--s-xl) var(--s-lg); }
.seiten-kopf h1 { font-size: clamp(1.8rem, 4vw, 2.6rem); max-width: 24ch; }
.krume { font-size: var(--t-xs); color: var(--leise); margin: 0 0 var(--s-md); }
.krume a { color: inherit; text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: var(--linie); transition: color var(--schnell) var(--raus); }
.krume a:hover { color: var(--text); }

/* Reduzierte Bewegung heißt weniger, nicht null: Scroll- und Endlos-
   Animationen fallen weg, kurze Überblendungen bleiben (siehe unten). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Feinschliff: Bewegung, Tastgefühl, Telefon.
   Steht bewusst am Ende und überschreibt gezielt, statt die Regeln oben
   umzuschreiben — so bleibt nachvollziehbar, was Grundlage und was
   Politur ist. Leitlinien: nur transform und opacity bewegen, eigene
   Kurven statt der schwachen Standardkurven, Rückmeldung beim Drücken,
   Hover nur bei echter Maus, alles unter prefers-reduced-motion ruhig.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --raus-stark: cubic-bezier(0.23, 1, 0.32, 1);
  --hin-her:    cubic-bezier(0.77, 0, 0.175, 1);
  --schublade:  cubic-bezier(0.32, 0.72, 0, 1);
  --leiste-h: 4.1rem;
}
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 260ms; }

html { scroll-padding-top: calc(var(--leiste-h) + 0.5rem); -webkit-tap-highlight-color: transparent; }
body { text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; }
::selection { background: oklch(53% 0.215 266 / 0.9); color: var(--auf-akzent); }
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

/* Feines Korn über der ganzen Seite: nimmt den Flächen das Digital-Glatte.
   Eine einzige feste Ebene, keine Mischmodi, damit Scrollen billig bleibt. */
body::after { content: ""; position: fixed; inset: 0; z-index: 950; pointer-events: none;
  opacity: 0.045;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='k'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23k)'/%3E%3C/svg%3E"); }

/* ─────────────── Kopfleiste: klebt oben, weicht beim Lesen aus ─────────────── */
.leiste { position: sticky; top: 0; z-index: 60;
  background: oklch(15.5% 0.028 265 / 0.72);
  -webkit-backdrop-filter: blur(14px) saturate(140%); backdrop-filter: blur(14px) saturate(140%);
  border-bottom-color: transparent;
  transition: transform 300ms var(--schublade), border-color 200ms ease, background-color 200ms ease; }
.leiste.ist-gescrollt { border-bottom-color: var(--linie-2); }
.leiste.ist-weg { transform: translateY(-101%); }
.leiste-innen { padding-block: var(--s-2xs); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .leiste { background: var(--grund); }
}
/* Lesefaden: wie weit die Seite gelesen ist, direkt an der Scroll-Leiste. */
.leiste-faden { position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--akzent); transform-origin: left; transform: scaleX(0); opacity: 0.9; }
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .leiste-faden { animation: faden linear both; animation-timeline: scroll(root); }
  }
}
@keyframes faden { to { transform: scaleX(1); } }

.marke-zeichen { display: block; color: var(--text); overflow: visible; }
.haupt a::after { content: ""; position: absolute; left: 0; right: 0; bottom: 10px; height: 1px;
  background: var(--akzent); transform: scaleX(0); transform-origin: right;
  transition: transform 260ms var(--raus-stark); }
.haupt a[aria-current]::after { transform: scaleX(1); transform-origin: left; }
.haupt a[aria-current] { color: var(--text); }
@media (hover: hover) and (pointer: fine) {
  .haupt a:hover::after { transform: scaleX(1); transform-origin: left; }
}
/* Trefferflächen mindestens 44px, ohne die Zeile zu vergrößern. */
.haupt a::before, .leiste-tel::before, .fuss-links a::before { content: ""; position: absolute; inset: -6px -8px; }
.fuss-links a { position: relative; }

/* ─────────────── Hero ─────────────── */
.hero { isolation: isolate; }
.kopf-wache { position: absolute; top: 0; left: 0; width: 1px; height: 1px; pointer-events: none; }
.feld { position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0;
  transition: opacity 1.4s ease;
  /* Hinter der Überschrift ruhiger, zum Foto hin kräftiger. */
  -webkit-mask-image: linear-gradient(100deg, rgb(0 0 0 / 0.28) 0%, rgb(0 0 0 / 0.5) 40%, #000 70%);
          mask-image: linear-gradient(100deg, rgb(0 0 0 / 0.28) 0%, rgb(0 0 0 / 0.5) 40%, #000 70%); }
.feld.ist-bereit { opacity: 1; }
.hero-innen { z-index: 1; }
@media (min-width: 60.01rem) {
  .hero { min-height: calc(100svh - var(--leiste-h)); display: grid; align-items: center; }
  .hero-innen { padding-block: var(--s-xl) var(--s-2xl); }
}

/* Die Markierung unter den beiden Schlüsselwörtern zieht sich nach dem
   Laden einmal durch. background-size statt Pseudo-Element: bricht ein
   Wort um, läuft der Strich über beide Zeilen mit. */
.hero mark {
  background-image: linear-gradient(oklch(71% 0.16 266 / 0.24), oklch(71% 0.16 266 / 0.24));
  background-repeat: no-repeat; background-position: 0 88%; background-size: 100% 0.28em;
  -webkit-box-decoration-break: clone; box-decoration-break: clone; }

@media (prefers-reduced-motion: no-preference) {
  .hero-text > *, .hero-bild-feld { animation: auftritt 900ms var(--raus-stark) both; }
  .hero h1           { animation-delay: 60ms; }
  .hero .hero-blei   { animation-delay: 160ms; }
  .hero .wege        { animation-delay: 240ms; }
  .hero-bild-feld    { animation-delay: 120ms; animation-duration: 1100ms; }
  .hero mark { animation: strich 900ms var(--hin-her) 700ms forwards; background-size: 0% 0.28em; }
  .hero h1 mark:nth-of-type(2) { animation-delay: 950ms; }
  .marke-zeichen path { stroke-dasharray: 1; stroke-dashoffset: 1;
    animation: zeichnen 1100ms var(--hin-her) forwards; }
  .marke-zeichen path:nth-child(2) { animation-delay: 90ms; }
  .marke-zeichen path:nth-child(3) { animation-delay: 180ms; }
  .marke-zeichen path:nth-child(4) { animation-delay: 270ms; }
}
/* Startet bei kaum sichtbar statt unsichtbar: Das Element gilt damit für
   die Ladezeitmessung (LCP) sofort als gemalt. */
@keyframes auftritt { from { opacity: 0.01; transform: translateY(14px); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: blur(0); } }
@keyframes strich { to { background-size: 100% 0.28em; } }
@keyframes zeichnen { to { stroke-dashoffset: 0; } }

/* Foto neigt sich zur Maus, mit einem Glanz, der mitwandert. */
.hero-foto { transform-style: preserve-3d; will-change: transform; }
.hero-foto::after { content: ""; position: absolute; inset: 0; border-radius: 10px; pointer-events: none;
  background: radial-gradient(circle at var(--glanz-x, 50%) var(--glanz-y, 50%),
    oklch(100% 0 0 / 0.16), transparent 55%);
  opacity: 0; transition: opacity 300ms ease; }
.hero-foto.ist-geneigt::after { opacity: 1; }
.hero-foto img { box-shadow: 0 30px 60px -30px oklch(8% 0.03 265 / 0.9), 0 0 0 1px oklch(100% 0 0 / 0.06); }

@media (max-width: 60rem) {
  .hero-innen { gap: var(--s-xl); padding-block: var(--s-lg) var(--s-xl); }
  .hero-foto { max-width: 13rem; }
  .feld { -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.55), rgb(0 0 0 / 0.7) 45%, #000 75%);
                  mask-image: linear-gradient(to bottom, rgb(0 0 0 / 0.55), rgb(0 0 0 / 0.7) 45%, #000 75%); }
}
@media (max-width: 30rem) {
  :root { --t-h1: 2.05rem; }
  .hero-blei { font-size: var(--t-base); }
  .wege { margin-top: var(--s-md); }
  .knopf { width: 100%; justify-content: center; }
}

/* ─────────────── Knöpfe: drückbar, magnetisch, mit Lichtkante ─────────────── */
.knopf { overflow: hidden; isolation: isolate; -webkit-user-select: none; user-select: none;
  transition: background-color 160ms ease, border-color 160ms ease, translate 380ms var(--raus-stark),
    scale 160ms var(--raus-stark), box-shadow 220ms ease;
  box-shadow: 0 10px 30px -14px oklch(53% 0.215 266 / 0.6); }
.knopf:hover { transform: none; }
.knopf:active { scale: 0.97; transition-duration: 160ms, 160ms, 380ms, 120ms, 220ms; }
.knopf::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(120px circle at var(--licht-x, 50%) 50%, oklch(100% 0 0 / 0.35), transparent 70%);
  opacity: 0; transition: opacity 220ms ease; }
@media (hover: hover) and (pointer: fine) {
  .knopf:hover::before { opacity: 1; }
  .knopf:hover { box-shadow: 0 14px 34px -12px oklch(53% 0.215 266 / 0.75); }
}
.ergebnis .knopf { box-shadow: 0 12px 30px -14px oklch(12% 0.05 266 / 0.55); }
.ergebnis .knopf::before { background: radial-gradient(120px circle at var(--licht-x, 50%) 50%, oklch(55% 0.2 266 / 0.32), transparent 70%); }
.anruf:active, .gross:active, .haupt a:active, .leiste-tel:active { opacity: 0.7; }

/* ─────────────── Lichtkante an Karten und Abbildungen ─────────────── */
.lichtkante { position: relative; }
.lichtkante::after { content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none;
  padding: 1px;
  background: radial-gradient(260px circle at var(--zx, -300px) var(--zy, -300px), oklch(71% 0.16 266 / 0.8), transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  opacity: 0; transition: opacity 250ms ease; }
.lichtkante:hover::after { opacity: 1; }

/* ─────────────── Eigener Zeiger ───────────────
   Nur bei echter Maus (app.js prüft hover:hover/pointer:fine) und nur,
   wenn JavaScript läuft — ohne die Klasse .zeiger-eigen bleibt der normale
   Systemzeiger, die Seite verlangt also nichts Unmögliches von sich selbst.
   Punkt sitzt exakt am Zeiger, der Ring läuft ihm gedämpft hinterher. */
html.zeiger-eigen, html.zeiger-eigen a, html.zeiger-eigen button, html.zeiger-eigen .knopf { cursor: none; }
.zeiger-punkt, .zeiger-ring { position: fixed; top: 0; left: 0; z-index: 999; pointer-events: none;
  border-radius: 50%; }
.zeiger-punkt { width: 6px; height: 6px; background: var(--akzent); opacity: 0;
  transition: opacity 200ms ease, scale 200ms var(--raus); }
.zeiger-ring { width: 34px; height: 34px; border: 1.5px solid oklch(71% 0.16 266 / 0.55); opacity: 0;
  transition: opacity 200ms ease, scale 280ms var(--raus), border-color 280ms var(--raus); }
html.zeiger-eigen.zeiger-da .zeiger-punkt, html.zeiger-eigen.zeiger-da .zeiger-ring { opacity: 1; }
html.zeiger-eigen.zeiger-aktiv .zeiger-ring { scale: 1.7; border-color: oklch(71% 0.16 266 / 0.85); }
html.zeiger-eigen.zeiger-aktiv .zeiger-punkt { scale: 0; }
html.zeiger-eigen.zeiger-druck .zeiger-ring { scale: 0.85; }
@media (prefers-reduced-motion: reduce), (hover: none), (pointer: coarse) {
  .zeiger-punkt, .zeiger-ring { display: none; }
}

/* ─────────────── Leistungen ─────────────── */
/* Das Suchfeld tippt sich beim Hereinscrollen selbst voll. */
.such-eingabe { position: relative; transform-origin: left; }
.such-eingabe::after { content: ""; position: absolute; right: -4px; top: -3px; width: 1px; height: 12px;
  background: #252b38; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .such-eingabe { animation: tippen linear both; animation-timeline: view();
      animation-range: cover 6% cover 22%; }
    .such-eingabe::after { animation: cursor 1s steps(2, start) infinite; }
  }
}
@keyframes tippen { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes cursor { to { visibility: hidden; } }

.laden-echt { margin-top: var(--s-2xs); font-size: var(--t-xs); color: var(--leise);
  max-width: 26rem; text-align: left; align-self: stretch; }
.laden-echt .zahl { color: var(--akzent); font-size: 1em; }
@media (min-width: 52.01rem) { .zeile-bild .laden-echt { align-self: center; width: min(100%, 26rem); } }

@media (hover: hover) and (pointer: fine) {
  .mini-geraet { transition: translate 260ms var(--raus-stark); }
  .mini-geraete:hover .mini-geraet { translate: 0 2px; }
  .mini-geraete .mini-geraet:hover { translate: 0 -8px; }
}

/* ─────────────── Ablauf: auf dem Telefon von unten statt von der Seite ───────────────
   Seitlich hereingleitende Karten ragten auf schmalen Bildschirmen über den
   rechten Rand hinaus. Dort kommt jede Karte deshalb von unten. */
@media (max-width: 56rem) {
  .ablauf-karte { border-radius: 6px; }
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) and (max-width: 56rem) {
    .ablauf-links .ablauf-karte, .ablauf-rechts .ablauf-karte {
      animation-name: karte-hoch, karte-markieren;
      animation-range: cover 5% cover 30%, cover 25% cover 75%; }
  }
}
@keyframes karte-hoch { from { opacity: 0; transform: translateY(28px) scale(0.98); } to { opacity: 1; transform: none; } }

/* ─────────────── Ergebnis ─────────────── */
.ergebnis h2 { margin-bottom: var(--s-sm); }
.ergebnis .knopf { margin-top: var(--s-2xs); }
.geraet-iphone { opacity: 0; transition: opacity 700ms ease; }
.geraet-iphone.ist-geladen { opacity: 1; }
@media (max-width: 56rem) {
  .ergebnis-innen { gap: var(--s-md); padding-block: var(--s-lg); }
  .ergebnis h2 { font-size: clamp(1.6rem, 7vw, var(--t-2xl)); }
  .ergebnis p:not(.kopfzeile) { font-size: var(--t-base); }
  /* Gerät passt samt Text in einen Bildschirm, auch mit Adressleiste. */
  .geraet-iphone-buehne { width: auto; height: min(42svh, 24rem); aspect-ratio: 3 / 4; }
}

/* ─────────────── Kontakt ─────────────── */
.gross { position: relative; }
.gross::after { content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform 250ms var(--raus-stark); }
@media (hover: hover) and (pointer: fine) {
  .gross:hover::after { transform: scaleX(1); transform-origin: left; }
}
.mail-zeile { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-xs) var(--s-sm); }
.kopieren { position: relative; display: inline-grid; min-height: 36px; padding: 0 var(--s-sm);
  font: inherit; font-size: var(--t-xs); letter-spacing: 0.04em; color: var(--text-2);
  background: var(--grund-3); border: 1px solid var(--linie); border-radius: 999px; cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease, scale 120ms var(--raus-stark); }
.kopieren::before { content: ""; position: absolute; inset: -6px; }
.kopieren:active { scale: 0.96; }
@media (hover: hover) and (pointer: fine) { .kopieren:hover { color: var(--text); border-color: var(--text-2); } }
.kopieren-text { grid-area: 1 / 1; align-self: center; text-align: center;
  transition: opacity 200ms ease, filter 200ms ease, transform 200ms var(--raus-stark); }
.kopieren-text[data-zustand="fertig"] { opacity: 0; filter: blur(3px); transform: translateY(4px); color: var(--akzent); }
.kopieren.ist-kopiert .kopieren-text[data-zustand="bereit"] { opacity: 0; filter: blur(3px); transform: translateY(-4px); }
.kopieren.ist-kopiert .kopieren-text[data-zustand="fertig"] { opacity: 1; filter: none; transform: none; }
.kopieren.ist-kopiert { border-color: var(--akzent); }
@media (max-width: 30rem) { .gross { font-size: 1.28rem; } }

/* ─────────────── Schwebender Anruf-Knopf (nur schmale Bildschirme) ─────────────── */
.anruf-schwebe { display: none; }
@media (max-width: 40rem) {
  .anruf-schwebe { position: fixed; z-index: 70; right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    display: inline-flex; align-items: center; gap: 0.55rem; min-height: 52px; padding: 0 1.15rem 0 1rem;
    border-radius: 999px; background: var(--flaeche); color: var(--auf-akzent); text-decoration: none;
    font-weight: 600; font-size: var(--t-sm);
    box-shadow: 0 16px 34px -12px oklch(8% 0.03 265 / 0.8), 0 0 0 1px oklch(100% 0 0 / 0.12) inset;
    opacity: 0; transform: translateY(18px) scale(0.96); pointer-events: none;
    transition: opacity 220ms ease, transform 320ms var(--raus-stark), scale 120ms var(--raus-stark); }
  .anruf-schwebe.ist-da { opacity: 1; transform: none; pointer-events: auto; }
  .anruf-schwebe:active { scale: 0.96; }
  .anruf-schwebe svg { width: 18px; height: 18px; flex: none; }
  .anruf-schwebe .zahl { font-size: 0.95em; }
}

/* ─────────────── Mobile Feinheiten ─────────────── */
@media (max-width: 40rem) {
  :root { --leiste-h: 3.6rem; }
  .leiste-innen { gap: var(--s-2xs) var(--s-md); }
  .haupt { gap: var(--s-sm); }
  .zeilen { gap: var(--s-xl); margin-top: var(--s-xl); }
  .kontakt-weg + .kontakt-weg { margin-top: var(--s-md); }
  .fuss-links { gap: var(--s-2xs) var(--s-md); }
  .fuss-links a { min-height: 40px; display: inline-flex; align-items: center; }
}
/* Luft zwischen Abschnittsüberschrift und Einleitung. */
.h2 + .blei, .ergebnis h2 + p { margin-top: var(--s-sm); }

/* ─────────────── Hero-Foto: bleibt länger neben dem Text ───────────────
   Vorher sprang das Foto schon unter 60rem (halbes Laptopfenster, Tablet)
   unter den Text. Jetzt bleibt es bis 40rem daneben und wird nur kleiner.
   Auf dem Telefon folgt es nach dem Text: erst das Angebot, dann das
   Gesicht dazu. Immer im natürlichen Hochformat, nie beschnitten, und
   bündig mit der Textkante statt frei in der Mitte schwebend. */
@media (min-width: 40.01rem) and (max-width: 60rem) {
  .hero-innen { grid-template-columns: minmax(0, 1.4fr) minmax(0, 0.9fr);
    gap: var(--s-xl); align-items: center; }
  .hero h1 { font-size: clamp(1.9rem, 4.6vw, 2.6rem); }
  .hero-foto { max-width: 17rem; }
  .hero { min-height: calc(100svh - var(--leiste-h)); display: grid; align-items: center; }
}
@media (max-width: 40rem) {
  .hero-innen { gap: var(--s-xl); }
  .hero-bild-feld { justify-items: start; }
  .hero-foto { width: min(100%, 16rem); max-width: none; margin-inline: 0; }
  .hero-foto img { width: 100%; height: auto; aspect-ratio: 4 / 5; }
}
/* Auf der kräftigen Kobaltfläche braucht der Fokusring Weiß statt Kobalt. */
.ergebnis :focus-visible { outline-color: #fff; }

/* ─────────────── Ablauf auf dem Telefon: Linie an der Textkante ───────────────
   Vorher lief die Linie 10px vom Bildschirmrand, der Punkt klebte fast an
   der Kante. Jetzt sitzt sie genau auf dem Seitenrand (--rand), also
   bündig mit Überschriften und Text darüber. Dieselbe Rechnung wie oben,
   nur mit --spur-x statt der festen 10px: Die Spur ist 2px breit und
   beginnt deshalb 1px vor ihrer Mitte. */
@media (max-width: 56rem) {
  .ablauf-szene { --spur-x: var(--rand); }
  .ablauf-spur { left: var(--spur-x); }
  .ablauf-punkt-flaeche { left: calc(50vw - var(--spur-x) + 1px); --punkt-x: var(--spur-x); }
  .ablauf-punkt { --punkt-x: 1px; }
  .ablauf-schritt, .ablauf-links, .ablauf-rechts {
    padding-left: calc(var(--spur-x) + var(--s-md)); padding-right: var(--rand); }
}

/* ═══════════════════════════════════════════════════════════════════════
   Einmal einblenden (app.js setzt .einmal und je Block .ist-sichtbar).
   Ersetzt die an den Scroll gekoppelten Einblendungen: Die liefen beim
   Zurückscrollen rückwärts und spielten bei jedem Vorbeiscrollen neu.
   Jetzt passiert jede Einblendung genau einmal, mit starker ease-out-Kurve
   und kurzer Staffelung. Ohne JavaScript bleibt alles sofort sichtbar.
   ═══════════════════════════════════════════════════════════════════════ */
.js.einmal :is(.auftauchen, .zeile-text, .zeile-bild, .such-treffer li, .laden-teil,
  .laden-fuellung, .laden-fertig, .mini-geraet, .mini-telefon, .such-eingabe) { animation: none; }

/* Texte: steigen auf, Überschriften zusätzlich aus einer unsichtbaren Kante. */
.js.einmal .auftauchen { transition: opacity 700ms var(--raus-stark), transform 900ms var(--raus-stark),
  clip-path 900ms var(--raus-stark); transition-delay: var(--verz, 0ms); }
.js.einmal .auftauchen:not(.ist-sichtbar) { opacity: 0; transform: translateY(18px); }
/* Überschriften bekommen zusätzlich Schärfe und Größe als Bewegung dazu
   (kinetische Typografie) — bleibt aber derselbe einmalige Auftritt wie
   bei jedem anderen Text, kein an den Scroll gekoppeltes Scrubben. */
.js.einmal :is(.h2, h2).auftauchen { transition: opacity 700ms var(--raus-stark), transform 950ms var(--raus-stark),
  clip-path 950ms var(--raus-stark), filter 750ms var(--raus-stark); clip-path: inset(-0.2em -0.2em -0.3em -0.2em); }
.js.einmal :is(.h2, h2).auftauchen:not(.ist-sichtbar) { transform: translateY(0.55em) scale(0.94);
  clip-path: inset(0 0 100% 0); filter: blur(7px); }

/* Leistungs-Zeilen: erst der Text, dann die Abbildung. */
.js.einmal .zeile :is(.zeile-text, .zeile-bild) {
  transition: opacity 800ms var(--raus-stark), transform 900ms var(--raus-stark); }
.js.einmal .zeile .zeile-bild { transition-delay: 120ms; }
.js.einmal .zeile:not(.ist-sichtbar) .zeile-text { opacity: 0; transform: translateY(20px); }
.js.einmal .zeile:not(.ist-sichtbar) .zeile-bild { opacity: 0; transform: translateY(28px) scale(0.98); }

/* Suche: Das Feld tippt sich voll, danach kommen die Treffer, Ihre Seite zuletzt
   und mit ihrer Markierung, die von oben nach unten aufgeht. */
.js.einmal .such-eingabe { clip-path: inset(0 0 0 0); transition: clip-path 650ms steps(12, end) 350ms; }
.js.einmal .zeile:not(.ist-sichtbar) .such-eingabe { clip-path: inset(0 100% 0 0); }
.js.einmal .such-treffer li { transition: opacity 450ms var(--raus-stark), transform 550ms var(--raus-stark);
  transition-delay: calc(1000ms + var(--n, 0) * 70ms); }
.such-treffer li:nth-child(2) { --n: 3; }
.such-treffer li:nth-child(3) { --n: 1; }
.such-treffer li:nth-child(4) { --n: 2; }
.js.einmal .zeile:not(.ist-sichtbar) .such-treffer li { opacity: 0; transform: translateY(8px); }
.js.einmal .such-treffer .ihre::before { transform-origin: top;
  transition: transform 500ms var(--raus-stark) 1420ms; }
.js.einmal .zeile:not(.ist-sichtbar) .such-treffer .ihre::before { transform: scaleY(0); }

/* Geräte: wachsen nacheinander ein, das Telefon dreht sich dabei in die Frontale. */
.js.einmal .mini-geraet { transform-origin: bottom;
  transition: opacity 600ms var(--raus-stark), transform 900ms var(--raus-stark), translate 260ms var(--raus-stark);
  transition-delay: calc(220ms + var(--n, 0) * 90ms), calc(220ms + var(--n, 0) * 90ms), 0ms; }
.mini-tablet { --n: 1; } .mini-laptop { --n: 2; }
.js.einmal .zeile:not(.ist-sichtbar) .mini-geraet { opacity: 0; transform: translateY(18px) scale(0.94); }
.js.einmal .zeile:not(.ist-sichtbar) .mini-telefon { transform: perspective(700px) translateY(18px) rotateY(-35deg) scale(0.94); }

/* Laden: Die Seite baut sich in echter Zeit auf, während der Balken vollläuft.
   Der Balken ist ein Fortschritt und läuft deshalb linear (0,9 s). */
.js.einmal .laden-teil { transition: opacity 350ms var(--raus-stark), transform 450ms var(--raus-stark);
  transition-delay: calc(300ms + var(--n, 0) * 160ms); }
.laden-teil.t2 { --n: 1; } .laden-teil.t3 { --n: 2; } .laden-reihe .laden-teil { --n: 3; }
.js.einmal .zeile:not(.ist-sichtbar) .laden-teil { opacity: 0; transform: translateY(6px); }
.js.einmal .laden-fuellung { transition: transform 900ms linear 300ms; }
.js.einmal .zeile:not(.ist-sichtbar) .laden-fuellung { transform: scaleX(0); }
.js.einmal .laden-fertig { transition: opacity 300ms ease 1220ms, transform 400ms var(--raus-stark) 1220ms; }
.js.einmal .zeile:not(.ist-sichtbar) .laden-fertig { opacity: 0; transform: translateY(4px); }
.js.einmal .laden-echt { transition: opacity 500ms ease 1150ms; }
.js.einmal .zeile:not(.ist-sichtbar) .laden-echt { opacity: 0; }

/* Ergebnis: Sobald die Fläche steht, kommen Kopfzeile, Überschrift, Text und
   Knopf nacheinander dazu. */
.js.einmal .ergebnis-innen > div:first-child > * {
  transition: opacity 700ms var(--raus-stark), transform 900ms var(--raus-stark);
  transition-delay: calc(var(--n, 0) * 80ms + 100ms); }
.js.einmal .ergebnis-innen > div:first-child > :nth-child(2) { --n: 1; }
.js.einmal .ergebnis-innen > div:first-child > :nth-child(3) { --n: 2; }
.js.einmal .ergebnis-innen > div:first-child > :nth-child(4) { --n: 3; }
.js.einmal .ergebnis-innen:not(.ist-sichtbar) > div:first-child > * { opacity: 0; transform: translateY(18px); }

/* Browser ohne Scroll-Zeitleiste: Ablauf-Karten einmal einblenden. */
.js.ohne-zeitleiste .ablauf-karte { transition: opacity 700ms var(--raus-stark), transform 800ms var(--raus-stark); }
.js.ohne-zeitleiste .ablauf-karte:not(.ist-sichtbar) { opacity: 0; transform: translateY(20px); }

/* ─────────────── Hero-Auftritt: Wort für Wort ───────────────
   Die Überschrift setzt sich Wort für Wort zusammen (45 ms Versatz), jedes
   Wort steigt leicht auf und wird scharf. Das Foto öffnet sich danach wie
   ein Vorhang von unten, das Bild darin zoomt dabei sanft auf seine Größe. */
.hero h1 .w { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .hero h1 { animation: none; }
  .hero h1 .w { animation: wort 800ms var(--raus-stark) both;
    animation-delay: calc(80ms + var(--i) * 45ms); }
  .hero .hero-blei { animation-delay: 620ms; }
  .hero .wege      { animation-delay: 720ms; }
  .hero mark { animation-delay: 1000ms; }
  .hero h1 mark:nth-of-type(1) { animation-delay: 1000ms; }
  .hero h1 .w:nth-child(9) mark { animation-delay: 1250ms; }
  .hero-bild-feld { animation: none; }
  .hero .hero-foto { animation: vorhang 1200ms var(--hin-her) 250ms backwards; }
  .hero .hero-foto img { animation: heranzoomen 1600ms var(--raus-stark) 250ms backwards; }
  .hero .hero-blob { animation: blob-auf 1400ms ease 400ms backwards, schweben-blob 12s ease-in-out 1.8s infinite alternate; }
}
@keyframes wort { from { opacity: 0.01; transform: translateY(0.35em); filter: blur(8px); }
  to { opacity: 1; transform: none; filter: blur(0); } }
@keyframes vorhang { from { clip-path: inset(100% 0 0 0 round 10px); } to { clip-path: inset(0 0 0 0 round 10px); } }
@keyframes heranzoomen { from { transform: scale(1.14); } to { transform: none; } }
@keyframes blob-auf { from { opacity: 0; } }

/* Reduzierte Bewegung: nichts wandert, aber Inhalte blenden weich über. */
@media (prefers-reduced-motion: reduce) {
  .js.einmal :is(.auftauchen, .zeile-text, .zeile-bild, .such-treffer li, .laden-teil,
    .mini-geraet, .mini-telefon, .ergebnis-innen > div:first-child > *) {
    transform: none !important; clip-path: none !important; transition: opacity 300ms ease !important; }
  .js.einmal .laden-fuellung { transition: none !important; }
  .leiste { transition: border-color 200ms ease, background-color 200ms ease; }
}

/* Endzustand des Telefons ausdrücklich in derselben Form wie der Start,
   damit die Drehung sauber interpoliert statt über eine Matrix zu springen. */
.js.einmal .zeile.ist-sichtbar .mini-telefon { transform: perspective(700px) translateY(0) rotateY(0deg) scale(1); }

/* Über mich: Das Foto öffnet sich einmal wie ein Vorhang, wenn es ins Bild
   kommt. Der Endzustand ragt über das Bild hinaus, damit der Schatten
   nicht abgeschnitten wird. */
.js.einmal .ueber-innen .hero-foto { clip-path: inset(-40px -40px -70px -40px round 10px);
  transition: clip-path 1100ms var(--hin-her); }
.js.einmal .ueber-innen .hero-foto img { transition: transform 1500ms var(--raus-stark); }
.js.einmal .ueber-innen .hero-bild-feld:not(.ist-sichtbar) .hero-foto { clip-path: inset(100% 0 0 0 round 10px); }
.js.einmal .ueber-innen .hero-bild-feld:not(.ist-sichtbar) .hero-foto img { transform: scale(1.14); }
@media (prefers-reduced-motion: reduce) {
  .js.einmal .ueber-innen .hero-foto { clip-path: none; transition: none; }
  .js.einmal .ueber-innen .hero-bild-feld:not(.ist-sichtbar) .hero-foto img { transform: none; }
}

/* Der Punkt samt Leuchtring liegt über der wachsenden Fläche. Damit sein
   Schimmer nicht als Ring in der blauen Fläche stehen bleibt, blendet er
   aus, sobald die Fläche aufgeht: gleiche Zeitleiste, gleicher Start
   (36 %), nach wenigen Prozent ist er verschwunden. Das Pulsieren läuft
   als zweite, zeitbasierte Animation daneben weiter. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .ablauf-punkt {
      animation: puls 2.6s ease-in-out infinite, punkt-weg 1s linear both;
      animation-timeline: auto, --punkt-lauf;
      animation-range: normal, cover 36% cover 41%; }
  }
}
@keyframes punkt-weg { to { opacity: 0; } }

/* ─────────────── Fortschritt der Drehung ───────────────
   Oben und unten auf der Ergebnis-Fläche läuft je eine Leiste von links
   nach rechts voll, synchron zur Drehung des Telefons (phone-scroll.js
   setzt scaleX direkt). Ist sie voll, ist die Drehung fertig: Die Leisten
   leuchten kurz auf und treten dann zurück, als Zeichen, dass es weitergeht. */
.dreh-leiste { position: absolute; left: 0; right: 0; height: 3px; z-index: 2; pointer-events: none;
  background: oklch(100% 0 0 / 0.85); transform: scaleX(0); transform-origin: left;
  transition: opacity 400ms ease, background-color 400ms ease; }
.dreh-oben  { top: 0; }
.dreh-unten { bottom: 0; }
/* Die Leiste oben soll nicht unter der Kopfleiste verschwinden, solange
   diese sichtbar ist. */
.dreh-oben { transition: opacity 400ms ease, background-color 400ms ease, translate 300ms var(--schublade); }
.leiste:not(.ist-weg) ~ main .dreh-oben { translate: 0 var(--leiste-h); }
.dreh-fertig .dreh-leiste { background: oklch(100% 0 0); opacity: 0.45; }
@media (prefers-reduced-motion: no-preference) {
  .dreh-fertig .dreh-leiste { animation: leiste-fertig 700ms var(--raus-stark); }
}
@keyframes leiste-fertig { 0% { opacity: 1; box-shadow: 0 0 14px oklch(100% 0 0 / 0.8); } 100% { opacity: 0.45; box-shadow: none; } }
