:root{
  --brand: #ea5a0c;
  --brand-d: #cf4f0a;
  --brand-dd: #b8460a;
  --gold: #f6ba00;
  --ink: #32373c;
  --muted: #5f6873;
  --faint: #98a0aa;
  --line: #e9e6e2;
  --bg: #ffffff;
  --bg-soft: #fbf8f5;
  --bg-quote: #f7f2ea;
  --dark: #1b1d21;
  --radius: 14px;
  --maxw: 1180px;
  --sans: "Helvetica Neue", Helvetica, "Segoe UI", Roboto, Arial, sans-serif;
}
* { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  /* One-Pager mit Sprungnavigation (Issue #100): Die Kopfzeile klebt mit 70px Hoehe oben —
     ohne diesen Ausgleich verschwindet die Ueberschrift jedes Sprungziels darunter. */
  scroll-behavior: smooth;
  scroll-padding-top: 86px;
}
body {
  margin: 0; font-family: var(--sans); color: var(--ink); background: var(--bg);
  line-height: 1.6; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
/* h4 gehoert dazu, seit Karten- und Schritt-Titel innerhalb eines Abschnitts h4 sind (#100) —
   sonst erbt dieselbe Karte im Abschnitt die Body-Zeilenhoehe und sieht anders aus. */
/* overflow-wrap + hyphens sind das Sicherheitsnetz gegen deutsche Komposita (#158).
   Ohne sie laeuft ein Wort, das breiter ist als seine Spalte, ueber die Spaltenkante hinaus —
   im Hero verschwand es dadurch unter dem spaeter im DOM stehenden .hero-media-Bild
   (.hero-inner:has(.hero-media) legt die Textspalte auf minmax(0, 1fr) fest, sie kann also nicht
   mitwachsen; das max-width: 24ch an .hero h1 half nicht, weil das WORT breiter blieb).
   Bewusst an der gemeinsamen Regel und nicht nur an .hero h1: Dieselbe Konstellation trifft die
   h2/h3 in schmalen Karten. Beide Eigenschaften greifen ausschliesslich dann, wenn sonst ein
   Ueberlauf entstuende — passt die Ueberschrift, aendert sich nichts (Zusage aus dem Ticket:
   "kurze Titel sehen unveraendert aus"). hyphens braucht die Sprachauszeichnung; page.eta liefert
   <html lang="de">. */
h1, h2, h3, h4 { color: var(--ink); line-height: 1.2; letter-spacing: -.02em; overflow-wrap: break-word; hyphens: auto; }
a { color: var(--brand-d); text-decoration: none; }
a:hover { color: var(--brand-dd); }
img { max-width: 100%; }

/* Header / Nav */
.site-nav {
  position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 1.6rem;
  padding: 0 1.5rem; height: 70px; background: rgba(255,255,255,.9);
  backdrop-filter: saturate(150%) blur(10px); border-bottom: 1px solid var(--line);
}
.site-nav .brand { font-weight: 800; color: var(--ink); font-size: 1.15rem; }
.site-nav .brand-logo { height: 34px; width: auto; display: block; }
.site-nav nav { display: flex; gap: 1.4rem; flex-wrap: wrap; margin-left: auto; }
.site-nav nav a { color: var(--muted); font-weight: 600; font-size: .95rem; }
.site-nav nav a.active, .site-nav nav a:hover { color: var(--brand-d); }

/* Eyebrow */
/* Kicker in --brand-dd statt --brand-d (Issue #164). GEMESSEN, nicht geschaetzt: Auf der getoenten
   Hero-Flaeche kommt --brand-d auf 3,89:1 und faellt damit durch WCAG AA (4,5 fuer normalen Text) —
   auf dem alten `--bg-soft` waren es 4,16, es war also SCHON VORHER zu wenig. Der Verlauf allein
   kann das nicht heilen: Selbst bei 6 % Toenung bleibt --brand-d bei 4,09. Mit --brand-dd sind es
   4,74 auf der Toenung, also besser als der Ausgangszustand.
   Das Ticket nennt die Kicker-Zeile ausdruecklich unter "Lesbarkeit hat Vorrang". */
.eyebrow {
  display: inline-flex; align-items: center; gap: .6rem;
  font-size: .8rem; font-weight: 700; letter-spacing: .15em; text-transform: uppercase;
  color: var(--brand-dd); margin-bottom: 1rem;
}
.eyebrow::before { content: ""; width: 28px; height: 3px; border-radius: 2px; background: var(--brand); }

/* Hero */
.hero {
  /* KEIN horizontales Padding: Es kaeme zur Zentrierung von .hero-inner HINZU und schoebe den
     Hero-Text um genau diesen Betrag nach innen — die Kante lag dadurch 24px weiter links als die
     der Abschnitte darunter (im Browser gemessen, Issue #119). Der Innenabstand gehoert an
     .hero-inner, exakt wie bei .wrap. */
  position: relative; overflow: hidden; padding: 5.5rem 0 4rem;
  /* Weicher Verlauf statt Flaeche (Issue #164), an der Referenzseite gemessen: VERTIKAL (nicht
     diagonal, wie der Ticket-Rumpf vermutete) und bereits bei 50 % vollstaendig in --bg ausgelaufen.
     Genau daraus folgen zwei Zusagen des Tickets von selbst: Der Uebergang zum naechsten Abschnitt
     hat konstruktiv KEINE Farbkante, und die Merkmals-Chips (#163) stehen unten im Hero auf
     neutralem Grund.
     Aus der Markenfarbe BERECHNET (color-mix), nicht fest verdrahtet — aendert sich --brand, zieht
     der Verlauf mit. Die 10 % sind bewusst schwach: Die Lesbarkeitszusage aus dem Ticket gilt nur,
     solange die Toenung nachweislich zurueckhaltend bleibt.
     Er ERSETZT `background: var(--bg-soft)`; zusaetzlich laege eine flaechige Toenung unter dem
     auslaufenden Verlauf und genau die Kante entstuende wieder, die Abschnitt 4 ausschliesst. */
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--brand) 10%, var(--bg)) 0%,
    var(--bg) 50%,
    var(--bg) 100%);
  border-bottom: 1px solid var(--line);
}
/* Issue #119: Der Hero-Inhalt bekommt DIESELBE Kante wie `.wrap` — gleiche max-width, gleiche
   Zentrierung der Box. Ohne diesen Container saesse der Text am Viewport-Rand, die Abschnitte
   darunter aber an der --maxw-Kante, und der Blick spraenge zwischen beiden.
   Zweispaltiges Raster mit vorerst EINER belegten Spalte: Issue #118 stellt das Bild daneben,
   ohne die Ausrichtung noch einmal anzufassen. */
.hero-inner {
  position: relative; z-index: 1;
  /* Dieselben drei Werte wie .wrap — max-width, Zentrierung UND seitliches Padding. Nur alle drei
     zusammen ergeben dieselbe linke Kante; zwei davon reichen nicht. */
  max-width: var(--maxw); margin: 0 auto; padding: 0 1.5rem;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 2.5rem; align-items: center;
}
/* Die frueheren zwei radialen Verlaeufe aus den Ecken sind mit #164 entfallen: Sie und der neue
   vertikale Verlauf zusammen waeren zwei Effekte uebereinander — und die Ecken-Verlaeufe reichten
   bis in die untere Haelfte des Hero, wo der neue bewusst schon ausgelaufen ist. */
.hero::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 4px; z-index: 1;
  background: linear-gradient(90deg, var(--brand) 0%, var(--gold) 100%);
}
/* max-width 24ch statt 18ch: Der alte Wert war auf eine ZENTRIERTE Komposition gerechnet und
   laesst die Zeile linksbuendig zu kurz wirken. Vorschlagswert — am realen Satz zu pruefen. */
.hero h1 { color: var(--ink); font-weight: 800; font-size: clamp(2rem, 5vw, 3.4rem); margin: 0; max-width: 24ch; }
.hero .sub { color: var(--muted); font-size: clamp(1.05rem, 2vw, 1.25rem); max-width: 60ch; margin: 1.1rem 0 1.8rem; }

/* Abschnittskopf innerhalb des One-Pagers (Issue #100) */
.page-head { padding: 2.5rem 0 .5rem; max-width: var(--maxw); margin: 0 auto; }
.page-head h2 { font-size: clamp(1.6rem, 3.6vw, 2.2rem); margin: 0; }
.page-head .sub { color: var(--muted); font-size: 1.15rem; max-width: 70ch; }

/* Buttons */
.cta-row { display: flex; gap: .8rem; justify-content: flex-start; flex-wrap: wrap; }
.btn {
  display: inline-flex; align-items: center; gap: .5rem; font-weight: 600; font-size: .98rem;
  padding: .8rem 1.5rem; border-radius: 10px; border: 1px solid transparent; cursor: pointer;
  background: var(--brand); color: #fff;
  box-shadow: 0 10px 22px color-mix(in srgb, var(--brand) 28%, transparent);
  transition: transform .15s ease, background .15s ease, box-shadow .15s ease;
}
.btn:hover { background: var(--brand-d); color: #fff; transform: translateY(-1px); }
.hero .btn:first-child { background: var(--gold); color: #3a2c00; box-shadow: 0 10px 22px color-mix(in srgb, var(--gold) 30%, transparent); }
.hero .btn:first-child:hover { filter: brightness(.96); background: var(--gold); }

/* Content + Blocks */
/* Issue #121: KEIN vertikales Padding mehr. Es kam zu den Blockabstaenden hinzu und machte
   ausgerechnet den ersten (1rem) und den letzten Abstand (3.5rem) anders als alle dazwischen. */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 1.5rem; }
.block { padding: 4rem 0; border-bottom: 1px solid var(--line); }
.block:last-child { border-bottom: 0; }
/* Sprungziel-Ausgleich: EINE Quelle, naemlich `scroll-padding-top` an der Wurzel (oben).
   Frueher stand hier zusaetzlich `scroll-margin-top: 86px`. Beides ist nicht redundant, sondern
   ADDIERT sich laut Spezifikation: Das angesprungene Kapitel landete dadurch bei 172px statt 86px.
   Solange es nur ums Scrollen ging, fiel das nicht auf; mit dem Scrollspy aus #122 wurde daraus ein
   sichtbarer Fehler, weil das VORHERIGE Kapitel noch in den Beobachtungsbereich ragte und deshalb
   nach jedem Klick als aktiv markiert wurde (im Browser nachgemessen).
   Die Regel bleibt als 0-Wert stehen, damit ein spaeter ergaenztes `scroll-margin-top` an anderer
   Stelle nicht unbemerkt wieder aufaddiert. */
.page-section, .block[id] { scroll-margin-top: 0; }
.hero { scroll-margin-top: 0; }
/* Der letzte Block eines Abschnitts braucht keine Trennlinie — der naechste Abschnittskopf ist
   bereits die Zaesur. */
.page-section .block:last-child { border-bottom: 0; }
/* Blockueberschrift haengt an einer KLASSE, nicht an der Baumstellung (Issue #206).
   Ebene h2 UND h3: Bloecke stehen auf der Startseiten-Ebene (h2) und innerhalb eines Abschnitts
   (h3, weil dessen Titel bereits das h2 ist) — Issue #100. Die Klasse traegt beide.

   VORHER stand hier der Kind-Kombinator `.block > :is(h2, h3)`. Er traf nur, was DIREKT unter
   .block steht, und ist genau daran zweimal gescheitert: Die Ueberschrift der Kontaktkarte liegt
   zwei Ebenen tiefer (#206), die des Text-Bild-Blocks wandert seit #207 in die linke Spalte.
   Beide fielen still auf die Browser-Vorgabe fuer h2 zurueck — andere Groesse, andere
   Schriftstaerke, anderer Abstand, kein goldener Balken. Im Diff faellt so etwas nicht auf.

   Die Klasse setzt der Renderer an jede Blockueberschrift. Zwischenueberschriften in .card,
   .steps li und .md-body bekommen sie NICHT und behalten damit ihre eigene Groesse — das ist
   dieselbe Zusage, die vorher der Kind-Kombinator gegeben hat, nur ohne die Abhaengigkeit von
   der Verschachtelung. */
.block-title { position: relative; font-size: clamp(1.4rem, 3vw, 1.9rem); font-weight: 800; margin: 0 0 1.2rem; }
.block-title::after { content: ""; display: block; width: 54px; height: 3px; border-radius: 2px; background: var(--gold); margin-top: .8rem; }

/* Bullets */
.bullets { columns: 2; gap: 2rem; margin: 0; padding-left: 1.1rem; }
.bullets li { margin: 0 0 .6rem; }
@media (max-width: 640px) { .bullets { columns: 1; } }

/* Cards */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 1.4rem; }
.card {
  position: relative; overflow: hidden; background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.6rem 1.5rem;
  box-shadow: 0 1px 2px rgba(50,55,60,.05), 0 8px 24px rgba(50,55,60,.06);
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.card::before { content: ""; position: absolute; left: 0; top: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--brand), var(--gold)); }
.card:hover { transform: translateY(-4px); box-shadow: 0 22px 55px color-mix(in srgb, var(--brand) 14%, transparent); }
.card :is(h3, h4) { margin: .3rem 0 .5rem; font-size: 1.2rem; font-weight: 800; }
.card p { margin: 0; color: var(--muted); }

/* Steps */
.steps { list-style: none; counter-reset: step; padding: 0; display: grid; gap: 1rem; }
.steps li { position: relative; background: var(--bg-soft); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.2rem 1.3rem 1.2rem 3.6rem; }
.steps li::before {
  counter-increment: step; content: counter(step); position: absolute; left: 1.1rem; top: 1.2rem;
  width: 1.8rem; height: 1.8rem; border-radius: 50%; background: var(--brand); color: #fff;
  display: grid; place-items: center; font-weight: 700;
}
.steps :is(h3, h4) { margin: 0 0 .3rem; font-size: 1.1rem; }
.steps p { margin: 0; color: var(--muted); }

/* FAQ */
.faq dt { font-weight: 700; color: var(--ink); margin-top: 1.2rem; }
.faq dd { margin: .3rem 0 0; color: var(--muted); }

/* Kennzahlen-Leiste (Issue #124).
   Drei Spalten, Zahl gross in der Markenfarbe, Beschriftung klein und gedaempft darunter.
   Bewusst KEINE Rahmen und keine Kacheln — die Zahlen sollen fuer sich stehen und nicht wie
   Feature-Kacheln aussehen; genau deshalb ist es ein eigener Blocktyp und kein `cards`. */
.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2rem; }
.stat { display: flex; flex-direction: column; gap: .4rem; }
.stat-value { font-size: clamp(2rem, 4.5vw, 3rem); font-weight: 800; line-height: 1.1; color: var(--brand); }
.stat-label { color: var(--muted); font-size: .98rem; }
/* Auf schmalen Viewports EINE Spalte — aber mit kleinem Abstand: Drei Zahlen duerfen dort nicht
   drei volle Bildschirmhoehen werden (ausdrueckliche Vorgabe im Ticket). */
@media (max-width: 720px) {
  .stats { grid-template-columns: minmax(0, 1fr); gap: 1.2rem; }
}

/* CTA-Band (dunkel/markig) */
.cta-box {
  position: relative; overflow: hidden; color: #fff; border-radius: 20px; padding: 2.6rem 2.2rem;
  background: linear-gradient(120deg, color-mix(in srgb, var(--brand) 85%, #fff) 0%, var(--brand) 52%, var(--brand-d) 100%);
  box-shadow: 0 20px 50px color-mix(in srgb, var(--brand) 30%, transparent);
}
.cta-box::after { content: ""; position: absolute; right: -60px; top: -60px; width: 240px; height: 240px; border-radius: 50%; background: radial-gradient(circle, color-mix(in srgb, var(--gold) 45%, transparent), transparent 65%); pointer-events: none; }
.cta-box > * { position: relative; z-index: 1; }
.cta-box :is(h2, h3) { color: #fff; }
.cta-box :is(h2, h3)::after { display: none; }
.cta-box p { font-size: 1.15rem; margin: 0 0 1.3rem; color: rgba(255,255,255,.92); }
.cta-box .btn { background: #fff; color: var(--brand-d); box-shadow: 0 8px 20px rgba(0,0,0,.14); }
.cta-box .btn:hover { background: #fff4ec; color: var(--brand-dd); }

/* Markdown */
.md-body :is(h1,h2,h3) { color: var(--ink); }
.md-body a { color: var(--brand-d); text-decoration: underline; }
.md-body code { background: var(--bg-soft); padding: 0 .3rem; border-radius: .3rem; }

/* Footer */
.site-foot { margin-top: 2rem; padding: 2.4rem 1.5rem; text-align: center; color: rgba(255,255,255,.7); background: var(--dark); font-size: .9rem; }
.site-foot .brand-logo { height: 26px; width: auto; margin: 0 auto .6rem; display: block; }

/* Rück-Link (Header) + Footer-Links zur Übersicht & Legal */
.site-nav .ll-back { color: var(--muted); font-weight: 600; margin-right: 16px; text-decoration: none; }
.site-nav .ll-back:hover { color: var(--brand-d); }
.site-foot .foot-links { display: flex; gap: 18px; flex-wrap: wrap; justify-content: center; margin: 6px 0; }
.site-foot .foot-links a { color: rgba(255,255,255,.85); text-decoration: none; }
.site-foot .foot-links a:hover { color: #fff; text-decoration: underline; }

/* Schmale Viewports (Issue #121): 4rem oben UND unten sind auf dem Smartphone viel Leerraum —
   drei Abschnitte fuellen sonst den Bildschirm, ohne etwas zu sagen. Vorschlagswert, am realen
   Geraet zu pruefen. */
@media (max-width: 720px) {
  .block { padding: 2.5rem 0; }
  /* Innenabstand der Kachel bleibt sichtbar (#166), nur etwas knapper. */
  .quote { padding: 1.6rem 1.4rem 1.4rem; }
  .hero { padding: 3.5rem 0 2.5rem; }
  /* Issue #122, Maintainer-Entscheidung: keine Sprungmarken auf dem Mobilgeraet. Fuenf Eintraege
     plus Logo passen dort nicht nebeneinander, und damit eruebrigen sich Umbruch, horizontales
     Scrollen und ein Klappmenue. */
  .site-nav nav { display: none; }
}

/* Kundenzitat (Issue #123). Typografisch hervorgehoben, die Attribution klar abgesetzt darunter —
   ein Zitat als Feature-Kachel zu bauen wuerde den Beleg entwerten. Fehlt ein Bild im Pool-Eintrag,
   bleibt der Abschnitt ohne Bild statt mit Platzhalter (ausdrueckliche Vorgabe im Ticket). */
/* Beige Kachel statt weisser Flaeche (Issue #166): Zwischen zwei Textabschnitten ging der Beleg
   unter und las sich beim Scrollen wie ein weiterer Absatz. Die Abhebung entsteht ueber die FLAECHE
   — bewusst ohne Rahmen und ohne kraeftigen Schatten.
   Der farbige Strich links vom Zitat ist damit ENTFALLEN (Maintainer-Entscheidung): Zwei
   konkurrierende Signale in einem Block sind eines zu viel; der Strich war ohnehin nur das
   Behelfsmittel, solange es keine Flaeche gab. */
.quote {
  margin: 0; background: var(--bg-quote); border-radius: var(--radius);
  padding: 2.2rem 2.2rem 1.8rem;
}
.quote blockquote {
  margin: 0 0 1.6rem; padding: 0;
  font-size: clamp(1.15rem, 2.4vw, 1.5rem); line-height: 1.5; color: var(--ink);
}
.quote figcaption { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
/* 80 px statt 56 (Ticket-Richtwert): Bei der bisherigen Groesse war ein Gesicht kaum zu erkennen,
   und damit verpuffte der Effekt, den ein Portraet an dieser Stelle haben soll. Feste Pixelgroesse
   auch auf schmalen Viewports — der im Ticket befuerchtete Fall "halbe Bildschirmbreite" tritt so
   gar nicht erst ein. */
.quote-photo { width: 80px; height: 80px; border-radius: 50%; object-fit: cover; }
.quote-who { display: flex; flex-direction: column; }
.quote-role { color: var(--muted); font-size: .95rem; }
/* Logo bleibt klein und rechts — es belegt den Kunden, es bewirbt ihn nicht. */
/* Feste Anzeigebox statt einer einzelnen Begrenzung (Issue #159). Mit `max-height` allein
   entschied bei einem breiten Wortmarken-Logo faktisch die Restbreite der Zeile (globale Regel
   `img { max-width: 100% }`), und es landete bei deutlich unter 34 px — waehrend ein quadratisches
   Logo die volle Hoehe erreichte. Mit fester Hoehe, Breitendeckel und `object-fit: contain` wirken
   beide Formen gleich stark, und verzerrt wird nie. */
.quote-logo { height: 48px; width: auto; max-width: 180px; object-fit: contain; margin-left: auto; }

/* Hero-Motiv (Issue #118, Version 1: klar abgegrenztes Bild statt Hintergrund-Fuellung).
   Die zweite Spalte entsteht NUR mit Bild — ohne bleibt `.hero-inner` einspaltig und die Ausgabe
   ist byte-identisch zu vorher (No-op-Zusage aus #82). */
.hero-inner:has(.hero-media) { grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); }
/* Kleinere Obergrenze, solange zwei Spalten stehen (#158). `clamp(2rem, 5vw, 3.4rem)` rechnet den
   vw-Anteil gegen die VOLLE Viewport-Breite, die Ueberschrift belegt hier aber nur gut die Haelfte
   — bei 1280 px wurde ein langer Titel dadurch dreizeilig mit Trennstrich schon im ersten Wort.
   Bewusst NUR ab 861 px: Unterhalb stapeln die Spalten, die Ueberschrift hat die volle Breite und
   braucht keine Verkleinerung. */
@media (min-width: 861px) {
  .hero-inner:has(.hero-media) h1 { font-size: clamp(2rem, 3.4vw, 2.8rem); }
}
.hero-media img {
  display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); box-shadow: 0 20px 50px rgba(0, 0, 0, .14);
}
/* Auf schmalen Viewports untereinander — nebeneinander waeren beide Spalten zu schmal, um zu
   wirken. Das Bild steht dann UNTER dem Text: Die Aussage kommt zuerst. */
@media (max-width: 860px) {
  .hero-inner:has(.hero-media) { grid-template-columns: minmax(0, 1fr); }
  .hero-media img { aspect-ratio: 16 / 9; }
}

/* Merkmals-Chips am unteren Hero-Rand (Issue #163).
   Die Werte sind an der Referenzseite GEMESSEN, nicht geschaetzt: 38 px hoch, 14 px Schrift,
   16 px Icon, Innenabstand 8/16, Pill-Radius. Das Ticket nennt diese Groesse ausdruecklich als
   OBERGRENZE — die Reihe ist ein ruhiger Zusatz und darf Titel und Knopf nicht die Aufmerksamkeit
   nehmen.
   Farben ueber die vorhandenen Tokens: Ein roher Hex-Wert waere eine zweite Farbwahrheit neben dem
   Styleguide und zoege bei einem Farbwechsel nicht mit. */
.hero-chips {
  position: relative; z-index: 1; list-style: none;
  /* Dieselbe Kante wie .hero-inner und .wrap — alle drei Werte, nicht zwei (#119). */
  max-width: var(--maxw); margin: 3rem auto 0; padding: 0 1.5rem;
  display: flex; flex-wrap: wrap; gap: .75rem;
}
.chip {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: 8px 16px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--bg-soft); color: var(--ink);
  font-size: 14px; font-weight: 600; line-height: 1.4;
  /* Ein Chip bricht NIE um (Ticket-Vorgabe): Der Text steht einzeilig. */
  white-space: nowrap;
}
.chip-icon { width: 16px; height: 16px; flex: 0 0 auto; color: var(--brand); }
/* 4 → 2x2 → 1 Spalte (Ticket-Vorgabe). Der natuerliche `flex-wrap`-Umbruch ergaebe je nach
   Textlaenge 3+1 oder 2+2 — auf schmalen Viewports wird deshalb auf ein RASTER umgeschaltet, damit
   die Reihe verlaesslich als 2x2 steht und nicht in unterschiedlich lange Reste zerfaellt. */
@media (max-width: 860px) {
  .hero-chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chip { white-space: normal; }
}
@media (max-width: 480px) {
  .hero-chips { grid-template-columns: minmax(0, 1fr); }
}

/* CTA-Formular (Issue #65). Nur Tokens, kein eigenes :root — das kommt aus dem Styleguide. */
.ll-form { max-width: var(--maxw); margin: 0 auto; padding: 2.5rem 1.5rem 3rem; }
.ll-form h2 { color: var(--ink); }
.ll-form-frame { display: block; width: 100%; border: 0; background: transparent; min-height: 480px; }
.ll-form-stub { border: 2px dashed var(--line); border-radius: var(--radius); padding: 2rem; background: var(--bg-soft); color: var(--muted); }
.ll-form-stub strong { color: var(--ink); }
a.btn { text-decoration: none; }

/* ---------------------------------------------------------------------------
 * Overlay — geteilt von Kontaktanfrage (#116) und Whitepaper-Download (#99).
 *
 * Stand bis #116 in download.css. Dort war es richtig, solange es nur EIN Overlay gab; seit die
 * Kontaktanfrage ebenfalls eines nutzt, haette ein Produkt mit Kontakt-, aber ohne
 * Download-Formular ein ungestyltes Overlay bekommen. form.css kommt bei BEIDEN mit.
 *
 * Nur var(--token) aus renderStyleguideVars — --color-* gibt es dort NICHT.
 * ------------------------------------------------------------------------ */
/* <button class="btn"> erbt die Schriftart NICHT — styles.css setzt an .btn kein font-family,
 * weil dort urspruenglich nur <a class="btn"> stand. */
button.btn { font: inherit; }

/* In der Vorschau ist der Knopf bewusst kein Knopf: Das Vorschau-iframe laeuft ohne
 * allow-scripts, das Overlay ginge dort gar nicht auf. Ein klickbarer Knopf, der nichts tut,
 * wuerde als kaputt gemeldet. */
.ll-btn-inert { opacity: .7; cursor: default; }

.ll-modal[hidden] { display: none; }
.ll-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.ll-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
}

.ll-modal-box {
  position: relative;
  background: var(--bg, #fff);
  border-radius: var(--radius, 14px);
  max-width: 44rem;
  width: 100%;
  max-height: 90vh;
  overflow: auto;
  padding: 1.5rem;
}

.ll-modal-x {
  position: absolute;
  top: .5rem;
  right: .75rem;
  background: none;
  border: 0;
  font-size: 1.75rem;
  line-height: 1;
  cursor: pointer;
  color: var(--muted);
}

/* Mobil: Das Formular ist hoeher als der Bildschirm (Issue #116). Ohne eigene Hoehenbegrenzung
   waechst der Kasten aus dem Viewport heraus und der Schliessen-Knopf ist nicht mehr erreichbar —
   auf dem Smartphone die haeufigste Sackgasse bei Overlays.
   `100dvh` statt `100vh`: Nur das dynamische Mass beruecksichtigt die ein- und ausfahrende
   Browserleiste; mit `100vh` bliebe der Knopf genau dann verdeckt, wenn sie sichtbar ist.
   `overscroll-behavior: contain` verhindert, dass das Scrollen am Ende des Overlays auf die
   Seite dahinter durchschlaegt. */
.ll-modal-box { max-height: 100dvh; overflow-y: auto; overscroll-behavior: contain; }
@media (max-width: 720px) {
  .ll-modal-box { width: 100%; border-radius: 0; }
}

/* Kontaktkarte am Seitenende (Issue #157).
   Wird NUR angehaengt, wenn ein Ansprechpartner gepflegt ist — ohne ihn entsteht weder Karte noch
   Regel und die Ausgabe bleibt byte-identisch zu vorher (No-op-Zusage aus #82).
   Ausschliesslich Tokens, die `renderStyleguideVars` setzt: ein `--color-*` waere "invalid at
   computed-value time" und fiele wirkungslos aus (#99). */
.block-contact { border-top: 1px solid var(--line); padding-top: 2.5rem; }
.contact-card { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; align-items: center; }
/* Hier standen bis #206 zwei Sonderregeln: `color: var(--brand-d)` und `::after { display: none }`.
   Sie machten die Kontakt-Ueberschrift zur einzigen Abschnittsueberschrift der Seite in der
   Markenfarbe und ohne goldenen Balken. #206 nimmt beides zurueck — die Ueberschrift soll sich in
   nichts von den uebrigen unterscheiden. Wieder einzufuegen waere das Ticket nicht erfuellt.
   `margin-top: 0` geht dabei nicht verloren: es steckt in `margin: 0 0 1.2rem` von `.block-title`. */
.contact-call p { color: var(--muted); margin: 0 0 1.4rem; }
.contact-person { display: flex; flex-direction: column; align-items: center; text-align: center; gap: .25rem; }
/* Rund per CSS, nicht per Zuschnitt beim Upload: Die Originaldatei bleibt unangetastet
   (Maintainer-Entscheidung). Ein quadratisch vorbereitetes Foto sitzt damit mittig im Kreis. */
.contact-photo {
  width: 160px; height: 160px; border-radius: 50%; object-fit: cover;
  margin-bottom: .6rem; box-shadow: 0 10px 30px rgba(0, 0, 0, .12);
}
.contact-name { font-weight: 800; font-size: 1.15rem; }
.contact-role { color: var(--muted); }
.contact-tel, .contact-mail { color: var(--brand-d); }
/* Auf schmalen Viewports untereinander: Textteil oben, Ansprechpartner darunter. */
@media (max-width: 860px) {
  .contact-card { grid-template-columns: 1fr; gap: 1.8rem; }
}

/* Zweispaltiger Fliesstext-Block: Text links, Bild rechts (Issue #154).
   Wird NUR angehaengt, wenn der Block auch entsteht — also bei mindestens zwei Fliesstext-Bloecken
   UND einem freien Motiv (No-op-Zusage aus #82).
   Festes Seitenverhaeltnis plus `object-fit: cover`: Unterschiedlich grosse Mediathek-Bilder
   sprengen so die Blockhoehe nicht. */
.prose-media { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2.5rem; align-items: center; }
.prose-media-img img {
  display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
  border-radius: var(--radius); box-shadow: 0 14px 40px rgba(0, 0, 0, .12);
}
/* Auf schmalen Viewports gestapelt — Text zuerst, Bild darunter: Die Aussage kommt vor der
   Illustration (dieselbe Reihenfolge wie beim Hero-Motiv, #118). */
@media (max-width: 860px) {
  .prose-media { grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
}

/* src/render/templates/product/video.css — Produktvideo (Issue #161)

   Wird NUR angehaengt, wenn ein Video gesetzt ist. Ohne Video bleibt styles.css byte-identisch zu
   vorher — sonst erzeugte allein das Ausrollen dieser Version bei jedem Produkt einen Commit im
   Ziel-Repo, setzte staging_dirty und loeste den CI-Webhook aus, ohne inhaltliche Aenderung
   (No-op-Zusage aus #82). Ein Test pinnt das.

   Nur Tokens, die renderStyleguideVars auch setzt — ein --color-* waere "invalid at
   computed-value time" und fiele wirkungslos aus. */
.ll-video {
  display: block;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--dark);
}

/* Whitepaper-Seite (Issue #99).
 *
 * Wird NUR an styles.css angehaengt, wenn ein Whitepaper-Text existiert — sonst aenderte allein das
 * Ausrollen dieser Version jede styles.css, jeder Rebuild erzeugte einen Commit im Ziel-Repo,
 * setzte staging_dirty und loeste den CI-Webhook aus, ohne inhaltliche Aenderung (#82).
 *
 * Nur var(--token) — die Farben kommen aus dem Styleguide (:root steht in renderStyleguideVars). */

.ll-wp {
  /* Lesbare Zeilenlaenge: Das hier ist Fliesstext ueber mehrere Seiten, keine Marketing-Kachel. */
  max-width: 46rem;
  margin: 0 auto;
  padding: 2.5rem 1.5rem 3rem;
}

.ll-wp-head {
  display: flex;
  align-items: center;
  gap: 1rem;
  border-bottom: 1px solid var(--line);
  padding-bottom: 1rem;
  margin-bottom: 2rem;
}

.ll-wp-head .brand-logo { height: 2rem; }
.ll-wp-product { color: var(--muted); font-size: .95rem; }

.ll-wp-body h1 { font-size: 2rem; line-height: 1.2; margin: 0 0 1.2rem; }
.ll-wp-body h2 { font-size: 1.35rem; margin: 2.2rem 0 .8rem; }
.ll-wp-body p, .ll-wp-body li { line-height: 1.65; }
.ll-wp-body ul, .ll-wp-body ol { padding-left: 1.4rem; }

/* Checkliste: `- [ ]` wird von marked zu <li> mit deaktivierter Checkbox. Ohne diese Regeln steht
 * der Punkt daneben und die Kaestchen sitzen zu eng — genau die Liste, die ausgedruckt wird. */
.ll-wp-body li:has(> input[type="checkbox"]) { list-style: none; margin-left: -1.4rem; }
.ll-wp-body input[type="checkbox"] {
  width: 1rem; height: 1rem;
  margin-right: .6rem;
  vertical-align: -.1rem;
}

@media print {
  /* Zum Ausdrucken bzw. „Als PDF speichern": Der Browser ist hier der PDF-Erzeuger — PDF als
   * eigenes Ausgabeformat bleibt Ausbaustufe (Binaerpfad + Headless-Chromium im Image). */
  .ll-wp { max-width: none; padding: 0; }
  .site-foot { border: 0; }
  .ll-wp-body h2 { break-after: avoid; page-break-after: avoid; }
  .ll-wp-body li, .ll-wp-body p { break-inside: avoid; page-break-inside: avoid; }
  a { text-decoration: none; color: inherit; }
}
