/* ══════════════════════════════════════════════════════════════════════════
   tobiaslohmann.de — Startseite
   Typography and motion carry this page. Nothing decorative without function.

   Structure of this file:
     1. Tokens and base
     2. The page, laid out STATICALLY — every word readable, nothing hidden.
        This is what you get without JavaScript and with reduced motion on.
     3. The kinetics, scoped to html[data-motion="kinetic"] — sticky stages,
        hidden start states, scroll-driven travel. Purely additive.
     4. Small screens.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 0. Archivo, self-hosted ────────────────────────────────────────────────
   Served from this domain rather than fonts.gstatic.com: a German site that
   pulls Google Fonts at request time hands visitor IP addresses to a third
   country without consent (LG München I, 3 O 17493/20). Archivo is OFL-1.1,
   see assets/fonts/OFL.txt.

   These are the VARIABLE cuts — the wdth axis (62–125%) carries the breathing
   „Ihr" in the hero and the width shift as the scattered words find their
   line. A static cut would silently kill both. */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url('../fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url('../fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── 1. Tokens ──────────────────────────────────────────────────────────── */

:root {
  /* Brand — taken from the logo. */
  --ink:          #2B2B27;
  /* Gedeckter, warmer Sandton. Die --ground-Abstufungen darunter sind
     derselbe Ton mit Deckkraft — sie liegen als helle Schrift und helle
     Linien auf der Tinte und müssen deshalb mitwandern, sonst steht auf den
     dunklen Abschnitten ein kühleres Weiß als auf dem Papier daneben. */
  --ground:       #EBE1D2;

  /* Derselbe Akzent, für kleine Schrift auf dem Papier abgedunkelt. Die
     Koralle trägt als Fläche und als Plakatzeile; bei 16px Marginalie kommt
     sie auf 2.53:1 und ist damit zu schwach. Dieser Ton kommt auf 4.59:1 und
     erfüllt die 4.5:1, die kleine Schrift verlangt.
     Er gilt ausdrücklich nur auf hellem Grund: auf der Tinte liegt die
     Koralle bei 4.35:1 und dieser Ton bei 2.39:1 — dort wäre er der deutlich
     schlechtere von beiden. Deshalb zwei Werte und nicht ein dunklerer. */
  --accent-ink:   #BC2C2E;
  /* Und das Gegenstück: derselbe Akzent, für kleine Schrift auf der Tinte
     aufgehellt. Dort steht die Koralle bei 4.35:1 und verfehlt die 4.5:1
     knapp; dieser Ton kommt auf 4.81:1. Die beiden Namen sagen, wohin der
     Akzent gezogen wurde — --accent-ink zur Tinte hin, --accent-ground zum
     Papier hin —, und beide gelten nur für kleine Schrift. Flächen,
     Plakatzeilen und Buttons führen den Logo-Ton --accent, auch dort, wo er
     die Schwelle nicht hält: das ist eine Markenentscheidung, kein Versäumnis. */
  --accent-ground: #FF6062;
  --accent:       #FF4D4F;

  --ink-72:       rgba(43, 43, 39, 0.72);
  --ink-14:       rgba(43, 43, 39, 0.14);
  --ground-82:    rgba(235, 225, 210, 0.82);
  --ground-70:    rgba(235, 225, 210, 0.70);
  --ground-66:    rgba(235, 225, 210, 0.66);
  --ground-62:    rgba(235, 225, 210, 0.62);
  --ground-60:    rgba(235, 225, 210, 0.60);
  --ground-25:    rgba(235, 225, 210, 0.25);
  --ground-16:    rgba(235, 225, 210, 0.16);

  --font:         'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* One gutter for the whole page — every full-bleed section aligns to it. */
  --gutter:       clamp(20px, 4vw, 64px);

  /* ── Die Decke über allen Seitenüberschriften ────────────────────────────
     Die H1-Größe rechnet sich aus der Zeile: je kürzer der Text, desto größer
     die Schrift, damit die Zeile die Spalte füllt. Das ist richtig, hat aber
     kein oberes Ende — eine sehr kurze Überschrift wuchs deshalb weit über
     die längeren der Nachbarseiten hinaus. Gemessen bei 1440px lag das Feld
     zwischen 90,7px (Bildungsorganisationen) und 212,1px (Impressum), und
     dieser Abstand ist im Blättern durch die Seiten zu sehen.

     9,81cqw sind bei 1440px genau 130px. Die Decke wächst mit dem Fenster,
     statt in Pixeln festzustehen: auf einem breiten Schirm darf eine
     Schlagzeile größer werden, sie soll nur nicht mehr aus der Reihe fallen.

     Das `max(56px, …)` ist dabei kein Beiwerk. Eine Decke aus reinem cqw
     wirkt in beide Richtungen: bei 390px wären 9,81cqw nur 34,3px, und die
     Decke hätte fünf Seiten auf dem Telefon kleiner gemacht, statt auf dem
     Schreibtisch die größten einzufangen. 56px sind die größte Überschrift,
     die das schmale Layout bisher hervorbringt — darunter darf die Decke
     nicht fallen, sonst deckelt sie, wo nichts zu deckeln ist.

     Sie gilt für beide Überschriftenklassen — `.hero__title` der Startseite
     wie `.page-hero__title` der elf Unterseiten. Eine Decke, die nur manche
     Seiten kennt, wäre keine. */
  --h1-deckel:    max(56px, 9.81cqw);

  --ease-out:     cubic-bezier(.16, 1, .3, 1);
  --header-h:     80px;   /* Sprungmarken-Abstand, bewusst etwas großzügiger */

  /* Der Balken wird aus diesen drei Werten gebaut. Wer ihn ändert, ändert sie —
     dann wandert die Kante mit, an die sich der Auftakt auf „Über mich" legt. */
  --header-pad:   18px;
  --header-logo:  30px;
  --header-bar:   calc(2 * var(--header-pad) + var(--header-logo) + 2px);
}

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

html {
  scroll-behavior: smooth;
  /* Anchor targets must clear the fixed header. */
  scroll-padding-top: var(--header-h);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: clamp(16px, 1.22vw, 23px);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; max-width: 100%; height: auto; }
a   { color: var(--ink); text-decoration: none; }
a:hover { color: var(--accent); }
::selection { background: var(--accent); color: #fff; }

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

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 12px 18px; background: var(--ink); color: var(--ground);
  font-size: 16px; font-weight: 700;
}
.skip-link:focus { left: 0; color: var(--ground); }


/* Section kickers — the small, wide-tracked caps used across the page.
   --ink-72 und nicht --ink-68: bei 12px ist das kleine Schrift, und die
   braucht 4,5:1. Mit 68 stand sie auf 4,48 — zwei Hundertstel daneben, und
   damit auf der falschen Seite einer Schwelle, die keine Verhandlung kennt. */
.kicker {
  margin: 0;
  font-size: clamp(12px, 0.9vw, 18px); font-weight: 700; letter-spacing: 0.28em;
  text-transform: uppercase; color: var(--ink-72);
}
.kicker--onDark { color: var(--ground-66); }
/* Die bewegliche Anzeige der Rollenbühne — sie wechselt beim Scrollen von
   „Von außen“ über „An der Seite“ zu „Mittendrin“. Sie stand in derselben
   Koralle wie der Kicker daneben; seit der größer und im Akzent steht, wirkte
   sie wie dessen verkümmerter Ableger statt wie eine eigene Anzeige. In vollem
   Grund hat sie wieder ein eigenes Gesicht, und die Koralle bleibt der Ansage
   vorbehalten. */
.kicker--marker { color: var(--ground); }
/* A kicker carrying a full sentence rather than a two-word label. It holds the
   wide tracking on one line at desktop width and gives some of it back once it
   has to wrap (see the small-screen block). Don't cap this in `ch` — the 0.28em
   tracking makes a rendered character far wider than 1ch, so a ch-based
   max-width wraps the line long before it needs to. */
/* Dieser eine Kicker trägt einen ganzen Satz und stand bisher in gedämpftem
   Grund auf Tinte — er ging unter. Größer und im Akzent, damit er die
   Rollenbühne ansagt, statt sie zu flüstern. Der Akzentton für Tinte, nicht
   die Logo-Koralle: bei 15px am unteren Ende bleibt das kleine Schrift, und
   die braucht 4,5:1. */
.kicker--statement {
  text-wrap: pretty;
  font-size: clamp(15px, 1.28vw, 26px); letter-spacing: 0.2em;
  color: var(--accent-ground);
}

/* ══════════════════════════════════════════════════════════════════════════
   2. The static page
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Header ─────────────────────────────────────────────────────────────── */

.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 32px;
  padding: var(--header-pad) var(--gutter);
  background: rgba(235, 225, 210, 0.86);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-bottom: 2px solid transparent;
  transition: border-color .3s ease;
}
.site-header.is-scrolled { border-bottom-color: var(--ink); }

/* ── Ein Logo, das sich mit der Seite zusammenzieht ────────────────────────
   Am Seitenanfang steht die Wortmarke ein Drittel größer; sobald gescrollt
   wird, zieht sie sich auf ihr Arbeitsmaß zusammen. Gekoppelt an die
   Scrollposition, nicht an ein einmaliges Ereignis — beim Zurückscrollen
   wächst sie wieder.

   Das Wachstum läuft über transform, nicht über die Höhe, und das ist der
   Kern: die Marke belegt im Layout immer ihr kompaktes Maß, gleich in welchem
   Zustand. Der Balken kann dadurch gar nicht die Höhe wechseln, die
   Navigation bekommt keinen Platz weggenommen und nichts unter dem Kopf
   verschiebt sich. Das Logo wächst in den Innenabstand hinein statt den
   Balken aufzublähen — ein Zusammenziehen, kein Ruckeln.

   (Eine frühere Fassung führte stattdessen das Padding gegenläufig mit:
   13 + 40 + 13 gegen 18 + 30 + 18. Die Rechnung stimmt nur, solange das Logo
   das höchste Element im Balken ist. Ab etwa 2100px ist die Navigation höher,
   und der Kopf sprang um 6,5px; bei 761–800px drückte die breitere Marke die
   Navigation in den Umbruch. Beides fällt mit transform weg.)

   Nur unter Kinetik: bei prefers-reduced-motion und ohne JavaScript wird das
   Attribut nie gesetzt, und der Kopf bleibt durchgehend kompakt. Das
   Größenspiel ist selbst eine Bewegung, nicht nur sein Übergang. */
.site-header__brand { display: block; flex: none; }
.site-header__brand img {
  height: var(--header-logo); width: auto;
  transform-origin: left center;
  transition: transform .3s var(--ease-out);
}

[data-motion="kinetic"] .site-header:not(.is-compact) .site-header__brand img {
  transform: scale(1.34);
}

.site-nav {
  display: flex; align-items: center; gap: clamp(14px, 2.2vw, 34px);
  font-size: clamp(14px, 1.01vw, 21px); font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
}
.site-nav__cta { color: var(--accent-ink); }
.site-nav__cta:hover { color: var(--ink); }
/* The section you are currently inside, marked with the same coral underline
   the page uses for its other standing links. */
.site-nav .is-current { border-bottom: 2px solid var(--accent); padding-bottom: 2px; }

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  min-height: 100svh;
  display: grid; grid-template-rows: auto 1fr auto;
  padding: clamp(70px, 9vh, 116px) var(--gutter) clamp(16px, 2.4vh, 32px);
  /* Die Zeile misst sich an diesem Kasten, nicht am Fenster — siehe --h1-em. */
  container-type: inline-size;
}
/* Der Überschuss der dehnbaren Zeile gehört über die Überschrift, nicht um sie
   herum. Zentriert schob er die Hälfte davon zwischen H1 und Triade, und genau
   diese Lücke war das, was auf dem großen Schirm nach leerem Blatt aussah.
   Unten geschlossen: Überschrift und Angebot stehen zusammen, die Luft sammelt
   sich oben unter dem Header, wo sie als Anlauf gelesen wird. Sitzt am
   Wrapper, seit die Bildmarke daneben liegt — der Wrapper ist die Rasterzelle. */
.hero__poster { align-self: end; }

.hero__overline-clip { overflow: hidden; }
.hero__overline {
  margin: 0;
  font-size: clamp(15px, 1.45vw, 26px); font-weight: 800; letter-spacing: 0.34em;
  text-transform: uppercase; color: var(--accent-ink);
}

.hero__title {
  margin: clamp(16px, 3vh, 44px) 0 0;
  /* ── Wie groß eine Überschrift wird ───────────────────────────────────────
     Eine feste vw-Zahl kann nur für eine Zeilenlänge stimmen. „Begleitung."
     und „Verantwortung übernehmen," sind aber beide H1 dieser Website, und
     mit derselben vw-Zahl steht die eine über die Fensterkante hinaus,
     während die andere auf halber Breite endet — das war der Grund, warum die
     Schriften „auf den einzelnen Seiten unterschiedlich groß" wirkten.

     Deshalb rechnet die Größe hier aus der Zeile selbst: --h1-em ist die
     Breite der längsten Zeile dieser Seite, gemessen in em (Schriftgröße 1em
     → so viele em breit). 100cqw geteilt durch diesen Wert ist genau die
     Größe, bei der die Zeile die Spalte ausfüllt; 98 statt 100 lässt einen
     Rest für Rundung und Scrollbalken. Der Wert steht als Inline-Style am
     h1 jeder Seite und wird bei Textänderungen neu gemessen
     (scratchpad/h1em.mjs). Die erste Deklaration ist der Rückfall für
     Browser ohne Container-Einheiten und für ein fehlendes --h1-em.

     Die zweite Grenze ist die Höhe. Ein fester vh-Deckel taugt dafür nicht,
     weil er nichts von der Zeilenzahl weiß — drei Zeilen brauchen bei gleicher
     Fensterhöhe ein Drittel der Größe von einer, und genau das war der Grund,
     warum derselbe Deckel auf der einen Seite passte und auf der nächsten
     nicht. Gedeckelt wird deshalb der Block, nicht die Zeile: die Überschrift
     nimmt höchstens 66% der Fensterhöhe ein, --h1-lines Zeilen à 0.84.
     Auf einem gewöhnlichen Fenster greift diese Grenze nie — dort bestimmt die
     Breite. Sie greift in flachen Fenstern, und da soll sie greifen.

     Die dritte Grenze ist --h1-deckel, und sie ist die einzige, die nichts vom
     Text weiß. Je kürzer eine Überschrift, desto größer wird sie nach der
     Rechnung oben — ohne oberes Ende. Damit eine sehr kurze Zeile nicht aus
     der Reihe der Nachbarseiten fällt, deckelt --h1-deckel sie; siehe den
     Tokenblock oben. Sie gilt für alle zwölf Seiten.

     Und die Untergrenze hat ihre eigene Grenze. Eine feste Untergrenze in px
     kann nur behaupten, dass die Zeile nie kleiner wird — ob das längste Wort
     dieser Zeile bei dieser Größe überhaupt noch auf den Schirm passt, weiß
     sie nicht. Auf einem 320px-Gerät stand „VERANTWORTUNG" bei 34px genau
     21px über dem Rand und schob die ganze Seite zur Seite. --h1-word ist die
     Breite des längsten Wortes in em, gemessen wie --h1-em; die Untergrenze
     gibt nach, sobald dieses Wort sonst nicht mehr in die Spalte passt. Ein
     Umbruch mitten im Wort wäre die Alternative — bei einer Plakatzeile ist
     das keine. */
  font-size: clamp(48px, min(12.93vw, 34vh, 130px), 366px);
  font-size: clamp(min(44px, calc(98cqw / var(--h1-word, 4))),
    min(calc(98cqw / var(--h1-em, 5)),
        calc(66svh / (var(--h1-lines, 3) * 0.84)),
        var(--h1-deckel)),
    366px);
  line-height: 0.84; font-weight: 800; letter-spacing: -0.035em;
  text-transform: uppercase;
}
.hero__line { display: block; padding-bottom: 0.04em; }
.hero__line-inner { display: inline-block; }
/* The accent sits on „Ihr" — the reader, not the offer. */
.hero__breathe { color: var(--accent); }

/* Beratung · Coaching · Interim — the offer, legible at a glance. */
.triad { margin-top: clamp(12px, 2vh, 30px); border-top: 2px solid var(--ink); }

.triad__grid {
  margin: 0; padding: 0; list-style: none;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 clamp(20px, 3vw, 44px);
}
.triad__item {
  display: grid; align-content: start; gap: 8px;
  padding: 20px 0 4px;
}
.triad__item + .triad__item {
  padding-left: clamp(20px, 3vw, 44px);
  border-left: 2px solid var(--ink-14);
}
.triad__term {
  margin: 0;
  /* Der vh-Deckel steht in der Klammer, nicht darum: außen stach er auch die
     Untergrenze, und in einem flachen Fenster wurde „BERATUNG" kleiner als
     seine eigene Unterzeile. Innen begrenzt er nur noch das Wachstum. */
  font-size: clamp(25px, min(3.78vw, 11vh), 74px);
  line-height: 1; font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase;
}
.triad__gloss {
  margin: 0;
  font-size: clamp(16px, 1.5vw, 30px); line-height: 1.45;
  color: var(--ink-72); text-wrap: pretty;
}


/* ── Aus Spannung wird Richtung ─────────────────────────────────────────── */

.tension { position: relative; }

/* Der Abschnitt hing einmal an der Scrollposition: die Wörter lagen verstreut
   und fanden ihre Zeile erst, während man daran vorbeiscrollte. Das kostete
   eine anderthalbfache Bildschirmhöhe Anlauf, und wer nicht scrollte, bekam
   den Satz nie zu lesen. Er steht jetzt fertig da — beim ersten Bild, ohne
   Bedingung — und der Anlauf ist auf einen normalen Abstand zusammengefallen.
   Oben weniger als unten, damit die Aussage dicht auf das Angebot folgt. */
.tension__panel {
  display: flex; flex-direction: column;
  gap: clamp(16px, 2.8vh, 34px);
  padding: clamp(26px, 4vh, 56px) var(--gutter) clamp(40px, 6.5vh, 88px);
}

.tension__headline {
  margin: 0;
  /* Auch hier ein vh-Deckel: in einem flachen Fenster passten Kicker, Zeile,
     Frage und Linie nicht mehr in die stehende Tafel, und der Kicker wurde
     oben abgeschnitten. Greift erst unterhalb von etwa 690px Fensterhöhe. */
  font-size: clamp(33px, min(6.83vw, 17vh), 143px); line-height: 1.02;
  font-weight: 700; letter-spacing: -0.025em; max-width: 22ch;
}
/* Jedes Wort steht für sich — früher, damit es seinen Weg in die Zeile finden
   konnte, heute, damit es einzeln atmen kann. Siehe tl-float weiter unten. */
.tension__headline > span { display: inline-block; }

.tension__question { margin: 0; display: flex; align-items: baseline; gap: clamp(16px, 3vw, 40px); }
.tension__question > span {
  display: inline-block;
  font-size: clamp(44px, min(10.36vw, 26vh), 223px); line-height: 0.9;
  font-weight: 800; letter-spacing: -0.04em; color: var(--accent);
}

.tension__rule { height: 2px; background: var(--ink); transform-origin: left; }

/* ── Die Antwort ────────────────────────────────────────────────────────── */

.answer { padding: clamp(10px, 1.6vh, 22px) var(--gutter) clamp(34px, 5.6vh, 76px); }

/* Auf der Startseite folgt dieser Abschnitt dem Spannungsfeld, das mit viel
   Luft und einer eigenen Kontur endet — dort genügen die 14px oben. Hinter
   einem `page-hero` stehen dagegen zwei Schlagzeilen unmittelbar übereinander,
   getrennt nur von der Haarlinie des Hero, und das liest sich gedrängt.
   Besonders dort, wo keine Subline mehr dazwischensteht.

   Deshalb ein eigener Anlauf, wo die Nachbarschaft besteht: rund das Maß, mit
   dem auf diesen Seiten auch ein gewöhnlicher Abschnitt öffnet. */
.page-hero + .answer { padding-top: clamp(40px, 6.5vh, 88px); }

.answer__inner {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(18px, 3vh, 42px);
  max-width: 1740px; margin-inline: auto;
}
/* The answer carries the same weight as the question it follows. */
.answer__headline {
  margin: 0;
  font-size: clamp(33px, 6.34vw, 131px); line-height: 1.03;
  font-weight: 700; letter-spacing: -0.035em; max-width: 19ch; text-wrap: pretty;
}

.answer__body {
  /* min(320px, 100%): unter 320px Fensterbreite ist die Spaltenuntergrenze
     sonst breiter als der Platz, den es gibt — die Spur bleibt bei 320px
     stehen und schiebt die Seite um genau die Differenz zur Seite. */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: clamp(28px, 5vw, 80px);
}
.answer__rule-cell { display: flex; align-items: flex-start; }
.answer__rule { display: block; width: 64px; height: 3px; background: var(--accent); margin-top: 14px; }

.answer__text {
  /* Als Eigenschaft und nicht als Wert, weil das Maß an zwei Stellen gebraucht
     wird: hier und in .prose__lead-rest, das aus dem größeren Lead-Absatz auf
     die Fließtextgröße zurückmuss. Zwei gleich geschriebene clamp() wären zwei
     Stellen, die auseinanderlaufen können. */
  --fliesstext: clamp(16px, 1.46vw, 28px);
  display: grid; gap: clamp(14px, 1.5vw, 22px);
  font-size: var(--fliesstext); line-height: 1.6; max-width: 66ch;
}
/* Dieselbe Stufe wie im Fließtext der übrigen Seiten — siehe .prose__lead. */
.answer__text .prose__lead { margin-bottom: 2px; }
/* Die Fortsetzung desselben Absatzes, eine Stufe kleiner. Sie erbt vom
   Lead-Absatz dessen Größe, Gewicht, Zeilenhöhe und Zeilenmaß — alle vier
   werden hier zurückgenommen, sonst stünde der Rest in halber Lead-Größe mit
   Lead-Durchschuss auf 46 Zeichen Breite. Der Abstand darüber ist kleiner als
   der zwischen zwei Absätzen: es ist einer. */
/* Das Zeilenmaß sitzt auf den beiden Teilen, nicht mehr auf dem Absatz. Behielte
   das <p> seine 46ch, könnte die Fortsetzung nie breiter werden als der Lead —
   und liefe damit schmaler als der gleich große Absatz darunter. Zwei
   verschiedene Zeilenlängen bei derselben Schriftgröße sehen nach Versehen aus.

   Der Absatz selbst bekommt deshalb kein eigenes Maß: die Spalte begrenzt
   ohnehin bei 66ch. Ein 66ch auf dem <p> wäre sogar falsch — ch rechnet gegen
   die Schrift des Elements, auf dem es steht, und das ist hier die größere
   Lead-Schrift. Auf den beiden Teilen stimmt die Rechnung: einmal gegen die
   Lead-Größe, einmal gegen die Fließtextgröße. */
.answer__text .prose__lead { max-width: none; }
/* Dieselbe Größe wie die zweite Zeile der Überschrift, und das ist der Punkt:
   dort die Frage in Koralle, hier die Antwort in Tinte. Zwei Sätze auf einer
   Stufe, die sich gegenseitig meinen — deshalb steht die Sprosse hier ein
   zweites Mal und nicht die Lead-Größe darüber.

   Das Zeilenmaß ist mitgewandert: 46ch waren für 2vw gedacht. Bei 4,27vw ist
   ein Satz dieser Länge ein Bild und keine Textspalte; 20ch sind dafür das
   Maß, das auch `.statement` führt. */
.prose__lead-satz {
  display: block; max-width: 20ch;
  font-size: clamp(26px, 4.27vw, 83px); line-height: 1.12;
}
.prose__lead-rest {
  display: block; margin-top: 0.7em;
  font-size: var(--fliesstext); font-weight: 400;
  line-height: 1.6; letter-spacing: 0; max-width: 66ch;
}
.answer__text p { margin: 0; }
.answer__closing { font-weight: 600; }

.button-row { margin: 8px 0 0; display: flex; flex-wrap: wrap; gap: 12px; }

/* ── Die Schaltflächen ────────────────────────────────────────────────────
   Gerundete Ecken, und die neue Farbe läuft beim Überfahren von der Mitte
   nach außen. Der Kreis dafür ist ein Pseudo-Element, das über `scale`
   wächst — nicht über `background-size` eines Farbverlaufs. Das ist der
   Unterschied zwischen einer Bewegung, die der Compositor übernimmt, und
   einer, die den Browser jedes Bild neu zeichnen lässt.

   Der Kreis liegt zwischen Fläche und Schrift, deshalb steckt die Beschriftung
   in einem eigenen `span`: ein nackter Textknoten in einem Flex-Kasten wird zu
   einem anonymen Element, und ein anonymes Element lässt sich nicht über den
   Kreis heben.

   `overflow: hidden` schneidet den Kreis an der gerundeten Kante ab —
   ohne das liefe er als Quadrat über die Ecken hinaus. */
.btn {
  position: relative; isolation: isolate; overflow: hidden;
  display: inline-flex; align-items: center; gap: 10px;
  /* Seit der Rückrufbitte trägt die Klasse auch ein <button>. Das bringt
     eigene Voreinstellungen mit — Systemschrift, ein Rahmen, ein anderer
     Zeiger —, die hier für alle Träger gleich zurückgesetzt werden. Für
     <a> ändern sie nichts. */
  font-family: inherit; border: 0; cursor: pointer;
  /* 32px, und dahinter steckt eine Rechnung statt eines Geschmacks.
     Ein Radius wird vom Browser auf die halbe Höhe begrenzt. Eine einzeilige
     Schaltfläche ist 59 bis 64px hoch, ihre halbe Höhe also 29,5 bis 32px —
     bei 32px ist sie damit voll gerundet, eine echte Pille. In einer Seite aus
     Haarlinien und harten Kanten ist sie so das einzige Weiche, und genau das
     macht sie zum Griff.

     Bricht die Beschriftung auf zwei Zeilen um, wird die Schaltfläche 90px
     hoch. Ein voller Radius rundete dann auf 45px und machte aus dem Griff
     eine Kapsel; 32px sind dort nur noch zwei Drittel davon und lassen die
     Fläche Fläche bleiben.

     Die Form folgt damit der Gestalt des Elements — ohne Umbruchpunkt, denn
     umbrechen können die Beschriftungen auch bei 900px. */
  border-radius: 32px;
  /* 19px und nicht 16px, und der Grund ist Lesbarkeit, nicht Geschmack: Weiß
     auf der Koralle sind 3,27:1. Als kleine Schrift verfehlt das die Schwelle
     von 4,5:1. Ab 18,66px fett gilt Schrift als groß, dort liegt die Schwelle
     bei 3:1, und 3,27:1 trägt. Die Farbe bleibt damit unangetastet — es ist
     die Größe, die die Zeile über die Schwelle hebt, nicht ein neuer Ton. */
  font-size: 19px; font-weight: 700;
  transition: color .25s ease, border-color .25s ease;
}
.btn__text { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 10px; }
.btn::before {
  content: ''; position: absolute; z-index: 0;
  left: 50%; top: 50%; width: 145%; aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  scale: 0;
  transition: scale .42s var(--ease-out);
}
.btn:hover::before, .btn:focus-visible::before { scale: 1; }

/* Der Kreis deckt die Fläche rechnerisch vollständig — sein Radius ist 180px,
   die entfernteste Ecke liegt 128px von der Mitte. Beim Beschneiden an der
   gerundeten Kante blieb trotzdem ein zwei Pixel breiter Saum der alten Farbe
   an der Unterkante stehen, ein Rundungsartefakt zwischen dem Kasten auf
   57,59px und einem Zuschnitt auf ganze Pixel.

   Deshalb hängt der Endzustand nicht am Kreis: die Fläche selbst wechselt
   mit, nur eben ohne Dauer und erst dann, wenn der Kreis angekommen ist.
   Beim Verlassen springt sie sofort zurück, damit der schrumpfende Kreis
   etwas hat, wovon er sich abhebt. Deswegen zwei Übergänge statt einem. */
.btn { transition: color .25s ease, border-color .25s ease, background-color 0s linear 0s; }
.btn:hover, .btn:focus-visible {
  transition: color .25s ease, border-color .25s ease, background-color 0s linear .42s;
}

/* Bei Bewegungsreduzierung springt die Farbe um, statt zu laufen. Das
   Hineinlaufen ist selbst eine Bewegung, nicht nur ihr Übergang. */
@media (prefers-reduced-motion: reduce) {
  .btn::before { transition: none; }
  .btn:hover, .btn:focus-visible { transition: color .25s ease, border-color .25s ease; }
}

.btn--accent { padding: 15px 22px; background: var(--accent); color: #fff; letter-spacing: 0.02em; }
.btn--accent::before { background: var(--ink); }
.btn--accent:hover, .btn--accent:focus-visible { background: var(--ink); color: #fff; }

.btn--outline { padding: 15px 22px; border: 2px solid var(--ink); }
.btn--outline::before { background: var(--ink); }
.btn--outline:hover, .btn--outline:focus-visible { background: var(--ink); color: var(--ground); }

/* Auf der Tinte kehrt sich die Kontur-Pille um. Ohne das stünde sie in Tinte
   auf Tinte — unsichtbar. Sie steht so auf Interim-Management und Executive
   Coaching, wo die zweite Aufforderung am Fuß des dunklen Abschnitts sitzt.
   Grundton auf Tinte sind 10,99:1. */
.block--dark .btn--outline { border-color: var(--ground); color: var(--ground); }
.block--dark .btn--outline::before { background: var(--ground); }
.block--dark .btn--outline:hover,
.block--dark .btn--outline:focus-visible { background: var(--ground); color: var(--ink); }

/* ── Drei Arten von Nähe ────────────────────────────────────────────────── */

.roles {
  position: relative;
  border-top: 2px solid var(--ink);
  background: var(--ink); color: var(--ground);
}

/* Static: each role stands full size with its description directly below,
   in reading order. `display: contents` on the two wrappers lets headline and
   description interleave even though the markup groups them for the stage. */
.roles__panel {
  display: flex; flex-direction: column; gap: clamp(16px, 2.4vh, 30px);
  padding: clamp(46px, 7vh, 88px) var(--gutter) clamp(22px, 4vh, 46px);
}
.roles__stage, .roles__meta-band { display: contents; }

.roles__head { display: flex; justify-content: space-between; gap: 24px; align-items: baseline; }

/* The three offer names are the persistent route to their pages. The role
   descriptions carry a link too, but each is only clickable inside its own
   scroll band — these are reachable at every scroll position. */
.roles__title a { color: inherit; }
.roles__title a:hover, .roles__title a:focus-visible { color: var(--accent); }

.roles__title {
  margin: 0;
  font-size: clamp(26px, min(5.85vw, 14vh), 128px);
  line-height: 0.94; font-weight: 800; letter-spacing: -0.04em; text-transform: uppercase;
  min-width: 0;
  transform-origin: left center;
  color: var(--ground);
}

.roles__meta {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px 40px; max-width: 1100px;
  border-top: 2px solid var(--ground-25); padding-top: 14px;
}
.roles__meta p { margin: 0; }
.roles__meta-label {
  font-size: 16px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent-ground);
}
.roles__meta-text { font-size: clamp(17px, 1.55vw, 32px); line-height: 1.5; color: var(--ground-82); }
.roles__meta-link { color: var(--ground); border-bottom: 2px solid var(--accent); white-space: nowrap; }
.roles__meta-link:hover { color: var(--accent); }

/* Reading order for the static stack: headline, its description, next headline… */
.roles__head                     { order: 0; }
.roles__title[data-role="0"]     { order: 1; }
.roles__meta[data-role-meta="0"] { order: 2; }
.roles__title[data-role="1"]     { order: 3; }
.roles__meta[data-role-meta="1"] { order: 4; }
.roles__title[data-role="2"]     { order: 5; }
.roles__meta[data-role-meta="2"] { order: 6; }
.roles__scale                    { order: 7; }

.roles__scale { display: grid; gap: 10px; margin-top: clamp(10px, 2vh, 20px); }
.roles__scale-bar {
  position: relative; height: 3px;
  background: linear-gradient(90deg, var(--ground-16) 0%, rgba(255, 77, 79, 0.5) 50%, var(--accent) 100%);
}
.roles__scale-marker {
  position: absolute; top: -7px; left: 0;
  width: 2px; height: 17px; background: var(--ground);
  display: none;
}
.roles__scale-labels {
  display: flex; justify-content: space-between;
  font-size: 11px; font-weight: 700; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ground-62);
}

/* ── Übergang ───────────────────────────────────────────────────────────── */

/* Der Übergang steht auf Tinte wie die Rollenbühne direkt darunter. Beide
   bilden damit ein zusammenhängendes dunkles Feld: erst die Zusage, dann ihre
   Entfaltung in den drei Rollen — eine Aussage, nicht zwei. Die Kante nach oben
   trägt jetzt dieser Abschnitt, weil er der erste dunkle ist; die gleichlautende
   Kante an .roles liegt danach Tinte auf Tinte und fällt nicht mehr auf. */
.bridge {
  border-top: 2px solid var(--ink);
  background: var(--ink); color: var(--ground);
  padding: clamp(40px, 6.5vh, 86px) var(--gutter) clamp(26px, 4.2vh, 56px);
}
.bridge__lead {
  margin: 0; max-width: 34ch;
  font-size: clamp(26px, 4.14vw, 87px); line-height: 1.14;
  font-weight: 600; letter-spacing: -0.03em; text-wrap: pretty;
}
/* Die zweite Zeile trägt die Aussage weiter und steht deshalb im Akzent: der
   Blick aufs Ganze ist die Beobachtung, die Lösung ist das Versprechen. Eine
   eigene Zeile, kein eigener Absatz — beides gehört zu einem Satz. */
.bridge__lead-accent {
  display: block; margin-top: 0.18em;
  color: var(--accent);
  /* balance statt pretty: bei zwei Zeilen in dieser Größe fällt eine kurze
     Schlusszeile auf. Lieber zwei ähnlich lange. */
  text-wrap: balance;
}
.bridge__note {
  margin: clamp(18px, 2.8vh, 34px) 0 0 auto; max-width: 56ch;
  font-size: clamp(16px, 1.46vw, 28px); line-height: 1.6;
  border-left: 2px solid var(--accent); padding-left: 22px;
  color: var(--ground-82);
}
/* Auf Tinte ist das Hervorgehobene das Hellste, nicht das Dunkelste. */
.bridge__note strong { font-weight: 700; color: var(--ground); }

/* ── Kontakt ────────────────────────────────────────────────────────────── */

/* Heller Grund wie der Rest der Seite, die Schlagzeile im Akzentton. Die
   Koralle liegt jetzt auf der Schrift statt auf der Fläche — das trägt weiter,
   weil die Zeile groß gesetzt ist. Die Kontaktdaten bleiben in Tinte: 15px in
   Koralle auf hellem Grund kämen auf rund 3:1 und wären als Fließtext nicht
   mehr sicher lesbar. Sie bekommen die Koralle als Unterstreichung. */
.contact {
  background: var(--ground); color: var(--ink);
  padding: clamp(80px, 13vh, 170px) var(--gutter) clamp(44px, 7vh, 92px);
}
/* Die Zeile vor dem Abschluss stand auf 7,8vw und war damit die größte Schrift
   der Seite — größer als die Blockzeilen (5,36vw) und größer als die
   Aussagen, zu denen sie gehört (4,27vw). Sie hat den Inhalt überschrien, den
   sie eigentlich nur abschließt.

   Jetzt 4,9vw: eine Stufe unter den Blockzeilen und eine über den Aussagen.
   Damit bleibt sie ein Schlussakkord und wird kein Plakat. Die Zeilenhöhe geht
   von 0,94 auf 1,0 mit — enge Durchschüsse tragen bei 112px, bei 70px wirken
   sie gedrückt. */
.contact__headline {
  margin: 0; max-width: 24ch;
  /* Ein Versalwort, das breiter ist als die Spalte, schiebt sonst die ganze
     Seite zur Seite. „UNTERSCHIEDLICHE" misst bei 320px Fensterbreite 310px,
     die Spalte hat 280px — dieselbe Arithmetik wie bei der Überzeile auf
     Organisationsentwicklung. `hyphens: auto` greift nur dann und trennt nach
     den deutschen Regeln (das `lang="de"` am <html> ist die Voraussetzung);
     wo kein Wort anstößt, ändert sich nichts. Und wenn der Browser keine
     Trennstelle kennt, bricht `overflow-wrap` notfalls hart um — ein harter
     Umbruch ist immer noch besser als eine verschobene Seite. */
  hyphens: auto; overflow-wrap: break-word;
  font-size: clamp(30px, 4.9vw, 96px); line-height: 1.0;
  font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase;
  color: var(--accent);
}
.contact__row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px 32px;
  margin-top: clamp(24px, 4.4vh, 48px);
  border-top: 2px solid var(--accent); padding-top: 24px;
}
/* Steht im Abschluss eine Rückrufbitte, wird aus der Flex-Zeile dasselbe
   Raster wie bei .cta-paar: die dritte Spalte nimmt die verbleibende Breite,
   damit das aufgeklappte Formular dort Platz hat, und `align-items: start`
   hält die beiden Pillen oben bündig, während der Kasten darunter wächst.
   Ohne das müssten sie sich beim Aufklappen neu ausrichten und wegspringen. */
.contact__row:has(.rueckruf) {
  display: grid; grid-template-columns: auto auto minmax(0, 1fr);
  align-items: start; gap: clamp(12px, 1.5vw, 22px);
}
/* Telefon und E-Mail stehen deshalb nicht mehr in derselben Zeile: neben einem
   Kasten, der auf 600px Höhe aufklappt, müssten sie sich zwischen dessen
   Oberkante und dessen Mitte entscheiden, und beides sähe falsch aus. Eine
   eigene Zeile darunter — die Reihenfolge bleibt, der Rang auch. */
.contact__direkt {
  margin: clamp(16px, 2.4vh, 26px) 0 0;
  display: flex; flex-wrap: wrap; gap: 12px 32px;
}
@media (max-width: 760px) {
  .contact__row:has(.rueckruf) { grid-template-columns: minmax(0, 1fr); justify-items: start; }
  .contact__row:has(.rueckruf) .cta-paar__oder { padding: 0; }
  .contact__row:has(.rueckruf) .rueckruf { width: 100%; }
}

.contact__link {
  color: var(--ink); font-size: clamp(16px, 1.17vw, 23px); font-weight: 600;
  border-bottom: 2px solid var(--accent);
}
.contact__link:hover { color: var(--accent); }
/* Eine Zeile, die unter der Kontaktreihe steht statt in ihr. Der Abstand
   stammt aus derselben Staffel wie der Rest des Abschnitts. */
.contact__aside { margin: clamp(14px, 2vh, 22px) 0 0; }
.contact :focus-visible { outline-color: var(--accent); }

/* ── Footer ─────────────────────────────────────────────────────────────── */

.site-footer {
  background: var(--ink); color: var(--ground-70);
  padding: clamp(40px, 7vh, 72px) var(--gutter);
  display: flex; flex-wrap: wrap; gap: 24px 48px;
  align-items: flex-end; justify-content: space-between;
}
.site-footer__logo { height: 34px; width: auto; }
.site-footer__nav {
  display: flex; flex-wrap: wrap; gap: 12px 28px;
  font-size: clamp(13px, 0.94vw, 20px); font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase;
}
.site-footer__nav a { color: var(--ground-70); }
.site-footer__nav a:hover { color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════════
   3. Kinetics — only when JavaScript is running and motion is welcome.
      html[data-motion="kinetic"] is set by the inline boot script in <head>
      and cleared again if site.js never takes over.
   ══════════════════════════════════════════════════════════════════════════ */

/* Hero — the poster builds itself, line by line, out of the trim. */
[data-motion="kinetic"] .hero__overline { animation: tl-fade .9s cubic-bezier(.2, .7, .2, 1) .1s both; }
/* Der Zeilenschnitt schnitt die Umlautpunkte ab: die Zeilenhöhe ist mit 0.84
   kleiner als der Oberlängenraum der Schrift, und „FÜHREN." oder „MÜSSEN"
   verlieren dabei oben ihre Punkte. Das padding gibt dem Schnitt Luft, die
   negative margin nimmt sie aus dem Fluss wieder heraus — die Zeile steht
   danach an genau derselben Stelle wie vorher. */
[data-motion="kinetic"] .hero__line {
  overflow: hidden;
  padding-top: 0.16em; margin-top: -0.16em;
}
[data-motion="kinetic"] .hero__line-inner { animation: tl-rise 1s var(--ease-out) both; }
[data-motion="kinetic"] .hero__line:nth-child(1) .hero__line-inner { animation-delay: .18s; }
[data-motion="kinetic"] .hero__line:nth-child(2) .hero__line-inner { animation-delay: .32s; }
[data-motion="kinetic"] .hero__line:nth-child(3) .hero__line-inner { animation-delay: .46s; }
[data-motion="kinetic"] .hero__breathe { animation: tl-breathe 9s ease-in-out 1.6s infinite; }

[data-motion="kinetic"] .triad__item { animation: tl-fade .8s ease both; }
[data-motion="kinetic"] .triad__item:nth-child(1) { animation-delay: .80s; }
[data-motion="kinetic"] .triad__item:nth-child(2) { animation-delay: .95s; }
[data-motion="kinetic"] .triad__item:nth-child(3) { animation-delay: 1.10s; }

/* Aus Spannung wird Richtung — 210vh Scrollweg für eine stehende Tafel.
   Vorher 280vh: dreitausend Pixel für einen Satz waren zu viel, zumal die
   Bewegung im ersten Viertel schon vorbei war. */
/* ── Der Atem ──────────────────────────────────────────────────────────────
   Was hier bleibt, ist kein Effekt, sondern ein Lebenszeichen: die Wörter
   heben und senken sich um drei Pixel, jedes mit eigener Phase, über elf
   Sekunden. Das ist langsam genug, dass man es nicht als Bewegung liest,
   sondern nur merkt, dass die Zeile nicht tot ist — wer hinsieht, findet
   nichts, wer wegsieht, spürt es. Die Frage nimmt fünf Pixel und eine andere
   Periode, damit sie nicht im Gleichtakt mit der Zeile schwingt.

   Die negativen Verzögerungen sind der Grund, warum nichts synchron startet:
   jedes Wort beginnt mitten in seinem eigenen Zyklus, statt dass alle sieben
   beim Laden gemeinsam losheben. Nichts davon verändert den Textfluss —
   translateY auf einem inline-block bewegt kein Layout.

   Unter prefers-reduced-motion läuft nichts davon: die ganze Gruppe hängt an
   html[data-motion="kinetic"], und das Attribut wird dort gar nicht gesetzt. */
@keyframes tl-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}
@keyframes tl-float-question {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}
[data-motion="kinetic"] .tension__headline > span {
  animation: tl-float 11s ease-in-out infinite;
  will-change: transform;
}
[data-motion="kinetic"] .tension__headline > span:nth-child(1) { animation-delay: -0.4s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(2) { animation-delay: -1.9s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(3) { animation-delay: -3.6s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(4) { animation-delay: -5.2s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(5) { animation-delay: -6.8s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(6) { animation-delay: -8.3s; }
[data-motion="kinetic"] .tension__headline > span:nth-child(7) { animation-delay: -9.7s; }
[data-motion="kinetic"] .tension__question > span {
  animation: tl-float-question 14s ease-in-out infinite;
  will-change: transform;
}

/* Drei Arten von Nähe — one dark stage, three arrivals. */
[data-motion="kinetic"] .roles { height: 400vh; }
[data-motion="kinetic"] .roles__panel {
  position: sticky; top: 0; height: 100svh; overflow: hidden;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  padding: clamp(62px, 9vh, 110px) var(--gutter) clamp(20px, 3vh, 42px);
}
[data-motion="kinetic"] .roles__stage {
  display: grid; align-self: center;
  grid-template-columns: minmax(0, 1fr); grid-auto-rows: min-content;
  align-content: center; gap: clamp(6px, 1.4vh, 18px);
  width: 100%; min-width: 0;
}
[data-motion="kinetic"] .roles__title { will-change: transform, filter; color: var(--ground-60); }

/* The descriptions get their own, non-compressible band and cross-fade there —
   inside the stage's grid track they were squeezed below their own content
   height and clipped. */
[data-motion="kinetic"] .roles__meta-band {
  display: block; position: relative;
  min-height: clamp(88px, 15vh, 116px);
  border-top: 2px solid var(--ground-25);
  margin-top: clamp(10px, 2vh, 20px);
  margin-bottom: clamp(8px, 1.6vh, 18px);
}
[data-motion="kinetic"] .roles__meta {
  position: absolute; left: 0; right: 0; top: 0;
  border-top: 0; padding-top: 14px;
  opacity: 0; pointer-events: none;
  transition: opacity .4s ease, transform .4s var(--ease-out);
}
[data-motion="kinetic"] .roles__scale { margin-top: 0; }
[data-motion="kinetic"] .roles__scale-marker { display: block; }

/* Scroll reveals */
[data-motion="kinetic"] [data-reveal] {
  opacity: 0; transform: translateY(22px);
  transition: opacity .9s var(--ease-out), transform .9s var(--ease-out);
}
[data-motion="kinetic"] [data-reveal].is-revealed { opacity: 1; transform: none; }

/* ── Keyframes ──────────────────────────────────────────────────────────── */

@keyframes tl-rise   { from { transform: translateY(130%) } to { transform: translateY(0) } }
@keyframes tl-fade   { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: none } }
@keyframes tl-breathe{ 0%, 100% { font-stretch: 100% } 50% { font-stretch: 107% } }
/* ══════════════════════════════════════════════════════════════════════════
   4. Small screens — the prototype was drafted for desktop. Below 760px the
      header wraps to two rows and the triad stacks, so nothing is clipped.
   ══════════════════════════════════════════════════════════════════════════ */

@media (max-width: 760px) {
  :root { --header-h: 92px; }

  .site-header { flex-wrap: wrap; gap: 10px 20px; padding-block: 12px; }
  /* Auf dem Telefon steht die Navigation ohnehin in einer zweiten Zeile. Das
     Logo skaliert auch hier über transform, belegt also weiter seine 24px im
     Layout — die zweite Zeile rutscht nicht. */
  .site-header__brand img { height: 24px; }
  .site-nav {
    width: 100%; justify-content: space-between;
    gap: 8px; font-size: 11px; letter-spacing: 0.1em;
  }

  .hero { padding-top: calc(var(--header-h) + 16px); }

  .triad__grid { grid-template-columns: minmax(0, 1fr); }
  .triad__item { padding: 16px 0; }
  .triad__item + .triad__item {
    padding-left: 0; border-left: 0; border-top: 2px solid var(--ink-14);
  }
  .triad__term { font-size: clamp(31px, 10.97vw, 66px); }

  .roles__head { flex-wrap: wrap; gap: 6px 24px; }
  /* Three lines of 0.28em-tracked caps is a wall; give the tracking back. */
  .kicker--statement { letter-spacing: 0.16em; }

  /* Three roles plus a description have to share one viewport height —
     give the description band the room its text actually needs. */
  [data-motion="kinetic"] .roles__title { font-size: clamp(24px, 7.8vw, 50px); }
  [data-motion="kinetic"] .roles__meta-band { min-height: 200px; }
}

@media (max-width: 420px) {
  [data-motion="kinetic"] .roles__meta-band { min-height: 232px; }
  .button-row .btn, .contact__row .btn { width: 100%; justify-content: center; }
}

/* „Beobachterdistanz" is long enough that the three scale labels run into each
   other on the narrowest phones — trade tracking for the gaps that separate
   them, so the scale still reads as three marks and not one string. */
@media (max-width: 440px) {
  .roles__scale-labels { font-size: 9px; letter-spacing: 0.1em; }
}

/* ══════════════════════════════════════════════════════════════════════════
   5. Angebot pages — Organisationsentwicklung, Executive Coaching,
      Interim-Management.

      Same voice as the Startseite, one step down: a poster headline that rises
      line by line out of its trim with one coral word breathing on the width
      axis, coral labels running down the left edge, rules that draw themselves
      in from the left before their row builds, and a dark band before the
      coral close — so the page has the same light / dark / coral rhythm the
      Startseite has, instead of one uninterrupted light field.
   ══════════════════════════════════════════════════════════════════════════ */

.page-hero {
  display: grid; gap: clamp(10px, 1.7vh, 22px);
  padding: clamp(84px, 12vh, 148px) var(--gutter) 0;
  container-type: inline-size;
}
.page-hero__overline {
  margin: 0;
  /* Untergrenze 18px statt 13px: die Überzeile soll auf keiner Fensterbreite
     kleiner werden. Damit weicht sie bewusst von .hero__overline und
     .opening__overline ab, die weiter bei 13px beginnen. */
  font-size: clamp(18px, 1.3vw, 22px); font-weight: 700; letter-spacing: 0.34em;
  text-transform: uppercase; color: var(--accent-ink);
}
/* „ORGANISATIONSENTWICKLUNG" ist bei 18px und 0.34em Sperrung 439px breit —
   ein Wort, das sich nicht umbrechen lässt, und auf einem 360px-Gerät stehen
   dafür 320px zur Verfügung. Ohne diese Regel schob es die ganze Seite um bis
   zu 99px zur Seite. Die Sperrung gibt zuerst nach, weil sie das Maß ist, das
   hier am wenigsten trägt; reicht das nicht, bricht das Wort um. Die
   Schriftgröße bleibt in jedem Fall bei 18px.

   Das min-width gehört dazu: als Rasterzelle wächst die Zeile sonst auf die
   Breite ihres längsten Wortes, statt es umbrechen zu lassen — die Spalte gibt
   nach, und der Umbruch kommt nie zum Zug. */
@media (max-width: 700px) {
  .page-hero__overline {
    min-width: 0; letter-spacing: 0.12em; overflow-wrap: break-word;
  }
}
/* Unter 430px reicht auch 0.12em nicht: „ORGANISATIONSENTWICKLUNG" braucht dort
   344px und hat 320px. Die Sperrung geht deshalb fast auf null zurück — auf
   einem Telefon ist eine gesperrte Überzeile ohnehin kaum als Sperrung lesbar,
   ein mitten durchs Wort laufender Umbruch dagegen sofort als Fehler. Der
   Umbruch bleibt als Sicherung stehen, greift aber nicht mehr. */
@media (max-width: 430px) {
  .page-hero__overline { letter-spacing: 0.03em; }
}
/* The page's own poster. Uses the Startseite's own line components, so the
   rise, its easing and its stagger are literally the same animation. */
.page-hero__title {
  margin: 0;
  /* Dieselbe Rechnung wie auf der Startseite — siehe .hero__title, dort steht
     sie ausführlich. Der Höhenanteil ist etwas kleiner, weil unter der Zeile
     noch die Subline steht und mit auf den Schirm gehört. Die Decke
     --h1-deckel ist dieselbe: sie gilt für alle zwölf Seiten. */
  font-size: clamp(36px, min(7.4vw, 26vh, 130px), 260px);
  font-size: clamp(min(34px, calc(98cqw / var(--h1-word, 6))),
    min(calc(98cqw / var(--h1-em, 8)),
        calc(62svh / (var(--h1-lines, 2) * 0.92)),
        var(--h1-deckel)),
    260px);
  line-height: 0.92; font-weight: 800; letter-spacing: -0.04em;
  text-transform: uppercase;
}
.page-hero__subline {
  margin: 0; max-width: 46ch;
  font-size: clamp(19px, 2.07vw, 39px); line-height: 1.4;
  font-weight: 600; letter-spacing: -0.02em; color: var(--ink-72); text-wrap: balance;
}
.page-hero__rule { height: 2px; background: var(--ink); transform-origin: left; }

/* Two columns: the block's name on the left, its text on the right, so every
   body column on the page starts on the same vertical axis. */
/* ── Der Rhythmus der Abschnitte ──────────────────────────────────────────
   Vorher trug jeder Abschnitt oben und unten dasselbe Maß. Bei gleich viel
   Luft über und unter dem Text steht er in der Mitte seines Kastens, und wenn
   das für jeden Abschnitt gilt, liest sich die ganze Seite als eine Folge
   gleich großer, gleich gefüllter Tafeln — viel Weiß, wenig Gefälle.

   Deshalb sind die Maße jetzt ungleich: oben mehr als unten. Der Text hängt
   dadurch am oberen Rand seines Abschnitts statt in dessen Mitte zu schweben,
   die Trennung zwischen zwei Abschnitten wird ablesbar, und die Seite wird
   kürzer, ohne dass irgendwo etwas klebt.

   Die großen Momente sind davon ausgenommen und stehen weiter unter eigenen
   Regeln: .tension und .roles auf der Startseite, .closing auf „Über mich",
   .approach und der Koralle-Schluss auf den Angebot-Seiten. Ein Gefälle
   entsteht nur, wenn nicht alles gleich laut ist. */
.block { padding: clamp(30px, 4.6vh, 62px) var(--gutter) clamp(20px, 3vh, 40px); }
.block--tight { padding-block: clamp(18px, 2.6vh, 34px) clamp(14px, 2vh, 26px); }
/* Das Maß ist die Textspalte, nicht das Fenster: 66 Zeichen sind bei dieser
   Schriftgröße rund 1050px, und wenn der Kasten breiter ist als Index + Abstand
   + diese 1050px, bleibt der Rest rechts leer stehen. Bei 1440px füllt der Text
   seine Spalte aus, und was übrig ist, verteilt sich als Rand auf beide Seiten,
   statt sich rechts zu sammeln. */
.block__inner {
  max-width: 1440px; margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(180px, 20%) minmax(0, 1fr);
  gap: clamp(14px, 2.2vh, 26px) clamp(28px, 4.5vw, 88px);
}
.block__rule {
  grid-column: 1 / -1;
  height: 2px; background: var(--ink); transform-origin: left;
}
/* The left edge of the page reads as a coral index. */
.block__title {
  grid-column: 1; margin: 0;
  font-size: 16px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent-ink); text-wrap: pretty;
}
.block__body { grid-column: 2; min-width: 0; }

@media (max-width: 900px) {
  .block__inner { grid-template-columns: minmax(0, 1fr); }
  .block__title, .block__body { grid-column: 1; }
}

.prose {
  display: grid; gap: clamp(14px, 1.5vw, 22px);
  font-size: clamp(16px, 1.46vw, 28px); line-height: 1.6; max-width: 66ch;
}
.prose p { margin: 0; }
/* ── Die fehlende Stufe ───────────────────────────────────────────────────
   Die Leiter ging von der Blockzeile (86px) über die Lede (45px) direkt auf
   den Fließtext (23px). Der letzte Schritt halbiert die Größe — das liest
   sich nicht als Abstufung, sondern als Absturz: die große Zeile steht für
   sich, und darunter fängt etwas anderes an.

   Der erste Satz eines Textblocks steht deshalb eine Stufe höher als der
   Rest. Kein eigener Ton, keine eigene Farbe, nur Grad und Gewicht — er ist
   derselbe Text, nur der Einstieg in ihn. Die Stufe ist mit Absicht schmaler
   gesetzt als der Fließtext: eine größere Schrift auf gleicher Zeilenlänge
   liest sich schwerer, nicht leichter. */
.prose__lead {
  font-size: clamp(19px, 2vw, 36px); line-height: 1.36;
  font-weight: 500; letter-spacing: -0.015em;
  color: var(--ink); max-width: 46ch; text-wrap: pretty;
}
/* Textlinks im Fließtext, aber keine Schaltflächen: eine Schaltfläche, die
   im Fließtext steht — auf der Kontaktseite ist das so —, hat sich sonst die
   koralle Unterkante und die koralle Schrift beim Überfahren mitgenommen.
   Das fiel nicht auf, solange ihre Fläche selbst koralle war; auf der Tinte
   des überfahrenen Zustands stand die Schrift dann koralle statt weiß, und
   mit den gerundeten Ecken lag die gerade Unterkante frei. */
.prose a:not(.btn) { border-bottom: 2px solid var(--accent); }
.prose a:not(.btn):hover { color: var(--accent); }

/* „Woran Sie das Ergebnis erkennen" — an editorial list on hairlines, not a
   card grid. The rule is a pseudo-element rather than a border so it can draw
   itself in and change colour as the reading position passes. These are a set
   of signals, not a sequence, so they carry no numbers. */
.signals { margin: 0; padding: 0; list-style: none; }
.signals li {
  position: relative;
  padding: clamp(14px, 2.1vh, 26px) 0;
  font-size: clamp(21px, 2.56vw, 50px); line-height: 1.24;
  font-weight: 600; letter-spacing: -0.025em;
  transform-origin: left center;
}
/* 30ch waren bei 41px Schriftgröße gut 700px — jedes Signal lief über drei
   Zeilen, und vier davon machten den Abschnitt bildschirmhoch, während rechts
   daneben Platz frei blieb. Auf 40ch stehen sie in zwei Zeilen: derselbe Text,
   ein Drittel weniger Höhe, und die Spalte ist ausgefüllt. */
.signals li > span { display: block; max-width: 40ch; text-wrap: pretty; }

/* Schwerpunkte / Formate / Einsatzfelder. The term is set at display size, not
   as a table cell — side by side with a small description it read like a
   printed spec sheet. */
.deflist { margin: 0; }
.deflist__row {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 6px;
  padding: clamp(14px, 2.1vh, 26px) 0;
  transform-origin: left center;
}
.deflist__row { gap: 10px; }
.deflist dt {
  margin: 0; min-width: 0; max-width: 20ch;
  /* Die Untergrenze ist von „TRANSFORMATIONSSTEUERUNG" diktiert: 24 Versalien,
     die auf 360px in die Spalte passen müssen. Mit dem allgemeinen
     Schriftzuwachs auf 22px standen sie 19px über dem Rand. Der obere Bereich
     ist mitgewachsen, die Grenze unten nicht — dort entscheidet ein Wort.
     Die Trennung steht als Sicherung dahinter. Ein harter Umbruch (break-word)
     stand hier auch schon: der zerlegte das Wort auf jeder Breite mitten im
     Schaft, weil die Spalte auf 20ch begrenzt ist und das Wort 24 Zeichen hat
     — die Grenze ist zum Ausbrechen da, nicht zum Zerbrechen. */
  font-size: clamp(19px, 2.81vw, 56px); line-height: 1.06;
  font-weight: 800; letter-spacing: -0.03em;
  text-transform: uppercase; text-wrap: pretty;
  hyphens: auto;
}
.deflist dd {
  margin: 0; max-width: 60ch;
  font-size: clamp(16px, 1.46vw, 28px); line-height: 1.55; color: var(--ink-72);
  text-wrap: pretty;
}

/* ── Dieselbe Liste, aber für ganze Sätze ─────────────────────────────────
   Die Beschreibungsliste ist für Fragen und Antworten genau das richtige
   Bauteil — dt ist der Begriff, dd seine Erläuterung — und sie bringt Zeilen,
   Haarlinien, Abstände und Einblendung schon mit. Nur die Etikettenform des
   dt passt nicht: 20ch Versalien auf bis zu 56px sind für „Telefon" gemacht,
   nicht für einen Satz mit neunzig Zeichen.

   Deshalb bekommt das dt hier die Stufe, die im Stylesheet ohnehin für
   Überschriften im Fließtext steht (.prose h2). Kein neuer Wert, nur ein
   anderer aus demselben Vorrat. Der Abstand zwischen den Absätzen einer
   Antwort ist der der .prose. */
/* Die Zeile behält ihre Klasse und damit Haarlinie, Abstände und Einblendung —
   aber nicht deren display: grid. Auf einem <details> macht das jedes Kind zu
   einem Rasterelement, auch das, was im zugeklappten Zustand verborgen bleiben
   soll: die Antwort stand dann offen da. Der Abstand zwischen Frage und
   Antwort kommt deshalb aus margin-top, nicht aus gap. */
.deflist--faq .faq { display: block; }

.deflist--faq .faq__frage {
  max-width: none;
  font-size: clamp(19px, 1.83vw, 34px); line-height: 1.2;
  font-weight: 800; letter-spacing: -0.02em; text-wrap: pretty;
  /* Das Auf- und Zuklappen macht der Browser. Das Dreieck, das er dafür
     mitbringt, passt nicht — an seine Stelle tritt das Winkelzeichen aus dem
     Navigationsmenü, damit die Seite nur ein Zeichen für „hier geht etwas auf"
     kennt. list-style deckt Firefox ab, der ::marker das Alte. */
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: clamp(16px, 2vw, 32px);
  cursor: pointer; list-style: none;
}
.deflist--faq .faq__frage::-webkit-details-marker { display: none; }
.deflist--faq .faq__frage::marker { content: ''; }
.deflist--faq .faq__frage::after {
  content: ''; flex: none;
  width: 9px; height: 9px; margin-top: 0.34em;
  border-right: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(45deg); transition: transform .25s ease;
}
.deflist--faq .faq[open] > .faq__frage::after { transform: rotate(-135deg); }
.deflist--faq .faq__frage:hover { color: var(--accent-ink); }

.deflist--faq .faq__antwort {
  display: grid; gap: clamp(14px, 1.5vw, 22px);
  max-width: 60ch; margin-top: clamp(10px, 1.2vw, 18px);
  font-size: clamp(16px, 1.46vw, 28px); line-height: 1.55; color: var(--ink-72);
  text-wrap: pretty;
}
.deflist--faq .faq__antwort p { margin: 0; }
.deflist--faq .faq__antwort strong { font-weight: 700; color: var(--ink); }

/* One hairline per row, drawn as a pseudo-element so the reading position can
   pick it out in coral as it passes. */
.signals li::before, .signals li:last-child::after,
.deflist__row::before, .deflist__row:last-child::after {
  content: ''; position: absolute; left: 0; right: 0; height: 2px;
  background: var(--row-rule, var(--ink-14));
  transform-origin: left;
  transition: background-color .35s ease;
}
.signals li::before, .deflist__row::before { top: 0; }
.signals li:last-child::after, .deflist__row:last-child::after { bottom: 0; }

/* „Verbindung zu den anderen Rollen" stands on the dark ground the three roles
   share on the Startseite — and breaks the page's light field before the coral
   close, the same light / dark / coral rhythm the Startseite has. */
.block--dark { background: var(--ink); color: var(--ground); }
.block--dark .block__rule { background: var(--ground-25); }
/* ── Kinetics for the Angebot pages ─────────────────────────────────────────
   Same vocabulary as the Startseite: the headline rises line by line out of
   its trim, rules draw themselves in from the left, and what belongs to a rule
   builds after it. Nothing here invents a new movement. */

[data-motion="kinetic"] .page-hero__overline { animation: tl-fade .9s cubic-bezier(.2, .7, .2, 1) .1s both; }
[data-motion="kinetic"] .page-hero__subline  { animation: tl-fade .8s ease .62s both; }

/* Rules draw in when their block arrives. */
[data-motion="kinetic"] .page-hero__rule,
[data-motion="kinetic"] .block__rule { transform: scaleX(0); transition: transform .9s var(--ease-out); }
[data-motion="kinetic"] .page-hero__rule { animation: tl-draw .9s var(--ease-out) .78s both; transition: none; }
[data-motion="kinetic"] .block__rule.is-revealed { transform: scaleX(1); }

/* A row builds from the left: first its rule, then the words on it. */
[data-motion="kinetic"] .signals li::before,
[data-motion="kinetic"] .signals li:last-child::after,
[data-motion="kinetic"] .deflist__row::before,
[data-motion="kinetic"] .deflist__row:last-child::after {
  transform: scaleX(0);
  transition: transform .9s var(--ease-out);
}
[data-motion="kinetic"] .signals li.is-revealed::before,
[data-motion="kinetic"] .signals li.is-revealed:last-child::after,
[data-motion="kinetic"] .deflist__row.is-revealed::before,
[data-motion="kinetic"] .deflist__row.is-revealed:last-child::after { transform: scaleX(1); }

/* The rows themselves are not revealed once and then finished — they track the
   reading position continuously (see [data-focus] in site.js), the way the role
   stage tracks distance. A list that only fades in once reads as a printed
   page; one that responds while you scroll reads as a live register. */
[data-motion="kinetic"] .signals li,
[data-motion="kinetic"] .deflist__row { will-change: transform, opacity; }

@keyframes tl-draw { from { transform: scaleX(0) } to { transform: scaleX(1) } }

/* ── Angebot menu ──────────────────────────────────────────────────────────
   „Angebot" has to reach the three offers, not just a section of the
   Startseite. Opens on hover and on focus without JavaScript; the script adds
   a click toggle so it also works by touch. */

.site-nav__group { position: relative; display: flex; align-items: center; }
.site-nav__toggle {
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
}
.site-nav__toggle:hover { color: var(--accent); }
.site-nav__toggle::after {
  content: ''; width: 6px; height: 6px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .25s ease;
}
.site-nav__group.is-open .site-nav__toggle::after { transform: rotate(-135deg); margin-top: 2px; }

.site-nav__panel {
  position: absolute; top: calc(100% + 14px); left: 50%; translate: -50% 0;
  display: grid; min-width: max-content;
  background: var(--ink); color: var(--ground);
  padding: 6px 0;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .22s ease, transform .22s var(--ease-out), visibility .22s;
}
.site-nav__group:hover .site-nav__panel,
.site-nav__group:focus-within .site-nav__panel,
.site-nav__group.is-open .site-nav__panel {
  opacity: 1; visibility: visible; transform: none;
}
/* Bridges the gap between the label and the panel so the pointer can cross it. */
.site-nav__group::after { content: ''; position: absolute; top: 100%; left: 0; right: 0; height: 16px; }
.site-nav__panel a {
  color: var(--ground-82); padding: 11px 22px;
  font-size: 13px; letter-spacing: 0.12em; white-space: nowrap;
}
.site-nav__panel a:hover, .site-nav__panel a:focus-visible { color: var(--accent); }
.site-nav__panel a[aria-current="page"] { color: var(--ground); box-shadow: inset 3px 0 0 var(--accent); }

@media (max-width: 760px) {
  .site-nav__group { position: static; }
  /* The panel spans the header instead of hanging under the label — and drops
     `min-width: max-content`, which otherwise forces the three names onto one
     594px row inside a 390px screen. */
  .site-nav__panel {
    left: 0; right: 0; translate: none; top: 100%;
    min-width: 0;
    display: flex; flex-wrap: wrap; gap: 0 20px;
    padding: 10px var(--gutter) 12px;
  }
  .site-nav__panel a { padding: 7px 0; font-size: 10px; letter-spacing: 0.08em; }
  .site-nav__panel a[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--accent); }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav__panel, .site-nav__toggle::after { transition: none; }
}


/* ── The statement before the close ─────────────────────────────────────────
   Not a section label but a claim in its own right, set well above the text it
   introduces and built line by line out of its trim like the page headline.
   The last word carries the coral, following the page's own rule that the
   deciding word in a headline is the one that gets the accent. */
.statement {
  grid-column: 1 / -1; margin: 0 0 clamp(20px, 3.5vh, 44px);
  font-size: clamp(26px, 4.27vw, 83px); line-height: 1.08;
  font-weight: 700; letter-spacing: -0.03em; max-width: 20ch;
}
.statement .hero__line { padding-bottom: 0.06em; }

/* In jedem anderen Block steht links die Beschriftung — „Schwerpunkte",
   „Typische Anlässe" — und der Einzug des Körpers hat ein Gegenüber. In diesem
   Abschnitt spannt die Aussage über beide Spalten, die Beschriftungsspalte
   bleibt also leer, und der eingerückte Text steht neben nichts. Das las sich
   als Versehen statt als Absicht.

   Deshalb rückt hier auch der Körper an die Kante der Aussage. Eine Kante
   statt zweier. */
.block__inner:has(.statement) > .block__body { grid-column: 1 / -1; }
.block--dark .statement { color: var(--ground); }

/* The statement sits far down the page, so its lines must not run their rise
   on load like the hero's do — they build when the block is actually reached. */

/* ── Typische Anlässe ───────────────────────────────────────────────────────
   A register, not a bullet list. Dots in front of short phrases are the one
   thing on these pages that reads as a template, so they are gone: each
   occasion holds its own line on a hairline, set large enough to be read as
   type rather than scanned as a checklist, two abreast where there is room.
   The rules draw in one after another, left to right. */
.occasions {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: 0 clamp(28px, 4vw, 80px);
}
.occasions li {
  position: relative;
  padding: clamp(14px, 2vh, 22px) 0 clamp(16px, 2.2vh, 26px);
  font-size: clamp(19px, 1.89vw, 37px); line-height: 1.28;
  font-weight: 600; letter-spacing: -0.022em; text-wrap: pretty;
}
.occasions li::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px;
  background: var(--ink-14); transform-origin: left;
}
[data-motion="kinetic"] .occasions li::before {
  transform: scaleX(0);
  transition: transform .8s var(--ease-out);
  transition-delay: calc(var(--i) * 70ms);
}
[data-motion="kinetic"] .occasions.is-revealed li::before { transform: scaleX(1); }
[data-motion="kinetic"] .occasions li {
  opacity: 0; transform: translateY(12px);
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
  transition-delay: calc(var(--i) * 70ms + 110ms);
}
[data-motion="kinetic"] .occasions.is-revealed li { opacity: 1; transform: none; }

/* ══════════════════════════════════════════════════════════════════════════
   6. Breaking the single left axis
      Every block used to hang on the same vertical line: label column left,
      body column right, all the way down. Consistent — and monotonous, with
      nothing for the eye to catch on. The blocks now step against each other.
   ══════════════════════════════════════════════════════════════════════════ */

/* The lede opens at the gutter across the full measure; the paragraphs that
   follow indent into the body column. A step, not a straight edge. */
.lede {
  grid-column: 1 / -1; margin: 0;
  font-size: clamp(23px, 2.81vw, 54px); line-height: 1.25;
  font-weight: 600; letter-spacing: -0.028em; max-width: 30ch; text-wrap: pretty;
}
/* Where the opening paragraph is too long to be a lede, the body takes the
   gutter at full measure rather than indenting — the block still steps against
   the ones around it, just from the other side. */
.block__body--wide { grid-column: 1 / -1; }
.prose--wide { max-width: 58ch; font-size: clamp(18px, 1.64vw, 32px); }
.block__mark { grid-column: 1 / -1; margin-bottom: clamp(6px, 1.4vh, 16px); }

/* A block headline, not a label: poster scale, full measure, built line by
   line out of its trim like the page headline, with the deciding word coral. */
.block__headline {
  grid-column: 1 / -1; margin: 0 0 clamp(16px, 2.6vh, 36px);
  font-size: clamp(31px, 5.36vw, 107px); line-height: 0.98;
  font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase;
}
.block__headline .hero__line { padding-bottom: 0.05em; }

/* „Woran Sie das Ergebnis erkennen" carries the page's promise, so it stands
   on the dark ground the roles share on the Startseite. */
.block--dark .signals li { color: var(--ground); }
.block--dark .signals li::before,
.block--dark .signals li:last-child::after { background: var(--row-rule, var(--ground-25)); }

/* The statement block already steps; keep its paragraph in the body column. */
.block--dark .statement { grid-column: 1 / -1; }


@media (max-width: 900px) {
  .lede, .block__headline, .block__mark { grid-column: 1; }
}

/* ── Ein Wort, das aus seinem eigenen Beschnitt steigt ─────────────────────
   Die Zeilen der Website steigen aus einem Beschnitt auf — .hero__line macht
   das für eine ganze Zeile. Für einen Satz, der sich Wort für Wort aufbaut,
   braucht dieselbe Bewegung eine Fassung auf Wortbreite: inline-block statt
   Block, damit die Wörter nebeneinander stehen und normal umbrechen.

   Zwei Feinheiten, ohne die es nicht funktioniert. Erstens verschiebt
   overflow:hidden an einem inline-block die Ausrichtung von der Grundlinie
   auf die Unterkante — ohne vertical-align:bottom stünden die Wörter einer
   Zeile auf verschiedenen Höhen. Zweitens hebt der negative Rand den
   Innenabstand wieder auf, den der Beschnitt für Umlautpunkte und
   Unterlängen braucht: sonst stünde zwischen zwei Wörtern mehr Luft als
   zwischen zwei Wörtern stehen darf. */
.rise-word { display: inline-block; vertical-align: bottom; }
[data-motion="kinetic"] .rise-word {
  overflow: hidden;
  padding: 0.16em 0.03em 0.12em;
  margin: -0.16em -0.03em -0.12em;
}
.rise-word .hero__line-inner { display: inline-block; }

/* Die beiden Satzhälften sind eigene Blöcke, damit jede ihren eigenen Versatz
   und ihr eigenes Tempo bekommt — und damit die zweite auf einer neuen Zeile
   beginnt. Als inline gesetzt lief „KI liefert sie" hinter „Ratschlägen." auf
   dieselbe Zeile: der Satz, der die Antwort gibt, klebte an dem, den er
   beantwortet, und die beiden Tempi liefen im selben Zeilenbild durcheinander. */
.answer__phrase { display: block; }
/* Hieß einmal `.dim`, und der Name log: die Klasse hat nie gedämpft, sondern
   immer den Akzent gesetzt.

   Seit dem 13. September steht der zweite Satz eine Stufe kleiner als der
   erste: 4,27vw statt 6,34vw. Der Wert ist nicht erfunden, sondern die
   nächste Sprosse der Leiter, auf der diese Seite ohnehin steht — dieselbe,
   auf der auch `.statement` sitzt.

   Die Größe trägt damit die Dramaturgie: der erste Satz stellt fest, der
   zweite setzt nach. Die Feststellung bleibt die größte Schrift. */
.answer__phrase--akzent {
  color: var(--accent);
  font-size: clamp(26px, 4.27vw, 83px);
}

/* Headlines below the fold are scrubbed off the scroll position by site.js, so
   they carry no animation and no transition of their own — only a resting state
   for the moment before the first frame runs. See trackRise(). */
[data-motion="kinetic"] .block__headline .hero__line-inner,
[data-motion="kinetic"] .answer__headline .hero__line-inner,
[data-motion="kinetic"] .statement .hero__line-inner {
  animation: none;
  transform: translateY(130%);
  will-change: transform;
}

/* ── 8 · Über mich, Kontakt und die beiden Rechtstexte ───────────────────── */

/* ── Der Auftakt auf „Über mich" ─────────────────────────────────────────
   Überschrift, Foto und Fließtext liefen untereinander weg und lasen sich wie
   eine Buchseite. Sie stehen jetzt in einem Feld: das Foto läuft oben und
   rechts aus dem Bild, die Zeile steht dagegen, und eine Koralle-Linie läuft
   unter beiden durch — sie näht die Hälften zusammen, statt sie nebeneinander
   abzustellen. Das Foto ist die bewusste Ausnahme einer Gestaltung, die sonst
   ganz auf Typografie läuft. */
.opening {
  position: relative;
  padding: clamp(70px, 9vh, 110px) var(--gutter) clamp(30px, 4.6vh, 56px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 4vh, 44px);
}

.opening__figure {
  position: relative; margin: 0; overflow: hidden;
  aspect-ratio: 4 / 5;
  perspective: 1200px;
  /* Die linke Kante ist der Grund, warum ein Foto neben Schrift wie eingeklebt
     aussieht: eine harte Senkrechte, die nichts mit der Seite zu tun hat. Sie
     wird hier weich, das Bild geht in den Grund über statt in ihm zu liegen. */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 16%);
          mask-image: linear-gradient(to right, transparent 0%, #000 16%);
}
.opening__figure img {
  position: absolute; inset: -7% 0;
  width: 100%; height: 114%;
  object-fit: cover;
  /* Das Gesicht sitzt im oberen Drittel — der Beschnitt hält es im Bild. */
  object-position: 50% 24%;
  will-change: transform;
  transform-origin: 62% 34%;
  /* Zurückgenommen, damit das Foto nicht als Fremdkörper in der Palette sitzt.
     Kein Duoton — der grüne Hintergrund ist der Grund für dieses Bild. */
  filter: saturate(0.82) contrast(1.04);
  transition: filter .7s var(--ease-out);
}
/* Ein Hauch Koralle über den Rändern bindet das Bild an die Palette, ohne es
   einzufärben: soft-light lässt Haut und Grün stehen und zieht nur die Tiefen
   in Richtung des Akzents. */
.opening__figure::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(120% 90% at 78% 26%, transparent 38%, rgba(255, 77, 79, 0.30) 100%),
    linear-gradient(to top, rgba(43, 43, 39, 0.34), transparent 46%);
  mix-blend-mode: soft-light;
  opacity: 1; transition: opacity .7s var(--ease-out);
}
/* Näher herangehen heißt: die Farbe kommt zurück. Das ist die Bewegung, die
   dieses Bild verdient — nicht ein Zoom um seiner selbst willen. */
.opening__figure:hover img { filter: saturate(1) contrast(1); }
.opening__figure:hover::after { opacity: 0.35; }

/* Bezugsrahmen für die Zeilengröße — siehe .opening__title. */
.opening__type { container-type: inline-size; }

.opening__overline {
  margin: 0 0 clamp(12px, 2vh, 22px);
  font-size: clamp(13px, 1.22vw, 22px); font-weight: 700; letter-spacing: 0.34em;
  text-transform: uppercase; color: var(--accent-ink);
}
.opening__title {
  margin: 0;
  /* Siehe .hero__title. Der Container ist hier die Textspalte neben dem Foto,
     nicht die Seite — die Zeile misst sich an dem, worin sie steht. */
  font-size: clamp(42px, min(9.02vw, 30vh), 200px);
  font-size: clamp(min(40px, calc(98cqw / var(--h1-word, 5))),
    min(calc(98cqw / var(--h1-em, 5.5)),
        calc(58svh / (var(--h1-lines, 2) * 0.88))),
    200px);
  line-height: 0.88; font-weight: 800; letter-spacing: -0.035em;
  text-transform: uppercase;
}
.opening__subline {
  margin: clamp(16px, 2.6vh, 30px) 0 0;
  max-width: 30ch;
  font-size: clamp(19px, 2.07vw, 40px); line-height: 1.35;
  font-weight: 600; letter-spacing: -0.02em; color: var(--ink-72);
  text-wrap: balance;
}
.opening__seam {
  height: 2px; background: var(--accent); transform-origin: left;
  margin-top: clamp(20px, 3.4vh, 44px);
}

/* Der Auftakt läuft ein: Überzeile, Zeile, Subline, dann zieht die Naht durch
   und das Foto wischt von oben herein. Alles auf derselben Zeitachse wie die
   Heros der übrigen Seiten — nur dass hier ein Bild mitspielt. */
[data-motion="kinetic"] .opening__overline { animation: tl-fade .7s ease .06s both; }
[data-motion="kinetic"] .opening__subline  { animation: tl-fade .8s ease .62s both; }
[data-motion="kinetic"] .opening__seam {
  transform: scaleX(0);
  animation: tl-draw .9s var(--ease-out) .78s both;
}
[data-motion="kinetic"] .opening__figure {
  clip-path: inset(0 0 100% 0);
  animation: tl-uncover 1.1s var(--ease-out) .24s both;
}
@keyframes tl-uncover { to { clip-path: inset(0 0 0 0) } }
.opening__text .prose {
  max-width: 66ch;
  font-size: clamp(18px, 1.61vw, 32px); line-height: 1.58;
}

@media (min-width: 1000px) {
  /* Zwei Spalten, aber keine zwei Kästen: das Bild greift über die rechte
     Seitenkante hinaus bis an den Rand des Fensters und beginnt oberhalb der
     Zeile, sodass Schrift und Foto sich überlappen statt sich abzuwechseln. */
  .opening {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.86fr);
    grid-template-areas:
      "type figure"
      "text figure-tail";
    column-gap: clamp(32px, 4vw, 72px);
    row-gap: clamp(18px, 2.6vh, 34px);
    padding-top: clamp(78px, 10.5vh, 136px);
    align-items: end;
  }
  /* Die Naht kreuzte das Foto genau am Hals — die einzige Höhe, auf der eine
     Linie über einem Porträt unangenehm wird. Luft unter der Subline schiebt
     sie hinunter aufs Sakko und gibt der Zeile zugleich Raum. */
  .opening__type { grid-area: type; padding-bottom: clamp(20px, 4.6vh, 62px); }
  /* Die Linie sitzt jetzt im Textblock und ist damit genau so breit wie er.
     Quer über das Porträt gezogen war sie als Naht gedacht, gelesen wird sie
     aber als Strich durchs Gesicht. */
  .opening__text { grid-area: text; padding-top: clamp(6px, 1.5vh, 18px); }

  .opening__figure {
    grid-area: figure / figure / figure-tail / figure-tail;
    align-self: stretch;
    /* bis an die Fensterkante, und oben unter dem Header hervor */
    margin: calc(var(--header-bar) - clamp(78px, 10.5vh, 136px)) calc(-1 * var(--gutter)) 0 0;
  }
  /* Auf voller Breite gibt die Rasterzelle die Höhe vor, nicht das Seitenmaß. */
  .opening__figure { aspect-ratio: auto; }
  .opening__title { max-width: 12ch; }
}

/* Gestapelt bleibt das Foto ein Anker, kein Aufmacher: es steht nach der Zeile
   und behält sein Hochformat, statt die ganze Spalte zu füllen. */
@media (max-width: 999px) {
  .opening { grid-template-areas: "type" "figure" "seam" "text"; }
  .opening__type { grid-area: type; }
  .opening__figure { grid-area: figure; max-width: 420px; }
  /* Die Linie sitzt jetzt im Textblock und ist damit genau so breit wie er.
     Quer über das Porträt gezogen war sie als Naht gedacht, gelesen wird sie
     aber als Strich durchs Gesicht. */
  .opening__text { grid-area: text; }
}

/* The legal pages are running text with headings in it, and they are the only
   pages that need them — every other heading on the site is a component. */
.prose h2 {
  margin: clamp(14px, 2.5vh, 30px) 0 0;
  font-size: clamp(19px, 1.83vw, 34px); line-height: 1.2;
  font-weight: 800; letter-spacing: -0.02em;
}
.prose h2:first-child { margin-top: 0; }


/* ── 9 · Qualifikationen als Bahn ───────────────────────────────────────────
   Vorher ein Ring um den Satz. Der zeigte, dass alles zur Mitte gehört, aber
   nicht, dass es über ein Berufsleben entstanden ist und sich summiert. Jetzt
   läuft eine Linie von der ersten Station bis zum Satz und wächst beim Scrollen
   mit: was sie erreicht hat, bleibt hell. Nichts schaltet sich wieder ab — das
   ist das Kumulative daran. Eine Bahn von oben nach unten braucht auch keinen
   eigenen Rückfall für schmale Fenster; sie ist dort dieselbe Figur, nur
   schmaler. */
.journey { position: relative; --rail: clamp(26px, 3.2vw, 48px); padding-left: var(--rail); }

.journey__line {
  position: absolute; left: 0; top: 0.7em; bottom: 0.6em; width: 2px;
  background: var(--ink-14);
}
.journey__line::after {
  content: ''; position: absolute; inset: 0;
  background: var(--accent);
  transform-origin: top; transform: scaleY(1);
}

.journey__stops { margin: 0; padding: 0; list-style: none; }
.journey__stop {
  position: relative;
  padding: clamp(14px, 2.2vh, 26px) 0;
  display: grid; gap: 3px;
}
.journey__stop::before {
  content: ''; position: absolute;
  left: calc(-1 * var(--rail) - 6px); top: 1.1em;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--accent);
  box-sizing: border-box;
  transition: background-color .4s ease, border-color .4s ease;
}
.journey__what {
  font-size: calc(clamp(15px, 1.32vw, 23px) * var(--s, 1));
  line-height: 1.14; font-weight: 700; letter-spacing: -0.022em; text-wrap: pretty;
}
.journey__where {
  font-size: clamp(13px, 1.13vw, 22px); line-height: 1.35;
  font-weight: 600; letter-spacing: 0.04em; color: var(--ink-72); text-wrap: pretty;
}

/* Der Satz steht am Fuß der Bahn: nicht eine weitere Station, sondern das,
   worauf sie hinausläuft. */
.journey__end {
  position: relative;
  margin: clamp(20px, 3.4vh, 40px) 0 0;
  font-size: clamp(26px, 4.14vw, 83px); line-height: 1.02;
  font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase;
  text-wrap: balance;
}
.journey__end::before {
  content: ''; position: absolute;
  left: calc(-1 * var(--rail) - 9px); top: 0.24em;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent); border: 3px solid var(--accent);
  box-sizing: border-box;
  transition: background-color .4s ease, border-color .4s ease;
}

/* Unter Kinetik wächst die Linie mit dem Scrollen, und eine Station leuchtet
   erst auf, wenn die Linie sie erreicht hat. Ohne Kinetik steht alles fertig. */
[data-motion="kinetic"] .journey__line::after { transform: scaleY(var(--grown, 0)); }
[data-motion="kinetic"] .journey__stop::before,
[data-motion="kinetic"] .journey__end::before {
  background: var(--ground); border-color: var(--ink-14);
}
[data-motion="kinetic"] .journey__stop.is-reached::before,
[data-motion="kinetic"] .journey__end.is-reached::before {
  background: var(--accent); border-color: var(--accent);
}

/* ── 10 · Der Schlussblock ───────────────────────────────────────────────────
   Die Pointe der Seite. Der Rhythmus kommt aus der Scrollposition, nicht aus
   einer Kette von Verzögerungen: die Bühne ist hoch, die Tafel darin bleibt
   stehen, jeder Satz hat seinen eigenen Abschnitt des Weges. Die Pause vor der
   Pointe ist deshalb wirklich eine Pause — man muss sie scrollen. Ein Timer
   liefe auch dann weiter, wenn niemand liest.

   Dunkler Grund, weil danach nur noch Engagement und der Koralle-Abschluss
   kommen und die Seite so ihren Hell/Dunkel/Koralle-Takt behält. */
.closing { position: relative; background: var(--ink); color: var(--ground); }

/* ── Die Frage nach dem Finale ────────────────────────────────────────────
   Derselbe Grund wie .closing darüber, damit kein Strich dazwischen steht und
   das dunkle Feld einfach weiterläuft. Oben viel Luft, unten weniger: der Satz
   soll auf den Abschluss folgen wie ein Atemzug, nicht wie ein neuer Anfang.

   Die Schaltfläche steht hier als einzige der Website auf Tinte. Ihre Koralle
   trägt dort gut, aber die Tinte, in die sie sonst läuft, wäre unsichtbar —
   deshalb läuft sie hier in den Grundton und dreht die Schrift auf Tinte. Der
   Wechsel ist derselbe wie überall, nur andersherum. */
.closing-cta {
  background: var(--ink); color: var(--ground);
  padding: clamp(20px, 4vh, 44px) var(--gutter) clamp(64px, 11vh, 128px);
}
.closing-cta__frage {
  margin: 0 0 clamp(20px, 3vh, 34px);
  max-width: 34ch;
  font-size: clamp(19px, 1.83vw, 34px); line-height: 1.25;
  font-weight: 600; letter-spacing: -0.02em; text-wrap: pretty;
  color: var(--ground-82);
}
.closing-cta .button-row { margin: 0; }
/* Die Umkehr der gefüllten Pille auf Tinte steht weiter oben bei den
   Schaltflächen, zusammen mit derselben Regel für .block--dark. */

.closing__panel {
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(72px, 13vh, 150px) var(--gutter);
  gap: clamp(12px, 1.8vh, 22px);
}
.closing__line {
  margin: 0; max-width: 26ch;
  font-size: clamp(21px, 2.68vw, 54px); line-height: 1.24;
  font-weight: 600; letter-spacing: -0.024em; text-wrap: pretty;
  color: var(--ground-82);
}
/* Mehr leerer Raum als irgendwo sonst auf der Seite. Das ist der Bruch. */
.closing__rest { height: clamp(44px, 11vh, 132px); }
.closing__punch {
  margin: 0;
  font-size: clamp(31px, 5.36vw, 110px); line-height: 1.04;
  font-weight: 800; letter-spacing: -0.035em; text-wrap: pretty;
  color: var(--ground);
}
/* Zwei Zeilen, zwei ganze Sätze — den Umbruch setzt das <br>, nicht das Maß.
   Mit einer Breitenbegrenzung fiel „bleibt." allein in eine dritte Zeile und
   sah nach Zufall aus statt nach Absicht. */
/* Der schmale Koralle-Strich der Wortmarke, hier als Unterschrift. Er schließt
   den Kreis zur Startseite, die der Besucher zuerst gesehen hat. */
/* ── Die Koralle läuft durch und kommt zurück ─────────────────────────────
   Drei Wörter. Die Farbe wandert von „Mensch" über „Berater" zu
   „Wegbegleiter" und springt dann auf „Mensch" zurück, wo sie bleibt. Der Weg
   geht hinaus und kommt heim.

   Eine gemeinsame Zeitachse statt drei versetzter Läufe: die Rückkehr muss
   auf das Ende der Reihe warten, und das lässt sich mit Verzögerungen nicht
   sagen, nur mit Prozentwerten auf derselben Dauer.

   Der Ruhezustand steht im Stylesheet, nicht in der Animation: ohne Kinetik,
   also bei Bewegungsreduzierung und ohne JavaScript, steht „Mensch" sofort in
   Koralle und der Rest in Sand — genau das, was am Ende ohnehin herauskommt.
   Es fehlt dann nur der Weg dorthin. */
.punch__wort { display: inline-block; }
.punch__wort--rast { color: var(--accent); }

@keyframes tl-punch-a {          /* Mensch: leuchtet zuerst und zuletzt */
  0%, 10%   { color: var(--accent); }
  24%, 62%  { color: var(--ground); }
  70%, 100% { color: var(--accent); }
}
@keyframes tl-punch-b {          /* Berater */
  0%, 18%   { color: var(--ground); }
  30%, 40%  { color: var(--accent); }
  52%, 100% { color: var(--ground); }
}
@keyframes tl-punch-c {          /* Wegbegleiter */
  0%, 42%   { color: var(--ground); }
  54%, 62%  { color: var(--accent); }
  74%, 100% { color: var(--ground); }
}

/* Einmalig, nicht in Schleife: die Klasse setzt das Skript ein einziges Mal,
   wenn die Zeile von unten ins Bild kommt, und nimmt sie nie wieder weg.
   `forwards` lässt jedes Wort danach in seinem Endzustand stehen. */
[data-motion="kinetic"] .closing__punch .punch__wort { color: var(--ground); }
[data-motion="kinetic"] .closing__punch.is-durchlauf .punch__wort {
  animation: tl-punch-b 1.9s ease-in-out forwards;
}
[data-motion="kinetic"] .closing__punch.is-durchlauf .punch__wort--rast {
  animation-name: tl-punch-a;
}
[data-motion="kinetic"] .closing__punch.is-durchlauf .punch__wort:last-child {
  animation-name: tl-punch-c;
}

.closing__mark {
  width: clamp(96px, 11vw, 190px); height: 4px;
  background: var(--accent); transform-origin: left;
  margin-top: clamp(20px, 3.4vh, 42px);
}

/* Kinetik: 300vh Weg für eine stehende Tafel. Ohne sie steht der Block ruhig
   da und sagt dasselbe — die Sätze sind dann einfach alle sichtbar. */
[data-motion="kinetic"] .closing { height: 300vh; }
[data-motion="kinetic"] .closing__panel {
  position: sticky; top: 0; height: 100svh;
  padding-block: 0;
  overflow: hidden;
}
[data-motion="kinetic"] .closing [data-step] { opacity: 0; }

/* ── 11 · Der Verweis auf die anderen Rollen als Treppe ──────────────────────
   Der Satz sagt: derselbe Blick, nur ein anderer Platz im Raum. Als
   durchlaufender Absatz war das eine Behauptung; als Treppe ist es zu sehen.
   Jede Stufe rückt ein Stück ein und wird ein Stück größer — größer heißt auf
   dieser Website näher, dieselbe Grammatik wie auf der Rollenbühne der
   Startseite. Die Auflösung steht wieder bündig links und am größten. */
.approach {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: clamp(22px, 3.2vh, 40px);
}
/* Die Stufen standen als Treppe da: jede Zeile ein Stück weiter eingerückt
   und ein Stück größer. Der Gedanke war richtig — es geht um Näherkommen —,
   aber drei ungleiche linke Kanten lesen sich als schiefer Satz, nicht als
   Bewegung. Die Näherung trägt jetzt ein Strich, der von Zeile zu Zeile
   länger wird: dieselbe Aussage, aber als Figur statt als Unfall. Die Zeilen
   selbst stehen bündig und in einer Größe. */
.approach__step {
  /* Das Zeilenmaß gehört auf die Zeile, nicht auf die Liste: ch und em rechnen
     gegen die Schrift des Elements, auf dem sie stehen. Auf .approach war das
     die geerbte Grundschrift, und die Zeilen wurden dadurch zufällig kurz. */
  max-width: 21em;
  font-size: clamp(19px, 1.92vw, 36px);
  line-height: 1.4; letter-spacing: -0.015em;
  color: var(--ground-82); text-wrap: pretty;
}
.approach__step::before {
  content: ''; display: block; height: 3px; background: var(--accent);
  width: calc(28px + var(--i) * clamp(26px, 3.4vw, 64px));
  margin-bottom: clamp(10px, 1.4vh, 18px);
  transform-origin: left;
}
.approach__step a { color: var(--ground); border-bottom: 2px solid var(--accent); }
.approach__step a:hover { color: var(--accent); }

/* Auf „Über mich" trägt jede Stufe zwei Teile: den Merksatz und seinen Grund.
   Der Merksatz behält die Größe der Stufe, der Grund fällt auf Fließtext
   zurück — sonst stünden zwei gleich laute Stimmen übereinander und die
   Treppe verlöre ihre Kontur.

   Das Zeilenmaß sitzt auf den beiden Teilen und nicht auf der Stufe: em rechnet
   gegen die Schrift des Elements, auf dem es steht, und das ist hier zweimal
   eine andere. Die 21em der Stufe würden am Grund 21 × 16px messen und ihn auf
   ein Drittel der gewollten Länge schnüren. Deshalb hebt .approach--paarig das
   Maß von der Stufe auf und gibt jedem Teil sein eigenes. */
.approach--paarig .approach__step { max-width: none; }
.approach__satz {
  display: block; max-width: 21em;
  color: var(--ground); text-wrap: pretty;
}
/* Der Grund steht eine Spur größer als der Fließtext auf Papier — 1,66vw statt
   1,48vw. Das ist keine Willkür: auf Tinte war der Text dieser Seite schon
   einmal zu klein, und dunkel.mjs hält die Lehre als Regel fest, dass im
   dunklen Abschnitt nichts unter ein Drittel der Aussage fallen darf. Mit
   1,48vw stand der Grund bei 1280px auf 19px gegen 19,25px Mindestmaß und
   fiel durch. Die Regel zu lockern wäre der falsche Weg gewesen — sie ist
   älter als dieser Abschnitt. */
.approach__grund {
  display: block; margin-top: clamp(10px, 1.4vh, 18px); max-width: 54ch;
  font-size: clamp(17px, 1.66vw, 30px);
  line-height: 1.6; letter-spacing: 0; font-weight: 400;
  /* --ground-70, nicht -72: das Token mit 72 gibt es nicht. Es stand hier einen
     Tag lang, und ein Token, das es nicht gibt, ist keine Fehlermeldung — die
     Deklaration wird ungültig, und `color` erbt. Der Grund stand dadurch auf
     den 0,82 der Stufe statt auf den gewollten 0,72, also lauter als gedacht.
     Kein sichtbarer Schaden, aber genau so entstehen welche. */
  color: var(--ground-70); text-wrap: pretty;
}
.approach__resolve {
  margin: clamp(22px, 3.6vh, 46px) 0 0; max-width: 24ch;
  font-size: clamp(25px, 3.42vw, 66px); line-height: 1.08;
  font-weight: 800; letter-spacing: -0.032em;
  color: var(--ground); text-wrap: balance;
}

/* Drei Worte, drei Punkte — die Setzung ist der Inhalt, also bekommt diese eine
   Zeile einen weiteren Takt als die übrigen Heros: die Pause zwischen den
   Worten ist hier das, was die Zeile sagt. */
[data-motion="kinetic"] .page-hero__title--beat .hero__line:nth-child(1) .hero__line-inner { animation-delay: .20s; }
[data-motion="kinetic"] .page-hero__title--beat .hero__line:nth-child(2) .hero__line-inner { animation-delay: .58s; }
[data-motion="kinetic"] .page-hero__title--beat .hero__line:nth-child(3) .hero__line-inner { animation-delay: .96s; }

/* Die beiden Durchführungsformen sind die Aussage des Satzes. Sie stehen darum
   in Koralle und der Satz eine Stufe über Fließtextgröße — sonst ist die
   Zeile eine Fußnote, die neben ihrer eigenen Überschrift verschwindet. */
.formats__lead {
  margin: 0 0 clamp(24px, 4vh, 40px); max-width: 34ch;
  font-size: clamp(21px, 2.31vw, 45px); line-height: 1.3;
  font-weight: 600; letter-spacing: -0.02em; text-wrap: pretty;
}

/* ── Zwei Wege nebeneinander: buchen oder zurückrufen lassen ───────────────
   Ein Raster und keine Flex-Zeile, und der Grund ist die dritte Spalte: das
   Formular klappt unter der Kontur-Pille auf und braucht dort die ganze
   verbleibende Breite. In einer Flex-Zeile wäre die Spalte nur so breit wie
   ihre Schaltfläche, das Formular also 250px schmal — oder es müsste beim
   Aufklappen in eine eigene Zeile umbrechen und die Pille dabei nach unten
   springen lassen. Mit `1fr` in der dritten Spalte tut es beides nicht.

   `align-items: start`, damit die beiden Pillen oben bündig bleiben, wenn das
   Formular die Zeile hoch werden lässt. */
/* ── Die drei Wege auf der Kontaktseite ──────────────────────────────────
   Drei Angebote untereinander, jedes mit einer Zeile Erklärung. Nicht
   nebeneinander: drei Pillen in einer Reihe lesen sich als Gruppe, aus der
   man wählen muss, und die mittlere klappt ein Formular auf, das in einer
   Reihe entweder die Nachbarn wegschiebt oder auf Pillenbreite zusammenfällt.

   Jeder Eintrag ist blockbreit, die Pille darin bleibt inline-flex. Deshalb
   hat das Formular beim Aufklappen den ganzen Satzspiegel und die Pille
   trotzdem ihre eigene Breite. */
.wege { container-type: inline-size; }
/* Der Abschnitt führt keine Beschriftungsspalte — es gibt keine Überschrift,
   die dort stünde. Ohne das säße der ganze Inhalt in Spalte zwei und wäre
   neben nichts eingerückt; dieselbe Überlegung wie bei .statement. Eine Kante
   statt zweier, deshalb wird das Raster hier aufgehoben und nur die Breite und
   Mittigkeit von .block__inner behalten. */
.wege__inner { display: block; }
/* Untereinander auf schmalen Schirmen, ab 1024px nebeneinander in drei
   gleichen Spalten. Der Einwand gegen das Nebeneinander war das Formular: in
   einer Flex-Zeile fiele es auf Pillenbreite zusammen oder schöbe seine
   Nachbarn weg. Im Raster tut es beides nicht — es bekommt seine Spalte, und
   `align-items: start` hält die beiden anderen oben stehen, statt sie auf die
   Höhe des aufgeklappten Kastens zu ziehen.

   1024px und nicht 900px als Grenze: darunter wäre eine Spalte schmaler als
   260px, und ein Formular in 260px ist kein Formular mehr, sondern eine
   Rinne. */
.wege__liste {
  margin: 0; padding: 0; list-style: none;
  display: grid; gap: clamp(22px, 3.4vh, 42px) clamp(24px, 3vw, 52px);
}
@container (min-width: 1024px) {
  .wege__liste { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
}
.wege__weg { min-width: 0; }
/* Der Satz, der die drei Wege abschließt. Die Haarlinie darüber trennt ihn von
   ihnen, ohne einen neuen Abschnitt zu behaupten — er gehört dazu, er kommt
   nur danach. */
.wege__schluss {
  margin-top: clamp(34px, 5vh, 60px);
  padding-top: clamp(28px, 4vh, 48px);
  border-top: 2px solid var(--ink-14);
}
.wege__schluss .prose__lead { max-width: 36ch; }
/* Die Erklärung gehört unter ihre Pille und nicht daneben: nebeneinander
   müsste sie sich zwischen Oberkante und Mitte einer 60px hohen Pille
   entscheiden, und beides sähe falsch aus. Dieselbe Überlegung wie bei
   Telefon und E-Mail im Abschluss. */
.wege__dazu {
  margin: clamp(10px, 1.4vh, 16px) 0 0; max-width: 58ch;
  font-size: clamp(16px, 1.36vw, 26px); line-height: 1.55;
  color: var(--ink-72); text-wrap: pretty;
}
.wege__dazu a { color: inherit; border-bottom: 2px solid var(--accent); }
.wege__dazu a:hover { color: var(--accent-ink); }
/* Klappt das Formular auf, steht die Erklärung darunter plötzlich weit weg von
   ihrer Pille und liest sich als Nachsatz zum Formular. Sie tritt deshalb ab,
   solange das Formular offen ist — sie hat dann ohnehin nichts mehr zu sagen. */
.wege__weg:has(.rueckruf[open]) .wege__dazu { display: none; }

.cta-paar {
  margin: 8px 0 0;
  display: grid; grid-template-columns: auto auto minmax(0, 1fr);
  align-items: start; gap: clamp(12px, 1.5vw, 22px);
}
.formats__lead + .cta-paar { margin-top: 0; }

/* Dasselbe Maß wie in einer Schaltfläche — gleiche Schriftgröße, gleicher
   Innenabstand oben und unten. Dadurch sitzt „oder" ohne einen einzigen
   ausgerechneten Wert auf der Höhe der beiden Beschriftungen daneben.
   Gewicht und Ton nehmen sich zurück: es ist die Fuge zwischen zwei
   Angeboten, nicht ein drittes. */
.cta-paar__oder { padding: 15px 0; font-size: 19px; color: var(--ink-72); }

.rueckruf { min-width: 0; }
/* Die Pille ist hier ein <summary>. Ohne diese beiden Zeilen setzt der
   Browser sein eigenes Dreieck davor — in Safari als ::-webkit-details-marker,
   anderswo als list-item-Markierung. */
.rueckruf > summary { list-style: none; cursor: pointer; }
.rueckruf > summary::-webkit-details-marker { display: none; }

/* Das Zeichen wechselt mit dem Zustand, damit die Pille sagt, was ein Klick
   tut — aufgeklappt weist es nach oben, wie im Frage-Akkordeon. */
.rueckruf > summary .btn__text::after {
  content: ''; width: 9px; height: 9px; margin-left: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .25s var(--ease-out);
}
.rueckruf[open] > summary .btn__text::after { transform: translateY(2px) rotate(-135deg); }

.rueckruf__feld {
  margin-top: clamp(18px, 2.6vh, 30px); max-width: 34em;
  padding: clamp(20px, 2.6vh, 30px) clamp(20px, 2.4vw, 32px);
  border: 2px solid var(--ink-14);
  border-radius: 18px;
}
.rueckruf__zeile {
  margin: 0 0 clamp(16px, 2.2vh, 24px);
  display: grid; gap: 6px;
}
/* Der abgedunkelte Akzent, nicht der Logo-Ton: eine Beschriftung bei 14px ist
   kleine Schrift, und dort trägt --accent nur 2,53:1. */
.rueckruf__zeile label {
  font-size: 14px; font-weight: 700; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent-ink);
}
/* „optional" gehört zur Beschriftung, nicht daneben: ohne Sperrung, ohne
   Versalien und im gedämpften Ton, damit es die Beschriftung ergänzt statt mit
   ihr um dieselbe Aufmerksamkeit zu ringen. */
.rueckruf__frei {
  margin-left: 6px; font-weight: 400; letter-spacing: 0; text-transform: none;
  color: var(--ink-72);
}
.rueckruf__zeile input,
.rueckruf__zeile select {
  width: 100%; box-sizing: border-box;
  padding: 10px 2px; border: 0; border-bottom: 2px solid var(--ink-14);
  background: transparent; color: var(--ink);
  font-family: inherit; font-size: 19px; line-height: 1.55;
  border-radius: 0;                  /* iOS rundet Felder sonst von selbst */
  appearance: none; -webkit-appearance: none;
}
/* `appearance: none` nimmt dem Auswahlfeld nicht nur die Systemoptik, sondern
   auch sein Dreieck — ohne Ersatz sähe es aus wie ein Textfeld, in das man
   tippen soll. Das Zeichen kommt deshalb als Hintergrundbild zurück, in
   derselben Form wie im Frage-Akkordeon. */
.rueckruf__zeile select {
  padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%232B2B27' stroke-width='2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 2px center;
  background-size: 12px 8px;
}
.rueckruf__zeile input:focus,
.rueckruf__zeile select:focus {
  outline: none; border-bottom-color: var(--accent);
}
.rueckruf__zeile input:focus-visible,
.rueckruf__zeile select:focus-visible {
  outline: 2px solid var(--ink); outline-offset: 4px;
}
.rueckruf__hinweis { margin: 0 0 clamp(18px, 2.4vh, 26px); font-size: 15px; color: var(--ink-72); }
.rueckruf__fuss { margin: clamp(16px, 2.2vh, 22px) 0 0; font-size: 15px; color: var(--ink-72); }
.rueckruf__hinweis a,
.rueckruf__fuss a { color: inherit; border-bottom: 2px solid var(--accent); }
.rueckruf__hinweis a:hover,
.rueckruf__fuss a:hover { color: var(--accent-ink); }

/* Die gefüllte Pille läuft auf Papier beim Überfahren in die Tinte. Auf Tinte
   verschwände sie dabei im Hintergrund — sie läuft dort in den Grundton,
   derselbe Wechsel wie überall, nur andersherum.

   Die Regel gilt nur für .closing-cta auf „Über mich", weil das die einzige
   gefüllte Pille auf Tinte ist. Sie stand einen Tag lang auch für .block--dark,
   solange die Kontaktseite dunkel war. */
.closing-cta .btn--accent::before { background: var(--ground); }
.closing-cta .btn--accent:hover,
.closing-cta .btn--accent:focus-visible { background: var(--ground); color: var(--ink); }

/* Die Falle für Formularroboter. Sie füllen jedes Feld aus, das sie finden;
   ein Mensch sieht dieses hier nie. `display: none` wäre der falsche Weg —
   manche Roboter überspringen genau das. Es steht deshalb außerhalb des
   Bildes, ist aus der Tabulatorreihenfolge genommen und für Vorleseprogramme
   ausgeblendet. */
.rueckruf__falle {
  position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;
}

@media (max-width: 760px) {
  .cta-paar { grid-template-columns: minmax(0, 1fr); justify-items: start; }
  .cta-paar__oder { padding: 0; }
  .rueckruf { width: 100%; }
}

/* ── Die Quittung ─────────────────────────────────────────────────────────
   Die Seite, die rueckruf.php nach dem Absenden ausgibt. Sie hat weder
   Kopfzeile noch Fußzeile: sie ist kein Ort, an dem man sich aufhält,
   sondern eine Antwort. Der Weg zurück steht als einzige Schaltfläche
   darunter. */
.quittung {
  min-height: 100svh; box-sizing: border-box;
  padding: clamp(40px, 8vh, 96px) var(--gutter);
  display: grid; align-content: center; justify-items: start;
  gap: clamp(18px, 2.6vh, 32px); max-width: 44em;
}
.quittung__marke img { height: 30px; width: auto; display: block; }
.quittung__titel {
  margin: 0; max-width: 16ch;
  font-size: clamp(30px, 4.9vw, 96px); line-height: 1.0;
  font-weight: 800; letter-spacing: -0.035em; text-transform: uppercase;
}
.quittung__text { max-width: 34em; font-size: clamp(17px, 1.4vw, 24px); }
.quittung__text p { margin: 0 0 0.7em; }
.quittung__text a { color: inherit; border-bottom: 2px solid var(--accent); }
.quittung__text a:hover { color: var(--accent-ink); }


/* ══════════════════════════════════════════════════════════════════════════
   9 · Knäuel – Weg – Netzwerk
      Die Bildmarke im Hero. Der Block darunter ist das gelieferte Snippet,
      unverändert übernommen — einschließlich seiner Bewegungsreduzierung.
      Hier steht nur, wie es in die Seite eingesetzt ist.

      Die Marke sitzt im freien Keil rechts oben: die erste und zweite Zeile
      der Überschrift enden deutlich vor der dritten, und dieser Platz gehört
      keiner Zeile. Absolut gesetzt statt als eigene Spalte, weil eine Spalte
      der Überschrift Breite wegnähme — sie misst sich an --h1-em am ganzen
      Kasten, und jede Verschmälerung ließe sie kleiner werden.

      Wie groß sie sein darf, ist gemessen und auf jeder Breite dieselbe Zahl:
      neben der ersten Zeile sind 21,9% der Titelbreite frei, neben der zweiten
      42,4%, neben der dritten nichts. Die erste Zeile ist damit das bindende
      Maß. Die Breite steht deshalb als „Keil minus Abstand" da und nicht als
      runde Zahl — so wächst die Marke mit der Überschrift mit und behält
      überall denselben Abstand zur Schrift. Größer geht nur, indem man der
      Überschrift Breite wegnimmt; warum das nicht passiert, steht oben.

      Unter 1000px entfällt sie: dort ist der Keil nur noch gut 150px breit,
      und der Hero hat auf einem Telefon Wichtigeres zu tun.

      Ab 1500px bekommt sie stattdessen eine eigene Spalte. Dann ist genug
      Platz für beides: die Marke wächst um rund die Hälfte und wird groß
      genug, dass man das Knäuel als Knäuel und das Netz als Netz liest,
      und die Überschrift bleibt trotz der schmaleren Spalte größer, als sie
      unterhalb dieser Schwelle ohnehin wäre. Darunter bleibt es beim Keil —
      dort kostet die Spalte die Überschrift ein Drittel ihrer Größe, und das
      ist der schlechtere Tausch.

      In der Spalte misst sich die Überschrift an .hero__type statt am ganzen
      Kasten. Deshalb steht container-type nur in dieser Abfrage: darunter ist
      .hero__type ein gewöhnlicher Block, und der nächste Container ist wieder
      .hero — die Überschrift misst sich dann wie bisher am ganzen Textfeld.
   ══════════════════════════════════════════════════════════════════════════ */

.hero__poster { position: relative; align-self: end; }

/* Beide Klassennamen, nicht nur einer: das Snippet setzt weiter unten
   .knaeuel { display: inline-block }, und bei gleicher Spezifität gewinnt die
   spätere Regel. Ohne diesen zweiten Klassennamen stand die Marke auf
   Telefonen mitten in der dritten Zeile der Überschrift. */
.knaeuel.hero__mark { display: none; }
@media (min-width: 1000px) {
  .knaeuel.hero__mark {
    display: block;
    position: absolute; right: 0; top: 7%;
    width: calc(21.9% - clamp(28px, 2vw, 46px));
    /* Sie ist Bild, kein Ziel: nichts an ihr soll Zeiger oder Fokus fangen. */
    pointer-events: none;
  }
}

/* ── Warum die Marke eine eigene Ebene bekommt ─────────────────────────────
   Der Pfad-Morph zeichnet sich jedes Bild neu. Ohne eigene Ebene liegt dieser
   Neuzeichnungsbereich in derselben Schicht wie die Überschrift daneben, und
   der Browser rastert im Zweifel die riesigen Buchstaben mit — sechzig Mal in
   der Sekunde, dreizehn Sekunden lang. contain: paint sagt ihm, dass nichts
   der Neuzeichnungsbereich in derselben Schicht wie die Überschrift daneben.
   will-change: transform hebt die Marke auf eine eigene Ebene — der Aufwand
   bleibt dann bei ihr, statt die riesigen Buchstaben mitzurastern, sechzig Mal
   in der Sekunde, dreizehn Sekunden lang.

   Nur will-change, nicht contain: paint und kein overflow: hidden. Beides
   würde beschneiden, und beschneiden darf man hier nicht: bei 4,4s ragt der
   Koralle-Punkt des gehenden Paares 2,7 Einheiten über die linke Kante des
   viewBox hinaus, bei 6s einer der einlaufenden Punkte unten heraus. Das
   Snippet setzt overflow: visible aus genau diesem Grund.

   Die Ebene steht dauerhaft, weil die Marke dauerhaft läuft. Das ist der Preis
   der Schleife: eine Ebene kostet Speicher, solange sie besteht. Liefe die
   Marke nur einen Durchgang, dürfte sie ihn danach wieder freigeben. */
@media (min-width: 1500px) {
  .hero__poster {
    display: grid; grid-template-columns: minmax(0, 1fr) 30%;
    column-gap: clamp(28px, 3vw, 72px); align-items: center;
  }
  .hero__poster > .hero__type { container-type: inline-size; }
  .knaeuel.hero__mark {
    position: static; width: 100%; top: auto; right: auto;
  }
}

.knaeuel.hero__mark { will-change: transform; }

/* ── Ab hier das Snippet, wie geliefert ─────────────────────────────────── */
.knaeuel { display: inline-block; line-height: 0; }
.knaeuel svg { width: 100%; height: auto; display: block; overflow: visible; }

@keyframes kn-walk { 0%, 26% { opacity: 0; } 30%, 90% { opacity: 1; } 97%, 100% { opacity: 0; } }
@keyframes kn-goal { 0%, 20% { opacity: 0.12; } 32%, 56% { opacity: 0.22; } 72%, 100% { opacity: 0; } }
@keyframes kn-frame { 0%, 28% { opacity: 0; } 36%, 92% { opacity: 0.3; } 99%, 100% { opacity: 0; } }
@keyframes kn-rest { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.14); } }
@keyframes kn-join-1 { 0%, 34% { opacity: 0; transform: translate(10px, 24px); } 37%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(7.2px, 27.4px); } 100% { opacity: 0; transform: translate(7.2px, 27.4px); } }
@keyframes kn-join-2 { 0%, 37% { opacity: 0; transform: translate(10px, 24px); } 40%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(-28px, 23px); } 100% { opacity: 0; transform: translate(-28px, 23px); } }
@keyframes kn-join-3 { 0%, 40% { opacity: 0; transform: translate(10px, 24px); } 43%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(-15.3px, 50.5px); } 100% { opacity: 0; transform: translate(-15.3px, 50.5px); } }
@keyframes kn-join-4 { 0%, 43% { opacity: 0; transform: translate(10px, 24px); } 46%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(-23.6px, -27.3px); } 100% { opacity: 0; transform: translate(-23.6px, -27.3px); } }
@keyframes kn-join-5 { 0%, 46% { opacity: 0; transform: translate(10px, 24px); } 49%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(-51.5px, 1.4px); } 100% { opacity: 0; transform: translate(-51.5px, 1.4px); } }
@keyframes kn-join-6 { 0%, 49% { opacity: 0; transform: translate(10px, 24px); } 52%, 56% { opacity: 1; transform: translate(0, 0); } 70%, 92% { opacity: 1; transform: translate(-76.5px, 24.6px); } 100% { opacity: 0; transform: translate(-76.5px, 24.6px); } }
@keyframes kn-edge-a { 0%, 66% { opacity: 0; stroke-dashoffset: 100; } 70% { opacity: 1; } 76%, 92% { opacity: 1; stroke-dashoffset: 0; } 99%, 100% { opacity: 0; stroke-dashoffset: 0; } }
@keyframes kn-edge-b { 0%, 69% { opacity: 0; stroke-dashoffset: 100; } 73% { opacity: 1; } 79%, 92% { opacity: 1; stroke-dashoffset: 0; } 99%, 100% { opacity: 0; stroke-dashoffset: 0; } }
@keyframes kn-edge-c { 0%, 72% { opacity: 0; stroke-dashoffset: 100; } 76% { opacity: 1; } 82%, 92% { opacity: 1; stroke-dashoffset: 0; } 99%, 100% { opacity: 0; stroke-dashoffset: 0; } }

.knaeuel .kn-goal  { animation: kn-goal 16s ease-in-out infinite both; }
.knaeuel .kn-frame { animation: kn-frame 16s ease-in-out infinite both; }
.knaeuel .kn-pair  { animation: kn-walk 16s linear infinite both; }
.knaeuel .kn-edge  { animation-duration: 16s; animation-timing-function: ease-out; animation-iteration-count: infinite; animation-fill-mode: both; }
.knaeuel .kn-edge-a { animation-name: kn-edge-a; }
.knaeuel .kn-edge-b { animation-name: kn-edge-b; }
.knaeuel .kn-edge-c { animation-name: kn-edge-c; }
.knaeuel .kn-f { animation-duration: 16s; animation-timing-function: cubic-bezier(0.4,0,0.2,1); animation-iteration-count: infinite; animation-fill-mode: both; }
.knaeuel .kn-f1 { animation-name: kn-join-1; }
.knaeuel .kn-f2 { animation-name: kn-join-2; }
.knaeuel .kn-f3 { animation-name: kn-join-3; }
.knaeuel .kn-f4 { animation-name: kn-join-4; }
.knaeuel .kn-f5 { animation-name: kn-join-5; }
.knaeuel .kn-f6 { animation-name: kn-join-6; }
.knaeuel .kn-rest { transform-box: fill-box; transform-origin: center; animation-name: kn-rest; animation-timing-function: ease-in-out; animation-iteration-count: infinite; animation-fill-mode: both; }
.knaeuel .kn-r1 { animation-duration: 5s;   animation-delay: 0s; }
.knaeuel .kn-r2 { animation-duration: 5.6s; animation-delay: 0.8s; }
.knaeuel .kn-r3 { animation-duration: 4.8s; animation-delay: 1.6s; }
.knaeuel .kn-r4 { animation-duration: 6s;   animation-delay: 2.4s; }
.knaeuel .kn-r5 { animation-duration: 5.2s; animation-delay: 3.2s; }
.knaeuel .kn-r6 { animation-duration: 4.4s; animation-delay: 4s; }
.knaeuel .kn-r7 { animation-duration: 5.4s; animation-delay: 0.4s; }
.knaeuel .kn-r8 { animation-duration: 4.6s; animation-delay: 2.8s; }

/* Bewegungsreduzierung: Standbild im Netzwerk-Zustand */
@media (prefers-reduced-motion: reduce) {
  .knaeuel [class^="kn-"] { animation: none !important; }
  .knaeuel .kn-pair { opacity: 1; }
  .knaeuel .kn-goal { opacity: 0; }
  .knaeuel .kn-frame { opacity: 0.3; }
  .knaeuel .kn-edge { opacity: 1; stroke-dashoffset: 0; }
  .knaeuel .kn-f1 { opacity: 1; transform: translate(7.2px, 27.4px); }
  .knaeuel .kn-f2 { opacity: 1; transform: translate(-28px, 23px); }
  .knaeuel .kn-f3 { opacity: 1; transform: translate(-15.3px, 50.5px); }
  .knaeuel .kn-f4 { opacity: 1; transform: translate(-23.6px, -27.3px); }
  .knaeuel .kn-f5 { opacity: 1; transform: translate(-51.5px, 1.4px); }
  .knaeuel .kn-f6 { opacity: 1; transform: translate(-76.5px, 24.6px); }
}
