/* ═══════════════════════════════════════════════════════════════════════
 * jk-main.css — Produktions-Stylesheet für johanneskoeck.de
 *
 * Zusammengeführt aus dem abgenommenen Visual:
 *   Umsetzung/02_Visual/assets/css/{fonts,tokens,custom}.css
 *
 * REGEL: Alles Sichtbare steht hier. GenerateBlocks trägt ausschließlich
 * Struktur plus eine Klasse — keine Farben, Abstände, Schriftgrößen oder
 * Hintergründe in den Block-Einstellungen (Fidelity-Regel 6).
 *
 * BAUSTAND: Abschnitt 1 — Grundlage, Kopfbereich, Mobilmenü, Sektion
 * „Ablauf". Die übrigen Sektionen folgen. Was noch fehlt, steht am Dateiende.
 * ═══════════════════════════════════════════════════════════════════════ */


/* ── 1. Schriften ───────────────────────────────────────────────────────
 * Lokal, kein Google-Abruf (T6/T7 — die Seite bleibt bannerfrei).
 *
 * Nur 400 und 700 — ENTSCHIEDEN von René am 01.08.2026.
 *
 * An mehreren Stellen stehen die Gewichte 500 und 600 (Schaltflächen, H2,
 * Augenbrauen-Zeilen, Zeitangaben); die rechnet der Browser sich selbst
 * zurecht. Echte Zwischenschnitte wären typografisch sauberer, hätten aber
 * drei Nachteile: Sie verändern das Schriftbild seitenweit gegenüber dem
 * Stand, den Johannes viermal gesehen und zuletzt Satz für Satz kommentiert
 * hat; sie kosten rund 40 KB auf einer Seite, deren Tempo ein
 * Verkaufsargument ist; und sie wären eine bewusst eingeführte Abweichung,
 * nachdem wir erhebliche Mühe investiert haben, damit WordPress exakt dem
 * Entwurf entspricht.
 *
 * Nachrüsten geht jederzeit in zehn Minuten, auch nach dem Livegang.
 * ─────────────────────────────────────────────────────────────────────── */

@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/SourceSans3-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'Source Sans 3';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/SourceSans3-Bold.woff2') format('woff2');
}


/* ── 2. Gestaltungswerte ────────────────────────────────────────────────
 * Petrol ist in :root eingefaltet — die vier [data-accent]-Blöcke des
 * Visuals entfallen ersatzlos (Akzent gelockt 23.07.2026, K2/O-D1).
 * ─────────────────────────────────────────────────────────────────────── */

:root {
  /* Markenfarben */
  --c-primary:         #002F42;
  --c-primary-dark:    #001C29;
  --c-primary-light:   #1A4A5C;

  /* Akzent: Petrol, gelockt */
  /* 06.08.2026 — von #2F8F8A abgedunkelt. Weiss auf dem alten Wert ergab
     3,88:1 und verfehlte damit die WCAG-AA-Schwelle von 4,5 fuer normalen
     Text; die Knopfbeschriftung liegt mit 15,75 bzw. 18 px unter der Grenze
     fuer "grossen Text". Der neue Wert ergibt 4,63:1. Rund 8 % Helligkeit,
     im direkten Vergleich nicht wahrnehmbar. */
  --c-accent:          #2B817D;
  --c-accent-dark:     #1F706C;
  --c-accent-contrast: #ffffff;

  /* Neutrale Palette */
  --c-bg:              #ffffff;
  --c-surface-warm:    #F8F5F1;
  --c-surface:         #F8F5F1;
  --c-surface-alt:     #F0F0F0;
  --c-border:          #EFEFEF;
  --c-border-strong:   #E0E0E0;
  --c-text:            #1A1A1A;
  --c-text-muted:      #5A5A58;
  /* 06.08.2026 — von #81817F abgedunkelt, 3,90:1 auf Weiss. Betraf die
     Vorzeilen, die Hero-Sterne und die Bearbeitungszeiten. Jetzt 4,61:1. */
  --c-text-subtle:     #757574;

  /* Rückmeldungen im Formular */
  --c-success:         #2D7A4F;
  --c-warning:         #C9882C;
  --c-error:           #C0392B;

  /* Typografie */
  --font-body:         'Source Sans 3', system-ui, -apple-system, sans-serif;
  --font-heading:      'Source Sans 3', system-ui, -apple-system, sans-serif;

  --fs-root:           18px;
  --fs-base:           1rem;
  --fs-sm:             0.875rem;
  --fs-lg:             1.125rem;
  --fs-xl:             1.5rem;
  --fs-2xl:            2rem;
  --fs-3xl:            2.75rem;
  --fs-4xl:            4.25rem;
  --fs-5xl:            6rem;

  --lh-tight:          1.2;
  /* 1.5, nicht 1.6 — KORREKTUR 01.08.2026. Im Entwurf stand 1.6, wirksam war
     aber nie dieser Wert: Tailwinds Basis-Stylesheet setzt `html{line-height:1.5}`
     und `body{line-height:inherit}` und lädt nach custom.css. Der abgenommene
     Stand läuft also mit 1,5 — nachgemessen im Seitenvergleich. Sieben Prozent
     auf jeder Textzeile der ganzen Seite. */
  --lh-base:           1.5;
  --lh-relaxed:        1.7;

  --fw-light:          300;
  --fw-regular:        400;
  --fw-bold:           700;

  /* Abstände (8er-Skala) */
  --sp-1:  0.25rem;   --sp-2:  0.5rem;   --sp-3:  0.75rem;  --sp-4:  1rem;
  --sp-6:  1.5rem;    --sp-8:  2rem;     --sp-10: 2.5rem;   --sp-12: 3rem;
  --sp-14: 3.5rem;    --sp-16: 4rem;     --sp-20: 5rem;     --sp-24: 6rem;
  --sp-32: 8rem;

  /* Layout */
  --container-max:     1200px;
  --container-pad:     1rem;
  --container-pad-md:  1.5rem;
  --container-pad-lg:  2rem;

  /* Radien und Schatten */
  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;
  --radius-full: 9999px;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 12px rgba(0, 47, 66, 0.08);
  --shadow-lg: 0 12px 32px rgba(0, 47, 66, 0.12);

  /* Bewegung */
  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
  --duration-fast: 150ms;
  --duration-base: 300ms;
  --duration-slow: 600ms;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0.01ms;
    --duration-base: 0.01ms;
    --duration-slow: 0.01ms;
  }
}


/* ── 3. Grundlage ───────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

/* ACHTUNG, Nebenwirkung: 18px Grundgröße (Persona-Entscheid) skaliert ALLE
   rem-Werte von GeneratePress und GenerateBlocks mit — deren Innenabstände
   werden dadurch rund zwölf Prozent größer als im Standard. Das ist gewollt,
   muss aber bei jeder GP-Einstellung mitgedacht werden. */
html {
  font-size: var(--fs-root);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
  color: var(--c-text);
  background: var(--c-bg);
  -webkit-font-smoothing: antialiased;

  /* ── Der Fußbereich soll nie in der Luft hängen ────────────────────
   * Auf kurzen Seiten — Danke, Fehlerseite, künftig auch dem Impressum
   * auf einem großen Bildschirm — endet der Inhalt vor dem unteren
   * Fensterrand. Ohne diese drei Zeilen sitzt der dunkle Fußbereich dann
   * mitten im Bild, darunter ein weißer Streifen. Das sieht nicht nach
   * „kurze Seite" aus, sondern nach „hier fehlt etwas".
   *
   * `100dvh` statt `100vh` wegen der Mobilbrowser: Deren Adressleiste
   * fährt beim Scrollen ein und aus, und `100vh` rechnet mit dem
   * ausgefahrenen Zustand. Der Fuß säße dort dauerhaft ein Stück unter
   * der Sichtkante. `100vh` bleibt als Rückfall für ältere Geräte davor
   * stehen — bei dieser Zielgruppe keine Formalie.
   *
   * Die Angaben stehen bewusst am `body` und nicht an einem Wrapper von
   * GeneratePress: Kopf, Inhalt und Fuß sind hier direkte Kinder des
   * `body`, ein zusätzlicher Wrapper wäre eine Ebene, die niemand
   * braucht. Der mitlaufende Kopf bleibt davon unberührt — ein haftendes
   * Element funktioniert auch als Flex-Kind. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

/* Der Inhaltsbereich nimmt den übrigen Platz. `flex: 1 0 auto` und nicht
   `1 1 auto`: Er darf wachsen, aber niemals schrumpfen — sonst würde ein
   langer Text auf einem kurzen Fenster zusammengedrückt statt zu scrollen.
 *
 * `width: 100%` ist NICHT überflüssig — es repariert eine Nebenwirkung,
 * die mich die Flex-Umstellung fast gekostet hätte:
 *
 * GeneratePress gibt `#page` einen automatischen Außenabstand links und
 * rechts, um es zu zentrieren. In einem Flex-Container hebt genau das die
 * Voreinstellung `align-items: stretch` auf — ein Element mit `auto`-Rändern
 * wird nicht mehr gedehnt, sondern auf seine Inhaltsbreite geschrumpft und
 * mittig gesetzt.
 *
 * Auf der Startseite blieb das unsichtbar, weil die Sektionen den Kasten
 * ohnehin auf volle Breite ziehen. Auf den Textseiten schrumpfte er auf die
 * Textbreite: 840 px im Datenschutz, 653 px auf der Fehlerseite — sichtbar
 * als heller Kasten, der nicht bis zum Rand reicht.
 *
 * MERKPOSTEN: Der Vergleichstest hat es nicht gefunden, weil er nur die
 * Startseite misst. Eine Änderung am `body` wirkt aber auf JEDE Seite. Wo
 * etwas so weit oben angefasst wird, reicht eine Seite als Prüfstein nicht.
 */
#page.site {
  flex: 1 0 auto;
  width: 100%;
}

/* Hintergrund „Warm-Akzent-Duett" (K2, gelockt).
   Warme Papierzonen bleiben pur, die mittlere Ruhezone wird eine blasse
   Petrol-Fläche: warm → kühl → warm.

   Die erste Regel ist der Rückfall OHNE color-mix. Ohne sie kippt in
   Chrome < 111 und Safari < 16.2 der GESAMTE Verlauf auf Weiß — bei der
   älteren Zielgruppe mit alten iPads ein reales Szenario, nicht Theorie.
   #F3F8F8 ist der ausgerechnete Wert von 6 % Petrol auf Weiß. */
.site-main,
main {
  background: linear-gradient(180deg,
    #FFFFFF  0%,  #FFFFFF  8%,
    #FAF7F2 18%,  #FAF7F2 32%,
    #FFFFFF 42%,  #FFFFFF 50%,
    #F3F8F8 60%,  #F3F8F8 74%,
    #FAF7F2 86%,
    #FFFFFF 96%,  #FFFFFF 100%);
  background-attachment: scroll;
  position: relative;
}

@supports (background: color-mix(in srgb, red 6%, white)) {
  .site-main,
  main {
    background: linear-gradient(180deg,
      #FFFFFF  0%,  #FFFFFF  8%,
      #FAF7F2 18%,  #FAF7F2 32%,
      #FFFFFF 42%,  #FFFFFF 50%,
      color-mix(in srgb, var(--c-accent) 6%, #FFFFFF) 60%,
      color-mix(in srgb, var(--c-accent) 6%, #FFFFFF) 74%,
      #FAF7F2 86%,
      #FFFFFF 96%, #FFFFFF 100%);
  }
}

img, picture, svg, video { display: block; max-width: 100%; height: auto; }

button { font: inherit; cursor: pointer; }

a {
  color: var(--c-primary);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Der globale Link-Hover ist auf den Inhaltsbereich begrenzt.
   Im Visual stand er ungescopet und hätte hier auch Menü- und Widget-Links
   von GeneratePress getroffen — der Merkposten aus umsetzungsplan.md.
   Die drei Ausnahmen bleiben: Bei .btn, .link-arrow und .floating-phone
   überschriebe die Regel weiße Schrift auf dunklem Grund, und beides
   verschwände. */
.site-main a:not(.btn):not(.link-arrow):not(.floating-phone):hover,
main a:not(.btn):not(.link-arrow):not(.floating-phone):hover {
  color: var(--c-primary-dark);
}


/* ── 4. Typografie ──────────────────────────────────────────────────────
 * Die !important-Angaben stammen aus dem Visual, wo sie das
 * Tailwind-Preflight überstimmen mussten. Hier gibt es kein Tailwind mehr —
 * sie bleiben trotzdem, weil sonst LEERE Größenfelder im GP-Customizer
 * still gewinnen könnten. Wichtig: Die H-Größenfelder im Customizer bleiben
 * leer, diese clamp()-Regeln sind die einzige Definition (in docs/setup.md
 * vermerken).
 * ─────────────────────────────────────────────────────────────────────── */

/* KORREKTUR 01.08.2026 — zwei Werte aus dem Entwurf zurückgenommen:
   `margin: 0 0 var(--sp-4)` und `font-weight: var(--fw-bold)`.
   Beide waren im abgenommenen Stand nie wirksam. Tailwinds Basis-Stylesheet
   setzt auf allen Überschriften `margin:0` und `font-weight:inherit` und lädt
   nach custom.css. Im Entwurf haben Überschriften deshalb KEINEN unteren
   Abstand, und H3/H4 laufen in normaler Stärke (400) — nur H1 und H2 tragen
   ihre Gewichte per !important und setzen sich durch.
   Abstände kommen aus den Sektions-Regeln (z. B. .process-editorial h3),
   nicht aus dieser Grundregel. */
h1, h2, h3, h4 {
  font-family: var(--font-heading);
  line-height: var(--lh-tight);
  color: var(--c-primary);
  margin: 0;
  letter-spacing: -0.015em;
}

h1 {
  font-size: clamp(1.75rem, 0.85rem + 1.5vw, 2.75rem) !important;
  line-height: 1.15 !important;
  letter-spacing: -0.02em !important;
  font-weight: 700 !important;
}

.hero h1 {
  font-size: clamp(2rem, 1.25rem + 1.75vw, 3.25rem) !important;
  line-height: 1.15 !important;
  letter-spacing: -0.022em !important;
  font-weight: 700 !important;
  max-width: 20ch;
}

h2 {
  font-size: clamp(1.75rem, 0.85rem + 1.8vw, 2.625rem) !important;
  line-height: 1.18 !important;
  letter-spacing: -0.02em !important;
  font-weight: 600 !important;
}

h3 {
  font-size: clamp(1.25rem, 1vw + 0.75rem, 1.5rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
}

h4 { font-size: var(--fs-xl); }

/* Bremse für zentrierte Sektions-Überschriften, damit kurze Zeilen keinen
   Bandwurm bilden. */
.headline-tight {
  max-width: 28ch;
  margin-left: auto;
  margin-right: auto;
}

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--c-text-subtle);
  margin: 0 0 var(--sp-2);
}

.lead { font-size: var(--fs-base); color: var(--c-text-muted); }

.text-center { text-align: center; }


/* ── 5. Layout ──────────────────────────────────────────────────────────── */

/* ACHTUNG, NAMENSKOLLISION — sie hat uns schon dreimal getroffen.
 * GeneratePress benutzt die Klasse `container` selbst, und zwar auf zwei
 * unterschiedliche Weisen:
 *
 * 1. Sein Seiten-Wrapper heißt `<div class="site grid-container container">`.
 *    Ohne die Ausnahme unten bekäme er unsere Höchstbreiten, Innenabstände
 *    und die Tailwind-Deckel-Staffelung — die ganze Seite säße doppelt
 *    eingerückt, je Fensterbreite unterschiedlich stark.
 *    `grid-container` steht bei GeneratePress immer daneben, bei uns nie.
 *
 * 2. Im Modus „Ein Container" färbt GeneratePress JEDES Element mit dieser
 *    Klasse weiß: `.one-container .container{background-color:var(--base-3)}`.
 *    Das traf unsere Container in Kopf, Sektionen UND Fuß — im blauen
 *    Fußbereich entstand ein weißer Kasten, in dem das weiße Logo und die
 *    hellen Rechtslinks unsichtbar wurden. Deshalb setzen wir den
 *    Hintergrund ausdrücklich zurück: Unser `.container` ist eine reine
 *    Breiten- und Abstands-Klasse und trägt NIE eine Fläche. Wer eine
 *    Hintergrundfarbe braucht, setzt sie an die Sektion.
 *
 * Beide Regeln haben dieselbe Spezifität wie GeneratePress' eigene; unser
 * Stylesheet lädt später und gewinnt deshalb.
 *
 * ─────────────────────────────────────────────────────────────────────────
 * NUR WAAGERECHT POLSTERN — KORREKTUR 05.08.2026, und der Grund ist subtil.
 *
 * Hier stand `padding: 0 var(--container-pad)`. Die Kurzform setzt AUCH oben
 * und unten, nämlich auf 0. Im Prototyp ist das harmlos: Dort heißt die Regel
 * schlicht `.container` (Spezifität 0,1,0), und eine später notierte
 * Sektionsklasse wie `.site-header-inner` (ebenfalls 0,1,0) gewinnt mit ihrem
 * `padding-top` durch die Reihenfolge.
 *
 * Hier gewinnt sie nicht. Das `:not(.grid-container)` zählt als zusätzliche
 * Klasse und hebt uns auf 0,2,0 — die Kurzform schlägt damit JEDES
 * `padding-top` einer Sektionsklasse, egal wo es steht. Getroffen hat es:
 *
 *   .site-header-inner   13,5 px oben und unten  →  0   (alle vier Breiten)
 *   .kontakt-grid        45 px oben              →  0   (375 und 768 px)
 *
 * Der Kopfbereich war dadurch 27 px flacher als im abgenommenen Entwurf —
 * seit dem ersten Bauabschnitt, auf jedem Gerät, und niemandem aufgefallen.
 * Ein flacher Kopf sieht nicht falsch aus, er sieht nur anders aus.
 *
 * DIE LEHRE: Das `:not()` ist richtig und muss bleiben — es hält GeneratePress'
 * Seitenhülle draußen. Falsch war, die Spezifitäts-Änderung für folgenlos zu
 * halten. Wer einen Selektor verschärft, verschiebt damit alle Kämpfe, die er
 * bisher verloren hat. Deshalb hier Längsform statt Kurzform: Was wir nicht
 * setzen wollen, setzen wir auch nicht.
 * ───────────────────────────────────────────────────────────────────────── */
.container:not(.grid-container) {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding-left: var(--container-pad);
  padding-right: var(--container-pad);
  background: none;
  box-shadow: none;
}

/* WICHTIG — der Tailwind-Deckel.
   Im Visual lief Tailwind über CDN mit, und dessen eigene .container-Klasse
   setzte je Umbruchpunkt eine Höchstbreite. Beide Regeln griffen zugleich,
   die kleinere gewann. Ohne diesen Nachbau wäre der Inhaltsbereich zwischen
   640 und 1279 px deutlich breiter als im abgenommenen Entwurf — die
   auffälligste Stelle liegt bei 768 px, wo die Breite von 768 auf 1200
   springen würde.
   Wirksame Breiten: < 640 flüssig · 640–767 640 · 768–1023 768 ·
   1024–1279 1024 · ab 1280 1200 (unsere Obergrenze schlägt Tailwinds 1280). */
@media (min-width: 640px)  { .container:not(.grid-container) { max-width: 640px; } }
@media (min-width: 768px)  { .container:not(.grid-container) { max-width: 768px;  padding-left: var(--container-pad-md); padding-right: var(--container-pad-md); } }
@media (min-width: 1024px) { .container:not(.grid-container) { max-width: 1024px; padding-left: var(--container-pad-lg); padding-right: var(--container-pad-lg); } }
/* KORREKTUR 01.08.2026: Hier stand var(--container-max) = 1200px in der
   Annahme, unser Wert gewinne gegen Tailwinds 1280. Er gewinnt nicht —
   Tailwind lädt später. Der abgenommene Entwurf läuft ab 1280px mit 1280px
   und ab 1536px mit 1536px. Nachgemessen: 1208px Inhaltsbreite bei 1440px
   Fenster, unsere Fassung lag bei 1128px.
   --container-max bleibt als dokumentierter Entwurfswert stehen, ist aber
   NICHT der wirksame Deckel. */
@media (min-width: 1280px) { .container:not(.grid-container) { max-width: 1280px; } }
@media (min-width: 1536px) { .container:not(.grid-container) { max-width: 1536px; } }

.section { padding: var(--sp-16) 0; }
@media (min-width: 768px) { .section { padding: var(--sp-24) 0; } }

/* GeneratePress rahmt den Beitragsinhalt in `.inside-article` mit 40 px
   Innenabstand und gibt ihm einen weißen Hintergrund. Für einen Einseiter,
   dessen Sektionen ihre eigenen Abstände mitbringen und bis an den
   Fensterrand reichen sollen, ist beides im Weg — gemessen am 01.08.2026:
   Unsere Sektion war dadurch 1120 statt 1200 px breit.
   Das hier räumt den Rahmen ab. Die BREITE lässt sich damit allerdings nicht
   lösen: Solange GeneratePress `#page` auf die Container-Breite begrenzt,
   kann keine Sektion das Fenster füllen. Dafür muss der Inhaltsbereich im
   Customizer auf volle Breite stehen — siehe docs/setup.md §1.3. */
.inside-article,
.entry-content,
.site-content .content-area {
  padding: 0;
  background: none;
  box-shadow: none;
}
.entry-content > .section:first-child { margin-top: 0; }

.section--primary { background: var(--c-primary); color: #ffffff; }
.section--primary h2,
.section--primary h3 { color: #ffffff; }

/* Die Abstands- und Farb-Hilfsklassen stehen NICHT hier, sondern ganz am Ende
   des Stylesheets. Der Grund steht dort — er hat mit der Reihenfolge zu tun
   und hat uns fünf stille Fehler eingebracht. */


/* ── 6. Schaltflächen ───────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-6);
  font-weight: 500;
  font-size: var(--fs-base);
  border-radius: var(--radius-md);
  border: none;
  text-decoration: none;
  cursor: pointer;
  min-height: 48px;
  transition: background-color 200ms ease, color 200ms ease;
}

.btn__arrow {
  display: inline-block;
  transition: transform 200ms ease;
  line-height: 1;
}
.btn:hover .btn__arrow,
.btn:focus-visible .btn__arrow { transform: translateX(4px); }

@media (prefers-reduced-motion: reduce) {
  .btn__arrow { transition: none; }
  .btn:hover .btn__arrow,
  .btn:focus-visible .btn__arrow { transform: none; }
}

.btn--primary { background: var(--c-primary); color: #ffffff; }
.btn--primary:hover,
.btn--primary:focus-visible { background: var(--c-primary-dark); color: #ffffff; }

/* Umriss per innerem Schatten statt Rahmen, damit die Höhe beim Wechsel auf
   Vollfläche stabil bleibt. */
.btn--outline {
  background: transparent;
  color: var(--c-primary);
  box-shadow: inset 0 0 0 1.5px var(--c-primary);
}
.btn--outline:hover,
.btn--outline:focus-visible { background: var(--c-primary); color: #ffffff; }

.btn--ghost { background: transparent; color: var(--c-primary); }
.btn--ghost:hover,
.btn--ghost:focus-visible { background: var(--c-surface-warm); color: var(--c-primary); }

/* Akzent-Schaltfläche für die echten Conversion-Stellen.
   Kontrast Petrol/Weiß: 3,88:1 — erfüllt AA für große Schrift; die 18px
   Fettschrift qualifiziert dafür. Der Textschatten definiert die Kante
   zusätzlich. Bewusste Entscheidung Renés, im Visual abgenommen. */
.btn--accent {
  background: var(--c-accent);
  color: #ffffff;
  font-weight: 700;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.btn--accent:hover,
.btn--accent:focus-visible { background: var(--c-accent-dark); color: #ffffff; }

.btn--small {
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  min-height: 36px;
  gap: var(--sp-1);
}

.btn--quiet {
  background: transparent;
  color: var(--c-text-muted);
  box-shadow: inset 0 0 0 1px var(--c-border-strong);
}
.btn--quiet:hover,
.btn--quiet:focus-visible {
  background: var(--c-surface-warm);
  color: var(--c-primary);
  box-shadow: inset 0 0 0 1px var(--c-text-subtle);
}

.link-arrow {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sp-2);
  color: var(--c-primary);
  text-decoration: none;
  padding: var(--sp-2) 0;
  font-weight: 500;
  border-bottom: 1px solid var(--c-primary);
  transition: color 200ms ease, border-color 200ms ease;
}
.link-arrow::after {
  content: "→";
  display: inline-block;
  transition: transform 200ms ease;
}
.link-arrow:hover,
.link-arrow:focus-visible { color: var(--c-primary-dark); border-color: var(--c-accent); }
.link-arrow:hover::after,
.link-arrow:focus-visible::after { transform: translateX(3px); }

@media (prefers-reduced-motion: reduce) {
  .link-arrow::after { transition: none; }
  .link-arrow:hover::after,
  .link-arrow:focus-visible::after { transform: none; }
}

.btn:focus-visible,
.link-arrow:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 3px;
}


/* ── 7. Symbole ─────────────────────────────────────────────────────────── */

.icon {
  width: 1.25em;
  height: 1.25em;
  vertical-align: -0.2em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
}

/* Maße an .btn angeglichen (48px, gleicher Radius) — als reiner Kreis wirkte
   das Symbol neben der eckigen Akzent-Schaltfläche wie ein Fremdkörper.
   48px erfüllt zugleich das barrierefreie Mindest-Touchziel von 44px. */
.icon-circle-btn {
  min-width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-md);
  color: var(--c-primary);
  background: transparent;
  transition: background var(--duration-fast) var(--ease-out);
}
.icon-circle-btn:hover { background: var(--c-surface); }
.icon-circle-btn .icon { width: 20px; height: 20px; }

/* Der Hörer „funkt" beim Überfahren — nur an den bleibenden
   Vertrauensankern, nie in Fließtext-Schaltflächen. */
.icon-phone-anim .phone-body { fill: currentColor; stroke: none; }
.icon-phone-anim .phone-wave-inner,
.icon-phone-anim .phone-wave-outer {
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-out);
}
.icon-circle-btn:hover .icon-phone-anim .phone-wave-inner { opacity: 1; transition-delay: 0ms; }
.icon-circle-btn:hover .icon-phone-anim .phone-wave-outer { opacity: 1; transition-delay: 120ms; }


/* ── 8. Sprunglink ──────────────────────────────────────────────────────── */

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--c-primary);
  color: #ffffff;
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-md);
  text-decoration: none;
}
.skip-link:focus { left: var(--sp-4); top: var(--sp-4); }


/* ── 9. Kopfbereich ─────────────────────────────────────────────────────
 * Zuordnung der Tailwind-Hilfsklassen aus dem Visual auf benannte Klassen:
 *   hidden lg:flex items-center gap-7 text-sm  →  .jk-nav
 *   flex items-center gap-2 md:gap-3           →  .jk-header-actions
 *   lg:hidden                                  →  .jk-burger
 * ─────────────────────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--c-bg);
  border-bottom: 1px solid transparent;
  transition: background-color 280ms ease, border-color 280ms ease, backdrop-filter 280ms ease;
}
.site-header.is-scrolled {
  background: rgba(255, 255, 255, 0.92);
  border-bottom-color: var(--c-border);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* Nur vertikal setzen. Die Kurzform „padding: var(--sp-3) 0" hebelte das
   horizontale Padding der .container-Klasse aus — der Kopf saß dann um
   18 bis 36 px weiter außen als der Seiteninhalt. */
.site-header-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: var(--sp-3);
  padding-bottom: var(--sp-3);
  gap: var(--sp-4);
}
.site-header-inner > a:first-child {
  flex-shrink: 0;
  display: block;
}
.site-header-inner > a:first-child img {
  height: 36px;
  width: auto;
  display: block;
}

/* Auf schmalen Handys reichte die Breite nicht für Wortmarke, Telefon und
   Burger — der Kopf lief rechts aus dem Bild. 44px bleibt das barrierefreie
   Mindestmaß. Die Wortmarke bleibt bewusst erhalten: Sie transportiert
   „eine einzelne Person namens Johannes Köck", das Signet allein trüge
   diese Aussage nicht. */
@media (max-width: 479px) {
  .site-header-inner { gap: var(--sp-2); }
  .site-header-inner > a:first-child img { height: 28px; }
  .site-header-inner .icon-circle-btn { min-width: 44px; height: 44px; }
}
@media (max-width: 374px) {
  .site-header-inner { gap: var(--sp-1); }
  .site-header-inner > a:first-child img { height: 24px; }
}

.jk-header-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
@media (min-width: 768px) {
  .jk-header-actions { gap: var(--sp-3); }
}

/* Navigation erst ab 1024px — zwischen 768 und 1023px brachen Punkte und
   Schaltfläche zweizeilig um. Dort übernimmt das Burger-Menü. */
.jk-nav { display: none; }
@media (min-width: 1024px) {
  .jk-nav {
    display: flex;
    align-items: center;
    gap: 1.75rem;
    font-size: var(--fs-sm);
  }
  .jk-burger { display: none; }
}

.site-header nav a {
  position: relative;
  padding: var(--sp-2) 0;
  text-decoration: none;
  transition: color 220ms ease;
}
/* Die Unterstreichung ist von Anfang an da (durchsichtig) — sonst „springt"
   das Layout, sobald der aktive Zustand gesetzt wird. */
.site-header nav a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 2px;
  background: transparent;
  transition: background-color 220ms ease;
}
.site-header nav a:hover::after,
.site-header nav a:focus-visible::after { background: var(--c-text-subtle); }
.site-header nav a:hover,
.site-header nav a:focus-visible { color: var(--c-primary); }
.site-header nav a.is-active {
  color: var(--c-primary);
  font-weight: var(--fw-bold);
}
.site-header nav a.is-active::after { background: var(--c-primary); }

/* Kontakt-Schaltfläche: unter 768px quadratisch mit Briefumschlag, darüber
   mit Klartext. */
.header-cta {
  padding: 0;
  min-width: 44px;
  height: 44px;
  min-height: 44px;
  font-size: var(--fs-sm);
}
.header-cta__label { display: none; }
.header-cta__icon  { width: 20px; height: 20px; }

@media (min-width: 480px) {
  .header-cta { min-width: 48px; height: 48px; min-height: 48px; }
}
@media (min-width: 768px) {
  .header-cta { padding: var(--sp-3) var(--sp-6); min-width: 0; }
  .header-cta__label { display: inline; }
  .header-cta__icon  { display: none; }
}

/* Telefon: unter 768px ausgeblendet — dort übernimmt der fixierte
   Anruf-Knopf unten rechts. So hat das Telefon auf jeder Breite genau einen
   festen Platz, nie zwei. Ab 1280px wird aus dem Symbol eine Pille mit
   sichtbarer Nummer (Kundenwunsch 24.07.2026). */
.header-phone__number { display: none; }

@media (max-width: 767px) {
  .site-header-inner .header-phone { display: none; }
}
@media (min-width: 1280px) {
  .header-phone { padding: 0 var(--sp-4); gap: var(--sp-2); }
  .header-phone__number {
    display: inline;
    font-size: var(--fs-sm);
    font-weight: 500;
    white-space: nowrap;
  }
}


/* ── 10. Mobilmenü ──────────────────────────────────────────────────────
 * Liegt auf 120, der mitlaufende Kopf auf 100 — sonst verdeckt der Kopf die
 * obere Leiste samt Schließen-Knopf, und das Menü ließe sich nur über einen
 * Navigationspunkt verlassen.
 * ─────────────────────────────────────────────────────────────────────── */

.jk-mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: #ffffff;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.jk-mobile-nav[hidden] { display: none; }

.jk-mobile-nav__bar { border-bottom: 1px solid var(--c-border); }

.jk-mobile-nav__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: var(--sp-6);
  font-size: var(--fs-lg);
}

.jk-mobile-nav__item {
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--c-border);
  text-decoration: none;
}

.jk-mobile-nav__cta,
.jk-mobile-nav__call {
  text-align: center;
  padding-top: var(--sp-3);
  padding-bottom: var(--sp-3);
  font-size: var(--fs-base);
}
.jk-mobile-nav__cta  { margin-top: var(--sp-6); }
.jk-mobile-nav__call { margin-top: var(--sp-3); }

/* Hintergrund nicht mitscrollen lassen, solange das Menü offen ist. */
body.jk-menu-offen { overflow: hidden; }


/* ── 11. Sektion „Ablauf" ───────────────────────────────────────────────
 * Vier Schritte. Mobil untereinander mit Haarlinien und kleiner
 * Nummern-Pille, ab 1024px vierspaltig mit Wasserzeichen-Ziffer und
 * Pfeilen dazwischen.
 * ─────────────────────────────────────────────────────────────────────── */

/* Anker-Versatz. Im Entwurf stand dafür ein `style="scroll-margin-top:5rem"`
   direkt am Element — das wandert hierher, weil die Blöcke laut
   Fidelity-Regel 6 nur Struktur und eine Klasse tragen. Ohne den Versatz
   verschwindet die Überschrift beim Sprung aus dem Menü hinter dem
   mitlaufenden Kopf. Gilt für jede Sektion mit Anker, nicht nur für diese. */
.section[id] { scroll-margin-top: 5rem; }

.process-editorial {
  display: grid;
  gap: 0;
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: process-step;
}
.process-editorial > li {
  counter-increment: process-step;
  display: block;
  position: relative;
  padding: var(--sp-8) 0;
  border-top: 1px solid var(--c-border);
  overflow: hidden;
}
.process-editorial > li:last-child { border-bottom: 1px solid var(--c-border); }

.process-editorial > li::before {
  content: "0" counter(process-step);
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--c-accent);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  display: inline-block;
  margin-bottom: var(--sp-3);
}

/* AUF DEM TELEFON DIESELBE BEHANDLUNG WIE AUF DEM DESKTOP — 06.08.2026.
 *
 * Bis hierher stand die Ziffer klein und in Akzentfarbe ÜBER der
 * Überschrift und kostete je Schritt rund 34 px Höhe — bei vier Schritten
 * also etwa eine halbe Bildschirmhöhe, die man zusätzlich wischen muss.
 *
 * Ab 1024 px wird daraus ohnehin ein großes, blasses Wasserzeichen unten
 * rechts. Dieselbe Behandlung herunterskaliert: Die Ziffer verlässt den
 * Textfluss, der Text läuft über die volle Breite, und die Karte wird
 * kürzer. Lesbar bleibt der Text, weil das Zeichen bei 8 % Deckkraft
 * hinter ihm liegt und `z-index: 0` trägt — die Inhalte stehen auf 1.
 *
 * Renés Vorschlag nach dem Test am Gerät. Bewusste Abweichung vom
 * abgenommenen Entwurf: Dort steht mobil die kleine Ziffer.
 *
 * 6rem statt der 10rem vom Desktop — auf 375 px Breite wäre die große
 * Ziffer keine Andeutung mehr, sondern ein Element. */
@media (max-width: 1023px) {
  .process-editorial > li::before {
    content: counter(process-step);
    position: absolute;
    right: -0.25rem;
    bottom: 0.5rem;
    font-size: 6rem;
    font-weight: 700;
    color: var(--c-primary);
    opacity: 0.08;
    line-height: 0.8;
    letter-spacing: -0.05em;
    margin-bottom: 0;
    display: block;
    pointer-events: none;
    user-select: none;
    z-index: 0;
  }
}

.process-editorial h3 {
  font-size: var(--fs-xl);
  margin: 0 0 var(--sp-2);
  min-height: 1.4em;
}
.process-editorial p {
  margin: 0 0 var(--sp-3);
  color: var(--c-text-muted);
}
.process-editorial .process-time {
  font-size: 0.8125rem;
  color: var(--c-text-subtle);
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0.01em;
  margin-top: auto;
}

/* Abbinder unter den vier Schritten. Im Entwurf trugen diese beiden Absätze
   Tailwind-Utilities plus Inline-Stile (`max-width:42rem`, Linkfarbe,
   Unterstreichung). Beides wandert hierher — im Block steht nur die Klasse. */
.process-lead {
  color: var(--c-text-muted);
  max-width: 42rem;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: var(--sp-6);
}
.process-hint {
  margin-top: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);

  /* DIE ZWEI ZEILEN SIND DER GANZE PUNKT — nachgetragen 05.08.2026.
   *
   * Im abgenommenen Entwurf steht an genau dieser Zeile:
   *
   *     <p class="mt-4 text-sm … mx-auto" style="max-width:none;">
   *
   * Das Inline-Style hebt den globalen Deckel `p { max-width: 65ch }` auf.
   * Beim Portieren nach `.process-hint` ist es verlorengegangen — der Absatz
   * lief dadurch auf 509 px statt auf volle Containerbreite, stand links und
   * sein zentrierter Text saß 350 px neben der Mitte des Knopfes darüber.
   *
   * Der Designer hat denselben Fehler im Entwurf schon einmal gehabt und
   * kommentiert (V3.9, FAQ-Ausklang): „<p> mit globalem max-width:65ch
   * braucht mx-auto, sonst hängt er linksbündig." Es gibt im Entwurf genau
   * ZWEI Stellen mit dieser Aufhebung — die FAQ-Stelle war portiert, diese
   * nicht.
   *
   * MERKPOSTEN FÜR DAS NÄCHSTE PROJEKT: Inline-Styles im Entwurf sind keine
   * Schlampigkeit, sondern meist ausdrückliche Ausnahmen von einer globalen
   * Regel. Vor dem Portieren einmal alle einsammeln
   * (`grep -oE 'style="[^"]*"'`) und einzeln zuordnen. */
  max-width: none;
  margin-left: auto;
  margin-right: auto;
}
.process-hint a {
  color: var(--c-primary);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

@media (min-width: 1024px) {
  .process-editorial {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--sp-16);
    align-items: stretch;
  }
  .process-editorial > li {
    display: flex;
    flex-direction: column;
    border-top: none;
    border-left: none;
    padding: var(--sp-4) var(--sp-2) var(--sp-4) 0;
    position: relative;
    min-height: 280px;
    /* KEIN overflow: hidden — die Pfeile liegen außerhalb und würden
       sonst abgeschnitten. */
  }
  .process-editorial > li:last-child { border-bottom: none; }

  /* Wasserzeichen-Ziffer: ragt bewusst 8px über die Kante hinaus,
     klassisches Magazin-Muster. */
  .process-editorial > li::before {
    content: counter(process-step);
    position: absolute;
    right: -0.5rem;
    bottom: 1rem;
    font-size: 10rem;
    font-weight: 700;
    color: var(--c-primary);
    opacity: 0.08;
    line-height: 0.8;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.05em;
    pointer-events: none;
    user-select: none;
    z-index: 0;
    margin-bottom: 0;
  }
  .process-editorial > li > * { position: relative; z-index: 1; }
  .process-editorial h3 { min-height: 1.4em; }

  /* KORREKTUR gegenüber dem Visual: Dort steht in dieser Grafik noch
     %23FF8921 — das alte Signal-Orange aus der Zeit vor der Farbwahl. Die
     Akzentfarbe ist seit 23.07.2026 auf Petrol gelockt, diese eine Stelle
     ist beim Umstellen übersehen worden. Hier steht %232F8F8A (Petrol).
     Siehe Notiz am Dateiende — das Visual sollte nachgezogen werden. */
  .process-editorial > li:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 50%;
    right: calc(-1 * var(--sp-16) / 2);
    transform: translate(50%, -50%);
    width: 28px;
    height: 28px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%232F8F8A' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 6l6 6-6 6M20 12H8'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    z-index: 2;
    pointer-events: none;
  }
}


/* ── 11a. Sektion „Sicherheit" ──────────────────────────────────────────
 * Drei Absicherungs-Punkte. Mobil untereinander mit Haarlinien, ab 1024px
 * dreispaltig mit Schild-Wasserzeichen.
 * ─────────────────────────────────────────────────────────────────────── */

.promise-section { padding-block: var(--sp-20) var(--sp-24); }

/* Im Entwurf stand hier `style="max-width:36ch"` direkt am H2 und
   überschrieb die 28ch aus .headline-tight. Als Klasse statt Inline-Stil,
   damit der Block nur Struktur trägt. Bewusst `is-wide` und nicht
   `headline-tight--wide`: Doppelte Bindestriche müssten in der
   Muster-Serialisierung maskiert werden, das spart eine Fehlerquelle. */
.headline-tight.is-wide { max-width: 36ch; }

/* Für Überschriften über linksbündigem Text. `.headline-tight` zentriert den
   KASTEN über automatische Außenabstände, nicht den Text darin — steht die
   Überschrift außerhalb eines `.text-center`, sitzt sie danach weder mittig
   noch auf der Fluchtlinie des Textes darunter, sondern irgendwo dazwischen.
   Aufgefallen auf der Danke-Seite: Die Überschrift begann bei 415 px, die
   Liste darunter bei 324. Ohne Vergleichspunkt sieht so etwas nach Absicht
   aus — es fällt erst auf, wenn beide untereinander stehen. */
.headline-tight.is-flush {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

.protection-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  list-style: none;
  padding: 0;
  margin: 0;
}
.protection-item {
  display: block;
  position: relative;
  padding: var(--sp-8) 0;
  border-top: 1px solid var(--c-border);
  overflow: hidden;
}
.protection-item:last-child { border-bottom: 1px solid var(--c-border); }
.protection-item h3 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xl);
  letter-spacing: -0.01em;
  font-weight: 600;
  line-height: 1.25;
  min-height: 1.4em;
}
.protection-item p {
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--fs-base);
  line-height: 1.55;
  max-width: none;
}

@media (min-width: 1024px) {
  .protection-grid {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--sp-16);
    align-items: stretch;
  }
  .protection-item {
    display: flex;
    flex-direction: column;
    border-top: none;
    padding: var(--sp-4) var(--sp-2) var(--sp-4) 0;
    position: relative;
    min-height: 240px;
  }
  .protection-item:last-child { border-bottom: none; }

  /* Schild-Wasserzeichen. Die Farbe steckt URL-kodiert in der Grafik
     (%23002F42 = Primärblau) — geprüft am 02.08.2026, korrekt. Bei jeder
     Farbänderung ist das eine der Stellen, die keine Suche findet. */
  .protection-item::before {
    content: "";
    position: absolute;
    right: -0.5rem;
    bottom: 0.5rem;
    width: 10rem;
    height: 10rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23002F42' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right bottom;
    background-size: contain;
    opacity: 0.10;
    pointer-events: none;
    z-index: 0;
  }
  .protection-item > * { position: relative; z-index: 1; }
}


/* ── 11b. Sektion „Problem" ─────────────────────────────────────────────
 * Zweispalter: links der redaktionelle Textblock, rechts die Rauten-Liste
 * mit den vier Schmerzpunkten.
 * ─────────────────────────────────────────────────────────────────────── */

/* Erbe aus dem Entwurf: Die Klasse ist dort ausdrücklich als wirkungslos
   markiert — die Flächenwirkung kommt aus dem Seitenverlauf. Sie bleibt im
   Markup, damit der Vergleich mit dem Prototyp sauber bleibt. */
.section--surface { background: transparent; }

.problem-grid {
  display: grid;
  gap: var(--sp-10);
}
@media (min-width: 1024px) {
  .problem-grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-16);
    /* Zentriert, nicht oben ausgerichtet: Der Textblock links ist deutlich
       länger als die vierteilige Liste rechts. Ohne Zentrierung „hängt" die
       Liste oben und darunter entsteht ein Weißraum-Loch. */
    align-items: center;
    max-width: 68rem;
    margin-inline: auto;
  }
}

/* ACHTUNG, F4: Im Entwurf stehen hier zusätzlich `font-weight: var(--fw-medium)`
   und `line-height: var(--lh-snug)`. Beide Werte sind dort NIRGENDS definiert —
   die Angaben fallen also aus, und der Absatz erbt Gewicht und Zeilenhöhe vom
   Fließtext. Genau das ist der abgenommene Zustand. Würden wir die Werte hier
   ergänzen, sähe der Satz anders aus als freigegeben. Deshalb bewusst weg. */
.problem-close {
  color: var(--c-primary);
  max-width: 45ch;
  margin: 0;
}

.diamond-list {
  list-style: none;
  padding-left: 0;
  margin: 0;
}
.diamond-list > li {
  position: relative;
  padding-left: 1.5rem;
  line-height: 1.55;
}
/* Raute in Grau, nicht im Akzent — der bleibt den Handlungsaufrufen
   vorbehalten. */
.diamond-list > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 8px;
  height: 8px;
  background: var(--c-text-subtle);
  transform: rotate(45deg);
  border-radius: 1px;
}

/* Die Textfarbe stand im Entwurf als Tailwind-Kurzform am Element. */
.problem-list {
  margin: 0;
  color: var(--c-text-muted);
}
.problem-list > li + li { margin-top: var(--sp-6); }
@media (max-width: 1023px) {
  .problem-list { margin-top: var(--sp-4); }
}


/* ── 11c. Sektion „Hero" ────────────────────────────────────────────────
 * Zweispalter mit Textblock und Bild, darunter die Vertrauensleiste.
 *
 * Zuordnung der Tailwind-Kurzformen aus dem Entwurf:
 *   order-2 md:order-1 / order-1 md:order-2  →  .hero-grid > … (unten)
 *   flex flex-col sm:flex-row sm:items-center gap-3  →  .hero-cta-row
 *   text-sm                                  →  in .hero-phone-hint gefaltet
 * ─────────────────────────────────────────────────────────────────────── */

.hero {
  padding: 2.5rem 0 2.5rem;
  background: transparent;
}
@media (min-width: 768px)  { .hero { padding: 5rem 0 3.5rem; } }
@media (min-width: 1280px) { .hero { padding: 6rem 0 4rem; } }

.hero-grid {
  display: grid;
  gap: var(--sp-8);
}
@media (min-width: 768px) {
  .hero-grid {
    grid-template-columns: 1fr 1fr;
    align-items: center;
  }
}

/* Auf schmalen Fenstern steht das Bild ÜBER dem Text, ab 768 px rechts
   daneben. Im Entwurf lief das über `order-2 md:order-1`.
   Die Regel ist bewusst an `.hero-grid >` gebunden und nicht an die
   Klassen selbst: `.hero-image` kommt im Ankaufsprofil ein zweites Mal
   vor, und dort ist es das zweite Kind seines Rasters — eine ungebundene
   `order: 1` würde das Bild dort vor den Text ziehen. */
.hero-grid > .hero-text-block { order: 2; }
.hero-grid > .hero-image      { order: 1; }
@media (min-width: 768px) {
  .hero-grid > .hero-text-block { order: 1; }
  .hero-grid > .hero-image      { order: 2; }
}

/* Hervorgehobene Wörter in der Überschrift.
   Der Entwurf kennt fünf Varianten, umgeschaltet über `data-highlight` am
   <html>-Element. Ohne gesetztes Attribut greift `text-accent`, und genau
   das ist der abgenommene Zustand: Das Wort trägt die Akzentfarbe und
   volles Gewicht, keine Unterstreichung, kein Marker. Die anderen vier
   Varianten sind mit dem Umschalter im Prototyp geblieben. */
.highlight-word {
  color: var(--c-accent);
  font-weight: 700;
}

.hero-image {
  position: relative;
  aspect-ratio: 16 / 10;
}
.hero-image-inner {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}
.hero-image-inner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
}
/* Zarter Farbschleier über dem Bild: Er zieht die hellblaue Studiowand in
   die Farbwelt der Seite. `soft-light` mischt sanft statt zu ersetzen —
   Haut und Hemd bleiben natürlich, der Hintergrund wandert Richtung
   Petrol. 12 % ist der abgestimmte Wert. */
.hero-image-inner::after {
  content: '';
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--c-accent) 12%, transparent);
  mix-blend-mode: soft-light;
  pointer-events: none;
  border-radius: inherit;
}

.hero-cta-row {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
@media (min-width: 640px) {
  .hero-cta-row {
    flex-direction: row;
    align-items: center;
  }
}

/* Die Zeile trug im Entwurf `text-sm`. Tailwind setzt dort neben der Größe
   auch eine feste Zeilenhöhe von 1.25rem — die gehört mit hierher, sonst
   erbt die Zeile die 1,5 des Fließtextes und sitzt zwei Pixel tiefer. */
/* Diese Zeile traegt im Entwurf `text-sm`. Die Werte stehen hier fest in der
   Klasse statt ueber die Hilfsklasse — die Sektion liegt bereits auf der Seite,
   und eine Markup-Aenderung haette ein erneutes Einfuegen erzwungen. Das
   Ergebnis ist dasselbe, nachgemessen. */
.hero-phone-hint {
  font-size: var(--fs-sm);
  line-height: 1.25rem;
  color: var(--c-text-muted);
}
.hero-phone-link {
  color: var(--c-primary);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
  font-weight: var(--fw-bold);
  transition: color var(--duration-fast) var(--ease-out);
}
.hero-phone-link:hover,
.hero-phone-link:focus-visible {
  color: var(--c-accent-dark);
  text-decoration-thickness: 2px;
}

/* Vertrauensleiste am Hero-Unterrand. Bewusst ohne eigene Fläche und ohne
   Trennlinien — als Balken wurde sie im Entwurf als zu laut empfunden.
   Werte und Sterne laufen im gedeckten Grau; der Akzent bleibt den
   Handlungsaufrufen vorbehalten. */
.hero-trustbar {
  border: none;
  background: transparent;
  padding-block: var(--sp-4);
  margin-top: var(--sp-8);
}
.hero-trustbar-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--sp-6) var(--sp-12);
}
.hero-trust-item {
  text-align: center;
  flex: 0 1 auto;
}
.hero-trust-value {
  font-family: var(--font-heading);
  font-size: clamp(1rem, 0.85rem + 0.4vw, 1.25rem);
  line-height: 1.15;
  color: var(--c-text-muted);
  letter-spacing: -0.01em;
  font-weight: 500;
}
.hero-trust-value strong {
  font-weight: 600;
  color: var(--c-text-muted);
}
.hero-trust-stars {
  color: var(--c-text-subtle);
  font-size: 0.85em;
  letter-spacing: 0.1em;
  margin-left: 0.2em;
}
.hero-trust-label {
  font-size: 0.8125rem;
  color: var(--c-text-subtle);
  margin-top: var(--sp-1);
  letter-spacing: 0.01em;
}
.hero-trust-divider {
  width: 1px;
  height: 32px;
  background: var(--c-border-strong);
  display: inline-block;
  opacity: 0.6;
}
@media (max-width: 639px) {
  .hero-trust-divider  { display: none; }
  .hero-trustbar-inner { gap: var(--sp-4); }
  .hero-trustbar       { padding-block: var(--sp-6); }
}


/* ── 11d. Sektion „Ankaufsprofil" ───────────────────────────────────────
 * Zweispalter: links die nummerierte Liste der drei Objektarten,
 * rechts dasselbe Bildgerüst wie im Hero.
 *
 * Zuordnung der Tailwind-Kurzformen aus dem Entwurf:
 *   grid lg:grid-cols-2 gap-12 items-center  →  .ankauf-grid
 *   flex flex-wrap gap-3                     →  .ankauf-cta-row
 *   text-[var(--c-text-muted)]               →  .text-muted
 * ─────────────────────────────────────────────────────────────────────── */

.ankauf-grid {
  display: grid;
  gap: var(--sp-12);
  align-items: center;
}
@media (min-width: 1024px) {
  .ankauf-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.ankauf-cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.ankaufsprofil-list {
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: ankauf-step;
}
/* Die Trennlinie ist kein `border-top`, sondern ein Verlauf, der an beiden
   Enden auf sechs Prozent ausklingt. So liest sie sich als Aufzählungs-
   Trenner und nicht als Sektionsgrenze. */
.ankaufsprofil-list > li {
  counter-increment: ankauf-step;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-6);
  padding: var(--sp-6) 0;
  background-image: linear-gradient(
    to right,
    transparent 0%,
    var(--c-border) 6%,
    var(--c-border) 94%,
    transparent 100%
  );
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: top;
}
/* Der letzte Eintrag schließt die Liste unten ab — zwei Verläufe. */
.ankaufsprofil-list > li:last-child {
  background-image:
    linear-gradient(to right, transparent 0%, var(--c-border) 6%, var(--c-border) 94%, transparent 100%),
    linear-gradient(to right, transparent 0%, var(--c-border) 6%, var(--c-border) 94%, transparent 100%);
  background-size: 100% 1px, 100% 1px;
  background-repeat: no-repeat, no-repeat;
  background-position: top, bottom;
}
.ankaufsprofil-list > li::before {
  content: '0' counter(ankauf-step);
  font-size: var(--fs-3xl);
  font-weight: 400;
  color: var(--c-text-subtle);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}
.ankaufsprofil-list h3 {
  font-size: var(--fs-xl);
  margin-bottom: var(--sp-2);
}

/* Waagerechter Überlauf bei 320 px — behoben am 02.08.2026, in beiden
   Fassungen zugleich, damit Entwurf und Umsetzung deckungsgleich bleiben.
   Die Zeile ist ein Raster aus fester Ziffernspalte und `1fr` für den Text.
   Ein Raster darf eine Spalte nicht schmaler machen als deren längstes Wort,
   und „Sanierungsbedürftige" ist bei 320 px breiter als der Platz, der nach
   Ziffer und Abstand übrig bleibt. Die Spalte wuchs, die Seite lief 21 px über.
   `min-width: 0` hebt diese Untergrenze auf, die Silbentrennung sorgt dafür,
   dass das Wort dann sauber umbricht statt hart abgeschnitten zu werden;
   `overflow-wrap` ist die Rückfallebene, falls keine Trennmuster vorliegen.
   Greift ausschließlich unterhalb von rund 360 px. */
/* HIER STAND EIN WASSERZEICHEN — WIEDER ENTFERNT AM 06.08.2026.
 *
 * Kurz gab es an dieser Stelle dieselbe Behandlung wie bei den Ablauf-
 * Schritten: die Ziffer gross, blass und absolut in der rechten unteren Ecke.
 * Das war ein Fehlgriff, und die Messung zeigt genau, warum.
 *
 * Der Entwurf haelt die beiden Ziffern naemlich sehr wohl auseinander — nur
 * nicht ueber die Ecke, sondern ueber den Charakter:
 *
 *     Ablauf          180 px · Deckkraft 0,08 · absolut · „1"
 *     Ankaufsprofil  49,5 px · Deckkraft 0,70 · im Fluss · „01"
 *
 * Das eine ist ein Fluestern hinter dem Text, das andere ein sichtbares
 * Etikett davor. Wer beide zum Wasserzeichen macht, nimmt dem Wasserzeichen
 * seine Aussage („hier zaehlt die Reihenfolge") und laesst die drei
 * Objektarten wie vier Schritte aussehen.
 *
 * Und der vermeintliche Gewinn war keiner: Die Kachel misst in beiden
 * Fassungen exakt 339×179 px. Die Ziffernspalte kostet auf dem Telefon
 * nichts, was die Umstellung zurueckgeholt haette.
 *
 * REGEL DARAUS: Bevor eine Gestaltung auf ein zweites Element uebertragen
 * wird, erst pruefen, ob der Entwurf die beiden bewusst trennt. Aehnliche
 * Elemente sind nicht dasselbe Element. */

.ankaufsprofil-list > li > * {
  min-width: 0;
}
.ankaufsprofil-list h3 {
  hyphens: auto;
  overflow-wrap: break-word;
}


/* ── 11e. Sektion „Über Johannes" ───────────────────────────────────────
 * Asymmetrischer Zweispalter, 2fr Bild zu 3fr Text.
 *
 * Zuordnung der Tailwind-Kurzformen aus dem Entwurf:
 *   space-y-2                   →  .about-list > li + li
 *   text-[var(--c-text-muted)]  →  .text-muted
 * ─────────────────────────────────────────────────────────────────────── */

.about-grid {
  display: grid;
  gap: var(--sp-8);
}
@media (min-width: 1024px) {
  .about-grid {
    grid-template-columns: 2fr 3fr;
    gap: var(--sp-16);
    align-items: center;
  }
}

/* Der Rahmen ist 3:4, der Bildbehälter darin 110 % hoch und um 5 % nach
   oben gezogen. Der Überstand ist der Vorrat für die sehr zarte
   Parallaxe — ohne ihn liefe beim Scrollen ein Streifen leer.
   Aus derselben Rechnung kommt das Seitenverhältnis der Bilddatei:
   3:4 mal 1,1 ergibt 15:22, siehe bild-spezifikation.md. */
.about-image {
  position: relative;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.about-image-inner {
  width: 100%;
  height: 110%;
  margin-top: -5%;
}
.about-image-inner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about-list > li + li { margin-top: var(--sp-2); }


/* ── 11f. Sektion „Vergleich" ───────────────────────────────────────────
 * Gegenüberstellung Direktverkauf und Makler.
 *
 * ACHTUNG, F4: Drei Tokens in diesem Abschnitt sind NIRGENDS definiert —
 * `--fs-xs`, `--fw-medium` und `--lh-snug`. Das ist kein Versehen und wird
 * hier auch nicht repariert: Im abgenommenen Entwurf fallen diese Angaben
 * ersatzlos aus, und die Eigenschaften erben stattdessen von ihrer Umgebung.
 * Würden wir die Tokens definieren, sähe die Tabelle anders aus als
 * freigegeben.
 *
 * Unter 768 px bricht die Tabelle auf: Die Kopfzeile verschwindet, jede Zeile
 * wird zu einer eigenen Karte, und die Spaltennamen erscheinen als `::before`
 * vor den Werten. Deshalb stehen die Überschriften im Block fest — sie müssen
 * mit diesen beiden `content`-Angaben übereinstimmen.
 * ─────────────────────────────────────────────────────────────────────── */

/* Der Vorspann stand im Entwurf mit einer Inline-Breite am Element
   (`mx-auto` plus `max-width:46rem`). Er ist damit breiter als die
   allgemeine 65-Zeichen-Grenze fuer Absaetze — gewollt, weil er zentriert
   unter einer breiten Ueberschrift steht. */
.vergleich-lead {
  max-width: 46rem;
  margin-inline: auto;
}

.comparison-table {
  border: 1px solid color-mix(in srgb, var(--c-border) 80%, transparent);
  border-radius: 16px;
  overflow: hidden;
  background: var(--c-bg, #fff);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}

.comparison-header,
.comparison-row {
  display: grid;
  grid-template-columns: 1.1fr 1.5fr 1.9fr;
  border-bottom: 1px solid color-mix(in srgb, var(--c-border) 60%, transparent);
  transition: background-color 200ms ease-out;
}
.comparison-row:last-child { border-bottom: none; }
.comparison-row:hover {
  background-color: color-mix(in srgb, var(--c-accent) 3%, transparent);
}

.comparison-header {
  background: var(--c-surface, #f5f5f5);
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-text-muted);
  font-weight: var(--fw-bold);
}
.comparison-header .comparison-cell {
  padding-top: var(--sp-6);
  padding-bottom: var(--sp-6);
}
.comparison-header .comparison-cell--own {
  background: color-mix(in srgb, var(--c-accent) 8%, transparent);
  color: var(--c-accent-dark);
}

.comparison-cell {
  padding: var(--sp-8) var(--sp-12);
  line-height: var(--lh-snug);
  display: flex;
  align-items: center;
}
.comparison-cell--theme {
  font-weight: var(--fw-bold);
  color: var(--c-text);
}
.comparison-cell--own {
  color: var(--c-primary);
  font-weight: var(--fw-medium);
  background: color-mix(in srgb, var(--c-accent) 5%, transparent);
}
.comparison-cell--other { color: var(--c-text-muted); }

/* Im Entwurf stand die Fußnote mit vier Tailwind-Kurzformen und einer
   Inline-Breite am Element: `mt-8 text-sm mx-auto text-center` plus
   `max-width:48rem`. */
/* Im Entwurf steht an dieser Regel `line-height: var(--lh-relaxed)`. Der Wert
   ist dort WIRKUNGSLOS: Am selben Element haengt die Hilfsklasse `text-sm`,
   die gleich stark ist und spaeter steht — wirksam sind deren 1.25rem.
   Beide wirksamen Werte stehen deshalb hier direkt in der Klasse statt ueber
   `text-sm` im Markup: Die Sektion liegt bereits auf der Seite, und Muster
   werden beim Einfuegen kopiert, nicht verknuepft. Eine Markup-Aenderung haette
   ein erneutes Einfuegen erzwungen, ohne dass sich am Ergebnis etwas aendert. */
.comparison-footnote {
  color: var(--c-text-muted);
  font-size: var(--fs-sm);
  line-height: 1.25rem;
  letter-spacing: 0.01em;
  max-width: 48rem;
  margin-inline: auto;
  text-align: center;
}

@media (max-width: 768px) {
  .comparison-header { display: none; }

  .comparison-row {
    grid-template-columns: 1fr;
    padding-bottom: var(--sp-3);
  }

  .comparison-cell {
    padding: var(--sp-4) var(--sp-8);
    display: block;
  }

  .comparison-cell--theme {
    background: var(--c-surface, #f5f5f5);
    font-size: var(--fs-xs);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--c-text-muted);
    padding-top: var(--sp-6);
    padding-bottom: var(--sp-4);
  }

  .comparison-cell--own {
    background: color-mix(in srgb, var(--c-accent) 6%, transparent);
    padding-top: var(--sp-6);
    padding-bottom: var(--sp-6);
  }

  /* Diese beiden ersetzen die weggefallene Kopfzeile. Sie müssen mit den
     Überschriften im Block übereinstimmen — deshalb sind die dort fest. */
  .comparison-cell--own::before {
    content: "Bei mir: ";
    font-weight: var(--fw-bold);
    color: var(--c-text-subtle);
    margin-right: 0.3em;
  }
  .comparison-cell--other::before {
    content: "Über Makler: ";
    font-weight: var(--fw-bold);
    color: var(--c-text-subtle);
    margin-right: 0.3em;
  }
}


/* ── 11g. Sektion „FAQ" ─────────────────────────────────────────────────
 * Aufklappbare Fragen, danach der Ausklang mit zwei Handlungsaufrufen.
 *
 * Zuordnung der Tailwind-Kurzformen aus dem Entwurf:
 *   style="max-width:48rem"          →  .container--faq
 *   mb-2 mx-auto style="max-width:none"  →  .faq-outro-frage
 *   mb-6 mx-auto style="max-width:42rem" →  .faq-outro-text
 *   flex flex-wrap gap-3 justify-center  →  .faq-outro-cta
 * ─────────────────────────────────────────────────────────────────────── */

/* Der Lesebereich der Fragen ist schmaler als die übrigen Sektionen — bei
   Fließtext dieser Länge ist das der Unterschied zwischen lesbar und
   anstrengend. Zwei Klassen im Selektor, damit die Regel gegen die
   Breiten-Staffelung des Containers gewinnt. */
.container.container--faq { max-width: 48rem; }

/* Aufklappen und Zuklappen können `<details>` und `<summary>` von Haus aus,
   samt Tastaturbedienung und der richtigen Ansage in Vorlesesoftware. Auch
   das Pluszeichen und sein Wechsel zum Minus kommen ohne JavaScript aus. */
.accordion-item {
  border-bottom: 1px solid var(--c-border);
}

.accordion-toggle {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: var(--sp-4) 0;
  background: none;
  border: none;
  font-weight: var(--fw-bold);
  font-size: var(--fs-lg);
  color: var(--c-primary);
  text-align: left;
  cursor: pointer;
}

/* Das Zeichen bleibt bewusst grau. Der Akzent ist den Handlungsaufrufen
   vorbehalten — eine Fragenliste ist keine. Erst im aufgeklappten Zustand
   wechselt es auf die Hausfarbe, weil es dann „aktiv" bedeutet. */
.accordion-toggle::after {
  content: '+';
  font-size: var(--fs-xl);
  color: var(--c-text-subtle);
  font-weight: 400;
  transition: transform var(--duration-base) var(--ease-out);
}

/* Das Minuszeichen steht hier als ZEICHEN, nicht als CSS-Escape `2`.
   Der erste Versuch lief durch drei Ebenen — Shell, Python, CSS — und die
   mittlere hat `` als Oktalzahl gelesen. Herausgekommen ist ein
   unsichtbares Steuerzeichen plus die Ziffer „2", die dann aufgeklappt
   neben jeder Frage stand. Das Zeichen direkt zu schreiben kennt diese
   Fehlerquelle nicht. */
details[open] .accordion-toggle::after {
  content: '−';
  color: var(--c-primary);
}

.accordion-panel {
  padding: 0 0 var(--sp-4);
  color: var(--c-text-muted);
}
.accordion-panel[hidden] { display: none; }

.faq-outro-frage {
  margin: 0 auto var(--sp-2);
  max-width: none;
  color: var(--c-text-muted);
}
.faq-outro-frage strong { color: var(--c-primary); }

.faq-outro-text {
  margin: 0 auto var(--sp-6);
  max-width: 42rem;
  color: var(--c-text-muted);
}

.faq-outro-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  justify-content: center;
}


/* ── 11h. Sektion „Referenzen" ──────────────────────────────────────────
 * Waagerechter Kartenlauf mit drei Verhalten auf demselben Markup:
 *
 *   ab 768 px   an den Scrollverlauf gekoppelt (GSAP, siehe jk-motion.js)
 *   unter 768   native Wischgeste mit Einrastpunkten
 *   ohne Motion einfacher Schiebebereich
 *
 * Unterschieden wird ausschließlich hier und im Bewegungsmodul — im PHP gibt
 * es keine einzige Verzweigung.
 * ─────────────────────────────────────────────────────────────────────── */

/* Der Riegel gegen waagerechten Überlauf der ganzen Seite. Das Laufband ist
   absichtlich breiter als der Bildschirm; ohne diese Zeile ließe sich die
   komplette Seite seitwärts schieben. */
.ref-scroll-section { overflow: hidden; }

/* Der Vorspann stand im Entwurf mit `mx-auto` und einer Inline-Breite von
   42rem am Element — breiter als die allgemeine 65-Zeichen-Grenze, weil er
   zentriert unter einer breiten Ueberschrift steht. */
.referenzen-lead {
  max-width: 42rem;
  margin-inline: auto;
}

.ref-scroll-viewport {
  position: relative;
  padding-block: var(--sp-12) var(--sp-10);
}

.ref-scroll-track {
  display: flex;
  gap: var(--sp-8);
  padding-left: max(var(--sp-6), 12vw);
  padding-right: var(--sp-6);
  will-change: transform;
}

/* Leeres Element hinter der letzten Karte. Ohne ihn endet der Lauf, sobald
   die letzte Karte den rechten Rand erreicht — sie klebt dann am Bildschirm-
   rand, statt in der Mitte zu landen. Ein `padding-right` am Laufband täte es
   nicht: Browser zählen es bei Flex-Containern nicht zuverlässig zur
   Scrollbreite. */
.ref-scroll-spacer {
  flex: 0 0 30vw;
  align-self: stretch;
}

.ref-card {
  flex: 0 0 clamp(320px, 40vw, 560px);
  margin: 0;
}

/* Auf dem Telefon kein gekoppelter Lauf, sondern die Wischgeste mit
   Einrastpunkten — die kennt jeder aus Nachrichten-Apps. Die Bildlaufleiste
   wird ausgeblendet, weil sie hier nur stört. */
@media (max-width: 767px) {
  .ref-scroll-viewport { padding-block: var(--sp-6); }

  .ref-scroll-track {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .ref-scroll-track::-webkit-scrollbar { display: none; }

  .ref-card {
    scroll-snap-align: start;
    flex: 0 0 78vw;
  }
}

/* Wer Bewegungen abgeschaltet hat, bekommt einen gewöhnlichen
   Schiebebereich. `transform: none !important` ist nötig, falls GSAP vor der
   Auswertung schon etwas gesetzt hat. */
@media (prefers-reduced-motion: reduce) {
  .ref-scroll-viewport { overflow-x: auto; }
  .ref-scroll-track { transform: none !important; }
}

.ref-card .ref-media {
  position: relative;
  margin-bottom: var(--sp-3);
}
.ref-card .ref-media img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  display: block;
  border-radius: var(--radius-md);
  background: var(--c-surface-alt);
}

/* Das Jahres-Etikett auf dem Bild.
   Die Deckung von 80 % ist gemessen, nicht geschätzt: Bei 40 % — dem ersten
   Entwurf — sank der Kontrast der Zahl über hellem Himmel auf 3,4:1. Bei
   dieser Größe und Schriftstärke gilt 4,5:1, die Zahl war kaum lesbar. Mit
   80 % bleibt die Milchglas-Wirkung erhalten, aber der Untergrund ist
   unabhängig vom Bild hell genug — schlimmstenfalls rund 8:1. */
.ref-card .ref-year {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.55);
  color: var(--c-primary);
  font-family: var(--font-heading);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: var(--radius-md);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

.ref-card figcaption {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--c-text-muted);
}
.ref-card figcaption strong {
  display: block;
  color: var(--c-text);
  font-weight: 500;
  font-size: var(--fs-base);
  margin-bottom: var(--sp-1);
}


/* ── 11i. Sektion „Kontakt" ─────────────────────────────────────────────
 * Hintergrundbild mit diagonalem Verlauf, links der Einstieg, rechts das
 * Formular als heller Kasten darüber.
 *
 * DER ZWEITE TEIL DIESES ABSCHNITTS IST EINE ÜBERSETZUNGSSCHICHT.
 *
 * Das Formular kommt aus Fluent Forms und bringt sein eigenes Markup mit —
 * `.ff-el-group`, `.ff-el-form-control`, `.ff-el-form-check-label` und so
 * fort. Im Entwurf hießen dieselben Dinge `.input`, `.label` und `.chip`.
 *
 * Statt das Markup zu verbiegen, übersetzen wir hier: Jede Regel des
 * Entwurfs bekommt den Selektor, unter dem Fluent Forms dasselbe Element
 * ausliefert. Der Vorteil zeigt sich beim nächsten Update des Plugins — es
 * ändert dann höchstens seine Klassen, und wir passen eine Stelle an, statt
 * eine nachgebaute Formular-Ausgabe zu pflegen.
 *
 * Alles ist auf `.kontakt-form` eingegrenzt. Fluent Forms könnte später an
 * anderer Stelle stehen, und dort soll nichts davon greifen.
 * ─────────────────────────────────────────────────────────────────────── */

/* Der Kasten. Im Entwurf gibt es dazu eine zweite Regel `form.card` mit einem
   eigenen Schatten — und die GEWINNT gegen `.kontakt-form`, weil ein Element
   im Selektor schwerer wiegt als eine zweite Klasse allein (0,1,1 gegen 0,1,0).
   Der wirksame Schatten am Kontakt-Kasten ist also der leise von `form.card`,
   nicht der ausladende von `.kontakt-form`. Beim Lesen des Stylesheets sieht
   es genau umgekehrt aus. */
.card {
  background: var(--c-bg);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: var(--sp-6);
  position: relative;
}

form.card {
  box-shadow: 0 8px 24px -12px color-mix(in srgb, var(--c-primary) 25%, transparent);
}

/* Bei uns ist der Kasten ein `<div>` — das `<form>` darin liefert Fluent
   Forms. `form.card` greift deshalb nicht, und ohne diese Zeile bekäme der
   Kasten den ausladenden Schatten, den es im Entwurf nie zu sehen gab. */
.kontakt-form.card {
  box-shadow: 0 8px 24px -12px color-mix(in srgb, var(--c-primary) 25%, transparent);
}

.kontakt-section {
  position: relative;
  overflow: hidden;
  padding-block: var(--sp-12);
  isolation: isolate;
}

.kontakt-bg {
  position: absolute;
  inset: 0;
  z-index: -1;
}

/* Der Verlauf beginnt bewusst erst bei 45 Prozent: Links bleibt das Bild
   offen, damit Johannes' Gesicht sichtbar ist; rechts wird es fast
   vollflächig hell, damit das Formular lesbar darüber liegt. */
.kontakt-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0)    0%,
    rgba(255, 255, 255, 0)   45%,
    rgba(255, 255, 255, 0.85) 68%,
    rgba(255, 255, 255, 0.97) 100%
  );
}

.kontakt-bg img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 0% 35%;
  filter: saturate(0.95);
}

.kontakt-grid {
  display: grid;
  gap: var(--sp-10);
  align-items: center;
  min-height: 600px;
}
@media (min-width: 900px) {
  .kontakt-grid {
    grid-template-columns: 1fr minmax(420px, 520px);
    gap: var(--sp-16);
  }
}

.kontakt-intro h2,
.kontakt-intro .lead { color: var(--c-primary); }

.kontakt-direct {
  font-size: var(--fs-base);
  color: var(--c-text);
}
.kontakt-direct a {
  color: var(--c-primary);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.kontakt-form {
  background: rgba(255, 255, 255, 0.96);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 20px 60px -20px rgba(15, 30, 55, 0.35);
  border-color: rgba(255, 255, 255, 0.6);
}

/* Unter 900 px steht das Bild als Streifen über dem Formular, statt
   dahinter. Ein halbdurchsichtiger Kasten über einem Foto kostet auf
   älteren Geräten spürbar Leistung und ist schlechter lesbar. */
@media (max-width: 899px) {
  .kontakt-section { padding-block: 0 var(--sp-12); }

  .kontakt-bg {
    position: relative;
    inset: auto;
    height: 280px;
  }
  .kontakt-bg::after { display: none; }
  .kontakt-bg img {
    height: 100%;
    object-position: 30% 25%;
  }

  .kontakt-grid {
    padding-top: var(--sp-10);
    min-height: 0;
  }
  .kontakt-form {
    background: var(--c-bg);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* Die Zusage über dem Formular. Sie beantwortet die Frage, die vor dem
   Absenden im Kopf steht: „Und was passiert dann?" */
.kontakt-zusage {
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--c-text-muted);
  /* 1.25rem, nicht var(--sp-6). Im Entwurf steht dort `mb-5`, und eine 5 gibt
     es in unserer Abstands-Skala nicht (1, 2, 3, 4, 6, 8, 10, 12, …). Den
     Wert auf die naechste Stufe zu runden waere 4,5 Pixel daneben. */
  margin-bottom: 1.25rem;
}
.kontakt-zusage strong { color: var(--c-primary); }


/* ── Übersetzungsschicht auf das Markup von Fluent Forms ───────────────── */

/* ZUERST: die Gestaltungs-Variablen von Fluent Forms auf unsere Werte legen.
 *
 * Das Plugin schreibt eigene Regeln direkt in die Seite, etwa
 * `form.fluent_form_3 .ff-btn-submit { background: var(--fluentform-primary) }`.
 * Diese Regel ist stärker als unsere und lässt sich mit vertretbarem Aufwand
 * nicht überbieten — man käme in ein Wettrüsten mit Selektoren.
 *
 * Wir füttern sie stattdessen mit den richtigen Werten. Nebeneffekt: Auch
 * alles, was wir nicht einzeln angefasst haben — Fokusrahmen, Fehlerfarben,
 * Randungen — liegt damit von selbst in unserer Farbwelt.
 *
 * ZUGLEICH EINE KORREKTUR: Diese Variablen standen in
 * `fluentform-public-default.css`, die wir abmelden (siehe enqueue.php). Ohne
 * Ersatz war `--fluentform-primary` undefiniert — und eine undefinierte
 * Variable macht die ganze Angabe ungültig. Der Absende-Knopf bekam dadurch
 * einen durchsichtigen Hintergrund und stand weiß auf weiß, also unsichtbar.
 * Genau der Grund, warum man eine fremde Datei nicht abmeldet, ohne
 * nachzusehen, was noch darauf zeigt. */
.kontakt-form .frm-fluent-form {
  --fluentform-primary: var(--c-accent);
  --fluentform-secondary: var(--c-text-muted);
  --fluentform-danger: var(--c-error);
  --fluentform-border-color: var(--c-border-strong);
  --fluentform-border-radius: var(--radius-md);
  --fluentform-input-select-height: auto;
}

/* Abstand zwischen den Feldern. Im Entwurf kam er aus `space-y-4`. */
.kontakt-form .ff-el-group { margin-bottom: var(--sp-4); }
.kontakt-form .ff-el-group:last-child { margin-bottom: 0; }

/* `.label` */
.kontakt-form .ff-el-input--label label {
  display: block;
  font-weight: var(--fw-bold);
  color: var(--c-primary);
  margin-bottom: var(--sp-2);
  font-size: inherit;
}

/* Der Stern hinter Pflichtfeldern. Fluent Forms setzt dafür eine Klasse an
   die Hülle; im Entwurf stand er im Beschriftungstext. */
.kontakt-form .ff-el-is-required label::after {
  content: ' *';
  color: var(--c-text-subtle);
  font-weight: var(--fw-regular);
}

/* `.input`, `.textarea` */
.kontakt-form .ff-el-form-control {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  font: inherit;
  color: var(--c-text);
  background: var(--c-bg);
  border: 2px solid var(--c-border-strong);
  border-radius: var(--radius-md);
  transition: border-color var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out);
  min-height: 48px;
}
.kontakt-form .ff-el-form-control:hover { border-color: var(--c-text-subtle); }
.kontakt-form .ff-el-form-control:focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--c-accent) 18%, transparent);
}
.kontakt-form textarea.ff-el-form-control { min-height: 7rem; }

/* `.chip` — die Mehrfachauswahl.
   Das Ankreuzfeld selbst wird unsichtbar, bleibt aber im Dokument: So ist es
   weiterhin mit der Tastatur erreichbar und wird von Vorlesesoftware
   angesagt. `display: none` würde beides zerstören.
   Die Beschriftung übernimmt das Aussehen der Kachel. */
/* Im Entwurf liegen die Kacheln in einem Flex-Container mit `gap-2`. Das hat
   eine Folge, die man leicht uebersieht: Ein Flex-Kind wird "blockifiziert" —
   aus `inline-flex` wird `flex`. Genau das meldete der Vergleich.
   Wichtiger als der Zahlenwert ist aber, was daran haengt: Als Inline-Elemente
   wuerden die Kacheln zusaetzlich die Leerzeichen zwischen den Tags als Abstand
   rendern und an der Schriftlinie ausgerichtet — beides gibt es im Entwurf
   nicht. Deshalb hier dieselbe Konstruktion statt nachgestellter Aussenabstaende.
   Der `:has()`-Filter grenzt es auf die Gruppen mit Ankreuzfeldern ein; das
   Textfeld daneben soll kein Flex-Kind werden. */
.kontakt-form .ff-el-input--content:has(.ff-el-form-check:not(.ff-el-tc)) {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Fluent Forms schiebt zwischen Container und Kachel eine zusaetzliche Huelle.
   Damit waere SIE das Flex-Kind und nicht die Kachel — die bliebe `inline-flex`
   und wuerde weiterhin an der Schriftlinie ausgerichtet.
   `display: contents` loest die Huelle auf: Ihr Kasten verschwindet, ihr Kind
   rueckt an ihre Stelle im Flex-Layout. Damit ist die Kachel selbst das
   Flex-Kind, genau wie im Entwurf.
   Unbedenklich, weil die Huelle ein reines `div` ohne Bedeutung ist — bei
   Tabellen- oder Listenelementen waere `display: contents` heikel.

   ⚠️ ABER SIE HAT EINE NEBENWIRKUNG, die uns eingeholt hat — siehe die
   Regel für `.ff-el-form-check-label` direkt darunter. */
.kontakt-form .ff-el-form-check:not(.ff-el-tc) {
  display: contents;
}

/* DIE KACHEL BRAUCHT EINEN BEZUGSRAHMEN — nachgetragen 06.08.2026.
 *
 * DAS SYMPTOM: Auf dem Telefon sprang die Seite beim Antippen einer Auswahl
 * hoch zur Überschrift „Unverbindlich, in Ihrem Tempo" — also an den Anfang
 * des Formulars. Auf dem Desktop ebenfalls, nur weniger auffällig, weil der
 * Weg kürzer ist.
 *
 * DIE URSACHE, und sie ist hausgemacht: Das echte Kästchen ist
 * `position: absolute` (siehe nächste Regel) — der übliche Weg, es für die
 * Tastatur erreichbar zu halten und für das Auge zu verbergen. Ein absolut
 * gesetztes Element sucht sich als Bezugsrahmen den nächsten positionierten
 * Vorfahren. Die Hülle darüber steht durch `display: contents` **ohne
 * eigenen Kasten** da und kommt dafür nicht in Frage, die Kachel war
 * `static` — also fiel es bis zum Formular durch.
 *
 * Gemessen: ALLE Kästchen lagen auf derselben Stelle, `y=15075`, am oberen
 * Formularrand. Beim Antippen fokussiert der Browser das Kästchen und
 * scrollt dorthin, wo es liegt. Das war kein Fehler von Fluent Forms,
 * sondern die Folge meiner eigenen Zeile darüber.
 *
 * DIE LEHRE, zum zweiten Mal an einem Tag: Wer einem Element den Kasten
 * nimmt — durch `display: contents` — oder die Positionierung — durch
 * `static` —, nimmt ihm auch die Rolle als Bezugsrahmen. Was darin absolut
 * positioniert ist, wandert dann irgendwohin. Bei den Sternen der
 * Bewertungskarten war es dasselbe Muster. */
.kontakt-form .ff-el-form-check-label {
  position: relative;
}

.kontakt-form .ff-el-form-check:not(.ff-el-tc) .ff-el-form-check-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.kontakt-form .ff-el-form-check:not(.ff-el-tc) .ff-el-form-check-label {
  display: inline-flex;
  align-items: center;
  padding: var(--sp-2) var(--sp-4);
  background: var(--c-surface);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  font-size: var(--fs-sm);
  color: var(--c-text);
  cursor: pointer;
  transition: all var(--duration-fast) var(--ease-out);
  min-height: 40px;
  margin: 0;
}
.kontakt-form .ff-el-form-check:not(.ff-el-tc) .ff-el-form-check-label:hover {
  background: var(--c-surface-alt);
}

/* Angehakt. `:has()` färbt die ganze Kachel statt nur des Textes. */
.kontakt-form .ff-el-form-check:not(.ff-el-tc) .ff-el-form-check-label:has(input:checked) {
  background: var(--c-primary);
  color: #ffffff;
  border-color: var(--c-primary);
}

/* Der Fokusrahmen muss an der Kachel sichtbar werden — das Ankreuzfeld
   dahinter sieht ja niemand. Ohne diese Regel wäre die Auswahl mit der
   Tastatur unbedienbar, weil man nicht sieht, wo man gerade steht. */
.kontakt-form .ff-el-form-check:not(.ff-el-tc) .ff-el-form-check-label:has(input:focus-visible) {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

/* Die Einwilligungszeile mit dem eigenen Ankreuzfeld.
 *
 * Fluent Forms baut sie als CSS-Tabelle:
 *   `.fluentform .ff-el-tc label.ff_tc_label { display: table-row }`
 * mit `display: table-cell` an den Kindern und einem `padding-top: 8px
 * !important`. Das ergibt einen anderen Abstand als im Entwurf und lässt das
 * Häkchen und den Text unterschiedlich hoch sitzen.
 *
 * Der Selektor unten trägt deshalb zusätzlich das Element `label` — damit ist
 * er gleich stark wie ihrer, und unser Stylesheet lädt später. */
.kontakt-form .ff-el-tc label.ff_tc_label {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  cursor: pointer;
  line-height: 1.5;
  margin: 0;
}
.kontakt-form .ff-el-tc label.ff_tc_label a {
  color: var(--c-primary);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Die Tabellenzellen zurücknehmen. `!important` steht hier nur, weil die
   Regel des Plugins es ebenfalls trägt — anders kommt man nicht daran vorbei. */
.kontakt-form .ff-el-tc label.ff_tc_label > span,
.kontakt-form .ff-el-tc label.ff_tc_label > div {
  display: block;
  width: auto;
  padding-top: 0 !important;
}
.kontakt-form .ff_tc_checkbox { flex-shrink: 0; padding-top: 1px !important; }

.kontakt-form .ff_tc_checkbox input {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin: 2px 0 0;
  border: 2px solid var(--c-border-strong);
  border-radius: 5px;
  background: var(--c-bg);
  cursor: pointer;
  position: relative;
  transition: border-color 180ms ease, background-color 180ms ease,
              transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.kontakt-form .ff_tc_checkbox input:hover { border-color: var(--c-text-subtle); }
.kontakt-form .ff_tc_checkbox input:focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}
.kontakt-form .ff_tc_checkbox input:checked {
  background: var(--c-accent);
  border-color: var(--c-accent);
  transform: scale(1.08);
}
.kontakt-form .ff_tc_checkbox input:checked::after {
  content: '';
  position: absolute;
  /* Nachgerechnet, nicht geschaetzt: Der Haken ist ein 6x11-Kaestchen, um
     45 Grad um seinen Mittelpunkt gedreht. Bei left 5 / top 1 liegt seine
     sichtbare Mitte auf (8.00, 8.62) statt auf (9.00, 9.00) der 18x18 grossen
     Innenflaeche -- also einen Pixel zu weit links und einen halben zu hoch.
     Mit diesen Werten sitzt er mittig. */
  left: 6px;
  top: 1.5px;
  width: 6px;
  height: 11px;
  border: solid #ffffff;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
  animation: dsgvo-check 220ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes dsgvo-check {
  0%   { opacity: 0; transform: rotate(45deg) scale(0.5); }
  100% { opacity: 1; transform: rotate(45deg) scale(1); }
}

/* Die Absende-Schaltfläche bekommt das Aussehen unserer Akzent-Schaltfläche
   und die volle Breite — wie im Entwurf. */
.kontakt-form .ff-btn-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-6);
  min-height: 48px;
  border: none;
  border-radius: var(--radius-md);
  background: var(--c-accent);
  color: var(--c-accent-contrast);
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: var(--fw-bold);
  line-height: 1.2;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-out);
  margin-top: var(--sp-6);
}
.kontakt-form .ff-btn-submit:hover { background: var(--c-accent-dark); }
.kontakt-form .ff-btn-submit:focus-visible {
  outline: 2px solid var(--c-primary);
  outline-offset: 2px;
}

/* Fehlermeldungen. Fluent Forms setzt sie unter das Feld — das ist so
   eingestellt und richtig; hier bekommen sie nur unsere Farbe und Größe. */
.kontakt-form .text-danger,
.kontakt-form .error {
  color: var(--c-error);
  font-size: var(--fs-sm);
  margin-top: var(--sp-2);
}

/* Der Aufklapper um die optionalen Felder. Das `<details>` baut
   `jk-formular.js` zur Laufzeit — Fluent Forms kann in der kostenlosen
   Fassung keine aufklappbaren Abschnitte. */
.kontakt-form .details-toggle {
  border-top: 1px solid var(--c-border);
  padding-top: var(--sp-4);
  margin-bottom: var(--sp-4);
}
.kontakt-form .details-toggle__summary {
  cursor: pointer;
  color: var(--c-text-muted);
  font-size: 0.875rem;
  font-weight: 500;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  user-select: none;
  transition: color 180ms ease;
}
.kontakt-form .details-toggle__summary::-webkit-details-marker { display: none; }
.kontakt-form .details-toggle__summary:hover,
.kontakt-form .details-toggle__summary:focus-visible { color: var(--c-primary); }

.kontakt-form .details-toggle__icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  transition: transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
.kontakt-form .details-toggle[open] .details-toggle__icon { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .kontakt-form .details-toggle__icon { transition: none; }
  .kontakt-form .ff_tc_checkbox input { transition: none; }
  .kontakt-form .ff_tc_checkbox input:checked { transform: none; }
  .kontakt-form .ff_tc_checkbox input:checked::after { animation: none; }
}


/* ── 11j. Sektion „Bewertungen" ─────────────────────────────────────────
 * Links der Wert, rechts die drei Stimmen. Beim Scrollen bleibt der Wert
 * stehen, und die Karten stapeln sich sichtbar übereinander.
 *
 * Beides ohne eine Zeile JavaScript — `position: sticky` genügt. Und weil es
 * ausschließlich vom Scrollen des Besuchers abhängt, ist es auch kein
 * Bewegungs-Thema: Wer nicht scrollt, sieht ein Standbild.
 *
 * ACHTUNG, F4: `--header-height` ist NIRGENDS definiert — weder im Entwurf
 * noch hier. Der Rückfallwert `4.5rem` in `var(--header-height, 4.5rem)` ist
 * also der wirksame Wert. Bitte die Variable nicht „nachtragen": Der
 * mitlaufende Kopf ist tatsächlich 72 px hoch, und 4,5 rem sind bei unserer
 * Grundgröße 81 px. Die 9 px Unterschied sind der Abstand, mit dem die Karten
 * im abgenommenen Zustand unter dem Kopf einrasten.
 * ─────────────────────────────────────────────────────────────────────── */

/* Der Lesebereich ist schmaler als die übrigen Sektionen. `!important` steht
   hier wie im Entwurf — es muss gegen die Breiten-Staffelung des Containers
   ankommen, die dieselbe Spezifität hat. */
.reviews-container { max-width: 50rem !important; }

.reviews-layout {
  display: grid;
  gap: var(--sp-12);
}
.reviews-container .reviews-layout {
  grid-template-columns: 1fr;
  gap: var(--sp-8);
}

@media (min-width: 900px) {
  .reviews-layout {
    grid-template-columns: minmax(160px, 190px) minmax(0, 1fr);
    gap: var(--sp-12);
    /* `stretch`, nicht `start`. Sonst wäre die linke Spalte nur so hoch wie
       ihr Inhalt, und das `sticky` darin hätte keine Strecke zum Kleben —
       der Wert würde sofort mit nach oben scrollen. */
    align-items: stretch;
  }
  .reviews-container .reviews-layout {
    grid-template-columns: minmax(180px, 200px) minmax(0, 1fr);
    gap: var(--sp-8);
  }
}

.reviews-score  { min-width: 0; }
.reviews-stream { min-width: 0; }

.reviews-score-sticky {
  position: sticky;
  top: calc(var(--header-height, 4.5rem) + var(--sp-6));
}
@media (max-width: 899px) {
  .reviews-score-sticky {
    position: static;
    text-align: center;
  }
}

.reviews-stack {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

/* Jede Karte klebt am selben oberen Rand, aber 16 px tiefer als die vorige.
   Beim Scrollen wird dadurch sichtbar, dass sie aufeinanderliegen — wie ein
   Kartenstapel von oben gesehen. */
.review-card {
  position: sticky;
  top: calc(var(--header-height, 4.5rem) + var(--sp-6));
  background: #ffffff;
  border: 1px solid var(--c-border);
  border-radius: var(--radius-lg);
  padding: var(--sp-10) var(--sp-8);
  box-shadow:
    0 1px 2px rgba(15, 30, 55, 0.04),
    0 12px 32px -16px rgba(15, 30, 55, 0.18);
  overflow: hidden;
}

/* Die große, blasse Sternzeile hinten in der Karte. Sie liegt bewusst unter
   dem Text und außerhalb der Vorlese-Reihenfolge — reine Fläche. */
/* Der Versatz steht in `em`, nicht in `rem` — 06.08.2026.
 *
 * Rechnerisch identisch: Bei 5rem Schriftgröße sind 0.1em genau 0.5rem und
 * 0.2em genau 1rem. Auf dem Desktop ändert sich also nichts.
 *
 * Der Unterschied zeigt sich, sobald die Schrift kleiner wird. Die Sterne
 * hängen bewusst ein Stück über die Kartenkante hinaus; wie weit sie dabei
 * sichtbar bleiben, hängt an der Höhe des Buchstabenkastens — und die hängt
 * an der Schriftgröße. Als ich sie auf dem Telefon auf 3.25rem verkleinert
 * habe, blieb der Versatz bei festen −1rem stehen. Ein kleinerer Kasten hat
 * weniger Luft unter der Grundlinie, also rutschten die sichtbaren Sterne
 * relativ zur Karte nach unten. Genau das ist René am Gerät aufgefallen.
 *
 * In `em` zieht der Versatz jede künftige Größenänderung von selbst mit. Das
 * ist die eigentliche Lehre: Ich hatte einen Wert geändert und den davon
 * abhängigen nicht — statt ihn nachzurechnen, wird er jetzt abgeleitet. */
.review-card::before {
  content: "★★★★★";
  position: absolute;
  right: -0.1em;
  bottom: -0.2em;
  font-size: 5rem;
  letter-spacing: -0.08em;
  line-height: 1;
  color: var(--c-accent);
  opacity: 0.12;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  white-space: nowrap;
}
.review-card[data-stars="5"]::before { content: "★★★★★"; }
.review-card[data-stars="4"]::before { content: "★★★★☆"; }
.review-card[data-stars="3"]::before { content: "★★★☆☆"; }
.review-card[data-stars="2"]::before { content: "★★☆☆☆"; }
.review-card[data-stars="1"]::before { content: "★☆☆☆☆"; }

.review-card > * {
  position: relative;
  z-index: 1;
}

.review-card:nth-child(2) { top: calc(var(--header-height, 4.5rem) + var(--sp-6) + 16px); }
.review-card:nth-child(3) { top: calc(var(--header-height, 4.5rem) + var(--sp-6) + 32px); }
.review-card:nth-child(4) { top: calc(var(--header-height, 4.5rem) + var(--sp-6) + 48px); }

/* Auf dem Telefon kein Stapel — bei 375 px lägen die Karten zu eng
   übereinander, und man sähe nur noch Ränder.
 *
 * `relative` UND NICHT `static` — korrigiert 06.08.2026.
 *
 * Hier stand `static`, was den Haft-Effekt genauso abschaltet. Nur ist eine
 * statische Karte kein Bezugsrahmen mehr für ihr absolut gesetztes
 * Pseudo-Element: Die Sternzeilen ALLER drei Karten landeten dadurch auf
 * derselben Stelle weit unten auf der Seite, übereinander. Sichtbar war
 * das als ein einziger, riesig wirkender Sternblock am Ende der Sektion —
 * es waren drei Sätze à 90 px, die sich deckten.
 *
 * Der abgenommene Entwurf hat denselben Fehler; er ist geerbt und nicht
 * durch die Portierung entstanden. Nachgemessen: In beiden Fassungen
 * meldeten alle drei `::before` dasselbe `top`. */
@media (max-width: 899px) {
  .review-card,
  .review-card:nth-child(2),
  .review-card:nth-child(3),
  .review-card:nth-child(4) {
    position: relative;
    top: auto;
    padding: var(--sp-6);
  }

  /* Kleiner und blasser als auf dem Desktop — 06.08.2026.
     Die 5rem des Entwurfs sind auf einer 343 px breiten Karte kein
     Wasserzeichen mehr, sondern ein Bildelement: Fuenf Sterne dieser Groesse
     sind breiter als die Karte und werden am Rand abgeschnitten. Und was auf
     einer weiten Flaeche als Andeutung wirkt, draengt sich auf engem Raum
     vor den Text. */
  .review-card::before {
    font-size: 3.25rem;
    opacity: 0.07;
  }
}

.review-card blockquote {
  font-size: var(--fs-lg);
  line-height: 1.55;
  color: var(--c-text);
  font-weight: 400;
  margin: 0 0 var(--sp-4);
  max-width: none;
  font-style: normal;
}
.review-card blockquote::before,
.review-card blockquote::after { content: none; }

.review-card cite {
  font-style: normal;
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--sp-2);
}
.review-card cite::before { content: '—\00A0'; }
.review-card .cite-name {
  color: var(--c-text);
  font-weight: 500;
}

/* Der Wert links. Die Zahl kommt aus `jk-utilities` und erscheint nur, wenn
   Daten vorliegen — nie als „0,0". */
.score-display { text-align: center; }
@media (min-width: 768px) {
  .score-display { text-align: left; }
}

.score-google-logo {
  display: block;
  width: 64px;
  height: auto;
  color: var(--c-primary);
  opacity: 0.75;
  margin: 0 auto var(--sp-3);
}
@media (min-width: 768px) {
  .score-display .score-google-logo {
    margin-left: 0;
    margin-right: auto;
  }
}

.score-number {
  font-size: var(--fs-5xl);
  line-height: 1;
  font-weight: var(--fw-bold);
  color: var(--c-primary);
  letter-spacing: -0.04em;
}
.score-stars {
  font-size: var(--fs-2xl);
  color: var(--c-accent);
  margin-top: var(--sp-2);
  letter-spacing: 0.05em;
}
.score-caption {
  font-size: var(--fs-sm);
  color: var(--c-text-muted);
  margin-top: var(--sp-3);
}

/* Zwei Knopf-Varianten, die nur hier vorkommen: klein und zurückhaltend.
   Der Verweis auf das Google-Profil darf nicht mit dem Handlungsaufruf
   konkurrieren — deshalb grauer Rahmen statt Akzentfläche. */
.btn--small {
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-sm);
  min-height: 36px;
  gap: var(--sp-1);
}
.btn--quiet {
  background: transparent;
  color: var(--c-text-muted);
  box-shadow: inset 0 0 0 1px var(--c-border-strong);
}
.btn--quiet:hover,
.btn--quiet:focus-visible {
  background: var(--c-surface-warm);
  color: var(--c-primary);
  box-shadow: inset 0 0 0 1px var(--c-text-subtle);
}


/* ── 11k. Danke-Seite ───────────────────────────────────────────────────
 * Die einzige Sektion, die nicht aus dem abgenommenen Entwurf stammt — es
 * gibt sie dort nicht, sie war nur in der Formular-Strategie beschrieben.
 * Deshalb hier so wenig eigenes CSS wie möglich: Alles andere kommt aus den
 * vorhandenen Klassen, damit die Seite dieselbe Sprache spricht wie der Rest.
 *
 * Aufbau: Der Einstieg ist zentriert (Vorzeile, Überschrift, Zusage), alles
 * darunter linksbündig. Zentrierter Fließtext liest sich für die Zielgruppe
 * schlechter, und eine zentrierte Aufzählung hat keine Fluchtlinie, an der
 * das Auge zurückspringen kann.
 * ─────────────────────────────────────────────────────────────────────── */

/* WARUM HIER ÜBER DIE SEKTIONSMARKE UND NICHT ÜBER EIGENE KLASSEN
 *
 * Zuerst standen hier `.danke-intro` und `.is-flush`, gesetzt im Muster.
 * Sauberer im Prinzip — nur liegt der Seiteninhalt in der Datenbank, nicht
 * im Repository. Jede Klassenänderung im Muster verlangt deshalb, dass
 * jemand die Seite im Editor leert und das Muster neu einfügt. Nach dem
 * dritten Durchgang an derselben Seite ist das kein Prinzip mehr, sondern
 * eine Fehlerquelle: Wer den Schritt einmal vergisst, sucht den Fehler im
 * Stylesheet, wo er nicht ist.
 *
 * `data-section` steht ohnehin an jeder Sektion, wird von der
 * Scrollspy-Logik gebraucht und ändert sich nicht beiläufig. Als Anker ist
 * es hier stabiler als eine Klasse, die niemand nachträgt.
 *
 * ─────────────────────────────────────────────────────────────────────────
 * WAS DIE BEIDEN REGELN GERADERÜCKEN
 *
 * `.text-center` zentriert den TEXT, nicht den Kasten. Der Absatz erbt aus
 * dem Tailwind-Grundstylesheet ein `max-width: 65ch`, ist damit schmaler als
 * sein Elternteil und steht ohne automatische Außenabstände links. Sein
 * sauber zentrierter Text saß dadurch 105 px neben der Mitte der Überschrift
 * darüber (gemessen: 615 statt 720).
 *
 * `.headline-tight` zentriert ebenfalls nur den Kasten. Außerhalb eines
 * `.text-center` beginnt die Überschrift damit am linken Rand eines
 * mittigen Kastens — also weder mittig noch auf der Fluchtlinie des Textes
 * darunter (415 statt 324).
 *
 * Beides ist die tückische Sorte: Für sich betrachtet sieht jedes Element
 * richtig aus. Falsch wird es erst im Verhältnis zur Zeile darüber.
 *
 * NICHT im Editor sichtbar: Dessen Arbeitsfläche ist schmaler, dort füllt
 * der 65-ch-Kasten die Spalte aus und der Versatz entsteht gar nicht. Für
 * Ausrichtungsfragen ist der Editor keine verlässliche Vorschau. */
[data-section="Danke"] .text-center .lead {
  margin-left: auto;
  margin-right: auto;
}
[data-section="Danke"] h2.headline-tight {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}


/* ── 11l. Rechtstexte (Impressum, Datenschutz) ──────────────────────────
 * Zwei Seiten, die niemand liest — bis jemand sie liest, und dann meist,
 * weil er misstrauisch geworden ist. Genau dann entscheidet ihre Machart
 * mit: Eine Bleiwüste bestätigt den Verdacht, ein gegliederter, ruhiger
 * Text entkräftet ihn.
 *
 * WARUM ES DIESEN ABSCHNITT ÜBERHAUPT BRAUCHT
 *
 * Der Nachbau des Tailwind-Grundstylesheets setzt `h1…h6 { margin: 0 }` —
 * auf der Startseite richtig, weil dort jede Überschrift in einer Sektion
 * mit eigenen Abständen sitzt. Ein Rechtstext hat diese Sektionen nicht: Er
 * ist eine lange Folge aus Überschrift, Absatz, Überschrift. Ohne Abstände
 * klebt alles aneinander.
 *
 * Deshalb bekommen die Elemente hier ihre Abstände über die Sektionsklasse
 * statt über Hilfsklassen im Muster — sonst müsste an jeder einzelnen
 * Überschrift ein `mt-`Wert stehen, und beim Einfügen eines Absatzes durch
 * den Kunden fehlte er.
 * ─────────────────────────────────────────────────────────────────────── */

.rechtstext > h2 {
  margin-top: var(--sp-12);
  margin-bottom: var(--sp-3);
}
.rechtstext > h2:first-child {
  margin-top: 0;
}
.rechtstext > h3 {
  margin-top: var(--sp-6);
  margin-bottom: var(--sp-2);
}
.rechtstext > p {
  margin-bottom: var(--sp-4);
}
.rechtstext > ul {
  margin: 0 0 var(--sp-4);
}

/* Verweise im Fließtext eines Rechtstextes werden unterstrichen. Auf der
   Startseite trägt die Farbe allein — dort steht jeder Verweis in einem
   gestalteten Zusammenhang. Hier steht er mitten im Absatz, und Farbe
   allein ist kein Unterscheidungsmerkmal, auf das man sich verlassen darf
   (Kontrastsehen, Farbsinnstörungen).
 *
 * `:not(.btn)` IST NICHT OPTIONAL — 05.08.2026 teuer gelernt.
 *
 * Ohne die Ausnahme galt die Regel auch für Schaltflächen. `.rechtstext a`
 * hat eine Klasse plus ein Element (0,1,1) und schlägt damit `.btn--accent`
 * (0,1,0): Die Akzent-Schaltfläche bekam Petrol als Schriftfarbe — auf
 * petrolfarbenem Grund. Der Text war unsichtbar, bis der Mauszeiger darüber
 * fuhr und die Hover-Regel eine andere Farbe setzte.
 *
 * Das Muster ist dasselbe wie beim `:not(.grid-container)` weiter oben: Eine
 * Regel, die „alle Verweise hier" meint, meint tatsächlich auch die, die gar
 * keine Verweise sein wollen. Wer über ein Element selektiert, trifft alles,
 * was dieses Element benutzt — auch das, was wie etwas ganz anderes aussieht. */
.rechtstext a:not(.btn) {
  color: var(--c-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* Schaltflächen-Zeilen auf Textseiten beginnen an der Fluchtlinie des
   Textes, nicht in der Mitte.
 *
 * `.faq-outro-cta` stammt aus dem FAQ-Ausklang der Startseite und steht dort
 * in einem zentrierten Block — deshalb `justify-content: center`. Auf einer
 * linksbündigen Textseite sitzt die Knopfreihe damit mittig unter einem
 * Text, der links steht, und wirkt versehentlich verrutscht. Verstärkt noch
 * dadurch, dass die Absätze bei 65 Zeichen enden, die Knopfreihe aber die
 * volle Breite hat: Sie zentriert in einem breiteren Kasten als dem, den man
 * als Textspalte wahrnimmt.
 *
 * Die Regel der Startseite bleibt unangetastet — dort ist zentriert richtig.
 *
 * NACHTRAG 06.08.2026 — die Begründung oben gilt nur ab 768 px. Sie stützt
 * sich darauf, dass die Absätze bei 65 Zeichen enden, die Knopfreihe aber die
 * volle Breite hat. Auf einem Telefon IST die Textspalte die volle Breite;
 * damit fällt das Argument weg und die Reihe folgt der Telefonregel weiter
 * unten. */
@media (min-width: 768px) {
  .rechtstext .faq-outro-cta,
  [data-section="Danke"] .faq-outro-cta {
    justify-content: flex-start;
  }
}

/* KNOPFREIHEN AUF DEM TELEFON STEHEN MITTIG — 06.08.2026, René.
 *
 * Bis hierher folgte jeder Knopf der Ausrichtung seines Blocks: In einem
 * zentrierten Block stand er mittig, in einem linksbündigen links. Auf dem
 * Desktop trägt das, weil linksbündige Blöcke eine erkennbare Fluchtlinie
 * haben, an der das Auge ohnehin entlangläuft.
 *
 * Auf 375 px steht alles in einer einzigen schmalen Spalte untereinander.
 * Gemessen sassen die Knöpfe dort bei 18, 67, 71 und 74 px linkem Rand — die
 * Regel dahinter ist für einen Besucher nicht erkennbar, sie liest sich als
 * Unachtsamkeit. Deshalb ab hier eine einzige Regel: Handlungen stehen
 * mittig.
 *
 * AUSNAHME HERO. Seine beiden Knöpfe füllen mit 339 von 339 px bereits die
 * volle Spalte. Sie sind damit schon symmetrisch, brauchen keine Zentrierung
 * und sollen als Haupthandlung ihr eigenes Muster behalten. */
@media (max-width: 767px) {
  .ankauf-cta-row,
  .faq-outro-cta {
    justify-content: center;
  }

  /* „Über Johannes" hat als einzige Sektion keine Knopfhülle — der Knopf
     steht direkt zwischen den übrigen Blöcken. Ein `text-align` auf dem
     Elternteil würde deshalb auch dessen Fließtext zentrieren. Stattdessen
     wird der Knopf selbst zur eigenen Zeile: `flex` statt `inline-flex`
     macht ihn blockartig, `fit-content` hält seine natürliche Breite, und
     erst dadurch greifen die automatischen Seitenränder. */
  [data-section="Über Johannes"] a.btn {
    display: flex;
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
  }

  /* Der Telefon-Hinweis schließt die Handlungsgruppe des Heros ab und folgt
     ihr deshalb mit. Über ihm stehen zwei Knöpfe über die volle Spaltenbreite
     — ihre Beschriftung ist damit mittig. Bliebe die Zeile darunter als
     einzige linksbündig, läse sie sich als Rest statt als Abschluss.
     Der Fließtext des Heros ist davon nicht betroffen: Der bleibt links, weil
     durchgehend zentrierter Text für die Zielgruppe schlechter lesbar ist. */
  .hero-phone-hint {
    text-align: center;
  }
}

/* Anschrift und Kontaktzeilen.
 *
 * Hier stand zunächst ein `dl` mit `dt`/`dd` — semantisch das Richtige für
 * Bezeichnung-Wert-Paare. GenerateBlocks lässt das aber nicht zu, ohne dass
 * man es umständlich macht: `dt` und `dd` stehen zwar in der Tag-Liste des
 * ELEMENT-Blocks, der trägt jedoch nur Struktur; der TEXT-Block, der den
 * Inhalt hielte, kennt beide nicht. Jede Zeile bräuchte also ein
 * zusätzliches `span` darin.
 *
 * Für vier Zeilen Anschrift ist das zu viel Maschinerie — und der Kunde,
 * der später die Telefonnummer ändern soll, findet in der Blockliste dann
 * eine Verschachtelung statt eines Absatzes. Deshalb schlichte Absätze mit
 * Zeilenumbrüchen. */
.rechtstext-block {
  margin-bottom: var(--sp-4);
  line-height: 1.7;
}


/* ── 12. Fußbereich ─────────────────────────────────────────────────────
 * Zuordnung der Tailwind-Hilfsklassen aus dem Entwurf:
 *   grid sm:grid-cols-2 md:grid-cols-3 gap-8  →  .jk-footer-grid
 *   text-sm opacity-70 mt-4                   →  .jk-footer-claim
 *   space-y-2 text-sm opacity-85 mt-2         →  .jk-footer-list
 *   inline-flex items-center gap-2            →  .jk-footer-link-icon
 * ─────────────────────────────────────────────────────────────────────── */

/* ZWEITE Namenskollision, und diese ist sichtbar: GeneratePress umschließt
   den `generate_footer`-Hook mit `<div class="site-footer">`. Unser eigenes
   `<footer class="site-footer">` sitzt also IN einem Element mit demselben
   Klassennamen. Unqualifiziert griffen Hintergrund, Innenabstand und der
   Saum doppelt — doppelt so hoher Fußbereich und zwei Trennlinien
   übereinander.
   Lösung: Wir qualifizieren über das Element. GeneratePress' Hülle ist ein
   `div`, unsere ist ein `footer`. Der äußere Wrapper wird darunter
   ausdrücklich neutralisiert, damit auch aus dem Eltern-Stylesheet nichts
   durchschlägt. */
div.site-footer {
  background: none;
  padding: 0;
  margin: 0;
}

footer.site-footer {
  background: var(--c-primary);
  color: #ffffff;
  padding: var(--sp-16) 0 var(--sp-6);
  position: relative;
  margin-top: 0;
}

/* Feiner Saum als Übergang zur Kontakt-Sektion — waagerechter Verlauf,
   an den Rändern auslaufend. */
footer.site-footer::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 8px;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--c-primary-dark) 20%,
    var(--c-primary-dark) 80%,
    transparent 100%);
  pointer-events: none;
}

.jk-footer-grid {
  display: grid;
  gap: var(--sp-8);
}
@media (min-width: 640px)  { .jk-footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 768px)  { .jk-footer-grid { grid-template-columns: repeat(3, 1fr); } }

/* Echte weiße SVG-Fassung statt filter:invert(100%) wie im Entwurf — der
   Filter kostet Rechenzeit und liefert je nach Browser einen leicht anderen
   Weißton. */
.jk-footer-logo {
  height: 48px;
  width: auto;
  display: block;
}

.jk-footer-claim {
  font-size: var(--fs-sm);
  /* Im Entwurf stand hier Tailwinds `text-sm` — und das setzt neben der
     Schriftgröße auch eine Zeilenhöhe von 1.25rem mit. Ohne sie erbt der
     Absatz unsere 1,5 und läuft mit 23,625 px statt 22,5 px. Ein Achtel
     Pixel je Zeile, das man einzeln nicht sieht und über drei Zeilen doch. */
  line-height: 1.25rem;
  opacity: 0.7;
  margin-top: var(--sp-4);
}

.jk-footer-eyebrow { color: rgba(255, 255, 255, 0.5); }

.jk-footer-list {
  list-style: none;
  margin: var(--sp-2) 0 0;
  padding: 0;
  font-size: var(--fs-sm);
  opacity: 0.85;
}
.jk-footer-list > li + li { margin-top: var(--sp-2); }

.jk-footer-link-icon {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Die !important-Angaben stammen aus dem Entwurf: Dort überschrieb der
   globale Link-Hover die Fußzeilen-Farben, weil er bei gleicher Spezifität
   später im Stylesheet stand. Hier ist der globale Hover bereits auf den
   Inhaltsbereich begrenzt (Abschnitt 3) — die Angaben bleiben trotzdem, weil
   sie zusätzlich gegen Regeln von GeneratePress absichern. */
footer.site-footer a {
  color: #C5CCCF !important;
  text-decoration: none;
  transition: color 200ms ease;
}
footer.site-footer a:hover,
footer.site-footer a:focus-visible {
  color: #ffffff !important;
  text-decoration: underline !important;
  text-underline-offset: 0.2em;
}

.jk-footer-legal {
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  margin-top: var(--sp-8);
}
.jk-footer-legal .container {
  padding-top: var(--sp-4);
  padding-bottom: var(--sp-4);
  font-size: 0.75rem;
  opacity: 0.5;
  text-align: center;
}

/* Gestalter-Hinweis, eigene Zeile unter dem Copyright.
 *
 * Farbe geerbt statt Akzent: Der Hinweis soll auffindbar sein, nicht werben.
 * Die Unterstreichung steht dauerhaft — sie ist hier das EINZIGE Merkmal,
 * das ihn als Link ausweist, weil er die Farbe des Umtexts trägt. */
.jk-footer-credit {
  display: block;
  margin-top: var(--sp-1);
}
/* Der Selektor trägt `footer.site-footer` mit, weil die allgemeine Fuß-Regel
   dreißig Zeilen weiter oben mit (0,1,2) sonst gewinnt — sie setzt
   `text-decoration: none` für ALLE Links im Fuß. Genau die Falle, die in
   Abschnitt 14 schon einmal steht: Wer auf ein Element selektiert, trifft
   alles, was dieses Element benutzt. Die Farbe steht dort auf `!important`
   und bleibt deshalb die des Fußes — das ist richtig so, der Hinweis soll
   sich nicht von den Rechtslinks abheben. */
footer.site-footer .jk-footer-credit a {
  text-decoration: underline;
  text-decoration-thickness: from-font;
  text-underline-offset: 0.2em;
}
footer.site-footer .jk-footer-credit a:hover,
footer.site-footer .jk-footer-credit a:focus-visible {
  text-decoration-thickness: 2px;
}

/* Rechtslinks, solange die Seiten noch nicht existieren. Zeigerereignisse
   bleiben an, damit der erklärende Titel-Hinweis erscheint. */
a.is-disabled,
a[aria-disabled="true"] {
  color: var(--c-text-subtle);
  cursor: not-allowed;
  opacity: 0.7;
  pointer-events: auto;
}
a.is-disabled:hover,
a[aria-disabled="true"]:hover { color: var(--c-text-subtle); }
footer.site-footer a.is-disabled,
footer.site-footer a[aria-disabled="true"] { color: rgba(255, 255, 255, 0.45) !important; }


/* ── 13. Die beiden fixierten Knöpfe ────────────────────────────────────
 * Größe, Randabstand und Stapelung sind vereinheitlicht. In einer früheren
 * Fassung überlappten sie sich zwischen 641 und 767px, weil ihre
 * Umschaltgrenzen auseinanderliefen (640 gegen 768). Die Grenze des
 * Nach-oben-Knopfes ist deshalb an die Sichtbarkeit des Anruf-Knopfes
 * gekoppelt — so kann das nicht wiederkehren.
 *
 * Rangfolge bleibt ablesbar: Der Anruf trägt den Akzent-Ring als primäre
 * Aktion und sitzt unten am Daumen, Nach-oben sitzt darüber.
 * ─────────────────────────────────────────────────────────────────────── */

#scrollToTop {
  position: fixed;
  right: var(--sp-4);
  bottom: var(--sp-4);
  width: 56px;
  height: 56px;
  border-radius: var(--radius-full);
  background: var(--c-primary);
  color: #ffffff;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 24px rgba(0, 47, 66, 0.18);
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
  transition: opacity 220ms ease, transform 220ms ease, background-color 200ms ease;
  z-index: 90;
  padding: 0;
}
#scrollToTop.is-visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
#scrollToTop:hover,
#scrollToTop:focus-visible { background: var(--c-primary-dark); }

/* Der Ring sitzt mit r=25.25 und stroke-width 1.5 exakt an der Außenkante
   des Knopfes (r=26) — kein doppelter Rand.
   ACHTUNG: 158.65 ist 2π × 25.25 und steht ein zweites Mal in jk-main.js.
   Wird der Radius geändert, muss beides mitwandern. */
.scroll-top-progress {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
  pointer-events: none;
  overflow: visible;
}
/* STRICHSTÄRKE 3 UND NICHT 1,5 — angeglichen 06.08.2026.
 *
 * Der Telefon-Knopf daneben trägt einen 3 px starken Ring in Petrol, dieser
 * hatte 1,5. Zwei gleich große Kreise nebeneinander mit halb so dickem Ring
 * lesen sich nicht als Rangfolge, sondern als Unachtsamkeit.
 *
 * Die Rangfolge bleibt trotzdem erhalten — sie kommt jetzt über die FARBE:
 * Petrol als Akzent am Anruf-Knopf, blasses Blau am Fortschritt. Das ist
 * das leisere und verlässlichere Mittel; Strichstärken vergleicht das Auge
 * bei 56 px sofort, Farbwerte ordnet es ein.
 *
 * Der Entwurf hat dieselbe Ungleichheit — in beiden Fassungen nachgemessen.
 * Bewusste Abweichung, von René am 06.08.2026 angestoßen. */
.scroll-top-progress .track {
  fill: none;
  stroke: rgba(255, 255, 255, 0.15);
  stroke-width: 3;
}
.scroll-top-progress .progress {
  fill: none;
  stroke: #B8D4DC;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-dasharray: 158.65;
  stroke-dashoffset: 158.65;
  transition: stroke-dashoffset 80ms linear;
}
@media (prefers-reduced-motion: reduce) {
  .scroll-top-progress .progress { transition: none; }
}

.scroll-top-icon {
  width: 22px;
  height: 22px;
  position: relative;
  z-index: 1;
}

/* Solange der Anruf-Knopf sichtbar ist, rückt der Nach-oben-Knopf darüber:
   56px Knopfhöhe plus 12px Abstand. */
@media (max-width: 767px) {
  #scrollToTop { bottom: calc(var(--sp-4) + 56px + var(--sp-3)); }
}

.floating-phone {
  position: fixed;
  right: var(--sp-4);
  bottom: var(--sp-4);
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--c-primary);
  color: #ffffff;
  border: 3px solid var(--c-accent);
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-lg);
  z-index: 90;
  text-decoration: none;
  transition: transform var(--duration-base) var(--ease-out),
              box-shadow var(--duration-base) var(--ease-out),
              background-color var(--duration-base) var(--ease-out);
}
/* Der Farbwechsel läuft über den HINTERGRUND, das Symbol bleibt weiß. Färbte
   man das Symbol selbst ein, fiele der Kontrast beim Überfahren auf 1,24:1
   und der Hörer verschwände im Knopf. */
.floating-phone:hover {
  transform: scale(1.06);
  background: var(--c-primary-dark);
  box-shadow: 0 16px 36px rgba(0, 47, 66, 0.25);
}
@media (min-width: 768px) {
  .floating-phone { display: none; }
}

/* Die Wellen pulsieren beim Überfahren — nur an den bleibenden
   Vertrauensankern, nie in Fließtext-Schaltflächen. */
.floating-phone:hover .icon-phone-anim .phone-wave-inner {
  animation: phoneWaveInner 0.6s ease-in-out;
}
.floating-phone:hover .icon-phone-anim .phone-wave-outer {
  animation: phoneWaveOuter 0.7s ease-in-out 0.08s;
}
.icon-circle-btn:hover .icon-phone-anim .phone-wave-inner {
  animation: phoneWaveInner 0.6s ease-in-out;
}
.icon-circle-btn:hover .icon-phone-anim .phone-wave-outer {
  animation: phoneWaveOuter 0.7s ease-in-out 0.08s;
}
@keyframes phoneWaveInner {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.18); opacity: 0.55; }
}
@keyframes phoneWaveOuter {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.28); opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .floating-phone:hover .icon-phone-anim .phone-wave-inner,
  .floating-phone:hover .icon-phone-anim .phone-wave-outer,
  .icon-circle-btn:hover .icon-phone-anim .phone-wave-inner,
  .icon-circle-btn:hover .icon-phone-anim .phone-wave-outer { animation: none; }
  .floating-phone:hover { transform: none; }
}

/* Sichtbarer Fokus für Tastatur-Bedienung (WCAG 2.4.11, neu in 2.2).
   Steht bewusst am Ende, damit es nicht von früheren Regeln überschrieben
   wird. */
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--c-accent);
  outline-offset: 2px;
  border-radius: 2px;
}


/* ── 14. GenerateBlocks und GeneratePress zähmen ────────────────────────
 * Der Text-Block trägt zwingend die Klasse .gb-text — sein Rich-Text wird
 * über genau diesen Selektor ausgelesen, sie lässt sich nicht abschalten,
 * ohne den Block zu beschädigen. Damit sie unserer Typografie nicht
 * dazwischenfunkt, wird sie hier neutral gestellt: Sie soll Struktur
 * markieren, nicht gestalten.
 *
 * Der Element-Block gibt ohne gesetzte Styles gar keine eigene Klasse aus —
 * dort ist nichts zu tun.
 * ─────────────────────────────────────────────────────────────────────── */

/* HIER STAND EINE NEUTRALISIERUNG VON .gb-text — ENTFERNT AM 01.08.2026.
 *
 * Sie war vorsorglich eingebaut, für den Fall dass GenerateBlocks die Klasse
 * selbst gestaltet. Auf der Staging nachgemessen: Das Plugin liefert genau
 * vier Regeln aus — .gb-container, .gb-grid-wrapper, .gb-highlight und
 * .gb-shape. Für .gb-text gibt es nichts zu neutralisieren.
 *
 * Die Regeln haben stattdessen Schaden angerichtet: `padding: 0`,
 * `font-size: inherit` und `font-weight: inherit` standen später im
 * Stylesheet als `.btn` und gewannen bei gleicher Spezifität. Die
 * Akzent-Schaltfläche lief dadurch mit 15,75 px statt 18 px, und
 * `h3.gb-text` überschrieb den Abstand aus `.process-editorial h3`
 * (18 px statt 9 px).
 *
 * Lehre für die übrigen Sektionen: Klassen, die GenerateBlocks von sich aus
 * vergibt, erst dann anfassen, wenn sie nachweislich stören. Ein Element ist
 * `<h3 class="gb-text">` — unsere Regeln greifen darüber ohnehin, weil sie
 * über das Element oder die Sektions-Klasse selektieren.
 */


/* GeneratePress gestaltet <blockquote> von sich aus:
 *
 *   blockquote { border-left: 5px solid rgba(0,0,0,.05); padding: 20px;
 *                font-size: 1.2em; font-style: italic; margin: 0 0 1.5em;
 *                position: relative }
 *
 * Im Prototyp gibt es davon nichts. Dort hat das Element schlicht die
 * Browser-Vorgabe — Tailwinds Grundstylesheet nullt nur das `margin`, um
 * Polsterung und Rahmen muss es sich nicht kümmern, weil beide gar nicht
 * existieren.
 *
 * WIE DAS AUFGEFALLEN IST (05.08.2026, Messung der Bewertungs-Sektion):
 * Nicht am Rahmen, den man gesehen hätte, sondern an einer einzigen Zahl —
 * dem errechneten `top` von `.review-card::before`. Das Pseudo-Element hat
 * gar kein `top`, nur `bottom`; sein Wert ist deshalb aus der Kartenhöhe
 * abgeleitet. 40 px Abweichung = 20 px Polsterung oben plus 20 px unten. Die
 * dritte Karte lag 71,4 px daneben, weil die 20 px rechts den Textkörper
 * verschmälern und ihr längster Text dadurch eine Zeile mehr umbricht
 * (40 + 31,4 = 71,4).
 *
 * ZWEI LEHREN:
 *
 * 1. Eine abgeleitete Größe verrät mehr als eine gesetzte. Hätte ich nur
 *    `padding` verglichen, wäre es genauso aufgefallen — aber der Messpunkt
 *    für das Pseudo-Element war gar nicht dafür gedacht. Solche Werte
 *    mitzumessen kostet nichts und deckt Kettenwirkungen auf.
 *
 * 2. Eine halbe Neutralisierung ist gefährlicher als keine. Bis hierher stand
 *    im Tailwind-Nachbau ein `blockquote { padding-left: 0 }`. Das sah nach
 *    „ist behandelt" aus, war aber nur die eine Seite, die damals gemessen
 *    wurde — und es stand zudem im falschen Abschnitt: Tailwind setzt für
 *    blockquote ausschließlich `margin: 0`. Was ein fremdes Theme mitbringt,
 *    gehört hierher; was der Prototyp mitbringt, gehört in §14a. Sonst
 *    behauptet die Datei etwas Falsches über die Herkunft einer Regel.
 */
blockquote {
  padding: 0;
  border-left: 0;
  font-size: inherit;
  font-style: normal;
  position: static;
}


/* ═══════════════════════════════════════════════════════════════════════
 * NOCH OFFEN — Bauabschnitt 2 und folgende
 *
 * Sektionen:  Hero · Sicherheit · Vergleichstabelle · Problem ·
 *             Ankaufsprofil · Über Johannes · Referenzen · Bewertungen ·
 *             FAQ · Kontakt · Fußbereich · Floating-Knöpfe
 *
 * Drei undefinierte Werte aus dem Visual (--fs-xs, --fw-medium, --lh-snug):
 * bewusst noch NICHT gesetzt. Sie werden im Visual nirgends aufgelöst, die
 * betroffenen Regeln fallen dort also aus. Würde man sie hier definieren,
 * änderte sich das Aussehen gegenüber dem abgenommenen Stand (der
 * Vergleichs-Kopf würde kleiner). Auflösung laut F4: die betroffenen Regeln
 * auf die tatsächlich gerenderten Werte stellen — beim Bau der jeweiligen
 * Sektion, nicht vorher pauschal.
 *
 * ZWEI ENTSCHEIDUNGEN FÜR RENÉ:
 *
 * 1. Schriftschnitte. Vorhanden sind nur 400 und 700, verwendet werden auch
 *    500 und 600 (Schaltflächen, H2, Augenbrauen-Zeile, Zeitangaben). Der
 *    Browser rechnet sie sich derzeit zurecht. Echte Schnitte nachzuladen
 *    wäre typografisch sauberer, ändert aber das Schriftbild gegenüber dem
 *    abgenommenen Visual. Kosten: zwei zusätzliche woff2, rund 40 KB.
 *
 * 2. Der Tailwind-Deckel oben. Nachgebaut, weil das Visual so abgenommen
 *    wurde. Wirkung: Zwischen 768 und 1023px ist der Inhalt auf 768px
 *    begrenzt, obwohl 1200px zur Verfügung stünden. Ohne den Nachbau
 *    würde die Seite auf Tablets deutlich breiter — anders, nicht
 *    zwangsläufig schlechter, aber eben nicht der abgenommene Stand.
 * ═══════════════════════════════════════════════════════════════════════ */


/* ── 14a. Nachbau des Tailwind-Grundstylesheets ─────────────────────────
 * NACHGETRAGEN 02.08.2026. Der wichtigste Block dieser Datei nach den
 * Sektionsregeln — und der, der am längsten gefehlt hat.
 *
 * WAS HIER PASSIERT IST
 *
 * Der abgenommene Entwurf lädt Tailwind über ein CDN. Dessen Grundstylesheet
 * setzt Dutzende Element-Vorgaben zurück, und es lädt NACH custom.css — es
 * gewinnt also immer, wo unsere Regel kein `!important` trägt. Was dort wie
 * ein Browser-Standard aussieht, ist in Wahrheit Tailwinds Setzung.
 *
 * In WordPress gibt es das nicht. Dort gelten Browser- und
 * GeneratePress-Vorgaben — und die sind an 22 Stellen andere.
 *
 * Gefunden über einen Vergleich der Grundwerte: In beide Dokumente wird
 * derselbe unsichtbare Probeblock mit blanken Elementen eingehängt und
 * ausgelesen, was die jeweilige Kaskade daraus macht. Einzeln wäre man über
 * diese Unterschiede monatelang gestolpert — der erste war ein Absatz, der
 * 682 statt 581 Pixel breit lief.
 *
 * WARUM DER BLOCK GANZ HINTEN STEHT UND NICHT VORN
 *
 * Weil Tailwind im Entwurf ebenfalls hinten steht. Das ist keine Kosmetik:
 * Nur dadurch überschreibt er unsere blanken Element-Regeln — und genau das
 * tut er im abgenommenen Zustand auch.
 *
 * Unsere Sektionsregeln sind davon unberührt: Sie hängen alle an Klassen und
 * sind damit stärker als jede Regel hier, unabhängig von der Reihenfolge.
 *
 * ÜBERNOMMEN IST NUR, WAS NACHWEISLICH ABWEICHT. Kein blindes Kopieren des
 * ganzen Grundstylesheets — was in beiden Fassungen gleich ist, hat hier
 * nichts verloren.
 * ─────────────────────────────────────────────────────────────────────── */

/* Absätze tragen im abgenommenen Zustand KEINEN unteren Abstand — die
   Abstände kommen aus den mt-Klassen. Und sie sind auf 65 Zeichen begrenzt,
   die klassische Lesbarkeitsgrenze. Das Fehlen dieser einen Zeile hat den
   Absatz in „Über Johannes" hundert Pixel zu breit laufen lassen. */
p {
  margin: 0;
  max-width: 65ch;
}

/* Listen ohne Aufzählungszeichen und ohne Einzug. Jede Liste der Seite bringt
   ihre eigene Gestaltung mit (Rauten, Ziffern, Häkchen); die Standard-Punkte
   würden zusätzlich erscheinen. */
ul,
ol {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Verweise erben Farbe und Unterstreichung von ihrer Umgebung. GeneratePress
   färbt sie sonst blau und unterstreicht sie — was jeden Fließtext-Link und
   jede Schaltfläche ohne eigene Regel anders aussehen ließe. */
a {
  color: inherit;
  text-decoration: inherit;
}

/* Formularelemente. Zum Tragen kommt das erst mit dem Kontaktformular, gehört
   aber hierher: Die Formular-Gestaltung des Entwurfs setzt genau diesen
   zurückgesetzten Zustand voraus. Fehlte er, käme das Formular mit
   Browser-Rahmen, eigener Schrift und eigenen Innenabständen — und jede
   Korrektur daran wäre ein Kampf gegen Vorgaben statt Gestaltung. */
button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-size: 100%;
  font-weight: inherit;
  line-height: inherit;
  color: inherit;
  margin: 0;
  padding: 0;
  /* GeneratePress gibt Eingabefeldern einen zwei Pixel starken Rahmen. Im
     Entwurf haben sie gar keinen — ihre Umrandung kommt erst aus der
     Formular-Gestaltung. */
  border-width: 0;
  border-style: solid;
}

button,
[type='button'],
[type='reset'],
[type='submit'] {
  -webkit-appearance: button;
  background-color: transparent;
  background-image: none;
  border: 0;
}

table {
  border-collapse: collapse;
  border-color: inherit;
  text-indent: 0;
}

/* Tailwind setzt für blockquote genau das — nicht mehr. Was GeneratePress
   darüber hinaus mitbringt (Polsterung, Rahmen, Kursive), wird in §14
   abgeräumt, weil es von dort kommt und nicht von hier. */
blockquote {
  margin: 0;
}

hr {
  height: 0;
  color: inherit;
  border-top-width: 1px;
  border-top-style: solid;
}

small {
  font-size: 80%;
}

/* ACHTUNG, hier liegt eine Falle.
   H3 und H4 laufen im abgenommenen Zustand in der GRÖSSE DES FLIESSTEXTES.
   Das ist kein Versehen: Unsere Regeln dafür stehen in custom.css ohne
   `!important`, und Tailwind setzt danach `font-size: inherit`. Nur H1 und H2
   tragen dort `!important` und setzen sich durch.
   Jede Überschrift dritter Ebene auf der Seite bekommt ihre Größe deshalb aus
   ihrer Sektionsregel — `.ankaufsprofil-list h3`, `.process-editorial h3` und
   so weiter. Würden wir hier eine allgemeine Größe setzen, sähen alle
   Sektionen anders aus als freigegeben, und neue Sektionen bekämen stillschweigend
   eine Größe, die es im Entwurf nie gab. */
h3,
h4 {
  font-size: inherit;
  font-weight: inherit;
}


/* ── 15. Hilfsklassen — bewusst als Letztes ─────────────────────────────
 * Abstände und die gedämpfte Textfarbe. Im Entwurf lieferte Tailwind sie.
 *
 * WARUM AM ENDE UND NICHT OBEN BEI DEN ÜBRIGEN GRUNDLAGEN
 *
 * Diese Klassen stehen im Markup neben Sektionsklassen: `ankaufsprofil-list
 * mt-8`, `diamond-list mt-6`, `process-editorial mt-12`. Beide Seiten sind
 * eine einzelne Klasse und damit gleich stark — es entscheidet also die
 * Reihenfolge im Stylesheet, und zwar zugunsten der späteren Regel.
 *
 * Fast alle diese Sektionsklassen setzen `margin: 0`, um den Standard-Abstand
 * von Listen abzuräumen. Standen die Hilfsklassen weiter oben, gewann dieses
 * `margin: 0` — und der Abstand darüber fiel ersatzlos aus.
 *
 * Im abgenommenen Entwurf trat das nicht auf, weil Tailwind über das CDN NACH
 * custom.css geladen wurde und damit immer gewann. Diese Datei bildet das
 * nach, indem sie die Hilfsklassen zuletzt bringt.
 *
 * GEFUNDEN AM 02.08.2026 — beim Vergleich mit dem Prototyp fehlten dem
 * Ankaufsprofil 36 px und der Rautenliste 27 px. Die Suche nach der Ursache
 * hat drei weitere Stellen zutage gefördert, darunter zwei in Sektionen, die
 * bereits als geprüft galten: der Ablauf-Liste fehlten 54 px, dem
 * Sicherungs-Raster und dem Schlusssatz der Problem-Sektion je 27 px.
 *
 * Fünf Fehler, eine Ursache. Deshalb steht hier keine Ausnahmeregel je
 * Sektion, sondern die Reihenfolge ist geradegerückt.
 *
 * WER HIER ETWAS ERGÄNZT, ergänzt es ebenfalls unten — nicht oben.
 * ─────────────────────────────────────────────────────────────────────── */

.mt-3  { margin-top: var(--sp-3); }
.mt-4  { margin-top: var(--sp-4); }
.mt-6  { margin-top: var(--sp-6); }
.mt-8  { margin-top: var(--sp-8); }
.mt-12 { margin-top: var(--sp-12); }
/* `.mt-14` stand seit dem ersten Tag im Markup der Sektion „Sicherheit",
   eine Regel dazu gab es nie — im Entwurf kam sie von Tailwind. */
.mt-14 { margin-top: var(--sp-14); }
.mt-16 { margin-top: var(--sp-16); }
.mb-6  { margin-bottom: var(--sp-6); }

/* Im Entwurf stand die gedämpfte Textfarbe als Tailwind-Kurzform direkt am
   Element: `text-[var(--c-text-muted)]`. Diese Schreibweise mit eckigen
   Klammern und Doppelpunkt gehört zu Tailwinds Baukasten und hat im
   WordPress-Backend nichts verloren — hier trägt sie einen Namen. */
.text-muted { color: var(--c-text-muted); }

/* Tailwinds `text-sm` bringt NEBEN der Groesse eine eigene Zeilenhoehe mit —
   1.25rem, nicht das Vielfache der Schriftgroesse. Das ist der Grund, warum
   die Fussnote der Vergleichstabelle im Entwurf enger laeuft, als ihre eigene
   Regel vermuten laesst: Die Hilfsklasse steht spaeter und gewinnt.
   Wer nur die Groesse uebernimmt und die Zeilenhoehe vergisst, liegt um vier
   Pixel je Zeile daneben. */
.text-sm {
  font-size: var(--fs-sm);
  line-height: 1.25rem;
}
