/* ==========================================================================
   KNS Beschichtung, Sektionen
   Reihenfolge entspricht der Seite von oben nach unten.

   Rhythmus wie bei Rost Racing: alles steht auf #121212, Text-Sektionen
   wechseln sich mit dunklen Bild-Bannern ab. Die Banner sind die
   Atempausen, keine Trennlinien, keine Kaesten.
   ========================================================================== */

/* --- Ankuendigungsleiste -------------------------------------------------- */

.announce {
  display: grid;
  place-items: center;
  min-height: var(--announce-h);
  padding: 0.4rem var(--gutter);
  background: var(--bg-deep);
  color: var(--text);
  font-size: 0.875rem;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-align: center;
}

@media (max-width: 600px) {
  .announce-more {
    display: none;
  }
}

/* --- Header --------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: rgba(18, 18, 18, 0.94);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
}

/* Unschaerfe hinter dem Header kostet auf Handys bei jedem Scroll-Frame
   Rechenzeit. Mobil deshalb eine volle Flaeche, optisch kaum ein Unterschied.

   Diese Regeln standen bis zum 28.09.2026 VOR dem Block darueber und haben
   deshalb nie gegriffen: gleiche Staerke, und die spaetere Regel gewinnt.
   Zu sehen war es an den 6 Prozent Durchsichtigkeit - beim Scrollen lief der
   Text der Seite als Schatten durch den Header. */
@media (max-width: 900px) {
  .site-header {
    background: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

.header-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: var(--header-h);
  transition: height var(--dur) var(--ease);
}

.site-header.is-stuck .header-inner {
  height: calc(var(--header-h) - 12px);
}

.header-left {
  justify-self: start;
  margin-left: -10px;
}

.header-right {
  justify-self: end;
  display: flex;
  gap: 4px;
  margin-right: -10px;
}

/* Logo-Lockup nach Rost-Vorbild: "ROST (RR) RACING" wird zu
   "KNS (Schaedel) BESCHICHTUNG". Das Zeichen sitzt mittig, die Woerter
   stehen breit gesperrt links und rechts daneben. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  min-height: 44px;
  color: var(--text);
  text-decoration: none;
  line-height: 1;
}

.brand-mark {
  width: 58px;
  height: auto;
  transition: width var(--dur) var(--ease);
}

.site-header.is-stuck .brand-mark {
  width: 48px;
}

.brand-word {
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: var(--track-logo);
  text-transform: uppercase;
}

/* Die Laufweite haengt auch hinter dem letzten Buchstaben Luft an. Ohne
   Ausgleich stuende "KNS" optisch weiter vom Zeichen weg als "BESCHICHTUNG". */
.brand-word:first-child {
  margin-right: calc(-1 * var(--track-logo));
}

.brand-word--small {
  font-size: 0.9375rem;
}

@media (max-width: 720px) {
  .brand {
    --track-logo: 0.22em;
    gap: 0.55rem;
  }

  .brand-mark,
  .site-header.is-stuck .brand-mark {
    width: 42px;
  }

  .brand-word {
    font-size: 0.8125rem;
  }

  .brand-word--small {
    font-size: 0.75rem;
    letter-spacing: 0.16em;
  }

  /* Anrufen und WhatsApp stehen mobil in der festen Leiste unten. */
  .header-right .hide-mobile {
    display: none;
  }
}

/* --- Menue (Seitenleiste von links, wie bei Rost) ------------------------- */

.drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  visibility: hidden;
}

.drawer.is-open {
  visibility: visible;
}

.drawer-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}

.drawer.is-open .drawer-backdrop {
  opacity: 1;
}

.drawer-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  width: min(400px, 88vw);
  background: var(--bg);
  border-right: 1px solid var(--line);
  transform: translateX(-100%);
  transition: transform var(--dur) var(--ease);
}

.drawer.is-open .drawer-panel {
  transform: none;
}

.drawer-top {
  display: flex;
  align-items: center;
  height: var(--header-h);
  padding-inline: calc(var(--pad-l) - 10px);
  border-bottom: 1px solid var(--line);
}

.drawer-nav {
  flex: 1;
  overflow-y: auto;
  padding-block: 1rem;
}

.drawer-nav a {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.75rem var(--gutter) 0.75rem var(--pad-l);
  color: var(--text);
  font-size: 1.25rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color var(--dur) var(--ease);
}

.drawer-nav a:hover,
.drawer-group:hover {
  background: rgba(255, 255, 255, 0.05);
}

.drawer-nav a svg,
.drawer-group svg {
  width: 18px;
  height: 18px;
  opacity: 0.6;
}

/* "Leistungen" klappt die vier Verfahren auf (Kevins Wunsch: draufklicken,
   dann aufgelistet). Auf einer Leistungsseite ist die Gruppe schon offen. */
.drawer-group {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 0.75rem var(--gutter) 0.75rem var(--pad-l);
  border: 0;
  background: none;
  color: var(--text);
  font-size: 1.25rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}

.drawer-group svg {
  transform: rotate(90deg);
  transition: transform var(--dur) var(--ease);
}

.drawer-group[aria-expanded='true'] svg {
  transform: rotate(-90deg);
}

.drawer-sub {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease);
}

.drawer-sub.is-open {
  grid-template-rows: 1fr;
}

.drawer-sub > ul {
  min-height: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  list-style: none;
  visibility: hidden;
  transition: visibility 0s linear var(--dur);
}

/* "inherit" statt "visible": sonst waeren die Links auch im geschlossenen
   Menue (visibility: hidden) per Tab erreichbar. */
.drawer-sub.is-open > ul {
  visibility: inherit;
  transition-delay: 0s;
}

.drawer-nav .drawer-sub a {
  justify-content: flex-start;
  padding-block: 0.55rem;
  padding-left: calc(var(--pad-l) + 1.1rem);
  font-size: 1rem;
  color: var(--text-body);
}

.drawer-nav .drawer-sub a::before {
  content: '';
  width: 10px;
  height: 5px;
  margin-right: 0.75rem;
  background: currentColor;
  clip-path: var(--shape-slant);
  opacity: 0.5;
}

.drawer-nav .drawer-sub a[aria-current='page'] {
  color: var(--text);
}

.drawer-nav .drawer-sub a[aria-current='page']::before {
  opacity: 1;
}

.drawer-bottom {
  display: flex;
  gap: 4px;
  padding: 1rem calc(var(--pad-l) - 10px) calc(1rem + env(safe-area-inset-bottom));
  background: var(--bg-deep);
  border-top: 1px solid var(--line);
}

/* --- Hero -----------------------------------------------------------------
   Aufbau von hinten nach vorne:
     .hero-film    langsame Bildfahrt aus Kevins Arbeiten (statt Video)
     .hero-light   Spotlicht und Vignette darueber
     .hero-beam    Lichtkegel von oben, wandert leicht hin und her
     .hero-dust    Pulverstaub im Licht (Canvas)
     .hero-object  das Teil: mittig, gross, Drehung, Schweben, Glanzlicht
     .hero-grain   Filmkorn, zittert leicht
     .hero::after  Verlauf, damit der Text immer lesbar bleibt
     .hero-plate   Titelschild unten: Titelzeile, Haarlinie, Fuss
   Alles, was sich dauerhaft bewegt, laeuft ueber transform und opacity.
   Das rechnet die Grafikkarte, der Hauptprozessor bleibt frei.

   Die Anordnung ist Absicht: Teil in der Mitte, Titel als Zeile ueber die
   volle Breite darunter. Das uebliche "Ueberschrift links, Foto rechts"
   waere zwar einfacher, sieht aber aus wie jede andere Handwerkerseite. */

.hero {
  /* Eigene Hoehe als Variable, weil die Groesse des Teils daraus gerechnet
     wird: es soll nie in das Titelschild hineinragen (siehe --plate-h). */
  --hero-h: clamp(600px, calc(100svh - var(--header-h) - var(--announce-h) - 4px), 980px);
  /* Wie viel Platz unten fuer die Felge gesperrt ist. --foot-h misst hero.js
     (Oberkante der Fusszeile bis Buehnenrand), 120px ist der Rueckfall ohne
     JS. Die Titelzeile darf die Felge ueberlappen, die Fusszeile nicht. */
  --plate-h: var(--foot-h, 120px);
  position: relative;
  display: grid;
  /* Nicht "auto": eine Spalte, die sich nach dem Inhalt richtet, waechst an
     der durchlaufenden Titelzeile ueber die Fensterbreite hinaus. minmax(0,
     1fr) bindet sie an die Buehne, der Text laeuft notfalls darueber hinaus
     statt die Spalte aufzublaehen. */
  grid-template-columns: minmax(0, 1fr);
  align-items: end;
  height: var(--hero-h);
  overflow: hidden;
  isolation: isolate;
  background: var(--bg-deep);
}

.hero-stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  perspective: 1400px;
}

/* Bildfahrt ganz hinten. Drei Aufnahmen blenden ineinander, jede faehrt
   dabei langsam weiter (wie eine ruhige Kamerafahrt). Die Bilder haengt
   hero.js erst nach dem ersten Bildaufbau ein, vorher ist die Ebene leer.
   .is-on startet die Schleife, damit nichts mitten im Bild anspringt.

   Beim Scrollen wandert die ganze Ebene ein Stueck mit (--sy von hero.js).
   Der Rand von -8 Prozent gibt dafuer Luft, ohne dass eine Kante auftaucht. */
.hero-film {
  position: absolute;
  inset: -8% 0;
  overflow: hidden;
  transform: translate3d(0, calc(var(--sy, 0) * 5%), 0);
}

.hero-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--ox, 50%) var(--oy, 50%);
  opacity: 0;
  /* Abgedunkelt und weichgezeichnet: die Ebene ist Atmosphaere, kein Motiv.
     Sie darf der Felge und dem Text nie die Schau stehlen. Die Unschaerfe
     macht aus dem Foto eine Flaeche aus Licht und Farbe. */
  filter: brightness(0.52) saturate(0.7) contrast(1.05) blur(3px);
  will-change: opacity, transform;
}

.hero-film.is-on .hero-frame {
  animation: kns-film-a 33s linear infinite;
}

/* Positive Verzoegerung, nicht negative: Bild 2 und 3 warten auf ihren
   Auftritt, statt mittendrin einzusteigen. Sonst blitzt beim Start kurz das
   letzte Bild mit auf. Danach laeuft jedes alle 33 Sekunden wieder an. */
.hero-film.is-on .hero-frame:nth-child(2) {
  animation-name: kns-film-b;
  animation-delay: 11s;
}

.hero-film.is-on .hero-frame:nth-child(3) {
  animation-name: kns-film-c;
  animation-delay: 22s;
}

/* Spotlicht von oben rechts plus ein schwacher Schein auf dem Boden.
   Die dritte Ebene ist die Vignette: durchscheinend, damit die Bildfahrt
   darunter sichtbar bleibt, zum Rand hin fast deckend. */
.hero-light {
  position: absolute;
  inset: 0;
  /* Warmes Licht, nicht weisses: eine Werkstattlampe ist gelblich. Dazu
     setzt sich das kalte Chrom der Felge erst richtig davon ab. */
  background:
    radial-gradient(ellipse 40% 46% at 50% 30%, rgba(255, 236, 209, 0.16), transparent 72%),
    radial-gradient(ellipse 52% 14% at 50% 74%, rgba(255, 228, 196, 0.06), transparent 70%),
    radial-gradient(ellipse 92% 76% at 50% 36%, rgba(19, 19, 21, 0.44) 0%, rgba(8, 8, 9, 0.92) 74%);
  animation: kns-breathe 9s ease-in-out infinite;
}

/* Lichtkegel aus der Werkstattlampe: ein weicher Keil von oben, der ganz
   langsam pendelt. Weichgezeichnet und nur mit 7 Prozent Weiss, sichtbar
   wird er vor allem durch den Staub, der hindurchfliegt. */
.hero-beam {
  position: absolute;
  top: -28%;
  left: 14%;
  width: 72%;
  height: 128%;
  background: linear-gradient(to bottom, rgba(255, 240, 220, 0.08), rgba(255, 240, 220, 0) 74%);
  clip-path: polygon(40% 0, 60% 0, 100% 100%, 0 100%);
  filter: blur(18px);
  transform-origin: 50% 0;
  animation: kns-beam 19s ease-in-out infinite;
}

.hero-dust {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* Das Teil steht mittig und so gross, wie die Buehne ueber dem Titelschild
   es hergibt: Breite aus der freien Hoehe gerechnet (0.861 ist das Seiten-
   verhaeltnis der Felge), gedeckelt auf 56vw. Der untere Rand darf ruhig ins
   Titelschild reichen, dort loest ihn der Verlauf in .hero::after ins Dunkle
   auf - das ist der Kinoeffekt, kein Versehen.

   Mittig per margin-left, nicht per translate: translate gehoert dem
   Auftritt (.is-ready) und transform der Neigung zur Maus. */
.hero-object {
  /* --stage-top: Luft zum Header, damit die Felge nicht daran klebt.
     --free: was danach ueber dem Titelschild uebrig bleibt. */
  --stage-top: clamp(12px, 3vh, 34px);
  --free: calc(var(--hero-h) - var(--plate-h) - var(--stage-top));
  --w: min(56vw, 820px, calc(var(--free) / 0.861));
  position: absolute;
  left: 50%;
  margin-left: calc(var(--w) / -2);
  /* Der Faktor 0.62 statt 0.5: bleibt Hoehe uebrig, weil die Breite den
     Ausschlag gibt, rutscht die Felge etwas nach unten statt genau in die
     Mitte. Sonst steht sie auf hohen Handys frei im Raum und zwischen ihr
     und dem Titel klafft ein totes Loch. Wo die Hoehe den Ausschlag gibt
     (Desktop), bleibt der Faktor ohne Wirkung - dort ist der Rest null. */
  top: calc(var(--stage-top) + (var(--free) - var(--w) * 0.861) * 0.62);
  width: var(--w);
  transform-style: preserve-3d;
  will-change: transform;
}

/* Drehteller: das Teil dreht ganz langsam hin und her, als stuende es auf
   einem Teller im Fotostudio. Die Perspektive kommt von .hero-stage. Eigene
   Ebene, weil .hero-object schon die Neigung zur Maus traegt. */
.hero-turn {
  transform-style: preserve-3d;
  animation: kns-turn 26s ease-in-out infinite;
}

/* Einblenden, sobald das Bild dekodiert ist (hero.js setzt .is-ready).
   "translate" statt "transform", weil transform fuer die Neigung per Maus
   reserviert ist. */
.js .hero-object {
  opacity: 0;
  translate: 0 40px;
  transition: opacity 1.4s var(--ease), translate 1.8s var(--ease);
}

.js .hero.is-ready .hero-object {
  opacity: 1;
  translate: 0 0;
}

.hero-float {
  position: relative;
  animation: kns-float 10s ease-in-out infinite;
}

.hero-part {
  position: relative;
  aspect-ratio: 1400 / 1205;
}

.hero-part img {
  width: 100%;
  height: 100%;
}

/* Glanzlicht: ein weicher, schraeger Lichtstreifen wandert ueber das Teil.
   Die Maske ist das Teil selbst, das Licht landet also nur auf Metall und
   nie auf dem Hintergrund. Bewusst OHNE mix-blend-mode: Blend-Modi auf
   maskierten, animierten Ebenen flackern in Safari (ganze Felge wird kurz
   dunkel). Normales Ueberblenden mit Weiss sieht aus wie ein Lichtreflex. */
.hero-sheen {
  position: absolute;
  inset: 0;
  overflow: hidden;
  -webkit-mask-image: var(--mask);
  mask-image: var(--mask);
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.hero-sheen::before {
  content: '';
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 46%;
  /* Waagerechter Verlauf, die Schraege kommt nur vom skewX. Ein schraeger
     Verlauf in einem hohen, schmalen Streifen beginnt oben nicht bei 0 und
     zeichnet dort eine harte Kante. */
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.06) 24%,
    rgba(255, 255, 255, 0.42) 50%,
    rgba(255, 255, 255, 0.06) 76%,
    rgba(255, 255, 255, 0) 100%);
  transform: translateX(-160%) skewX(-16deg);
  animation: kns-sheen 10s var(--ease) 1.6s infinite;
}

/* Filmkorn. Liegt ueber allem in der Buehne und springt sechsmal je Sekunde
   ein Stueck weiter - deshalb steps(1): kein Gleiten, sondern das Zittern
   einer Filmkopie. Bewegt wird nur per transform, gezeichnet wird das Korn
   genau einmal. Die Ebene ist absichtlich groesser als die Buehne, damit
   beim Springen keine Kante hereinwandert.

   Das Korn kommt erst nach dem Laden dazu (.is-grainy setzt hero.js).
   Sonst zaehlt der Browser diese grosse Flaeche als groesstes Bildelement
   der Seite: im Test sprang der Messwert LCP dadurch von 2,9 auf 3,8
   Sekunden und die Bewertung von 95 auf 87. Dasselbe Spiel wie bei der
   Bildfahrt - Atmosphaere darf die Ladezeit nicht bestimmen. */
.hero-grain {
  position: absolute;
  inset: -8%;
  opacity: 0;
  transition: opacity 0.6s linear;
}

/* will-change erst hier: sonst haelt der Browser von Anfang an eine eigene
   Grafikebene fuer eine Flaeche vor, die noch gar nichts zeigt. */
.hero.is-grainy .hero-grain {
  opacity: 0.14;
  will-change: transform;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: kns-grain 1.1s steps(1, end) infinite;
}

/* Zwei Verlaeufe: unten die Titelzone abdunkeln, damit die Zeile auf jedem
   Bild steht und der untere Rand der Felge ins Dunkle laeuft. Dazu eine
   weiche Randabdunklung, die den Blick in der Mitte haelt. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(0deg, rgba(0, 0, 0, 0.96) 0%, rgba(0, 0, 0, 0.92) 18%, rgba(0, 0, 0, 0.62) 32%,
      rgba(0, 0, 0, 0.2) 46%, transparent 62%),
    radial-gradient(ellipse 80% 68% at 50% 36%, transparent 0%, rgba(0, 0, 0, 0.55) 100%);
  pointer-events: none;
}

/* --- Titelschild ---------------------------------------------------------
   Laeuft bis an die Seitenraender, nicht im Textraster (.container). Die
   Titelzeile soll die ganze Breite fuellen, alles andere richtet sich an
   ihren Kanten aus. */
.hero-plate {
  position: relative;
  z-index: 2;
  padding: 0 var(--pad-r) clamp(1.5rem, 4vh, 2.75rem) var(--pad-l);
}

/* Schriftgroesse setzt hero.js (--fit), sobald die Schrift geladen ist: die
   Zeile passt dann genau von Rand zu Rand.

   Der clamp() darunter ist der Rueckfall ohne JS. Er ist absichtlich dicht
   am gemessenen Wert (fuer den jetzigen Titel 5,23vw): waere er deutlich
   kleiner, wuerde die Zeile beim Nachmessen sichtbar springen, und genau
   das zaehlt Google als Layoutsprung (CLS). Wer den Titel aendert und laenger
   macht, sollte den Wert hier mit anpassen - mit JS stimmt die Groesse
   ohnehin, ohne JS liefe die Zeile sonst ueber den Rand. */
.hero-title {
  margin: 0;
  font-size: var(--fit, clamp(2.25rem, 5.15vw, 5.5rem));
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  color: var(--text);
}

.hero-title-in {
  display: inline-block;
  white-space: nowrap;
}

/* Haarlinie unter dem Titel, ueber die volle Breite und an beiden Enden
   ausgeblendet: eine harte Kante am Bildrand wirkt wie ein Strich zu viel. */
.hero-foot {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-top: clamp(1rem, 2.4vh, 1.5rem);
  padding-top: clamp(1rem, 2.4vh, 1.5rem);
}

.hero-foot::before {
  content: '';
  position: absolute;
  top: 0;
  left: calc(var(--pad-l) * -1);
  right: calc(var(--pad-r) * -1);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3) 10%,
    rgba(255, 255, 255, 0.3) 90%, transparent);
}

.hero-sub {
  max-width: 44rem;
  margin: 0;
  font-size: var(--fs-lead);
  color: rgba(255, 255, 255, 0.94);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* Text-Auftritt beim Laden: die Woerter des Titels gleiten nacheinander aus
   einer Maske nach oben, der Rest blendet gestaffelt ein. Nur mit JS, ohne
   JS steht alles sofort. */
.js .hero-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  padding-bottom: 0.08em;
  margin-bottom: -0.08em;
}

.js .hero-word > span {
  display: block;
  transform: translateY(110%);
  animation: kns-rise 1s var(--ease) forwards;
  animation-delay: calc(0.15s + var(--i) * 0.11s);
}

.js .hero-in {
  opacity: 0;
  transform: translateY(14px);
  animation: kns-fade-up 0.9s var(--ease) forwards;
  animation-delay: calc(0.2s + var(--i) * 0.09s);
}

/* Hero ausserhalb des Sichtfelds oder Tab im Hintergrund: nichts rechnet mehr.
   Das ist die einzige Pause, die es noch gibt - einen Knopf dafuer wollte
   Kevin nicht, die Buehne soll laufen, solange man sie ansieht. */
.hero.is-offscreen .hero-light,
.hero.is-offscreen .hero-beam,
.hero.is-offscreen .hero-frame,
.hero.is-offscreen .hero-turn,
.hero.is-offscreen .hero-float,
.hero.is-offscreen .hero-sheen::before,
.hero.is-offscreen .hero-grain {
  animation-play-state: paused;
}

/* Ein ruhiger Lichtzug alle zehn Sekunden, dazwischen steht das Teil still. */
@keyframes kns-sheen {
  0% { transform: translateX(-160%) skewX(-16deg); }
  40%,
  100% { transform: translateX(260%) skewX(-16deg); }
}

@keyframes kns-float {
  0%,
  100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

/* Ein Viertelgrad pro Sekunde. Man sieht die Drehung nicht anlaufen, nur
   dass das Bild nach ein paar Sekunden anders steht. */
@keyframes kns-turn {
  0%,
  100% { transform: rotateY(-7deg) rotateX(0.9deg); }
  50% { transform: rotateY(7deg) rotateX(-0.9deg); }
}

@keyframes kns-beam {
  0%,
  100% { transform: rotate(-2.6deg); }
  50% { transform: rotate(2.6deg); }
}

/* Bildfahrt. Drei Varianten, damit nicht dreimal dieselbe Kamerabewegung
   kommt: hineinfahren, seitlich ziehen, herausfahren.

   Die Zahlen greifen ineinander: ein Bild ist von 0 bis 40,3 Prozent zu
   sehen (33,3 Prozent = elf Sekunden, plus die Ueberblendung). Das naechste
   startet genau bei 33,3 Prozent. Waehrend es aufblendet, blendet das
   vorige im selben Takt ab, zusammen ergeben sie immer volle Deckung.
   Wer die Zeiten aendert, muss beide Enden gleich verschieben, sonst wird
   es zwischen zwei Bildern kurz dunkel. */
@keyframes kns-film-a {
  0% { opacity: 0; transform: scale(1.05) translate3d(0, 1%, 0); }
  7% { opacity: 1; }
  33.3% { opacity: 1; }
  40.3% { opacity: 0; }
  41%,
  100% { opacity: 0; transform: scale(1.28) translate3d(-2%, -1.5%, 0); }
}

@keyframes kns-film-b {
  0% { opacity: 0; transform: scale(1.24) translate3d(3.5%, 1%, 0); }
  7% { opacity: 1; }
  33.3% { opacity: 1; }
  40.3% { opacity: 0; }
  41%,
  100% { opacity: 0; transform: scale(1.24) translate3d(-3.5%, -1%, 0); }
}

@keyframes kns-film-c {
  0% { opacity: 0; transform: scale(1.3) translate3d(-1.5%, 1.5%, 0); }
  7% { opacity: 1; }
  33.3% { opacity: 1; }
  40.3% { opacity: 0; }
  41%,
  100% { opacity: 0; transform: scale(1.06) translate3d(1%, -1%, 0); }
}

@keyframes kns-breathe {
  0%,
  100% { opacity: 0.85; }
  50% { opacity: 1; }
}

/* Sechs Sprungbilder je Runde. Die Werte sind krumm, damit das Korn nicht
   in einen erkennbaren Takt faellt. */
@keyframes kns-grain {
  0% { transform: translate3d(0, 0, 0); }
  16% { transform: translate3d(-3%, 2%, 0); }
  33% { transform: translate3d(2.5%, -2.5%, 0); }
  50% { transform: translate3d(-2%, -3%, 0); }
  66% { transform: translate3d(3%, 1.5%, 0); }
  83% { transform: translate3d(-1.5%, 3%, 0); }
}

@keyframes kns-rise {
  to { transform: none; }
}

@keyframes kns-fade-up {
  to { opacity: 1; transform: none; }
}

/* Die Klasse fuer ein spaeteres Makro-Video (siehe README). */
.hero-media {
  position: absolute;
  inset: 0;
}

.hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 900px) {
  /* Mobil muss alles in die Hoehe zwischen Header und Kontaktleiste passen,
     auch wenn die Safari-Leisten ausgeklappt sind (iPhone 13: ca. 490 px).
     Deshalb:
       - kein Button im Hero, WhatsApp und Anrufen stehen immer unten
       - keine Bildunterschrift, kurzer Untertitel
       - Titel wieder in drei Zeilen, dafuer gross
       - Groesse der Felge aus der tatsaechlich freien Hoehe gerechnet
         (Hero-Hoehe minus Titelschild), nie breiter als 78vw */
  .hero {
    --hero-h: max(380px, calc(100svh - var(--header-h) - var(--announce-h) - 4px - var(--mobilebar-h)));
    --plate-h: 240px;
  }

  /* 88vw statt 78: auf hohen Handys (Pixel 7 und aehnlich) gibt die Breite
     den Ausschlag, nicht die Hoehe - dort stand die Felge sonst klein im
     Raum und zwischen ihr und dem Titel klaffte ein totes Loch.

     sizes am Bild in index.html steht bewusst NICHT auf 88vw, sondern auf
     78vw: meist begrenzt die Hoehe, die Felge wird also gar nicht so breit.
     Die Begruendung steht dort im Kommentar. */
  .hero-object {
    --w: min(88vw, 520px, calc(var(--free) / 0.861));
  }

  /* Drei Zeilen statt einer: quer passt "Hochglanz. Pulver. Strahlen." nicht
     nebeneinander. Nie trennen ("HOCH-GLANZ.") und so skalieren, dass das
     laengste Wort auch auf 320 px Breite in eine Zeile passt. */
  .hero-title-in {
    white-space: normal;
  }

  .hero-title-in .hero-word {
    display: block;
  }

  .hero-title {
    font-size: clamp(2rem, 11vw, 3.5rem);
    -webkit-hyphens: manual;
    hyphens: manual;
  }

  .hero-light {
    background:
      radial-gradient(ellipse 70% 34% at 50% 22%, rgba(255, 236, 209, 0.15), transparent 72%),
      radial-gradient(ellipse 120% 70% at 50% 24%, rgba(19, 19, 21, 0.42) 0%, rgba(8, 8, 9, 0.9) 72%);
  }

  /* Hochkant steht die Felge mittig, der Lichtkegel kommt von oben mittig. */
  .hero-beam {
    top: -22%;
    left: 6%;
    width: 88%;
    filter: blur(14px);
  }

  .hero::after {
    background:
      linear-gradient(0deg, rgba(0, 0, 0, 0.95) 0%, rgba(0, 0, 0, 0.88) 32%, rgba(0, 0, 0, 0.3) 52%, transparent 66%),
      radial-gradient(ellipse 110% 58% at 50% 26%, transparent 0%, rgba(0, 0, 0, 0.5) 100%);
  }

  .hero-plate {
    padding-bottom: 1.25rem;
  }

  .hero-foot {
    margin-top: 0.9rem;
    padding-top: 0.9rem;
  }

  .hero-sub {
    font-size: var(--fs-body);
    line-height: 1.6;
  }

  .hero-sub-more,
  .hero-actions {
    display: none;
  }

  /* Der Titel ist am Handy das groesste Element beim Laden (LCP). Er steht
     deshalb sofort da, statt erst nach einer Verzoegerung hineinzugleiten.
     Felge und Untertitel blenden weiter sanft ein. */
  .js .hero-word > span {
    transform: none;
    animation: none;
  }
}

/* Sehr kleine Displays (iPhone SE und aehnlich): weniger Hoehe fuer das
   Titelschild, damit die Felge nicht zusammenschrumpft. */
@media (max-width: 900px) and (max-height: 620px) {
  .hero {
    --plate-h: 180px;
  }
}

/* --- Handy quer -----------------------------------------------------------
   Nur 320 bis 430 px Hoehe. Ohne diese Regeln fressen Ankuendigung, Header
   und Kontaktleiste die halbe Hoehe und der Titel wird abgeschnitten.
   Deshalb: Ankuendigung und Kontaktleiste weg (WhatsApp und Anrufen stehen
   im Header), Titel wieder einzeilig, Titelschild flach, Felge klein. */

@media (max-width: 1000px) and (max-height: 500px) and (orientation: landscape) {
  .announce {
    display: none;
  }

  .header-right .hide-mobile {
    display: inline-grid;
  }

  .hero {
    --hero-h: max(260px, calc(100svh - var(--header-h) - 4px));
    --plate-h: var(--foot-h, 60px);
  }

  .hero-object {
    --stage-top: 10px;
    --w: min(52vw, calc(var(--free) / 0.861));
  }

  /* Quer ist wieder Platz fuer die durchlaufende Zeile. */
  .hero-title-in {
    white-space: nowrap;
  }

  .hero-title-in .hero-word {
    display: inline-block;
  }

  .hero-title {
    font-size: var(--fit, clamp(1.5rem, 4.4vw, 2.5rem));
  }

  .hero-sub-more {
    display: none;
  }

  .hero-plate {
    padding-bottom: 0.9rem;
  }

  .hero-foot {
    margin-top: 0.7rem;
    padding-top: 0.7rem;
  }

  .hero-sub {
    font-size: 0.9375rem;
    line-height: 1.55;
  }
}

/* Wer im Betriebssystem "Bewegung reduzieren" eingestellt hat, bekommt ein
   stehendes Bild. Die Bildfahrt laedt hero.js dann gar nicht erst. */
@media (prefers-reduced-motion: reduce) {
  .hero-float,
  .hero-light,
  .hero-beam,
  .hero-turn,
  .hero-sheen::before {
    animation: none;
  }

  /* Diese beiden bekommen ihre Animation weiter oben ueber ZWEI Klassen
     (.hero-film.is-on / .hero.is-grainy). Eine Ausnahme mit nur einer Klasse
     verliert dagegen, egal wie weit unten sie steht - deshalb hier dieselben
     Selektoren noch einmal. Wer oben eine Klasse ergaenzt, muss sie auch hier
     ergaenzen, sonst laeuft die Ebene trotz "Bewegung reduzieren" weiter. */
  .hero-film.is-on .hero-frame,
  .hero.is-grainy .hero-grain {
    animation: none;
  }

  .hero-film {
    transform: none;
  }
}

/* --- Aus der Werkstatt: Karussell mit Parallelogramm-Karten ---------------
   Rosts Produkt-Karussell, bei KNS mit Arbeiten statt Produkten. Klick
   oeffnet das Bild gross (Vollbild-Galerie weiter unten). */

/* Kartenbreite ueber die Zahl der sichtbaren Karten. Die angeschnittene
   Karte am rechten Rand bleibt, sie zeigt, dass es weitergeht (wie bei
   Rost). Wer hier etwas aendert, muss auch sizes bei den sechs Bildern in
   index.html anpassen, sonst laedt der Browser die falsche Groesse.
   Dieser Wert gilt fuer schmale Laptops (1025 bis 1399 px). */
.slider {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 3 * var(--gap)) / 3.6);
  gap: var(--gap);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--pad-l) var(--pad-r);
  padding-inline: var(--pad-l) var(--pad-r);
  padding-bottom: 0.5rem;
  scrollbar-width: none;
}

.slider::-webkit-scrollbar {
  display: none;
}

/* Mit der Maus ziehen (site.js). Waehrend des Ziehens kein Einrasten und
   keine Klicks auf Karten, sonst oeffnet jedes Ziehen einen Link. */
.slider.is-draggable {
  cursor: grab;
}

.slider.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none;
}

.slider.is-dragging .card {
  pointer-events: none;
}

/* Ab Laptop-Breite fuenf Karten auf einen Blick (Kevin, 22.09.2026). Die
   0,15 extra sind der Anschnitt der sechsten: ohne ihn sieht es aus, als
   waere die Reihe zu Ende.

   Das Karussell laeuft bewusst bis an den Bildschirmrand statt buendig mit
   dem 1200-px-Raster der Texte. Sonst blieben auf einem 1440er MacBook links
   und rechts je 120 px leer, und es passten nur vier Karten ins Bild. */
@media (min-width: 1200px) {
  .slider {
    grid-auto-columns: calc((100% - 4 * var(--gap)) / 4.15);
  }
}

@media (min-width: 1360px) {
  .slider {
    grid-auto-columns: calc((100% - 5 * var(--gap)) / 5.15);
  }
}

@media (max-width: 1024px) {
  .slider {
    grid-auto-columns: calc((100% - 2 * var(--gap)) / 2.15);
  }
}

/* Am Handy kein Karussell, sondern zwei Karten pro Reihe untereinander
   (Leandro, 27.09.2026). Vorher lag eine 84 % breite Karte im Bild und man
   musste fuenfmal wischen, um alle sechs Themen zu sehen. Jetzt stehen alle
   auf einmal da, jede halb so breit.

   Drei Sachen muessen dafuer zurueckgenommen werden:
   - grid-auto-flow: row hebt die Spalten-Automatik von oben auf, sonst
     laufen die Karten weiter alle in eine Zeile.
   - overflow-x und scroll-snap muessen weg. Zu scrollen gibt es nichts
     mehr, aber overflow-x: auto macht den Block trotzdem zum
     Scrollbehaelter, und der schneidet ab, was herausragt.
   Die Knoepfe unter dem Karussell fallen dazu weg (weiter unten bei
   .slider-controls, dort muss die Regel stehen, sonst gewinnt das
   display: flex von da).

   Das sizes der sechs Bilder passt danach: dort steht fuer bis 600 px 51vw,
   und eine Karte ist jetzt rund 45vw breit. Vorher waren es echte 84vw - da
   war der Wert zu klein und der Browser hat eine Stufe zu wenig geladen. */
@media (max-width: 600px) {
  .slider {
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem 0.75rem;
    overflow-x: visible;
    scroll-snap-type: none;
    padding-bottom: 0;
  }

  /* Ziehen mit der Maus greift am Handy ohnehin nicht, aber ein schmales
     Fenster am Rechner bekaeme sonst die Greifhand als Zeiger, obwohl es
     nichts zu ziehen gibt. */
  .slider.is-draggable {
    cursor: default;
  }

  .slider .card-media {
    margin-bottom: 0.9rem;
  }

  /* Halb so breite Karte, also auch kleinere Unterschrift: bei 19 px
     zerfiel "Hochglanzverdichtet" in drei Trennungen. */
  .slider .card-title {
    font-size: var(--fs-body);
  }

  .slider .card-text {
    font-size: 0.8125rem;
  }
}

.card {
  position: relative;
  margin: 0;
  scroll-snap-align: start;
  text-align: center;
  text-decoration: none;
  color: inherit;
}

.card-media {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  margin-bottom: 1.1rem;
  overflow: hidden;
  border-radius: var(--radius-card);
  clip-path: var(--shape-slant);
  background: var(--bg-deep);
}

/* Leicht hineingezoomt: Kevins Fotos haben rundum schwarzen Rand, dadurch
   wirkt das Teil sonst klein in der Karte. */
.card-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.06);
  transition: opacity var(--dur-slow) var(--ease), transform 1.2s var(--ease);
}

/* Hover wie bei Rost: das zweite Bild blendet ueber. Spaeter ideal fuer
   vorher/nachher desselben Teils. */
.card-media .img-alt {
  opacity: 0;
}

/* Lichtstreifen ueber die Karte beim Hover, wie das Glanzlicht im Hero. */
.card-media::after {
  content: '';
  position: absolute;
  top: -10%;
  bottom: -10%;
  left: 0;
  width: 38%;
  background: linear-gradient(100deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0));
  transform: translateX(-200%) skewX(-16deg);
  pointer-events: none;
}

@media (hover: hover) {
  .card:hover .card-media::after {
    transform: translateX(360%) skewX(-16deg);
    transition: transform 1.1s var(--ease);
  }

  .card.is-bereit:hover .card-media .img-alt {
    opacity: 1;
  }

  .card:hover .card-media img {
    transform: scale(1.12);
  }

  .card:hover .card-title {
    text-decoration: underline;
    text-underline-offset: 4px;
    text-decoration-thickness: 1px;
  }
}

.card-media[data-lightbox] {
  cursor: zoom-in;
}

/* Am Handy gibt es kein Hover. Damit die zweite Aufnahme trotzdem
   erreichbar ist, zeigt sie sich, solange der Finger auf der Karte liegt -
   ohne Ueberblendung, sonst ist der Tipp vorbei, bevor man etwas sieht. */
@media (hover: none) {
  /* .is-gedrueckt statt :active - warum, steht in site.js. */
  .card.is-bereit.is-gedrueckt .card-media .img-alt {
    opacity: 1;
    transition: none;
  }

  .card.is-gedrueckt .card-media::after {
    transform: translateX(360%) skewX(-16deg);
    transition: transform 0.7s var(--ease);
  }
}

/* --- Galerieseite ---------------------------------------------------------
   Die Themenkarten auf der Startseite fuehren hierher, jede auf ihren
   Abschnitt. Gleiche Karten wie im Karussell, nur im Raster statt in einer
   Reihe - dadurch muss nichts doppelt gestaltet werden. */

.gal {
  max-width: 1180px;
}

.gal > h1 {
  margin-bottom: 0.75rem;
}

.gal > .lead {
  max-width: 52ch;
}

.gal .ki-hinweis {
  margin-top: 1.25rem;
}

/* Sprungmarken: eine Reihe flacher Knoepfe, am Handy waagerecht scrollbar. */
.gal-sprung {
  margin: clamp(2rem, 5vw, 2.75rem) 0 0;
}

.gal-sprung ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.gal-sprung a {
  display: inline-block;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: var(--fs-small);
  color: var(--text-body);
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}

.gal-sprung a:hover,
.gal-sprung a:focus-visible {
  border-color: var(--line-strong);
  color: var(--text);
}

.gal-block {
  margin-top: clamp(2.75rem, 7vw, 4.5rem);
  /* Damit der Kopf beim Sprung nicht unter dem Header klebt. */
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
}

.gal-kopf {
  margin-bottom: clamp(1.25rem, 3vw, 1.75rem);
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--line);
}

.gal-kopf h2 {
  margin: 0;
  font-size: clamp(1.5rem, 3.4vw, 2rem);
}

.gal-kopf p {
  margin: 0.35rem 0 0;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.gal-raster {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: clamp(1rem, 2.5vw, 1.75rem);
}

.gal-raster .card-media {
  margin-bottom: 0.9rem;
}

.gal-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: clamp(3rem, 8vw, 5rem);
}

@media (max-width: 600px) {
  .gal-raster {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
  }
}

.card-title {
  display: block;
  margin-bottom: 0.2rem;
  color: var(--text);
  font-size: var(--fs-h3);
  font-weight: 500;
  line-height: 1.35;
}

.card-text {
  display: block;
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--text-muted);
}

/* Im Galerie-Raster sind die Spalten am kleinen Handy nur noch rund 138 px
   breit. Woerter wie "Glasperlengestrahlt" passen da nicht in eine Zeile und
   haben die Seite um 15 px ueber den Rand geschoben.

   Getrennt wird seit dem 10.10.2026 NUR an den &shy; im HTML, also an der
   Wortfuge ("Glasperlen-gestrahlt", "Motor-gehaeuse"). Vorher trennte der
   Browser selbst (hyphens: auto mit Grenzwerten 12 5 5). Chrome haelt sich
   an die Grenzen, Safari nicht: Es liest -webkit-hyphenate-limit-before/
   after zwar ein (CSS.supports sagt ja), trennte aber trotzdem "Galva-nik",
   "zweifar-big", "Pulverbe-schichtet", "Motorge-haeuse" (gemessen in WebKit
   bei 320 bis 430 px). Mit festen Trennstellen sieht es auf jedem Handy
   gleich aus.

   Wer einen Kartentext aendert: jedes Wort ab etwa 11 Buchstaben bekommt
   ein &shy; an der Fuge. anywhere bleibt als Notbremse, damit nie etwas
   ueber den Rand laeuft - bricht dann aber ohne Strich. */
.card-title,
.card-text {
  overflow-wrap: anywhere;
  -webkit-hyphens: manual;
  hyphens: manual;
}

.slider-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.75rem;
  font-size: var(--fs-small);
  color: var(--text-body);
}

.slider-controls .icon-btn svg {
  width: 18px;
  height: 18px;
}

.slider-controls .icon-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

.slider-count {
  min-width: 3.5ch;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* Am Handy steht das Karussell als Raster (oben bei .slider), da gibt es
   nichts zu blaettern: die Pfeile waeren zwei tote Tasten und die Zaehlung
   bliebe fuer immer bei "1 / 6". Die Regel muss hier unten stehen und nicht
   oben im Handy-Block, sonst gewinnt das display: flex von .slider-controls,
   weil es in der Datei spaeter kommt. */
@media (max-width: 600px) {
  .slider-controls {
    display: none;
  }
}

.works-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2rem;
}

/* --- Leistungen: ruhige Liste ---------------------------------------------
   Vier Verfahren untereinander, jedes fuehrt auf seine eigene Seite mit
   der Anfrage-Vorlage. Kleines schraeges Vorschaubild haelt das
   Racing-Motiv, sonst nur Typografie und feine Linien. */

.section-head p {
  margin-top: 1rem;
  font-size: var(--fs-lead);
}

/* Kennzeichnung der KI-bearbeiteten Bilder (Art. 50 KI-VO).

   So leise wie vertretbar: eine kurze Zeile, kleiner als Fliesstext und
   gedaempft in der Farbe. Die Erklaerung steht vollstaendig auf /ki-bilder/,
   hier steht nur der Verweis darauf.

   Warum sie trotzdem hier steht und nicht nur im Fuss: Art. 50 Abs. 5
   verlangt die Kennzeichnung "spaetestens zum Zeitpunkt der ersten
   Exposition". Wer nur im Fuss verlinkt, erreicht den Besucher erst, nachdem
   er die Bilder gesehen hat. Wer weiter kuerzen will, kuerzt den Text -
   nicht den Ort.

   Der Link bleibt bewusst mitten im Satz: eine komplett verlinkte Zeile ist
   nur 18 px hoch und faellt damit unter die 44-px-Regel fuer Tippflaechen
   (pruefen.mjs meldet das). Satzinterne Links sind davon ausgenommen. */
/* Die zweite Zeile im Selektor ist noetig: .section-head p setzt die
   Vorspann-Groesse und wuerde sonst gewinnen (zwei Stellen gegen eine). */
.ki-hinweis,
.section-head .ki-hinweis {
  max-width: 60ch;
  margin-top: 0.9rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.ki-hinweis a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.28);
  text-underline-offset: 0.25em;
  white-space: nowrap;
  transition: color var(--dur) var(--ease), text-decoration-color var(--dur) var(--ease);
}

.ki-hinweis a:hover,
.ki-hinweis a:focus-visible {
  color: var(--text);
  text-decoration-color: currentColor;
}

/* Auf den Leistungsseiten steht die Zeile unter dem Zickzack, frei im
   Textraster. Etwas Luft nach oben, aber keine Trennlinie mehr - die machte
   aus einem Nebensatz einen eigenen Abschnitt. */
.ki-hinweis--seite {
  margin: clamp(1.75rem, 4vw, 2.5rem) auto 0;
}

.services {
  max-width: 980px;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.service {
  position: relative;
  display: grid;
  grid-template-columns: 2.5rem 96px 1fr auto;
  align-items: center;
  gap: clamp(1rem, 3vw, 2.25rem);
  padding: 1.1rem clamp(0.25rem, 1.5vw, 1rem);
  border-bottom: 1px solid var(--line);
  color: inherit;
  text-decoration: none;
}

.service::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0));
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease);
  pointer-events: none;
}

.service-num {
  font-size: var(--fs-small);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.service-thumb {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 10px;
  clip-path: var(--shape-slant);
  background: radial-gradient(ellipse at 50% 30%, #232325 0%, var(--bg-deep) 75%);
}

.service-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.2s var(--ease);
}

.service-thumb .ph-logo {
  position: absolute;
  inset: 0;
  width: 56%;
  height: auto;
  margin: auto;
  object-fit: contain;
  opacity: 0.12;
}

.service-title {
  margin-bottom: 0.25rem;
  font-size: clamp(1.25rem, 1.3vw + 0.85rem, 1.875rem);
  font-weight: 500;
  line-height: 1.2;
  -webkit-hyphens: manual;
  hyphens: manual;
}

.service-text {
  display: block;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: var(--text-muted);
}

.service-arrow {
  width: 26px;
  height: 26px;
  color: var(--text);
  opacity: 0.45;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

.service:focus-visible {
  outline-offset: -2px;
}

@media (hover: hover) {
  .service:hover::before {
    opacity: 1;
  }

  .service:hover .service-arrow {
    opacity: 1;
    transform: translateX(6px);
  }

  .service:hover .service-thumb img {
    transform: scale(1.07);
  }
}

@media (max-width: 600px) {
  .service {
    grid-template-columns: 68px 1fr auto;
    gap: 1rem;
    padding-inline: 0;
  }

  .service-num {
    display: none;
  }

  .service-arrow {
    width: 22px;
    height: 22px;
  }
}

/* --- Bild-Banner ---------------------------------------------------------- */

.banner {
  position: relative;
  height: clamp(260px, 30vw, 440px);
  overflow: hidden;
  background: var(--bg-deep);
}

/* Bild ist hoeher als der Rahmen, site.js verschiebt es beim Scrollen
   langsamer als die Seite (Parallax). */
.banner img {
  position: absolute;
  left: 0;
  top: -12%;
  width: 100%;
  height: 124%;
  object-fit: cover;
  will-change: transform;
}

.banner::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--overlay);
}

/* Am Handy (02.10.2026, Leandro: "Abstaende und Hoehen ein bisschen zu
   gross"): Banner 200 statt 260 px hoch, und die Abschnitte davor und
   danach halten nur noch 40 statt 64 px Abstand zum Bild. Vorher lagen
   zwischen Text und Text rund 390 px, von denen 128 leer waren.
   Muss hinter der Grundregel .banner stehen, sonst gewinnt deren Hoehe. */
@media (max-width: 600px) {
  .banner {
    height: 200px;
  }

  .section:has(+ .banner) {
    padding-bottom: 2.5rem;
  }

  .banner + .section {
    padding-top: 2.5rem;
  }
}


/* --- Ueber KNS ------------------------------------------------------------ */

.about {
  display: grid;
  grid-template-columns: 5fr 6fr;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: center;
}

.about-media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius);
  background: radial-gradient(ellipse at 50% 25%, #232325 0%, var(--bg-deep) 72%);
  display: grid;
  place-items: center;
}

.about-media .ph-logo {
  width: 60%;
  opacity: 0.07;
}

/* Echtes Foto statt Platzhalter-Logo: fuellt den 4:5-Rahmen ganz aus. */
.about-media img:not(.ph-logo) {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about h2 {
  margin-bottom: 1.5rem;
}

.about-media .placeholder-tag {
  position: absolute;
  bottom: 1.25rem;
}

.about blockquote {
  margin: 0 0 1.5rem;
  font-size: var(--fs-lead);
  font-style: italic;
  line-height: 1.7;
  color: var(--text);
}

@media (max-width: 800px) {
  .about {
    grid-template-columns: 1fr;
  }

  .about-media {
    aspect-ratio: 4 / 3;
  }
}

/* Am Handy steht der Text unter dem Foto und nicht daneben. Dann wirkt er
   linksbuendig wie angeklebt, deshalb hier mittig auf einer Achse: kleine
   Zeile, Ueberschrift, Zitat, Text - genauso wie .section-head es auf der
   ganzen Seite macht (Leandro, 27.09.2026).

   Die kleinere Ueberschrift, die hier am 27.09.2026 stand, ist seit dem
   28.09.2026 ueberfluessig: --fs-h2 ist am Handy jetzt ueberall 26 px
   (tokens.css). Geblieben ist nur der engere Abstand darunter, weil der
   Block hier mittig steht und sonst auseinanderfaellt. */
@media (max-width: 600px) {
  .about-text {
    text-align: center;
  }

  .about-text h2,
  .about-text blockquote {
    margin-bottom: 1.1rem;
  }
}

/* --- Leistungsseiten: Zickzack wie Rost "Strahltechnik" -------------------
   Bild und Text im Wechsel, kleine Zeile, Ueberschrift, kurzer Text, ein
   fetter Teaser-Satz, dann "Zur Vorlage". Mobil immer Bild zuerst. */

.page-top {
  padding-top: clamp(2rem, 5vw, 4rem);
}

.crumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 1rem;
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Innenabstand vergroessert nur die Tippflaeche auf 44 px, nicht die Zeile. */
.crumbs a {
  margin-block: -0.9rem;
  padding-block: 0.9rem;
  color: var(--text-body);
  text-decoration: none;
}

.crumbs a:hover {
  color: var(--text);
}

.zz {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 6vw, 5.5rem);
  align-items: center;
}

.zz + .zz {
  margin-top: clamp(3.5rem, 8vw, 6.5rem);
}

.zz--flip .zz-media {
  order: 2;
}

.zz-media {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--bg-deep);
}

.zz-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.zz-media--empty {
  display: grid;
  place-items: center;
  background: radial-gradient(ellipse at 50% 30%, #232325 0%, var(--bg-deep) 72%);
}

.zz-media--empty .ph-logo {
  width: 46%;
  height: auto;
  opacity: 0.08;
}

.zz-media--empty .placeholder-tag {
  position: absolute;
  bottom: 1.25rem;
}

.zz-body {
  max-width: 520px;
}

/* Lange Verfahrensnamen nur an der vorgesehenen Stelle trennen
   ("Pulver-beschichtung", per &shy; im HTML), nie mitten im Wort.
   Seit 11.10.2026 steht die h1 der Leistungsseiten ueber der Vorlage
   (.anfrage-head), die Regel fuer .zz-body bleibt fuer den Fall, dass
   eine Seite wieder mit Bild beginnt. */
.zz-body h1,
.anfrage-head h1 {
  margin-bottom: 1.25rem;
  font-size: clamp(2rem, 1.9vw + 1rem, 2.75rem);
  font-weight: 500;
  line-height: 1.15;
  -webkit-hyphens: manual;
  hyphens: manual;
}

.zz-body h2 {
  margin-bottom: 1.1rem;
}

.zz-teaser {
  margin-top: 1.5rem;
  color: var(--text);
  font-weight: 600;
}

.zz-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
  margin-top: 1.75rem;
}

.zz-actions small {
  font-size: 0.875rem;
  color: var(--text-muted);
}

.zz-list {
  display: grid;
  gap: 1rem;
  margin: 1.5rem 0 0;
}

.zz-list div {
  padding-left: 1rem;
  border-left: 1px solid rgba(255, 255, 255, 0.3);
}

.zz-list dt {
  color: var(--text);
  font-weight: 600;
}

.zz-list dd {
  margin: 0.15rem 0 0;
  font-size: var(--fs-small);
  line-height: 1.65;
}

/* Mobil: Bild zuerst, im Querformat 4:3, damit die Ueberschrift noch auf
   den ersten Bildschirm passt (das Teil sitzt mittig, oben und unten ist
   nur schwarzer Hintergrund). */
@media (max-width: 800px) {
  .zz {
    grid-template-columns: 1fr;
  }

  .zz--flip .zz-media {
    order: 0;
  }

  .zz-media {
    aspect-ratio: 4 / 3;
  }

  .zz-actions .btn {
    flex: 1 1 100%;
  }
}

/* Handy quer: Bild und Text wieder nebeneinander, Bild quadratisch. */
@media (max-width: 1000px) and (max-height: 500px) and (orientation: landscape) {
  .zz {
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 2rem;
  }

  .zz--flip .zz-media {
    order: 2;
  }

  .zz-media {
    aspect-ratio: 1 / 1;
  }

  .zz-actions .btn {
    flex: 0 1 auto;
  }
}

/* Schmale Handys: Die Ueberschrift nennt das Verfahren ohnehin, die
   Brotkrume zeigt nur den Weg zurueck, einzeilig. */
@media (max-width: 480px) {
  .crumbs > [aria-hidden],
  .crumbs > [aria-current] {
    display: none;
  }
}

/* --- Anfrage --------------------------------------------------------------
   Links Ueberschrift, Ablauf und Direktkontakt, rechts die Vorlage.
   Mobil kommt die Vorlage direkt nach der Ueberschrift, der Ablauf danach.
   Die Leistungsseiten haben seit 12.10.2026 links noch ein Bild
   (.anfrage-bild), mobil seit 13.10.2026 ueber der Vorlage. Die
   Startseite hat keins, dort
   bleibt die Zeile leer. */

.anfrage {
  display: grid;
  grid-template-columns: 5fr 7fr;
  grid-template-areas:
    'head form'
    'side form'
    'bild form';
  grid-template-rows: auto auto 1fr;
  column-gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}

.anfrage-head {
  grid-area: head;
}

.anfrage-form {
  grid-area: form;
  min-width: 0;
}

.anfrage-side {
  grid-area: side;
}

.anfrage-head h2 {
  margin-bottom: 1rem;
}

/* Leistungsseiten: der kurze Text zum Verfahren zwischen h1 und Vorlage
   (Leandro, 12.10.2026: erst "Bereit für den Spiegel-Effekt?", dann das
   Formular). Die Frage ist eine Unterzeile der h1, deshalb kleiner als
   eine Abschnitts-Ueberschrift. */
.anfrage-intro h2 {
  margin-bottom: 0.75rem;
  font-size: clamp(1.25rem, 0.8vw + 1rem, 1.625rem);
}

.anfrage-intro .zz-list {
  margin-top: 1.25rem;
}

/* Das Bild stand bis 12.10.2026 im Zickzack neben dem Text (4:5).
   Quadratisch, weil oben und unten nur schwarzer Hintergrund ist. Nicht
   4:3 wie im Zickzack am Handy: Das schneidet die goldene Pulver-Felge
   (Teil reicht von 163 bis 698 von 800 px) und die gestrahlte Felge
   unten an. Quadratisch bleibt 100 bis 700 stehen, alle vier Teile ganz. */
.anfrage-bild {
  grid-area: bild;
  margin: 2.5rem 0 0;
}

.anfrage-bild img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  background: var(--bg-deep);
}

.anfrage-bild .ki-hinweis {
  margin-top: 0.75rem;
}

@media (max-width: 900px) {
  /* Bild ueber der Vorlage (Leandro, 13.10.2026: "so das wir ein Bild auch
     sehen über den Preis Formular"). Vorher stand es ganz unten. Im HTML
     steht es weiter hinter dem Ablauf, das Raster holt es nach oben. */
  .anfrage {
    grid-template-columns: 1fr;
    grid-template-areas:
      'head'
      'bild'
      'form'
      'side';
    grid-template-rows: auto;
  }

  /* Am Tablet nicht ueber die ganze Breite, sonst wird es hoeher als der
     Bildschirm. Mittig wie die Zeilen darueber. */
  .anfrage-bild {
    width: 100%;
    max-width: 540px;
    margin: 0 auto 1.5rem;
    text-align: center;
  }

  .anfrage-bild .ki-hinweis {
    margin-inline: auto;
  }

  .anfrage-head {
    margin-bottom: 1.75rem;
  }

  /* Leistungsseiten (Vorlage ganz oben): Ueberschrift und Vorlage dicht
     beieinander (Kevin: Zollgroessen "das das momentan bisschen unter
     geht"). Seit 12.10.2026 steht dazwischen der kurze Text zum
     Verfahren (Leandro), seit 13.10.2026 auch das Bild. Die Vorlage
     beginnt damit erst nach dem ersten Wischen. So wollte Leandro es. */
  .page-top .anfrage-head {
    margin-bottom: 1.25rem;
  }

  .page-top .anfrage-head h1 {
    margin-bottom: 1rem;
  }
}

/* Bis 12.10.2026 stand unter der h1 der Leistungsseiten noch ein Satz
   ("Felgen mit Richtpreis, alles andere nach Fotos."), am Handy
   ausgeblendet. Den ersetzt jetzt .anfrage-intro. */
@media (max-width: 600px) {
  .anfrage-side .steps {
    margin-top: 2.5rem;
  }
}

/* --- Anfrage hebt sich ab (10.10.2026) -----------------------------------
   Kevin: "muss mehr herausstechen, dass es nicht so untergeht" und "nicht
   so viel lesen". Lichtkegel von oben, helle Kanten, eine Vorlage, die
   leicht leuchtet, und statt vier Saetzen drei Stichworte. Bleibt
   monochrom wie der Rest der Seite. */

.section--anfrage {
  background:
    radial-gradient(ellipse 80% 55% at 50% 0%, rgba(255, 255, 255, 0.075), transparent 70%),
    var(--bg-deep);
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  border-bottom: 1px solid rgba(255, 255, 255, 0.16);
}

.section--anfrage .vorlage,
.section--anfrage .vorlage-fallback {
  position: relative;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border-color: rgba(255, 255, 255, 0.3);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.04), 0 30px 80px -30px rgba(255, 255, 255, 0.16);
}

/* Chromkante oben, dasselbe Motiv wie der Reflex auf den Knoepfen. */
.section--anfrage .vorlage::before,
.section--anfrage .vorlage-fallback::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 14px;
  right: 14px;
  height: 3px;
  border-radius: 0 0 3px 3px;
  background: var(--chrome);
}

.ablauf {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1.5rem 0 0;
  padding: 0;
  list-style: none;
  counter-reset: ablauf;
}

.ablauf li {
  counter-increment: ablauf;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.4rem 0.9rem 0.4rem 0.45rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.3;
}

.ablauf li::before {
  content: counter(ablauf);
  display: inline-grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0;
}

.anfrage-direkt {
  margin: 2rem 0 0;
  font-size: var(--fs-small);
  line-height: 1.9;
  color: var(--text-muted);
}

.anfrage-direkt a {
  color: var(--text);
  white-space: nowrap;
}

@media (max-width: 900px) {
  .anfrage-direkt {
    margin-top: 1.5rem;
    text-align: center;
  }

  /* Leistungsseiten: Ablauf unter der Vorlage, mittig wie die Zeile
     darunter. */
  .anfrage-side .ablauf {
    justify-content: center;
    margin-top: 1.75rem;
  }
}

.steps {
  display: grid;
  gap: 1.25rem;
  margin: 2rem 0 2.25rem;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

/* Nur die direkten Kinder: in den Schritten stehen eigene Listen
   (Abhaken), die nicht das Nummern-Raster erben duerfen. */
.steps > li {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: 0.75rem;
  align-items: start;
  counter-increment: step;
}

.steps > li::before {
  content: '0' counter(step);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  color: var(--text-muted);
  padding-top: 0.2rem;
}

/* Nur die Ueberschrift des Schritts, nicht jedes fette Wort im Text. */
.steps > li > div > strong {
  display: block;
  margin-bottom: 0.15rem;
}

.contact-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

.form-status {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text);
}

.form-status:empty {
  display: none;
}

@media (max-width: 800px) {
  .form-row {
    grid-template-columns: 1fr;
  }

  .contact-actions .btn {
    flex: 1 1 100%;
  }
}

/* --- Anfrage-Vorlage (anfrage.js) ------------------------------------------
   Rost verlinkt an dieser Stelle auf eine E-Mail-Vorlage zum Abtippen.
   Bei KNS ist die Vorlage das Formular selbst: Schritt fuer Schritt,
   jeder weitere Schritt erscheint erst, wenn er gebraucht wird. */

.vorlage {
  padding: clamp(1.25rem, 3vw, 2.25rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* Leistungsseiten (Vorlage ganz oben, seit 11.10.2026): Bis anfrage.js
   die Vorlage gebaut hat, steht dort nur der kleine Rueckfall. Ohne
   Platzhalter stand der Abschnitt darunter kurz im Bild und rutschte dann
   weg (Layout-Verschiebung, gemessen 0,03 bis 0,04 am Rechner). Solange
   der Rueckfall drin ist, haelt das hier den Bildschirm frei. Ohne
   JavaScript (keine .js-Klasse) bleibt alles klein. */
.js .page-top [data-vorlage]:has(> .vorlage-fallback) {
  min-height: 100vh;
}

/* Ohne JavaScript: nur die Direktkontakte. */
.vorlage-fallback {
  display: grid;
  gap: 1.25rem;
  padding: clamp(1.25rem, 3vw, 2.25rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.v-step {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}

/* Linie und Abstand nur zwischen sichtbaren Schritten. */
.v-step:not([hidden]) ~ .v-step {
  margin-top: 1.75rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--line);
}

.v-step.is-entering {
  opacity: 0;
  transform: translateY(12px);
  transition: none;
}

/* legend als normaler Block (float), sonst ignorieren Browser Abstaende. */
.v-legend {
  float: left;
  width: 100%;
  margin: 0 0 1.1rem;
  padding: 0;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.35;
}

.v-legend + * {
  clear: both;
}

.v-num {
  display: inline-block;
  min-width: 2.1rem;
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  vertical-align: 0.1em;
}

/* Auswahl-Kacheln (Leistung, Felgen, andere Teile oder Industrie). */
/* minmax(0, 1fr): lange Woerter ("Glasperlenstrahlen") duerfen die
   Spalten nicht breiter als den Bildschirm druecken. */
.v-choices {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
}

.v-choice {
  position: relative;
  display: block;
  cursor: pointer;
}

.v-choice input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.v-choice-body {
  position: relative;
  display: grid;
  align-content: start;
  gap: 0.3rem;
  height: 100%;
  padding: 1rem 2.5rem 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
  pointer-events: none;
}

.v-choice-body strong {
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: break-word;
  -webkit-hyphens: manual;
  hyphens: manual;
}

/* Auswahl-Markierung in Parallelogramm-Form, wie Karten und Eyebrows. */
.v-choice-body::after {
  content: '';
  position: absolute;
  top: 1.2rem;
  right: 1rem;
  width: 18px;
  height: 9px;
  background: rgba(255, 255, 255, 0.16);
  clip-path: var(--shape-slant);
  transition: background-color var(--dur) var(--ease);
}

.v-choice:hover .v-choice-body {
  border-color: rgba(255, 255, 255, 0.28);
}

.v-choice input:checked + .v-choice-body {
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, 0.05);
}

.v-choice input:checked + .v-choice-body::after {
  background: var(--text);
}

.v-choice input:focus-visible + .v-choice-body {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

/* Zollgroesse als Knoepfe, seit 11.10.2026. Vorher ein Schieberegler mit
   kleinen Zahlen darunter, Kevin: "ich finde das das momentan bisschen
   unter geht". Am Handy zwei Reihen (--halb), sobald die Vorlage breit
   genug ist eine (--spalten), beides setzt anfrage.js nach der Zahl der
   Groessen. Die gewaehlte ist weiss gefuellt wie der Hauptknopf, damit
   man sofort sieht, welche gilt. Ohne Container-Abfragen (iOS vor 16)
   bleibt es bei zwei Reihen. */
.v-size {
  container-type: inline-size;
}

.v-size-label,
.v-count-label {
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text);
}

.v-size-label {
  display: block;
  margin-bottom: 0.6rem;
}

.v-zoll {
  display: grid;
  grid-template-columns: repeat(var(--halb, 5), minmax(0, 1fr));
  gap: 0.4rem;
}

@container (min-width: 30rem) {
  .v-zoll {
    grid-template-columns: repeat(var(--spalten, 10), minmax(0, 1fr));
  }
}

.v-zoll label {
  position: relative;
  display: block;
  cursor: pointer;
}

.v-zoll input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.v-zoll span {
  display: grid;
  place-items: center;
  height: 48px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease), color var(--dur) var(--ease);
  pointer-events: none;
}

.v-zoll label:hover span {
  border-color: rgba(255, 255, 255, 0.28);
}

.v-zoll input:checked + span {
  border-color: var(--text);
  background: var(--text);
  color: var(--bg);
}

.v-zoll input:focus-visible + span {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* Bordsteinschaeden (11.10.2026): Frage oben, darunter fuenf Felder ueber
   die ganze Breite. "Keine" bekommt etwas mehr Platz als die Zahlen. */
.v-schaden {
  margin-top: 1.5rem;
}

/* Frage links, Aufschlag je Felge rechts (13.10.2026), wie bei den
   Extras. Wird es zu eng, rutscht der Preis in die naechste Zeile. */
.v-schaden-kopf {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.25rem 1rem;
  margin-bottom: 0.6rem;
}

.v-schaden-preis {
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

.v-schaden .v-seg {
  display: grid;
  grid-template-columns: 1.5fr repeat(4, minmax(0, 1fr));
  width: 100%;
}

.v-schaden .v-seg span:not(.sr-only) {
  width: auto;
}

/* Anzahl */
.v-count {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-top: 1.25rem;
}

.v-seg {
  display: inline-grid;
  grid-auto-flow: column;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}

.v-seg label {
  position: relative;
  cursor: pointer;
}

.v-seg label + label {
  border-left: 1px solid var(--line);
}

.v-seg input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.v-seg span:not(.sr-only) {
  display: grid;
  place-items: center;
  width: 46px;
  height: 44px;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-body);
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
  pointer-events: none;
}

.v-seg input:checked + span {
  background: var(--text);
  color: var(--bg);
}

.v-seg input:focus-visible + span {
  outline: 2px solid var(--text);
  outline-offset: -4px;
}

/* Ausfuehrung (RAL, Metallic, Candy). Drei Kacheln nebeneinander, jede mit
   dem Grundpreis fuer die eingestellte Groesse - so sieht man sofort, was
   der Unterschied kostet. Schmaler und ruhiger als die grossen
   Auswahl-Kacheln oben, weil es eine Unterentscheidung ist. */
.v-finish {
  margin-top: 1.5rem;
}

.v-finish-label {
  display: block;
  margin-bottom: 0.5rem;
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text);
}

.v-finish-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

/* Pflichtfrage einer Leistung (14.10.2026): Hochglanz ein- oder
   mehrteilig, Strahlen Sand oder Glasperlen. Zwei Kacheln, auch am Handy
   nebeneinander (die doppelte Klasse schlaegt die Ein-Spalten-Regel unter
   440 px). "Sand-" und "Glasperlenstrahlen" trennen dort an der weichen
   Trennstelle, ohne die ragte "Sandstrahlen" auf 320 px in den Rand. */
.v-finish-list.v-zwei {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.v-finish-list label {
  position: relative;
  display: block;
  cursor: pointer;
}

.v-finish-list input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.v-finish-body {
  display: grid;
  align-content: start;
  gap: 0.15rem;
  height: 100%;
  padding: 0.75rem 0.7rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.v-finish-body strong {
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.3;
}

.v-finish-price {
  margin-top: 0.2rem;
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.v-finish-list label:hover .v-finish-body {
  border-color: rgba(255, 255, 255, 0.28);
}

.v-finish-list input:checked + .v-finish-body {
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, 0.05);
}

.v-finish-list input:focus-visible + .v-finish-body {
  outline: 2px solid var(--text);
  outline-offset: 2px;
}

/* Unter 440 px sind drei Spalten nur noch gut 90 px breit, da passen
   "RAL-Standard" und der Preis nicht mehr nebeneinander. Lieber
   untereinander, Name links, Preis rechts. */
@media (max-width: 440px) {
  .v-finish-list {
    grid-template-columns: 1fr;
  }

  .v-finish-body {
    grid-template-columns: 1fr auto;
    align-items: baseline;
    column-gap: 0.75rem;
  }

  .v-finish-price {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    text-align: right;
  }
}

/* Extras zum Anklicken */
.v-extras {
  display: grid;
  gap: 0.6rem;
  margin-top: 1.5rem;
}

.v-extra {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.9rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background-color var(--dur) var(--ease);
}

.v-extra:hover {
  border-color: rgba(255, 255, 255, 0.28);
}

.v-extra:has(input:checked) {
  border-color: var(--line-strong);
  background: rgba(255, 255, 255, 0.05);
}

.v-extra input {
  width: 20px;
  height: 20px;
  margin: 0;
  accent-color: var(--text);
  cursor: pointer;
}

.v-extra-body {
  display: grid;
  gap: 0.1rem;
}

.v-extra-body strong {
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
}

.v-extra-body small {
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--text-muted);
}

.v-extra-price {
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--text);
  text-align: right;
  white-space: nowrap;
}

/* Richtpreis. Bis 13.10.2026 stand die Zahl im Chrom-Verlauf, seitdem in
   Gruen (Leandro: "Der Richtpreis soll immer in Grün angezeigt werden").
   Einfarbig statt Verlauf in der Schrift: Das ist auch im erzwungenen
   Dunkelmodus und im Kontrastmodus sicher lesbar (siehe "Preise auf
   Android-Handys" im README). */
.v-price {
  margin-top: 1.5rem;
  padding: 1.25rem 1.25rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--bg-deep);
}

.v-price-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-muted);
}

.v-price-value {
  display: block;
  margin: 0.4rem 0 0.15rem;
  /* Untergrenze 7.5vw unter 375 px: Auf 320 px (Galaxy S9+, groesser
     gestellte Android-Anzeige) passt "1.305 – 1.490 €" so in eine Zeile
     (24 statt 28 px). Ab 375 px unveraendert 1.75rem. */
  font-size: clamp(min(1.75rem, 7.5vw), 2.4vw + 0.9rem, 2.5rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--preis);
}

.v-price-meta {
  display: block;
  font-size: var(--fs-small);
  color: var(--text-body);
}

.v-price-note {
  margin: 0.9rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--line);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--text-muted);
}

/* Hinweise und Kontakt */
.v-hint {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
  margin: 0 0 1.1rem;
  font-size: var(--fs-small);
  line-height: 1.65;
  color: var(--text-body);
}

.v-hint svg {
  flex: none;
  width: 20px;
  height: 20px;
  margin-top: 0.1rem;
  color: var(--text);
}

.v-fields {
  display: grid;
  gap: 1rem;
}

.v-fields .v-hint {
  margin: 0;
}

.v-optional {
  margin-left: 0.35rem;
  font-weight: 400;
  color: var(--text-muted);
}

.v-submit {
  width: 100%;
}

/* Die Falle fuer Roboter. Nicht display:none, sonst fuellen sie das Feld
   trotzdem aus und merken nichts. Fuer Menschen ist sie unerreichbar:
   ausserhalb des Bildes, nicht mit Tab erreichbar, aria-hidden. */
.v-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Auffangnetz, wenn WhatsApp nicht aufgeht. */
.v-fallback {
  display: grid;
  gap: 0.75rem;
  margin-top: 0.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}

.v-fallback-hint {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.v-text {
  width: 100%;
  min-height: 9rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--bg-deep);
  color: var(--text-body);
  font: inherit;
  font-size: var(--fs-small);
  line-height: 1.5;
  resize: vertical;
}

@media (max-width: 480px) {
  .v-choices {
    gap: 0.5rem;
  }

  .v-choice-body {
    padding: 0.85rem 2rem 0.9rem 0.9rem;
  }

  .v-choice-body::after {
    right: 0.75rem;
    width: 14px;
    height: 7px;
  }

  /* Preis unter dem Namen, dicht dran; das Haekchen mittig ueber beide
     Zeilen. Vorher lag der volle Abstand von 0,9rem dazwischen, das fiel
     auf, seit die Keramik keine Zeile darunter mehr hat (10.10.2026). */
  .v-extra {
    grid-template-columns: auto 1fr;
    row-gap: 0.2rem;
  }

  .v-extra input {
    grid-row: span 2;
  }

  .v-extra-price {
    grid-column: 2;
    text-align: left;
  }

  .vorlage {
    padding: 1.1rem 1rem 1.25rem;
  }
}

/* Unter 380 px blieben neben der Markierung keine 80 px Text, dann bricht
   "Pulverbeschichtung" mitten im Wort. Dann lieber untereinander. */
@media (max-width: 380px) {
  .v-choices {
    grid-template-columns: 1fr;
  }
}

/* Die vier Leistungen am Handy immer untereinander. Seit die Kacheln nur
   noch den Namen tragen (10.10.2026), stand "Sand- & Glasperlenstrahlen"
   zweispaltig auf drei Zeilen neben einem einzeiligen "Cerakote". Als
   Liste ist jede Kachel eine Zeile, kaum hoeher und ruhiger. "Felgen" und
   "Andere Teile" passen weiter nebeneinander. */
@media (max-width: 600px) {
  .v-step[data-step='leistung'] .v-choices {
    grid-template-columns: 1fr;
  }

  /* Seit 30.10.2026 drei Kacheln (Industrie dazu). Am Handy steht
     "Felgen" ueber die volle Breite, die beiden anderen darunter. Drei
     nebeneinander liessen "Industrie" mitten im Wort brechen, und eine
     Kachel allein in der zweiten Reihe saehe vergessen aus. Unter 380 px
     sind ohnehin alle untereinander. */
  .v-step[data-step='art'] .v-choice:first-child {
    grid-column: 1 / -1;
  }
}

/* Ab 601 px alle drei in einer Reihe. */
@media (min-width: 601px) {
  .v-step[data-step='art'] .v-choices {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* Rueckmeldung beim Antippen, wo es kein Hover gibt. */
@media (hover: none) {
  .v-choice:active .v-choice-body,
  .v-extra:active {
    border-color: rgba(255, 255, 255, 0.4);
  }

  .service:active::before {
    opacity: 1;
  }
}

/* --- Karte mit Zwei-Klick-Loesung ----------------------------------------
   Google Maps laedt erst nach Klick bzw. Einwilligung "Externe Medien".
   Vorher geht kein einziger Request an Google. */

/* --- Karte: zurzeit nicht auf der Seite ----------------------------------
   Die Google-Karte im Anfrage-Bereich ist am 28.09.2026 entfernt worden.
   Diese Regeln bleiben stehen: ohne das Markup tun sie nichts (auch im
   kritischen CSS landen sie nicht mehr, das nimmt nur Regeln mit, die
   wirklich etwas treffen), und die Rueckkehr haengt sonst an drei Stellen
   statt an zweien. Wie sie zurueckkommt, steht im README unter "Karte". */
.map {
  position: relative;
  margin-top: clamp(3rem, 6vw, 4.5rem);
  aspect-ratio: 21 / 8;
  overflow: hidden;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface);
}

.map iframe {
  width: 100%;
  height: 100%;
  border: 0;
  filter: grayscale(1) invert(0.92) contrast(0.9);
}

.map-consent {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 1rem;
  padding: 1.5rem;
  text-align: center;
  background: repeating-linear-gradient(135deg, var(--surface) 0 14px, #1c1c1c 14px 28px);
}

.map-consent p {
  max-width: 460px;
  font-size: var(--fs-small);
  line-height: 1.6;
}

@media (max-width: 720px) {
  .map {
    aspect-ratio: 4 / 5;
  }
}

/* --- Vollbild-Galerie ---------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: 64px 16px;
  background: rgba(5, 5, 5, 0.96);
  opacity: 0;
  transition: opacity 0.35s var(--ease);
  touch-action: pan-y;
}

.lightbox.is-open {
  opacity: 1;
}

.lightbox-figure {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: 1rem;
  max-width: min(900px, 100%);
}

.lightbox-img {
  max-width: 100%;
  max-height: calc(100svh - 180px);
  width: auto;
  height: auto;
  border-radius: var(--radius);
  user-select: none;
  -webkit-user-drag: none;
  touch-action: none;
  cursor: grab;
  transition: transform 0.35s var(--ease), opacity 0.25s var(--ease);
}

.lightbox-img.is-dragging {
  transition: none;
}

.lightbox-caption {
  font-size: var(--fs-small);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-body);
  text-align: center;
}

.lightbox-close {
  position: absolute;
  top: max(12px, env(safe-area-inset-top));
  right: max(12px, env(safe-area-inset-right));
}

.lightbox-prev,
.lightbox-next {
  position: absolute;
  top: 50%;
  margin-top: -22px;
  background: rgba(255, 255, 255, 0.06);
}

.lightbox-prev {
  left: max(12px, env(safe-area-inset-left));
}

.lightbox-next {
  right: max(12px, env(safe-area-inset-right));
}

@media (max-width: 720px) {
  /* Am Handy wird gewischt, die Pfeile stehen unten statt ueber dem Bild. */
  .lightbox-prev,
  .lightbox-next {
    top: auto;
    bottom: calc(16px + env(safe-area-inset-bottom));
    margin-top: 0;
  }

  .lightbox-prev {
    left: calc(50% - 56px);
  }

  .lightbox-next {
    right: calc(50% - 56px);
  }
}

/* --- Footer --------------------------------------------------------------- */

.site-footer {
  overflow: hidden;
  background: var(--bg-deep);
  padding-block: clamp(3rem, 6vw, 4.5rem) 2rem;
  text-align: center;
}

.footer-logo {
  display: inline-block;
  width: 110px;
  margin-bottom: 1.5rem;
  color: var(--text);
}

.footer-social {
  display: flex;
  justify-content: center;
  gap: 4px;
  margin-bottom: 1.75rem;
}

.footer-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 2rem;
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
  font-weight: 500;
}

.footer-nav a {
  color: var(--text);
  text-decoration: none;
}

.footer-nav a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-info {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem 2rem;
  margin: 0 0 2.5rem;
  padding: 0;
  list-style: none;
  font-size: var(--fs-small);
}

.footer-info a {
  text-decoration: none;
}

.footer-info a:hover {
  text-decoration: underline;
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.25rem 1.25rem;
  margin: 0;
  padding: 1.5rem 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* Grosser Schriftzug als Abschluss, bewusst angeschnitten. */
.footer-wordmark {
  margin: clamp(2rem, 5vw, 3.5rem) 0 -0.2em;
  font-size: clamp(7rem, 30vw, 24rem);
  font-weight: 800;
  line-height: 0.8;
  letter-spacing: 0.04em;
  text-align: center;
  color: transparent;
  -webkit-text-stroke: 1px rgba(255, 255, 255, 0.09);
  user-select: none;
  /* Reine Deko. Die Glyphen ragen ueber die eigene Box hinaus und wuerden
     sonst Klicks auf Impressum und Cookie-Einstellungen abfangen. */
  pointer-events: none;
}

.footer-legal a,
.footer-legal button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font-size: inherit;
  text-decoration: none;
  cursor: pointer;
}

.footer-legal a:hover,
.footer-legal button:hover {
  color: var(--text);
}

/* Mit dem Finger: jeder Footer-Link 44 px hoch, dafuer kein Zeilenabstand
   mehr zwischen den Reihen. Optisch fast gleich, aber sicher zu treffen. */
@media (pointer: coarse) {
  .footer-nav,
  .footer-info,
  .footer-legal {
    row-gap: 0;
    /* Die Zeilen enthalten Links (44 px hoch) und reinen Text (eine
       Textzeile hoch) nebeneinander. Ueber die Schriftlinie ausgerichtet
       stehen beide gleich, egal wie hoch ihr Kasten ist. */
    align-items: baseline;
  }

  .footer-nav a,
  .footer-info a,
  .footer-legal a,
  .footer-legal button {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  /* Hier stand bis zum 28.09.2026 display: flex auf den <li>. Das war eine
     Falle: In einem Flex-Kasten fallen die Leerzeichen zwischen den Kindern
     weg. Aus "© <span>2026</span> KNS Beschichtung" wurde am Handy deshalb
     "©2026KNS Beschichtung" - und nur dort, weil die Regel in
     (pointer: coarse) steht, am Rechner sah alles richtig aus.

     Die 44 px zum Antippen bringen die Links selbst mit (Regel darueber),
     die <li> brauchen weder Hoehe noch Flex. Bitte auch nicht wieder
     einbauen: Jede Zeile, in der Text und ein Link zusammen stehen, verliert
     damit ihre Leerzeichen. */
}

/* --- Mobile Leiste unten -------------------------------------------------- */

/* Solange der Cookie-Banner, das Menue oder die Galerie offen ist, steht
   die Kontaktleiste nicht im Weg. */
.consent-pending .mobilebar,
.has-overlay .mobilebar {
  visibility: hidden;
  transition-delay: 0s;
}

/* Beim Tippen (Tastatur offen) wuerde die Leiste ueber dem Eingabefeld und
   dem Senden-Knopf schweben. Solange ein Textfeld aktiv ist, verschwindet sie.

   Weg ist sie sofort, zurueck kommt sie erst nach einer halben Sekunde
   (transition in .mobilebar). Bis zum 30.10.2026 stand hier display: none
   ohne Verzoegerung. Dann tauchte die Leiste beim Antippen von "Per
   WhatsApp senden" schon wieder auf, sobald das Namensfeld den Fokus
   verlor, und zwar unter dem Finger, wenn der Knopf im unteren Streifen
   lag. Der Tipp landete dann neben dem Knopf, die Anfrage ging nicht ab.
   Gefunden auf der Strahlen-Seite am Handy, in Safari und Chrome gleich.
   Auf Android bleibt das Feld aktiv, wenn man die Tastatur mit "Zurueck"
   schliesst, dort trifft es echte Besucher. */
:root:has(input[type='text']:focus, textarea:focus) .mobilebar {
  visibility: hidden;
  transition-delay: 0s;
}

.mobilebar {
  display: none;
  transition: visibility 0s linear 0.5s;
}

@media (max-width: 900px) {
  body {
    padding-bottom: calc(var(--mobilebar-h) + env(safe-area-inset-bottom));
  }

  .mobilebar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-mobilebar);
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 8px;
    padding: 10px max(12px, env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
    background: var(--bg-deep);
    border-top: 1px solid var(--line);
  }

  .mobilebar .btn {
    min-height: 50px;
    padding: 0 1rem;
  }

  /* "Jetzt Termin sichern" (10.10.2026) soll herausstechen: fetter, mit
     hellem Schein, und der Chrom-Reflex der Knoepfe laeuft hier von
     selbst, kurz nach dem Laden zweimal. Nicht endlos: Die Seite haelt
     sonst nichts in Bewegung, was niemand braucht (mobil-pruefen.mjs
     prueft genau das, wegen des Akkus). */
  .mobilebar-cta {
    font-weight: 700;
    letter-spacing: 0.03em;
    box-shadow: 0 0 22px rgba(255, 255, 255, 0.28);
  }

  .mobilebar-cta::after {
    animation: glanz 3s var(--ease) 1s 2;
  }

  /* WhatsApp und Anrufen (seit 13.10.2026 beide nur als Zeichen):
     quadratisch, so hoch wie der Termin-Knopf. */
  .mobilebar .mobilebar-icon {
    width: 52px;
    padding: 0;
  }

  .mobilebar-icon svg {
    width: 22px;
    height: 22px;
  }
}

/* Schmale Handys: Neben zwei Zeichen-Knoepfen bleiben fuer "Jetzt Termin
   sichern" auf 320 px nur 176 px. Etwas kleinere Schrift, weniger Rand,
   und unter 360 px ohne Kalender-Zeichen, damit der Text in eine Zeile
   passt. */
@media (max-width: 400px) {
  .mobilebar .mobilebar-cta {
    padding: 0 0.75rem;
    font-size: 0.875rem;
    letter-spacing: 0.01em;
  }
}

@media (max-width: 359px) {
  .mobilebar-cta svg {
    display: none;
  }

  /* 320 px: Mit 12 px Rand brach der Text noch in zwei Zeilen um
     (gemessen am 13.10.2026). Zeichen-Knoepfe 46 statt 52 px, weniger
     Rand und 13 px Schrift, dann passt er in eine. 46 px bleiben ueber
     der 44-px-Grenze fuer Tippflaechen. */
  .mobilebar {
    gap: 6px;
  }

  .mobilebar .mobilebar-icon {
    width: 46px;
  }

  .mobilebar .mobilebar-cta {
    padding: 0 0.5rem;
    font-size: 0.8125rem;
    letter-spacing: 0;
  }
}

@keyframes glanz {
  0% {
    transform: translateX(-180%) skewX(-18deg);
  }

  45%,
  100% {
    transform: translateX(320%) skewX(-18deg);
  }
}

/* Handy quer: keine feste Leiste, WhatsApp und Anrufen stehen im Header. */
@media (max-width: 1000px) and (max-height: 500px) and (orientation: landscape) {
  body {
    padding-bottom: env(safe-area-inset-bottom);
  }

  .mobilebar {
    display: none;
  }
}

/* --- Knopf unten rechts zur Vorlage (10.10.2026) -------------------------
   Leandro: "eine Art Pfeil ... wodurch man direkt zu der Vorlage kommt".
   Gegenstueck zur Handy-Leiste, deshalb nur dort, wo die Leiste fehlt
   (Rechner, Handy quer). Sichtbar schaltet ihn site.js: nach dem ersten
   Bildschirm, nicht solange die Vorlage oder der Fuss zu sehen ist. */

.sprung {
  position: fixed;
  right: max(24px, env(safe-area-inset-right));
  bottom: max(24px, env(safe-area-inset-bottom));
  z-index: var(--z-mobilebar);
  font-weight: 700;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6), 0 0 24px rgba(255, 255, 255, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(14px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
    background-color var(--dur) var(--ease), visibility 0s linear var(--dur);
}

.sprung.is-sichtbar {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease),
    background-color var(--dur) var(--ease);
}

.consent-pending .sprung,
.has-overlay .sprung {
  visibility: hidden;
}

/* Glanz jedes Mal, wenn der Knopf erscheint, zweimal, dann Ruhe. */
.sprung.is-sichtbar::after {
  animation: glanz 3s var(--ease) 0.5s 2;
}

.sprung svg {
  transition: transform var(--dur) var(--ease);
}

.sprung:hover svg {
  transform: translateY(3px);
}

/* Vorlage liegt oben (Leistungsseiten, site.js): Pfeil nach oben. */
.sprung.is-hoch svg {
  transform: rotate(180deg);
}

.sprung.is-hoch:hover svg {
  transform: rotate(180deg) translateY(3px);
}

@media (prefers-reduced-motion: reduce) {
  .sprung,
  .sprung.is-sichtbar {
    transform: none;
  }

  .sprung.is-sichtbar::after,
  .mobilebar-cta::after {
    animation: none;
  }
}

@media (max-width: 900px) {
  .sprung {
    display: none;
  }
}

@media (max-width: 1000px) and (max-height: 500px) and (orientation: landscape) {
  .sprung {
    display: inline-flex;
  }
}

/* --- Cookie-Banner und Einstellungen --------------------------------------
   Akzeptieren und Ablehnen sind bewusst gleich gross und gleich prominent.
   Ein schwaecherer Ablehnen-Button gilt nach Auffassung der deutschen
   Aufsichtsbehoerden als unzulaessige Beeinflussung. */

.cookie-banner {
  position: fixed;
  left: 50%;
  bottom: 16px;
  z-index: var(--z-banner);
  width: min(720px, calc(100% - 24px));
  padding: clamp(1.25rem, 3vw, 1.75rem);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
  transform: translate(-50%, 24px);
  opacity: 0;
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}

.cookie-banner.is-visible {
  transform: translate(-50%, 0);
  opacity: 1;
}

.cookie-banner h2,
.modal-card h2 {
  margin-bottom: 0.6rem;
  font-size: 1.125rem;
}

.cookie-banner p {
  margin-bottom: 1.25rem;
  font-size: var(--fs-small);
  line-height: 1.65;
}

.cookie-actions {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 0.75rem;
  align-items: center;
}

.cookie-actions .btn {
  min-height: 48px;
  padding: 0 1rem;
}

.cookie-actions .btn-link {
  padding: 0 0.5rem;
  font-size: var(--fs-small);
}

@media (max-width: 560px) {
  .cookie-actions {
    grid-template-columns: 1fr 1fr;
  }

  .cookie-actions .btn-link {
    grid-column: 1 / -1;
    justify-self: center;
    min-height: 44px;
  }
}

.modal {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.7);
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}

.modal.is-open {
  opacity: 1;
}

.modal-card {
  width: min(600px, 100%);
  max-height: calc(100svh - 32px);
  overflow-y: auto;
  padding: clamp(1.5rem, 4vw, 2.25rem);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.modal-intro {
  font-size: var(--fs-small);
  line-height: 1.65;
}

/* Ohne einwilligungspflichtigen Dienst steht im Dialog nur dieser Text,
   direkt ueber der Trennlinie der Knoepfe. Sonst liegt dort eine
   Kategorie mit eigenem Abstand. */
[data-consent-ohne-dienst] {
  margin-bottom: 1.25rem;
}

.consent-group {
  display: flex;
  gap: 1.25rem;
  justify-content: space-between;
  align-items: flex-start;
  padding: 1.1rem 0;
  border-top: 1px solid var(--line);
}

.consent-group h3 {
  margin-bottom: 0.3rem;
  font-size: 0.9375rem;
}

.consent-group p {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.switch {
  position: relative;
  flex: none;
  width: 46px;
  height: 26px;
  margin-top: 0.1rem;
}

.switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.switch input:disabled {
  cursor: not-allowed;
}

.switch-track {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: #3a3a3a;
  transition: background-color var(--dur) var(--ease);
  pointer-events: none;
}

.switch-track::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text);
  transition: transform var(--dur) var(--ease);
}

.switch input:checked + .switch-track {
  background: #8a8a8a;
}

.switch input:checked + .switch-track::after {
  transform: translateX(20px);
}

.switch input:disabled + .switch-track {
  opacity: 0.55;
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

.modal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}

.modal-actions .btn {
  flex: 1 1 auto;
  min-height: 48px;
}

/* --- Rechtstexte ---------------------------------------------------------- */

.legal {
  max-width: 760px;
  margin-inline: auto;
}

.legal h1 {
  font-size: var(--fs-h2);
  margin-bottom: 1.5rem;
}

.legal h2 {
  font-size: 1.25rem;
  margin: 2.5rem 0 0.75rem;
}

.legal h3 {
  font-size: 1.0625rem;
  margin: 1.75rem 0 0.5rem;
}

.legal ul {
  padding-left: 1.2rem;
}

.legal li {
  margin-bottom: 0.4rem;
}

/* Adressen ohne Leerzeichen ("www.universalschlichtungsstelle.de") sind am
   320er Handy breiter als die Spalte und schoben die Seite 7 px ueber den
   Rand. Getrennt wird nur, wenn sie wirklich nicht passen. */
.legal a {
  overflow-wrap: anywhere;
}

.legal code {
  padding: 0.1em 0.4em;
  border-radius: var(--radius-btn);
  background: var(--surface-2);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}

/* Der Kasten oben auf Impressum und Datenschutz: solange dort Entwurf
   steht, soll niemand den Text fuer fertig halten. */
.legal-hinweis {
  margin-bottom: 2.5rem;
  padding: 1rem 1.25rem;
  border: 1px dashed rgba(255, 255, 255, 0.28);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: var(--fs-small);
  color: var(--text-body);
}

.legal-hinweis .placeholder-tag {
  margin-right: 0.5rem;
}

.legal-stand {
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* --- Einschicken und Fehlerseite ------------------------------------------
   Zwei reine Textseiten. Sie nutzen, was es schon gibt (.steps, .crumbs,
   .contact-actions), und ergaenzen nur, was fehlt. */

.versand-head,
.versand-body {
  max-width: 760px;
  margin-inline: auto;
}

.versand-head h1 {
  margin-bottom: 1.25rem;
}

/* Die Schritte auf der Versandseite tragen ganze Absaetze, nicht nur eine
   Zeile wie im Anfrage-Bereich. Deshalb mehr Luft und eine Trennlinie. */
.steps--lang {
  gap: 0;
}

.steps--lang > li {
  padding-block: 1.75rem;
  align-items: start;
}

.steps--lang > li + li {
  border-top: 1px solid var(--line);
}

.steps--lang > li > div > strong {
  margin-bottom: 0.6rem;
  font-size: var(--fs-h3);
  font-weight: 500;
}

.steps--lang p {
  margin-bottom: 0.75rem;
  color: var(--text-body);
}

.steps--lang p:last-child {
  margin-bottom: 0;
}

/* Abhak-Listen: statt Punkten das schraege Zeichen der Marke. */
.haken {
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.haken li {
  position: relative;
  padding-left: 1.6rem;
  margin-bottom: 0.4rem;
  color: var(--text-body);
}

.haken li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 12px;
  height: 6px;
  background: currentColor;
  clip-path: var(--shape-slant);
  opacity: 0.75;
}

/* Was ueberhaupt per Paket geht. Steht direkt unter dem Vorspann, weil das
   die erste Frage ist, die jemand von weiter weg hat. */
.versand-was {
  margin-top: 1.25rem;
  padding: 0.9rem 1.1rem;
  border-left: 2px solid var(--line-strong);
  background: var(--surface);
  border-radius: 0 8px 8px 0;
}

.versand-was strong {
  color: var(--text);
}

.versand-box {
  margin-top: 2.5rem;
  padding: clamp(1.25rem, 4vw, 2rem);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.versand-box h2,
.versand-cta h2 {
  margin-bottom: 1rem;
  font-size: 1.25rem;
}

.versand-box .haken li:last-child {
  margin-bottom: 0;
}

.versand-cta {
  margin-top: 3rem;
}

.versand-cta p {
  margin-bottom: 1.5rem;
  color: var(--text-body);
}

/* Fehlerseite 404 */
.fehler {
  max-width: 640px;
  margin-inline: auto;
  text-align: center;
  padding-block: clamp(1rem, 6vh, 4rem);
}

.fehler .eyebrow::before {
  display: none;
}

.fehler h1 {
  font-size: var(--fs-h2);
  margin-bottom: 1.25rem;
}

.fehler .lead {
  color: var(--text-body);
}

.fehler-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.75rem;
  margin: 2.25rem 0 0;
  padding: 0;
  list-style: none;
}

.fehler-hilfe {
  margin-top: 2.5rem;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

/* --- Wissensblock ---------------------------------------------------------
   Laufender Text auf den Leistungsseiten. Google braucht Text, um eine
   Seite einordnen zu koennen; 190 Woerter reichen dafuer nicht. Die Spalte
   bleibt bei 68ch, damit die Zeilen lesbar kurz sind. */

.wissen {
  max-width: 68ch;
  margin-inline: auto;
}

.wissen h2 {
  font-size: var(--fs-h2);
  margin: 0 0 1.25rem;
}

.wissen h3 {
  font-size: 1.25rem;
  margin: 2.5rem 0 0.6rem;
  letter-spacing: var(--track);
}

.wissen h3:first-of-type {
  margin-top: 2rem;
}

.wissen p {
  margin: 0 0 1rem;
  color: var(--text-body);
}

.wissen p:last-child {
  margin-bottom: 0;
}

.wissen strong {
  color: var(--text);
}

.wissen .haken {
  margin: 1.25rem 0 1.5rem;
}

/* .zz-list bringt nur oben einen Abstand mit, weil sie im Zickzack immer
   als Letztes steht. Im Fliesstext folgt darauf noch Text. */
.wissen .zz-list {
  margin-bottom: 1.75rem;
}

/* --- Fragen und Antworten -------------------------------------------------
   Native <details>, damit Tastatur und Screenreader ohne JavaScript
   funktionieren. Der Inhalt steht im DOM, Google liest ihn also auch
   zugeklappt. */

.faq {
  max-width: 68ch;
  margin-inline: auto;
}

.faq-item {
  border-bottom: 1px solid var(--line);
}

.faq-item:first-of-type {
  border-top: 1px solid var(--line);
}

.faq-item summary {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.15rem 0;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.45;
  cursor: pointer;
  list-style: none;
  transition: color var(--dur) var(--ease);
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary:hover {
  color: var(--text);
}

.faq-item summary:focus-visible {
  outline: 2px solid var(--stripe);
  outline-offset: 3px;
}

/* Das Plus-Zeichen. Wird beim Aufklappen zum Minus gedreht.
   margin-left: auto schiebt es an den rechten Rand. Ohne stand es bei
   kurzen Fragen direkt hinter dem Text ("Ist das dasselbe wie Chrom? +"),
   weil der Fragetext als anonymes Flex-Element nur so breit ist wie er
   selbst (gesehen am Handy, 10.10.2026, galt auch am Rechner). */
.faq-item summary::after {
  content: '';
  flex: 0 0 auto;
  margin-left: auto;
  width: 14px;
  height: 14px;
  margin-top: 0.4em;
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 100% no-repeat;
  opacity: 0.65;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}

/* Aufgeklappt bleibt nur der Querstrich stehen: aus Plus wird Minus.
   Nicht drehen — das machte aus dem Strich einen senkrechten Balken. */
.faq-item[open] summary::after {
  background: linear-gradient(currentColor, currentColor) center / 100% 1.5px no-repeat;
  opacity: 1;
}

.faq-answer {
  padding: 0 0 1.35rem;
}

.faq-answer p {
  margin: 0 0 0.8rem;
  color: var(--text-body);
  font-size: var(--fs-small);
  line-height: 1.75;
}

.faq-answer p:last-child {
  margin-bottom: 0;
}

.faq-answer strong {
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  .faq-item summary,
  .faq-item summary::after {
    transition: none;
  }
}

/* --- Preistabelle ---------------------------------------------------------
   Die gleichen Zahlen wie im Rechner, nur als Text. Google fuehrt kein
   JavaScript aus und sieht die Preise im Rechner deshalb nicht. */

.preis-wrap {
  max-width: 68ch;
  margin: 2rem auto 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.preis-tabelle {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-small);
  font-variant-numeric: tabular-nums;
}

.preis-tabelle caption {
  margin-bottom: 0.9rem;
  color: var(--text-muted);
  font-size: var(--fs-small);
  text-align: left;
}

.preis-tabelle th,
.preis-tabelle td {
  padding: 0.7rem 0.9rem;
  border-bottom: 1px solid var(--line);
  text-align: right;
  white-space: nowrap;
}

.preis-tabelle thead th {
  border-bottom-color: var(--line-strong);
  color: var(--text);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
}

.preis-tabelle th[scope='row'] {
  color: var(--text);
  text-align: left;
}

.preis-tabelle td {
  color: var(--text-body);
}

.preis-tabelle tbody tr:last-child th,
.preis-tabelle tbody tr:last-child td {
  border-bottom: none;
}

.preis-note {
  max-width: 68ch;
  margin: 1.1rem auto 0;
  font-size: var(--fs-small);
  color: var(--text-muted);
}

.preis-note strong {
  color: var(--text);
}

/* Auf dem Handy muessen alle vier Spalten ins Bild passen. Wer nicht merkt,
   dass eine Tabelle seitlich scrollt, sieht die Candy-Preise sonst nie.
   overflow-x bleibt als Auffangnetz fuer sehr schmale Geraete stehen. */
@media (max-width: 620px) {
  .preis-tabelle {
    font-size: 0.8125rem;
  }

  .preis-tabelle th,
  .preis-tabelle td {
    padding: 0.6rem 0.35rem;
  }

  .preis-tabelle thead th {
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
  }

  .preis-tabelle th[scope='row'] {
    padding-left: 0;
  }

  /* Das Euro-Zeichen steht 24-mal in der Tabelle und kostet pro Spalte
     Platz, den die Zahlen brauchen. Die Einheit steht in der Beschriftung
     ueber der Tabelle, hier ist sie entbehrlich. */
  .preis-eur {
    display: none;
  }
}

/* Ganz schmale Geraete (iPhone SE und aehnlich): die Innenabstaende sind
   das Letzte, was sich noch kuerzen laesst, ohne Zahlen wegzunehmen. */
@media (max-width: 400px) {
  .preis-tabelle th,
  .preis-tabelle td {
    padding: 0.6rem 0.2rem;
  }
}
