: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; }
}

/* Kundenlogos-Reihe (Issues #210, #245).
   =================================================================================================
   Sozialer Beweis ganz oben: fremde Namen, dann eigene Zahlen — der Block steht direkt ueber der
   Kennzahlen-Leiste.

   OHNE UEBERSCHRIFT, bewusst: Die Reihe spricht fuer sich, und jede Formulierung („Unsere Kunden",
   „Vertrauen uns") waere eine Behauptung ueber die Art der Geschaeftsbeziehung, die an dieser
   Stelle niemand geprueft hat.

   ALLE Logos auf jeder Seite — es gibt keine Auswahl (Maintainer-Entscheidung, #210). Damit
   entfaellt die Stabilitaetsfrage: Der Ticket-Rumpf verlangte „pro Seite zufaellig", und das haette
   bei jedem Rebuild ein anderes Markup und einen Commit ohne inhaltliche Aenderung erzeugt (#82).

   GENAU EINE ZEILE, immer (#245): Mit erlaubtem Umbruch (`wrap`) wuchs die Reihe mit dem Vorrat — bei rund
   zwanzig Logos standen vier Zeilen Fremdlogos vor dem ersten Satz der Seite. Ab LOGO_MARQUEE_MIN
   Logos (SiteBuilder) rendert das Template die Liste zweimal in einem Band (`.logos-band`) und
   dieses CSS schiebt beide Kopien endlos nach links; darunter bleibt die statische, zentrierte
   Reihe. In BEIDEN Faellen ist der Umbruch aus: `nowrap` ist die Zusage, nicht die Animation.

   Der Block bekommt KEINE Trennlinie nach unten: Er gehoert visuell zur Kennzahlen-Leiste, die
   direkt folgt, und zwei Linien so dicht uebereinander zerschneiden den Vertrauensteil. */

.block-logos { padding-bottom: 0; border-bottom: 0; }

/* `flex` statt eines Rasters: Logos haben sehr verschiedene Seitenverhaeltnisse (gemessen an den
   vorhandenen: von 288x78 bis 1551x421). Ein Raster gaebe jedem dieselbe Zelle und liesse breite
   Wortmarken winzig erscheinen — genau der Fehler, den #159 an der Kundenstimme behoben hat. Hier
   bestimmt die HOEHE die Groesse, die Breite folgt.
   `nowrap` auch in der statischen Reihe: Passen wenige Logos auf einem schmalen Geraet nicht
   nebeneinander, duerfen die Zellen schrumpfen (`min-width: 0` + `max-width: 100%` am Bild) —
   lieber kleiner als zweizeilig. */
.logos {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: nowrap; align-items: center; justify-content: center;
  gap: 3rem;
}
.logos li { flex: 0 1 auto; min-width: 0; display: flex; justify-content: center; }

/* Dieselbe Loesung wie bei `.quote-logo` (#159): feste HOEHE plus Breitendeckel plus
   `object-fit: contain`. Nur `max-height` genuegt nicht — dann entschiede bei einer breiten
   Wortmarke faktisch die Restbreite der Zeile, und quadratische Logos wuerden viermal so gross
   dargestellt wie breite. */
.logos img {
  height: 34px; width: auto; max-width: min(160px, 100%); object-fit: contain;
  /* Graustufen und gedaempfte Deckkraft: Die Reihe ist ein Beleg, kein Farbakzent — bunte
     Fremdlogos ganz oben zoegen die Aufmerksamkeit von der Produktaussage ab. Beim Ueberfahren
     zeigt sich die Originalfarbe, damit die Marke erkennbar bleibt. */
  filter: grayscale(1); opacity: .55;
  transition: filter .18s ease, opacity .18s ease;
}
.logos img:hover { filter: grayscale(0); opacity: 1; }

/* Laufband (#245). Das Band schneidet den Ueberlauf ab und blendet die Raender weich aus, damit
   Logos nicht an einer harten Kante erscheinen und verschwinden. `mask-image` statt zweier
   ueberlagerter Verlaeufe in Hintergrundfarbe: Die Maske funktioniert auf jedem Untergrund, auch
   wenn der Hero-Verlauf (#164) oder ein Styleguide-Wechsel die Flaeche aendert. */
.logos-band {
  display: flex; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
/* Jede Kopie ist so breit wie ihr Inhalt und traegt den Abstand zur naechsten als `padding-right`
   — NICHT als `gap` am Band: Beide Kopien wandern um genau 100 % ihrer eigenen Breite; nur wenn
   der Zwischenraum Teil dieser Breite ist, steht am Ende des Durchlaufs Kopie 2 exakt dort, wo
   Kopie 1 begann, und der Sprung auf den Anfang ist unsichtbar. */
.logos-band .logos {
  flex: 0 0 auto; justify-content: flex-start; padding-right: 3rem;
  animation: logos-scroll var(--logos-duration, 40s) linear infinite;
}
.logos-band .logos li { flex: 0 0 auto; }
.logos-band .logos img { max-width: 160px; }
@keyframes logos-scroll { to { transform: translateX(-100%); } }
/* Anhalten beim Ueberfahren: Wer ein Logo erkennen will, soll es nicht jagen muessen — und der
   Farbwechsel beim Hover (oben) braucht ein stehendes Ziel. */
.logos-band:hover .logos { animation-play-state: paused; }
/* Wer Bewegung im System abgeschaltet hat, bekommt keine: Das Band steht, zeigt die erste Kopie
   und schneidet den Rest ab — die Zusage „eine Zeile" gilt auch hier, nur der Umbruch waere die
   Alternative, und den schliesst das Ticket aus. */
@media (prefers-reduced-motion: reduce) {
  .logos-band .logos { animation: none; }
  .logos-band .logos[aria-hidden] { display: none; }
  /* Ohne Bewegung keine Randblende: Sie liesse das erste Logo dauerhaft halb verschwunden stehen. */
  .logos-band { -webkit-mask-image: none; mask-image: none; }
}

@media (max-width: 640px) {
  /* Enger gestellt und etwas kleiner — auf schmalen Geraeten fressen 34 px hohe Logos sonst den
     halben ersten Bildschirm. */
  .logos { gap: 1.8rem; }
  .logos-band .logos { padding-right: 1.8rem; }
  .logos img { height: 26px; max-width: min(120px, 100%); }
  .logos-band .logos img { max-width: 120px; }
}

/* Kachel-Abschnitte auf dunklem Grund (Issue #214).
   =================================================================================================
   Nur Farben und Flaeche — ausdruecklich keine zusaetzlichen Gestaltungselemente (keine Kleinzeile
   ueber der Ueberschrift, keine Icons in den Kacheln). Inhalt, Reihenfolge und Markup der Seite
   bleiben unveraendert; das hier ist eine reine Stylesheet-Ergaenzung.

   WARUM `.block-cards` UND NICHT DIE BAUMSTELLUNG: Dieselbe Lehre wie bei `.block-title` (#206).
   Der Renderer setzt an jede Sektion `class="block block-<type>"`, die Zuordnung haengt also an
   einer Klasse und nicht daran, wo der Block gerade im Dokument steht. Betroffen sind damit genau
   die aus `home.sections` erzeugten Kachelbloecke — die renderer-exklusiven Abschnitte tragen
   eigene Typen (`block-stats`, `block-quote`, `block-cta`, `block-contact`, `block-video`) und
   bleiben unberuehrt.

   WARUM `--dark` UND KEIN NEUES STYLEGUIDE-FELD: Der Ton existiert bereits als Token (Default
   #1b1d21) und traegt heute schon Fussleiste und Videobuehne. Ein zweites Dunkelfeld waere eine
   zweite Farbwahrheit neben einer vorhandenen — und ein roher Hex-Wert hier waere es erst recht
   (#163). Nebeneffekt, der erwuenscht ist: Kachelabschnitt, Videoblock und Fussleiste stehen auf
   demselben Grund.

   WARUM box-shadow + clip-path UND NICHT `margin-inline: calc(50% - 50vw)`:
   Die Bloecke liegen in `main.wrap` (max-width, zentriert), die dunkle Flaeche soll aber ueber die
   VOLLE Breite laufen. Der uebliche Negativ-Margin rechnet mit `100vw` — und `100vw` schliesst in
   den meisten Browsern die Breite der Bildlaufleiste mit ein, erzeugt also eine waagerechte
   Bildlaufleiste. `box-shadow` und `clip-path` nehmen am Layout nicht teil und koennen das nicht.
   `inset(0 -100vmax)` weitet den Beschnitt nur seitlich; oben und unten bleibt er bei 0, damit die
   Flaeche exakt an der Blockkante endet. */

.block-cards {
  background: var(--dark);
  /* Die Flaeche IST die Zaesur — eine helle Trennlinie mitten im dunklen Abschnitt waere ein
     zweites Signal fuer dieselbe Aussage. */
  border-bottom: 0;
  box-shadow: 0 0 0 100vmax var(--dark);
  clip-path: inset(0 -100vmax);
}

/* Ueberschrift und goldener Balken bleiben unveraendert — nur die Schriftfarbe dreht.
   Gemessen gegen #1b1d21: 16,88:1 (WCAG AA verlangt 4,5:1). */
.block-cards .block-title { color: #fff; }

/* Kacheln „dunkel abgesetzt": eine Spur heller als der Abschnitt, damit sie als eigene Flaeche
   lesbar bleiben, ohne zu einem zweiten Farbakzent zu werden. Der weisse Kachelgrund aus
   `styles.css` waere hier das Gegenteil der Anforderung. */
.block-cards .card {
  background: color-mix(in srgb, #ffffff 7%, var(--dark));
  border-color: color-mix(in srgb, #ffffff 16%, var(--dark));
  /* Die hellen Schlagschatten aus `styles.css` sind auf dunklem Grund unsichtbar bis schmutzig —
     die Abhebung uebernimmt die Flaeche. */
  box-shadow: none;
}
.block-cards .card:hover {
  border-color: color-mix(in srgb, #ffffff 28%, var(--dark));
  /* Bewegung bleibt, der markenfarbene Schein daneben wuerde auf Dunkel nur schmutzen. */
  box-shadow: none;
}
/* Der Farbstreifen am oberen Kachelrand (brand → gold) bleibt bewusst stehen: Er ist auf dunklem
   Grund kraeftiger als auf hellem und das einzige Markenzeichen des Abschnitts. */

/* Ueberschriften der Kacheln: 13,79:1 auf dem Kachelgrund. */
.block-cards .card :is(h3, h4) { color: #fff; }
/* `--muted` (#5f6873) ist ein Ton FUER hellen Grund und kaeme auf dem Kachelgrund auf 2,44:1 —
   durchgefallen. Der Ersatz misst 9,11:1 auf dem Kachelgrund (#2b2d31). */
.block-cards .card p { color: color-mix(in srgb, #ffffff 80%, var(--dark)); }

/* 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; }
}
