/* ============================================================================
   seite-tuning  —  aus tuning.html des statischen Standes
   Automatisch extrahiert (_work/theme-css-extrakt.mjs), inhaltlich unveraendert.
   Einzige Aenderung: Bildpfade zeigen auf das Theme-Verzeichnis.
   ========================================================================= */


/* ============================================================================
   HERO — Inhaber-Vorlage "Circuit Landing" v3, 1:1 uebernommen (2026-08-03)
   ----------------------------------------------------------------------------
   Ersetzt den frueheren `.page-hero` (4:5-Bild rechts, Anton-Kursiv-H1,
   Breadcrumb-Zeile) UND das darunterliegende `.stats-banner` — dessen Rolle
   uebernimmt das Stat-Grid der Vorlage in der Textspalte. Beide alten Bloecke
   sind entfernt, nicht ueberschrieben: eine tote CSS-Leiche, die spaeter
   jemand wieder anfasst, ist teurer als der Loeschvorgang jetzt.

   Was von der Vorlage NICHT kommt (Regie-Notiz 12, Inhaber-Ansage):
   ihr eigener Header und ihr Logo. Unsere globale Nav bleibt die einzige.
   Die beiden Geister-Wortmarken ("Performance" / "Stage 2") gehoeren dagegen
   ausdruecklich zum Hero und sind uebernommen.

   Praefix `th-` = tuning-hero. Alle Werte stammen aus der Vorlage; wo eine
   Zahl abweicht, steht der Grund daneben.
   ========================================================================== */
.th-hero {
  position: relative; overflow: hidden; isolation: isolate;
  /* Vorlage: padding-top clamp(22px,2.6vw,44px). Bei uns steht darueber die
     FIXE Nav (76 px, ab 1024 px 88 px) — die Vorlage zeichnete ihre Nav in den
     Hero hinein und brauchte den Platz nicht. */
  padding: clamp(104px, 9vw, 132px) clamp(16px, 3.4vw, 64px) clamp(24px, 2.4vw, 40px);
}
.th-hero::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  /* Grundflaeche halbtransparent, damit die Platine unter dem Hero durchlaeuft
     (Werte gemessen: _work/_bericht-durchscheinen.md). Der frueher hier
     liegende rote Radial-Glow ist ENTFALLEN: die Vorlage baut ihr Rot aus dem
     Karten-Glow und der roten Headline-Zeile auf: ein zweiter roter Wasch
     dahinter haette genau die rot-auf-rot-Lage erzeugt, die auf dieser Seite
     schon einmal einen Text gerissen hat (Kommentar an der CTA-Sektion). */
  background: linear-gradient(180deg, rgba(5,5,5,.62), rgba(10,10,10,.52));
}
/* .55/.45 waren die gemessenen Werte des alten Heros. Die neue Headline ist
   fast doppelt so gross und steht in Rot statt Weiss — 0,07 mehr Dichte gibt
   ihr die Reserve ueber der 3:1-Schwelle, ohne dass die Platine im Hero
   sichtbar weniger durchlaeuft (gegengeprueft an den Screenshots). */

/* --- Geister-Wortmarken -----------------------------------------------------
   Riesige Konturschrift als Tiefenebene, ueber dem Rig und unter dem Inhalt.
   `nowrap` + vw-Groesse heisst: sie ragen bewusst weit ueber den Viewport
   hinaus — das `overflow:hidden` des Heros ist deshalb tragend, nicht
   kosmetisch (ohne es scrollt die ganze Seite waagerecht). */
.th-wm {
  position: absolute; z-index: 1; pointer-events: none; user-select: none;
  font-family: 'Archivo Black', Impact, sans-serif; line-height: 1;
  text-transform: uppercase; white-space: nowrap; color: transparent;
}
.th-wm-a {
  left: -3%; top: 9%; font-size: clamp(160px, 26vw, 420px);
  -webkit-text-stroke: 1px rgba(255,255,255,.045);
  animation: th-wmDrift 40s ease-in-out infinite alternate;
}
.th-wm-b {
  right: -2%; bottom: 6%; font-size: clamp(120px, 18vw, 300px);
  -webkit-text-stroke: 1px rgba(232,22,31,.06);
  animation: th-wmDrift 52s ease-in-out infinite alternate-reverse;
}

/* --- Raster ---------------------------------------------------------------- */
.th-grid {
  position: relative; z-index: 10;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(440px, 100%), 1fr));
  gap: clamp(26px, 4vw, 72px); align-items: center;
  max-width: 1680px; margin: 0 auto;
  min-height: min(calc(100svh - 220px), 900px);
}
.th-col { min-width: 0; }

/* --- Textspalte ------------------------------------------------------------ */
.th-eyebrow { display: flex; align-items: center; gap: 11px; margin-bottom: clamp(12px, 2vw, 30px); animation: th-fadeIn .8s ease both; }
.th-eyebrow i { width: 7px; height: 7px; background: var(--red); animation: th-redBlink 4.5s linear infinite; }
.th-eyebrow span { text-transform: uppercase; font-family: var(--font-mono); font-size: 11px; letter-spacing: 3.2px; color: #ff5058; }

.th-h1 {
  margin: 0; font-family: 'Archivo Black', Impact, sans-serif; font-weight: 400;
  font-size: clamp(34px, 5.7vw, 92px); line-height: .9; letter-spacing: -.022em;
  text-transform: uppercase; color: #fff;
}
/* Zeilen-Maske: die aeussere Zeile schneidet, die innere faehrt hoch. Die
   Padding/Margin-Paare heben sich auf — sie schaffen nur Platz fuer die
   Unterlaengen und die Scherung, ohne die Zeilen auseinanderzuziehen. */
.th-h1 .z { display: block; overflow: hidden; padding: 0 .18em .1em .02em; margin: 0 0 -.1em -.02em; }
.th-h1 .z > span { display: block; transform: skewX(-9deg); animation: th-lineUp 1s cubic-bezier(.16,1,.3,1) both; }
.th-h1 .z:nth-child(1) > span { animation-delay: .05s; }
.th-h1 .z:nth-child(2) > span { animation-delay: .16s; }
/* Die zwei roten Zeilen tragen das Rot der VORLAGE (#e8161f), nicht das
   Flaechen-Rot --red (#e10600) der Seite. Der Unterschied ist mit blossem Auge
   keiner — gemessen sind es aber 8 % mehr Leuchtdichte, und genau die fehlten:
   mit --red lag die Zeile ueber dem hellsten Punkt der Platine bei 2,85-2,99:1
   gegen die 3:1-Schwelle fuer grosse Schrift. Die Vorlage hatte hier von
   Anfang an den helleren Wert. */
.th-h1 .z:nth-child(3) > span { animation-delay: .27s; color: #e8161f; }
.th-h1 .z:nth-child(4) > span { animation-delay: .38s; color: #e8161f; text-shadow: 0 0 60px rgba(232,22,31,.4); }

.th-lede {
  margin: clamp(14px, 2.4vw, 34px) 0 0; max-width: 44ch;
  font-family: var(--font-body);
  font-size: clamp(15px, 1.15vw, 19px); line-height: 1.6;
  /* Vorlage: rgba(255,255,255,.62). Auf unserem Grund (halbtransparent, mit
     Platine darunter) sind das gemessen zu wenig — .74 entspricht #b4b4b4 und
     haelt die 4,5:1 auch ueber einem hellen Leiterbahn-Knoten. */
  color: rgba(255,255,255,.74); text-wrap: pretty;
  animation: th-rise .9s cubic-bezier(.16,1,.3,1) .5s both;
}
.th-lede b { color: #fff; font-weight: inherit; }

.th-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: clamp(18px, 2.6vw, 36px); animation: th-rise .9s cubic-bezier(.16,1,.3,1) .6s both; }
.th-btn {
  text-transform: uppercase;
  display: flex; align-items: center; gap: 12px;
  padding: 15px clamp(18px, 2vw, 26px); border-radius: 999px;
  font-family: var(--font-mono); font-size: clamp(11px, .85vw, 12px); letter-spacing: 1.6px;
  transition: transform .3s cubic-bezier(.16,1,.3,1), box-shadow .3s, border-color .3s, background .3s;
}
.th-btn-rot { background: var(--red); color: #fff; font-weight: 700; box-shadow: 0 14px 40px -14px rgba(225,6,0,.95); }
.th-btn-rot:hover { color: #fff; transform: translateY(-2px); box-shadow: 0 20px 48px -14px rgba(225,6,0,1); }
.th-btn-geist { border: 1px solid var(--border-2); color: #fff; background: rgba(255,255,255,.03); }
.th-btn-geist:hover { color: #fff; border-color: rgba(255,255,255,.42); background: rgba(255,255,255,.08); }
.th-btn:focus-visible { outline: 2px solid var(--red-bright); outline-offset: 3px; }

/* --- Stat-Grid (ersetzt das alte .stats-banner) -----------------------------
   Die 1px-Luecke des Grids auf hellem Grund IST das Trennlinien-Raster. */
.th-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(80px, 100%), 1fr));
  gap: 1px; margin-top: clamp(20px, 3.4vw, 52px);
  background: rgba(255,255,255,.09); border: 1px solid rgba(255,255,255,.09);
  animation: th-rise .9s cubic-bezier(.16,1,.3,1) .72s both;
}
.th-stats > div { padding: clamp(10px, 1.2vw, 16px) clamp(9px, 1vw, 14px); background: #08080a; }
.th-stats .v { font-family: 'Archivo Black', Impact, sans-serif; font-size: clamp(18px, 2.2vw, 32px); color: #fff; line-height: 1; transform: skewX(-9deg); transform-origin: left; }
.th-stats .v i { font-style: normal; font-size: .6em; color: #ff3b46; }   /* var(--red) faellt hier auf 3,3:1 gegen #08080a */
/* 8 px war die Vorlage. Als Beschriftung der Beleg-Zahlen ("Mehrleistung
   moeglich") ist das lesbare Information und gehoert nach Review 20/9 §2 auf
   mindestens 10 px; das Tracking geht dafuer von 1,1 auf 0,8 px zurueck,
   damit die 89-px-Zelle @390 nicht noch staerker trennen muss. */
.th-stats .l {
  text-transform: uppercase; margin-top: 7px; font-family: var(--font-mono);
  font-size: 10px; letter-spacing: .8px; color: rgba(255,255,255,.62);
  /* Bei 390 px ist eine Zelle 89 px breit — "LEISTUNGSMESSUNG" ist als EIN
     Wort breiter und lief gemessen in die Nachbarzelle. Silbentrennung statt
     harter Bruch: die Seite ist lang="de", Chrome trennt korrekt. */
  hyphens: auto; overflow-wrap: break-word;
}
/* Vorlage: rgba(255,255,255,.42) = 4,0:1 gegen die Kachelflaeche #08080a und
   damit unter der Schwelle — bei 8 px Schriftgroesse der schlechteste Ort der
   Seite fuer eine Abkuerzung. .62 = 6,8:1, optisch derselbe stille Grauton. */

/* --- Medienspalte ---------------------------------------------------------- */
.th-media { min-width: 0; perspective: 1400px; animation: th-cardIn 1.1s cubic-bezier(.16,1,.3,1) .3s both; }
.th-buehne { position: relative; }
.th-hatch { position: absolute; pointer-events: none; }
.th-hatch-a { right: -22px; top: -22px; width: 46%; height: 42%; opacity: .5; background: repeating-linear-gradient(135deg, rgba(232,22,31,.55) 0 2px, transparent 2px 13px); }
.th-hatch-b { left: -26px; bottom: -20px; width: 34%; height: 30%; opacity: .4; background: repeating-linear-gradient(135deg, rgba(255,255,255,.28) 0 1.5px, transparent 1.5px 14px); }
.th-tilt { position: relative; transform-style: preserve-3d; transition: transform .5s cubic-bezier(.16,1,.3,1); will-change: transform; }

.th-karte {
  position: relative; aspect-ratio: 16 / 9.6; overflow: hidden;
  /* Bezugsgroesse fuer die Typ-Wortmarke unten: sie muss sich an der KARTE
     messen, nicht am Viewport. Die Karte ist mal halb so breit wie das Fenster
     (zweispaltiger Hero) und mal fast so breit (einspaltig) — eine
     Viewport-Query trifft den Fall daher nicht. */
  container-type: inline-size;
  border: 1px solid var(--border-1); border-radius: 18px; background: #0c0c0e;
  box-shadow: 0 60px 120px -50px rgba(0,0,0,1), 0 0 0 1px rgba(255,255,255,.03) inset;
}
/* AUF DAS MOTIV UMGESTELLT 2026-08-23 (Cupra -> M850i).
   Der Ebenen-Stapel war fuer einen WEISSEN Wagen in heller Halle komponiert.
   Gemessen am neuen Bild: mittlere Luminanz 76 statt 118, und `contrast(1.06)`
   vertieft bei schwarzem Lack genau die Schwaerzen, die ohnehin schon zu sind.
   Der Filter geht deshalb auf contrast < 1 und etwas Helligkeit; die Datei
   selbst ist zusaetzlich schon aufgehellt (_work/azb-bilder.mjs) — im Bild
   statt nur im CSS, damit es den WordPress-Port ueberlebt. */
.th-karte > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: saturate(1.08) contrast(.98) brightness(1.08); }
/* Der staerkste Schwarzanteil sass unten (88 %). Beim Cupra lag dort
   unwichtiger heller Boden — beim M850i ist der Betonboden der EINZIGE helle
   Anker der Buehne, und der wurde von L 147 auf L 22 heruntergedrueckt.
   Jetzt bleibt nur das unterste Sechstel dunkel, wo der "Werkstatt
   geoeffnet"-Chip sitzt; die Bildmitte ist frei, die Oberkante mit dem
   AZB-Banner wird nicht mehr auf .35 gedimmt. */
.th-karte .lage-1 { position: absolute; inset: 0; background: linear-gradient(to top, rgba(5,5,6,.80) 0%, rgba(5,5,6,.45) 14%, rgba(5,5,6,.04) 34%, rgba(5,5,6,.22) 100%); }
/* Der rote Radial ist LICHT (mix-blend-mode: screen). Von 78%/18% nach
   64%/42% gewandert: dort streift er ueber Haube und Dach und gibt dem
   schwarzen Lack ein Glanzlicht statt einer leeren Flaeche. */
.th-karte .lage-2 { position: absolute; inset: 0; background: radial-gradient(circle at 64% 42%, rgba(232,22,31,.24), transparent 58%); mix-blend-mode: screen; }
.th-karte .scan { position: absolute; left: 0; right: 0; height: 38%; background: linear-gradient(to bottom, transparent, rgba(255,255,255,.055), transparent); animation: th-scanUp 7s linear infinite; pointer-events: none; }
.th-karte .marke { text-transform: uppercase; position: absolute; top: 16px; right: 16px; display: flex; align-items: center; gap: 8px; padding: 9px 14px; border-radius: 999px; background: var(--red); font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 1.8px; color: #fff; }
.th-karte .projekt {
  position: absolute; top: 16px; left: 16px; display: flex; flex-direction: column; gap: 6px;
  isolation: isolate;
}
/* Das Label steht direkt auf dem Foto — dort, wo der Verlauf der Karte am
   duennsten ist. Gemessen 2,3:1 gegen die hellste Stelle darunter. Statt das
   ganze Foto abzudunkeln bekommt nur diese eine Zeile einen weichen eigenen
   Grund (dieselbe Loesung wie bei .section-marker weiter unten). */
.th-karte .projekt::before {
  content: ""; position: absolute; inset: -12px -22px -14px -16px; z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 74% 170% at 24% 50%, rgba(5,5,6,.96) 0%, rgba(5,5,6,.88) 52%, rgba(5,5,6,0) 100%);
}
.th-karte .projekt s { display: block; width: 26px; height: 1px; background: rgba(255,255,255,.5); }
.th-karte .projekt span { text-transform: uppercase; font-family: var(--font-mono); font-size: 9px; letter-spacing: 1.6px; color: #fff; }
.th-karte .offen { position: absolute; left: 16px; bottom: 16px; display: flex; align-items: center; gap: 10px; padding: 9px 15px; border-radius: 999px; background: rgba(10,10,12,.72); backdrop-filter: blur(10px); border: 1px solid var(--border-1); }
.th-karte .offen i { width: 7px; height: 7px; border-radius: 50%; background: #3fdc78; animation: th-livePulse 2.4s ease-out infinite; }
/* ausserhalb der Oeffnungszeiten (Klasse setzt site.js aus den echten Zeiten) */
.th-karte .offen.ist-zu i { background: #8a8a8a; animation: none; }
.th-karte .offen span { text-transform: uppercase; font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.6px; color: #fff; }
.th-karte .typ { text-transform: uppercase; position: absolute; right: 16px; bottom: 16px; font-family: 'Archivo Black', Impact, sans-serif; font-size: clamp(28px, 3vw, 44px); line-height: 1; color: transparent; -webkit-text-stroke: 1px rgba(255,255,255,.35); transform: skewX(-9deg); }
/* Typ-Wortmarke und der "Werkstatt geoeffnet"-Chip teilen sich dieselbe
   Grundlinie am unteren Kartenrand. Ist die Karte schmal, laeuft die Wortmarke
   IN den Chip: gemessen 1.899 px2 Schnittflaeche bei 390 px Viewport und
   2.739 px2 bei 360 px — der deckende Chip verschluckte dort das "IB" von
   IBIZA, die Zeile las sich als "…IZA CUPRA".
   Sie weicht nicht nach oben aus, sondern entfaellt. Der Modellname steht
   ohnehin schon oben links ("Projekt · M850i"), und das Element ist
   aria-hidden — es geht also keine Information verloren, nur eine Zierde,
   fuer die kein Platz ist.
   NACHGEZOGEN 2026-08-23: Die urspruengliche Begruendung nannte hier die
   "weisse Flanke des Autos", auf der eine weisse Konturschrift unsichtbar
   waere. Mit dem schwarzen M850i traegt dieser Teil nicht mehr — die Schrift
   waere dort sogar gut lesbar. Die Regel bleibt trotzdem, aber jetzt allein
   wegen der Ueberlappung mit dem Chip. Die 450-px-Schwelle stammt aus der
   Wortbreite von "IBIZA CUPRA" (11 Zeichen); "M850i" hat 5 und braucht
   deutlich weniger Platz — nach dem Tausch bei 390 px nachgemessen und
   passend belassen. Wer die Wortmarke wieder verlaengert, muss neu messen.
   Die Schwelle ist knapp gewaehlt, damit NUR die Faelle kippen, die wirklich
   ueberlappen: gemessen ist die Luecke ~ Kartenbreite minus 441 px, bei 450 px
   bleiben also 9 px Luft. Betroffen sind damit die schmale Einspalten-Karte
   (390 px -> 358, 360 px -> 328) und die enge Zweispalten-Lage knapp oberhalb
   1000 px (Karte ~440). Bei 1024 px (Karte 457) bleibt alles wie gehabt. */
@container (max-width: 450px) {
  .th-karte .typ { display: none; }
}

/* --- Dyno-Panel (immer) / Projekt-Kacheln (unter 1000 px) -------------------
   Die Vorlage schaltete per JS-Breitenweiche zwischen beiden Bloecken. Bei uns
   entscheidet CSS: ein JS-Schalter haette bei deaktiviertem JS oder vor dem
   ersten Frame BEIDE Bloecke gezeigt.
   ABWEICHUNG von der Vorlage (Inhaber-Ansage): das Dyno-Panel bleibt auch auf
   Mobil stehen — es ist der Beleg der Seite, nicht ihr Zierat. Unter 1000 px
   kommen die zwei Projekt-Kacheln ZUSAETZLICH darunter, darueber nicht mehr
   (dort traegt die breite Karte den Bildanteil allein).
   Es gibt deshalb bewusst KEINE `display`-Regel fuer .th-dyno: sie stand hier
   frueher als leerer Rumpf und las sich wie ein vergessenes `display:none`. */
.th-kacheln { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 14px; }
@media (min-width: 1000px) {
  .th-kacheln { display: none; }
}

.th-dyno {
  position: relative; z-index: 3; margin: 14px 0 0; padding: 14px 16px 12px;
  border-radius: 16px; background: rgba(10,10,12,.82); backdrop-filter: blur(18px);
  border: 1px solid var(--border-1); box-shadow: 0 40px 80px -40px rgba(0,0,0,1);
  animation: th-floaty 9s ease-in-out infinite;
}
.th-dyno .kopf { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.th-dyno .kopf .quelle { text-transform: uppercase; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 2px; color: rgba(255,255,255,.66); }
/* Fruehere Kopfzeile rechts: gruen pulsierender "Beispiellauf". Gruen + Puls
   liest sich als "laeuft gerade" — bei einer Auslegung aus dem Anbieter-
   Konfigurator ist das eine Erfindung. Jetzt eine ruhige Stufen-Plakette. */
.th-dyno .kopf .stufe { text-transform: uppercase; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 1.6px; color: #ffb31a; border: 1px solid rgba(255,179,26,.42); border-radius: 999px; padding: 4px 9px; white-space: nowrap; }

/* Werte als Vorher/Nachher-Tabelle wie im Anbieter-Bild: Zeile "Original",
   darunter "Nach Tuning", rechts die beiden Deltas. */
.th-dyno .werte { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; margin-top: 12px; flex-wrap: wrap; }
.th-dyno .tabelle { display: grid; grid-template-columns: auto auto auto; align-items: baseline; column-gap: 16px; row-gap: 3px; }
.th-dyno .zl { text-transform: uppercase; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 1.4px; color: rgba(255,255,255,.58); align-self: center; }
.th-dyno .zl.stark { color: rgba(255,255,255,.82); }
.th-dyno .zw { display: flex; align-items: baseline; gap: 5px; }
.th-dyno .zw b { font-family: 'Archivo Black', Impact, sans-serif; font-size: 17px; line-height: 1; color: rgba(255,255,255,.62); transform: skewX(-9deg); display: inline-block; font-variant-numeric: tabular-nums; font-weight: 400; }
.th-dyno .zw i { font-style: normal; text-transform: uppercase; font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 1.2px; color: rgba(255,255,255,.5); }
.th-dyno .zw.gross b { font-size: clamp(28px, 2.5vw, 38px); }
.th-dyno .zw.gross b.ps { color: #ffb31a; }
.th-dyno .zw.gross b.nm { color: #ff5a63; }
.th-dyno .zw.gross i { font-size: 11px; letter-spacing: 1.4px; color: rgba(255,255,255,.7); }
.th-dyno .deltas { display: flex; flex-direction: column; gap: 5px; align-items: flex-end; }
.th-dyno .delta { padding: 5px 10px; border-radius: 999px; background: rgba(232,22,31,.16); border: 1px solid rgba(232,22,31,.5); font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: 1.4px; color: #ff5a63; white-space: nowrap; }

/* Das Diagramm traegt jetzt VIER Kurven statt einer. Auf 96 px Hoehe waeren
   das 7 PS je Pixel gewesen — die Linien waeren stellenweise ineinander
   gelaufen. 150-190 px geben ihnen den Platz, den die Aussage braucht. */
.th-dyno svg { display: block; width: 100%; height: clamp(150px, 13vw, 190px); margin-top: 12px; overflow: visible; }
.th-dyno .flaeche { animation: th-wipeIn 1.6s cubic-bezier(.16,1,.3,1) 1.5s both; }
/* pathLength="100" steht am <path>: damit ist die Zeichen-Animation von der
   echten Pfadlaenge UNABHAENGIG. Vorher stand hier ein fester dasharray-Wert
   von 640 bei tatsaechlich 329 px Pfadlaenge — die Zeichenfront war nach 49 %
   des Weges fertig und den Rest der Laufzeit passierte nichts. Diese Klasse
   Fehler kann mit pathLength nicht wiederkommen. */
.th-dyno .kurve { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.th-dyno .kurve.k-ps { stroke: #ffb31a; }
.th-dyno .kurve.k-nm { stroke: #ff2a33; }
/* Serie leise und flach, Stage 1 hell und mit Schein: die Hierarchie ersetzt
   eine Beschriftung an jeder einzelnen Kurve. Gestrichelt = Serie,
   durchgezogen = Stage 1 — dieselbe Zuordnung wie im Anbieter-Bild.
   Die Serienkurven koennen sich nicht "zeichnen" (ihr dasharray traegt schon
   das Strichmuster), sie blenden deshalb auf. */
.th-dyno .kurve.serie { stroke-width: 1.8; stroke-dasharray: 2.2 1.6; opacity: 0; animation: th-fadeCurve .9s ease-out .4s forwards; }
.th-dyno .kurve.stufe { stroke-width: 2.6; stroke-dasharray: 100; stroke-dashoffset: 100; animation: th-draw 1.4s cubic-bezier(.16,1,.3,1) 1s forwards; }
.th-dyno .kurve.stufe.k-ps { filter: drop-shadow(0 0 7px rgba(255,179,26,.55)); }
.th-dyno .kurve.stufe.k-nm { filter: drop-shadow(0 0 7px rgba(255,42,51,.5)); }
/* offset-path wird per JS aus dem `d` der Leistungskurve gesetzt (Skript am
   Seitenende). Frueher stand der Pfad-String hier ein ZWEITES Mal — wer nur
   das SVG aenderte, bekam einen Punkt, der neben der Kurve schwebte. */
.th-dyno .laeufer { offset-path: none; animation: th-runPath 5.4s cubic-bezier(.4,0,.6,1) 2.6s infinite; filter: drop-shadow(0 0 6px rgba(255,255,255,.9)); }

/* Legende. Farbe trennt Leistung/Drehmoment, Strichart trennt Serie/Stage 1. */
.th-dyno .legende { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px; }
.th-dyno .lg { display: inline-flex; align-items: center; gap: 6px; text-transform: uppercase; font-family: var(--font-mono); font-size: 10px; letter-spacing: .9px; color: rgba(255,255,255,.62); }
.th-dyno .sw { width: 16px; height: 0; border-top: 2px solid currentColor; flex: none; }
.th-dyno .sw-ps { color: #ffb31a; }
.th-dyno .sw-nm { color: #ff2a33; }
.th-dyno .sw-voll { color: rgba(255,255,255,.75); }
.th-dyno .sw-strich { color: rgba(255,255,255,.75); border-top-style: dashed; }
.th-dyno .fussnote { margin: 9px 0 0; font-family: var(--font-mono); font-size: 10px; letter-spacing: .6px; line-height: 1.5; color: rgba(255,255,255,.5); }
/* Achsen-Beschriftung des Diagramms: 8,5 px ist auch fuer Deko die
   Untergrenze unterschritten (Review 20/9 §2 — 10 px sind fuer
   aria-hidden-nahe Deko erlaubt, 8,5 px sind es nicht). Tracking 1,2 -> 0,9 px,
   damit die fuenf Marken in der Kartenbreite nebeneinander stehen bleiben. */
/* Die Marken werden ABSOLUT gesetzt, nicht per space-between verteilt.
   Grund, am Rendering gemessen: mit space-between belegt die Einheit "U/min"
   einen der sechs Verteilpunkte — "6000" landete dadurch bei 75 % statt am
   Ende der Achse, also nachweislich NICHT dort, wo die 6000er-Drehzahl im
   Diagramm liegt. Bei einer erfundenen Beispielkurve war das egal; bei einer
   digitalisierten Kurve ist eine Achse, die 25 % danebenliegt, ein Fehler.
   Die Drehzahl-Achse ist linear 0..6000 -> die Marken sitzen auf 0/25/50/75/100 %.
   Die Einheit steht deshalb zentriert in einer eigenen Zeile darunter, wie in
   jedem Diagramm. */
.th-dyno .achse { position: relative; height: 13px; font-family: var(--font-mono); font-size: 10px; letter-spacing: .9px; color: rgba(255,255,255,.58); margin-top: 4px; }
.th-dyno .achse span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.th-dyno .achse span:nth-child(1) { left: 0; transform: none; }
.th-dyno .achse span:nth-child(2) { left: 25%; }
.th-dyno .achse span:nth-child(3) { left: 50%; }
.th-dyno .achse span:nth-child(4) { left: 75%; }
.th-dyno .achse span:nth-child(5) { left: 100%; transform: translateX(-100%); }
.th-dyno .einheit { display: block; text-align: center; text-transform: uppercase; font-family: var(--font-mono); font-size: 10px; letter-spacing: 1.2px; color: rgba(255,255,255,.5); margin-top: 3px; }
/* Der Ladedruck-Balken ("1,4 bar") stand hier bis 2026-08-23 und ist ersatzlos
   entfallen: die Zahl war durch nichts belegt — sie kommt im Kennfeld-Bild des
   Anbieters nirgends vor. Dieselbe Fehlerklasse wie die frueheren "180+
   PROJEKTE" und die erfundenen 182 PS, nur zwei Runden lang uebersehen. An
   seiner Stelle steht jetzt `.fussnote` mit dem, was in der Quelle wirklich
   steht (ohne Getriebetuning, Kosten auf Anfrage). Mit ihm ist auch
   @keyframes th-boostFill entfallen — es hatte keinen zweiten Nutzer. */
/* Die kleinen Mono-Zeilen des Panels standen in der Vorlage bei .30-.50 Weiss.
   Auf der geblurrten Panelflaeche (rgba(10,10,12,.82) ueber der Platine) sind
   das 2,4-4,0:1 — angehoben auf .58-.66 (>= 4,6:1), Ton bleibt zurueckhaltend. */

.th-kachel { position: relative; display: block; aspect-ratio: 16 / 10; overflow: hidden; border-radius: 12px; border: 1px solid var(--border-1); }
/* Bildzoom auf den Familien-Wert .8s (Review 20/10, Inventar 1: dieselbe Geste
   lief site-weit auf .6/.7/.8/.9s). Kurve unveraendert. Das Kippen der Karte
   (.th-tilt, .5s) bleibt davon unberuehrt — das ist ein Tilt, kein Bildzoom. */
.th-kachel img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.95); transition: transform .8s cubic-bezier(.16,1,.3,1); }
.th-kachel:hover img, .th-kachel:focus-visible img { transform: scale(1.05); }
.th-kachel span { text-transform: uppercase; position: absolute; left: 10px; bottom: 9px; font-family: var(--font-mono); font-size: 9px; letter-spacing: 1.4px; color: #fff; text-shadow: 0 2px 8px rgba(0,0,0,.9); }
.th-kachel:focus-visible { outline: 2px solid var(--red-bright); outline-offset: 3px; }

/* --- Laufband ---------------------------------------------------------------
   Gehoert zum Hero (Regie-Notiz 5) und ist das einzige Laufband der Seite. */
.th-band {
  position: relative; z-index: 10; overflow: hidden;
  border-top: 1px solid var(--border-1); border-bottom: 1px solid var(--border-1);
  /* Vorlage: rgba(8,8,10,.6). Ueber unserer Platine schlugen dort helle
     Leiterbahn-Knoten durch und drueckten die 11-px-Zeile auf 2,5:1. .88
     laesst das Band noch als Flaeche und nicht als schwarzen Riegel wirken. */
  background: rgba(8,8,10,.88);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.th-band .spur { display: flex; width: max-content; animation: th-marquee 34s linear infinite; }
.th-band .spur > div { text-transform: uppercase; display: flex; align-items: center; gap: 34px; padding: 16px 17px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 2.6px; color: rgba(255,255,255,.72); white-space: nowrap; }
.th-band .spur b { color: #ff5058; font-weight: 400; }

@keyframes th-lineUp   { from { transform: translateY(112%) skewX(-9deg); } to { transform: translateY(0) skewX(-9deg); } }
@keyframes th-rise     { from { opacity: 0; transform: translateY(22px); } to { opacity: 1; transform: translateY(0); } }
@keyframes th-fadeIn   { from { opacity: 0; } to { opacity: 1; } }
@keyframes th-cardIn   { from { opacity: 0; transform: translateY(40px) scale(.97); } to { opacity: 1; transform: translateY(0) scale(1); } }
@keyframes th-wipeIn   { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes th-marquee  { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
@keyframes th-livePulse{ 0%,100% { opacity: 1; box-shadow: 0 0 0 0 rgba(64,220,120,.55); } 70% { opacity: .85; box-shadow: 0 0 0 7px rgba(64,220,120,0); } }
@keyframes th-redBlink { 0%,72% { opacity: 1; } 76%,84% { opacity: .25; } 88%,100% { opacity: 1; } }
/* 100, nicht 640: die Kurven tragen pathLength="100", der Offset ist damit in
   Prozent der Pfadlaenge angegeben und von der Geometrie unabhaengig. */
@keyframes th-draw     { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes th-fadeCurve{ from { opacity: 0; } to { opacity: .5; } }
@keyframes th-runPath  { from { offset-distance: 0%; } to { offset-distance: 100%; } }
@keyframes th-scanUp   { 0% { transform: translateY(105%); } 100% { transform: translateY(-105%); } }
@keyframes th-floaty   { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
@keyframes th-wmDrift  { from { transform: translate3d(-2%,0,0) skewX(-9deg); } to { transform: translate3d(2%,0,0) skewX(-9deg); } }

/* Ruhe-Modus: die Vorlage bringt eine globale Sperre mit (Regie-Notiz 3).
   Alles bleibt STEHEN, nichts bleibt unsichtbar — die Fuellwerte der
   `both`-Animationen sind der komponierte Endzustand. Fuer die vier
   Kennfeld-Kurven heisst das: die getunten stehen fertig gezeichnet
   (dashoffset 0), die Serienkurven auf ihrer Ziel-Deckkraft — sonst waeren
   sie bei `opacity: 0` fuer Ruhe-Nutzer schlicht unsichtbar, und das Diagramm
   haette ohne Vergleichslinien keine Aussage mehr. */
@media (prefers-reduced-motion: reduce) {
  .th-hero *, .th-band * { animation: none !important; transition: none !important; }
  .th-h1 .z > span { transform: skewX(-9deg); }
  .th-dyno .kurve.stufe { stroke-dashoffset: 0; }
  .th-dyno .kurve.serie { opacity: .5; }
  .th-dyno .flaeche { clip-path: none; }
  .th-band .spur { animation: none; }
}

/* GRAVIERTE PLAKETTEN (Kachel-Design v2, Inhaber-Vorlage 2026-08-03)
   ---------------------------------------------------------------------------
   Dieselbe Kachel wie auf index.html — die Vorlage ist dort ausfuehrlich
   kommentiert (Abweichungen: --red-rgb statt zweitem Hexwert, var(--border-1)
   statt harter .075, grid-auto-rows:1fr als Hoehen-Garant).
   ZWEI Besonderheiten dieser Seite:
   a) Die Kacheln sind KEINE Links — es gibt kein Ziel je Leistung. Sie tragen
      deshalb bewusst keinen CTA-Text und keinen Pfeil: eine Kachel, die wie
      ein Link aussieht und keiner ist, ist schlechter als eine, die ehrlich
      als Informationsflaeche auftritt. Die Fusszeile bleibt (Gravur-Linie),
      auf Mobil nimmt sie die Markenzeile auf.
   b) Die Kachel bleibt DECKEND (opake Verlaufs-Hexwerte) — sie traegt
      Fliesstext und steht ueber der durchscheinenden Platine.               */
.svc-grid { display: grid; gap: 16px; grid-template-columns: 1fr; grid-auto-rows: 1fr; }
@media (min-width: 700px)  { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .svc-grid { grid-template-columns: repeat(3, 1fr); } }

/* Die Kachel selbst (.azb-card / -edge / -halo / -head / -plate / -num /
   -title / -body / -foot / -rule) steht seit 2026-08-04 in shared.css am
   Dateiende — sie war hier und in index.html zeilengleich doppelt (Review 4
   F2). Hier bleibt nur, was DIESE Seite eigen hat: das Raster, die
   Stichpunktliste und die Markenzeile. */
.azb-liste { list-style: none; margin: 16px 0 0; padding: 0; font-size: 13px; color: rgba(255,255,255,.55); }
.azb-liste li { padding-left: 20px; position: relative; margin: 6px 0; }
.azb-liste li::before { content: ''; position: absolute; left: 0; top: 9px; width: 12px; height: 1px; background: var(--red); }


/* Markenzeile: sitzt jetzt in der Fusszeile der Plakette (dort, wo auf
   index.html der CTA steht) und uebernimmt dessen Mono-Machart. */
.svc-marken {
  display: none;
  font-family: var(--font-mono); text-transform: uppercase;
  letter-spacing: .14em; font-size: 9.5px;
  color: rgba(255,255,255,.62);
  margin: 0;
}

/* MOBIL-STRAFFUNG (2026-08-03): unter 768 px tragen die sechs Kacheln nur noch
   Plakette, Titel und den Beschreibungssatz — die Stichpunktliste entfaellt.
   Grund: einspaltig stapeln sich 6 Karten zu einem 2500 px langen Textblock,
   in dem die Marken-/Detailzeilen (13 px) nach der dritten Karte niemand mehr
   liest. Der Beschreibungssatz sagt dasselbe in Prosa; die Details stehen
   weiterhin auf Desktop und im Beratungsgespraech.
   Bewusst `display:none`, nicht visuell-versteckt: ein Screenreader soll auf
   Mobil dieselbe Seite hoeren, die ein sehender Nutzer dort sieht — eine
   Liste vorzulesen, die es dort nicht gibt, waere die schlechtere Variante.
   Die Markenzeile ersetzt die Liste in der Fusszeile.
   NEU ggue. der alten .svc: die Kachel hat jetzt eine Mindesthoehe und alle
   sechs sind ueber grid-auto-rows:1fr gleich hoch — der Unterschied zwischen
   einer Kachel mit und einer ohne Markenzeile erzeugt also keinen Versatz
   mehr, sondern nur etwas mehr Luft ueber der Gravur-Linie.                 */
@media (max-width: 767px) {
  .azb-liste { display: none; }
  .svc-marken { display: block; }
}

/* Process timeline */
.process {
  display: grid; gap: 24px;
  grid-template-columns: 1fr;
  position: relative;
}
@media (min-width: 768px) { .process { grid-template-columns: repeat(4, 1fr); } }
.step {
  padding: 28px 24px; background: var(--surface-1);
  border: 1px solid var(--border-1);
  border-radius: var(--r-lg);
  position: relative;
}
.step .n {
  font-family: var(--font-display); font-style: italic;
  font-size: 64px; line-height: 1; letter-spacing: -0.04em;
  color: var(--red); margin-bottom: 16px;
}
.step h3 { font-family: var(--font-display); font-style: italic; font-size: 22px; text-transform: uppercase; letter-spacing: -0.01em; margin-bottom: 6px; }
.step p { font-size: 13px; color: var(--text-secondary); line-height: 1.65; }

/* Das frueher hier stehende `.stats-banner` (4 Grosszahlen auf schwarzem Band
   direkt unter dem Hero) ist mit dem Hero-Umbau ENTFALLEN — seine Rolle
   uebernimmt das `.th-stats`-Grid in der Hero-Textspalte, mit denselben vier
   belegten Werten (+30 % / A-Z / 2 h / TUEV). */

/* Visual showcase */
.showcase { display: grid; gap: 16px; grid-template-columns: 1fr; }
/* VIER Kacheln seit 2026-08-23 (der Ibiza Cupra ist aus dem Hero hierher
   gewandert). Das Raster trug vorher genau drei: gross links ueber zwei
   Zeilen, zwei kleine rechts. Die vierte hing sonst als Waise in einer
   impliziten dritten Zeile in der schmalen Spalte. Sie bekommt deshalb eine
   eigene, volle Breite unten — das Cupra-Bild ist mit 5:3 ohnehin quer und
   sitzt dort besser als in einem 4:3-Kaestchen. */
@media (min-width: 768px) { .showcase { grid-template-columns: 2fr 1fr; grid-template-rows: 1fr 1fr auto; } }
.showcase .img {
  position: relative; aspect-ratio: 4/3; overflow: hidden;
  border-radius: var(--r-lg); border: 1px solid var(--border-2);
  box-shadow: var(--shadow-md);
}
.showcase .img:nth-child(1) { grid-row: span 2; aspect-ratio: auto; }
@media (min-width: 768px) { .showcase .img:nth-child(4) { grid-column: 1 / -1; aspect-ratio: 16 / 6; } }
.showcase .img img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease-out); }
.showcase .img:hover img { transform: scale(1.04); }
.showcase .img .label {
  position: absolute; left: 16px; bottom: 16px;
  padding: 6px 12px; font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.22em; text-transform: uppercase;
  background: rgba(5,5,5,.7); backdrop-filter: blur(12px);
  border: 1px solid var(--border-2); border-radius: var(--r-sm);
}

/* ----------------------------------------------------------------------------
   PARTNER-/HERSTELLER-LEISTE auf dieser Seite (Basis: assets/shared.css).
   Drei Abweichungen, und die erste ist keine Feinheit, sondern Pflicht:
   (1) `.partner` bringt `background: var(--bg-base)` mit — #050505, VOLL
       DECKEND. Auf dieser Seite ist `body` bewusst transparent, damit die
       fixe #platine-buehne durchlaeuft, und alle Sektionsflaechen sind dafuer
       halbtransparent (_work/_bericht-durchscheinen.md). Unveraendert
       eingesetzt stanzt der Block ein hartes schwarzes Rechteck in die
       Platine — genau der Defekt, gegen den jener Bericht geschrieben wurde.
   (2) Die Spur laeuft hier GEGENLAEUFIG und langsamer als `.th-band` (34 s
       vorwaerts). Liefen beide gleich, laesen sie sich als derselbe Trick.
   (3) Mobil nur EIN Band. Die Startseite laesst unter 768 px ein ZWEITES,
       gegenlaeufiges Band mitlaufen (.p-band-b). Hier steht es gar nicht erst
       im Markup — es waere sonst doppelt schaedlich: `.p-spur-rev` ist bereits
       `reverse`, und weil das Hauptband hier ohnehin schon `reverse` laeuft
       (Punkt 2), liefen mobil BEIDE gleich; die "gegenlaeufig"-Idee waere
       still gestorben. Weglassen statt reparieren halbiert zugleich die
       zusaetzliche Bewegung auf dem Geraet, das am wenigsten davon vertraegt. */
body.seite-tuning .partner { background: transparent; border-top: 1px solid var(--border-1); }
body.seite-tuning .p-band { background: rgba(8,8,10,.88); }
/* 52 px waren fuer die Startseite gerechnet, wo ueber dem Kopf noch der
   .p-marker sitzt. Hier traegt .section-marker die Nummer und steht schon
   darueber — 28 px halten den Abstand zum Band, ohne die Sektion aufzublaehen. */
body.seite-tuning .p-kopf { margin-bottom: 28px; }
@media (prefers-reduced-motion: no-preference) {
  body.seite-tuning .p-spur { animation-duration: 52s; animation-direction: reverse; }
}

/* ----------------------------------------------------------------------------
   Technik-Bento — "Teile & Technik"
   Drei Stufen statt einer: 1-spaltig / 2-spaltig / echtes Bento.
   Warum nicht direkt ab 700 px ins 6-Spalten-Raster: dort ist eine Spalte nur
   ~100 px breit, die grosse Kachel geriete auf ~1,3:1 und wuerde die 16:9-Fotos
   an den Seiten aufschneiden. Zwischen 700 und 1000 px liegt deshalb ein
   ruhiges 2-Spalten-Raster.
   Die Zeilenhoehe ist fluid (`clamp`), damit die grosse Kachel (4 Spalten x
   2 Zeilen) ueber die ganze Desktop-Breite bei ~1,79:1 bleibt — also praktisch
   exakt 16:9. Gerechnet fuer 1000 / 1100 / 1280 / 1440 px: 1,76 / 1,81 / 1,79 /
   1,79. Damit croppt kein Studio-Foto nennenswert.
   -------------------------------------------------------------------------- */
.bento { display: grid; gap: 16px; grid-template-columns: 1fr; }
.bento .tile {
  position: relative; overflow: hidden; aspect-ratio: 16/9;
  border-radius: var(--r-lg); border: 1px solid var(--border-2);
  box-shadow: var(--shadow-md);
}
.bento .tile.hoch { aspect-ratio: 4/3; }
.bento .tile img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .8s var(--ease-out); }
.bento .tile:hover img { transform: scale(1.04); }
.bento .tile .label {
  position: absolute; left: 16px; bottom: 16px;
  padding: 6px 12px; font-family: var(--font-mono); font-size: 10px;
  letter-spacing: 0.22em; text-transform: uppercase;
  background: rgba(5,5,5,.7); backdrop-filter: blur(12px);
  border: 1px solid var(--border-2); border-radius: var(--r-sm);
}
@media (min-width: 700px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .bento .t-kw { grid-column: span 2; }
}
@media (min-width: 1000px) {
  .bento {
    grid-template-columns: repeat(6, 1fr);
    grid-auto-rows: clamp(165px, 16.2vw, 215px);
    /* Zwei Reihen dazu (2026-08-23) fuer die Fahrzeuge aus dem Shooting.
       Sie stehen bewusst HIER in der Teile-Galerie und nicht als eigene
       Sektionen: der Inhaber will sie praesent, aber kompakt. Der Mini
       bekommt mit vier Spalten denselben Platz wie das KW-Fahrwerk oben —
       das ist seine Hervorhebung, ohne dass die Seite dafuer einen eigenen
       Abschnitt aufmachen muss. */
    grid-template-areas:
      "a a a a b b"
      "a a a a c c"
      "d d e e e e"
      "d d e e e e"
      "f f f f g g"
      "f f f f h h";
  }
  /* Im Bento bestimmt das Raster die Hoehe, nicht das Bildformat. */
  .bento .tile, .bento .tile.hoch { aspect-ratio: auto; }
  .bento .t-kw         { grid-column: auto; grid-area: a; }
  .bento .t-endrohre   { grid-area: b; }
  .bento .t-messkopf   { grid-area: c; }
  .bento .t-leiterbahn { grid-area: d; }
  .bento .t-auspuff    { grid-area: e; }
  .bento .t-mini       { grid-column: auto; grid-area: f; }
  .bento .t-m850i      { grid-area: g; }
  .bento .t-licht      { grid-area: h; }
}
/* Die drei Shooting-Fotos sind zu ueber 70 % fast schwarz. Ihre Bildkante
   loest sich sonst im Seitengrund auf (gemessen 1,05:1 ohne Linie) — in der
   Bento-Reihe faellt das weniger auf als bei einem freistehenden Grossbild,
   aber eine kraeftigere Kante brauchen sie trotzdem. */
.bento .t-mini, .bento .t-m850i, .bento .t-licht { border-color: rgba(225,6,0,.5); }
/* NUR die 2-Spalten-Stufe: dort bekommt der Mini die volle Breite wie das
   KW-Fahrwerk, sonst stuende das Querformat in einer halben Spalte.
   Die Obergrenze 999px ist Pflicht, nicht Kosmetik — ohne sie greift die
   Regel auch im 6-Spalten-Bento darueber, steht dort NACH `grid-area: f`
   und haette den Mini von vier auf zwei Spalten zusammengezogen (gemessen:
   392 px statt 800). Reihenfolge schlaegt Spezifitaet. */
@media (min-width: 700px) and (max-width: 999px) {
  .bento .t-mini { grid-column: span 2; }
}


/* ============================================================================
   PLATINEN-BUEHNE — der cinematische Schaltkreis, NUR fuer die Tuning-Seite
   ----------------------------------------------------------------------------
   Ersetzt den frueheren STATISCHEN Stapel vollstaendig: die fuenf
   background-image-Ebenen am <html>, das Sweep-Pseudoelement am <body> und die
   Mobil-Sonderquery (260 % / .62) sind ersatzlos entfallen. Es gibt jetzt genau
   EIN Rig — <div id="platine-buehne"> als erstes Kind des <body>. Zwei Rigs
   nebeneinander waeren doppelte Paint-Kosten fuer denselben Effekt.

   Warum ein eigenes DOM-Geruest statt background-image:
   Die Leiterbahnen LEBEN nur als Inline-SVG. Die Animations-Klassen (fl/rv/br/
   pd/fk) stehen im SVG, die zugehoerigen Keyframes hier im Seiten-CSS — als
   background-image oder img-Element ist ein SVG ein Bild und ruehrt sich nicht.

   Warum viewport-hoch (fixed) statt dokumenthoch:
   EINE Kachel hat ~2.377 SVG-Knoten. Ueber die volle Dokumenthoehe (mobil
   ~10.000 px) gekachelt waeren das 30+ Kacheln = 70.000+ Knoten — auf einem
   Handy nicht vertretbar. Das Rig deckt deshalb nur den VIEWPORT ab
   (Kachelzahl = ceil(Viewporthoehe / Kachelhoehe) + 1 Reserve, real 2-3) und
   bekommt seine Tiefe aus einem leichten Scroll-Parallax per rAF, der MODULO
   Kachelhoehe umlaeuft — die Kachel ist vertikal nahtlos (Pfade laufen bewusst
   ueber y=0 und y=1620 hinaus), deshalb ist der Umlauf unsichtbar.

   Sichtbarkeit: die Host-Ebene laeuft UNGEDAEMPFT — der frueher gerechnete
   .78-Schleier (Platine effektiv 22 %) ist weg. Die Raender druecken jetzt
   Vignetten, Scanlines und das Tilt-Shift-Band. Wo ein Text dadurch reisst,
   wird LOKAL die Halbtransparenz der betroffenen Sektion angehoben (Block
   DURCHSCHEINEN weiter unten) — nicht wieder global gedaempft.

   `mix-blend-mode: screen` der Vorlage ist ueberall durch normales Alpha
   ersetzt: auf fast schwarzem Grund (#050505) ist screen optisch nicht von
   normal zu unterscheiden, kostet aber auf iOS-Safari zusammen mit `fixed`
   Repaints. Einzige Ausnahme: das Korn (overlay) — dort traegt der Blend-Modus
   den Effekt, ohne ihn waere die Textur entweder unsichtbar oder ein Grauschleier.
   ========================================================================== */

/* Der <body> traegt in shared.css ein deckendes `background: var(--bg-base)`.
   Das wuerde die Buehne (z-index:-1) vollstaendig verdecken. Die Grundfarbe
   haelt stattdessen das Wurzelelement — sonst zeigte der Canvas bei
   transparentem html UND body die UA-Default-Farbe. */
html:has(body.seite-tuning) { background-color: #050505; }
body.seite-tuning { background-color: transparent; }

/* --- Die Buehne selbst -------------------------------------------------- */
#platine-buehne {
  position: fixed; inset: 0;
  z-index: -1;                 /* immer hinter dem Inhalt */
  pointer-events: none;        /* faengt keinen einzigen Klick ab */
  contain: strict;             /* clippt + haelt Layout/Paint lokal */
  overflow: hidden;
  background-color: #050505;

  /* Kachelbreite = Viewportbreite x Zoom. Der Zoom ist der Hebel gegen den
     Mobil-Befund des Inhabers ("Platine unsichtbar"): bei 1:1 laege eine
     1920er Kachel auf 390 px, die 1,4-px-Leiterbahnen faelen unter die
     Geraetepixel-Schwelle und wuerden zu Grauschleier. Bei Zoom 3 liegt sie
     auf 1170 px — die Bahnen lesen sich wieder als Linien. Nebeneffekt: die
     Kachel wird hoeher als der Viewport, es reicht EINE + Reserve statt drei. */
  --pb-zoom: 1;

  /* Die Kachel-Textur der drei unscharfen Ebenen (far/near/ghost). Sie stand
     bis 2026-08-04 dreimal als `url('/wp-content/themes/azb-performance/assets/circuit-anim.svg')` direkt in den
     Regeln — dieselbe Datei, die das Skript unten per fetch() holt, um sie als
     Inline-SVG zu klonen. Gemessen waren das ZWEI Netz-Requests a 172 KB fuer
     denselben Inhalt (auch mit ETag/Cache-Control: der CSS-Hintergrund und der
     fetch laufen parallel los, der Cache kann noch nicht greifen).
     Jetzt liefert das Skript nach genau EINEM fetch eine Blob-URL in diese
     Variable; faellt der fetch aus, traegt es hier die Datei-URL nach (dann
     laedt sie einmal, statt nie). */
  --pb-tex: none;
}
@media (max-width: 640px)  { #platine-buehne { --pb-zoom: 3.4; } }
@media (min-width: 641px) and (max-width: 1023px) { #platine-buehne { --pb-zoom: 1.6; } }

#platine-buehne > * { position: absolute; }

/* (1) FERNE — unscharfe, kleine Kachel-Textur ganz hinten, mit Mit-Parallax.
   Bewegt wird sie per `transform`, NICHT per `background-position`: eine
   verschobene background-position zwingt den Browser, die Flaeche in jedem
   Scroll-Frame neu zu zeichnen UND neu weichzuzeichnen — gemessen sprang die
   Bildzeit dadurch von 88 ms auf 795 ms. Ein transform wird dagegen einmal
   gerastert und danach nur noch verschoben. Damit dabei nie eine Kante
   auftaucht, ragt das Element oben und unten um genau EINE Hintergrund-
   Kachelhoehe hinaus (setzt das Skript) und der Versatz laeuft modulo dieser
   Hoehe um. Die px-Werte fuer Groesse/Ueberstand kommen aus dem Skript; die
   Angaben hier sind die Rueckfallebene ohne JS. */
.pb-far {
  left: -14px; right: -14px; top: -60%; bottom: -60%;
  background-image: var(--pb-tex);
  background-repeat: repeat;
  background-size: calc(46% * var(--pb-zoom)) auto;
  opacity: .26;
  filter: blur(1.1px) saturate(.8);
  will-change: transform;
}

/* (2) HOST — die lebende Hauptebene. Kacheln kommen per JS als Inline-SVG.
   Die Maske ersetzt das `backdrop-filter`-Tilt-Shift-Band der Vorlage: sie
   blendet die SCHARFE Ebene oben und unten aus, waehrend far/near (statisch
   weichgezeichnet) dort stehenbleiben. Optisch dasselbe Ergebnis — nur das
   Mittelband traegt Zeichnung, die Raender nur Dunst — aber die Maske wird
   EINMAL gerastert, waehrend `backdrop-filter` den kompletten Stapel darunter
   in JEDEM Frame neu rastern muss. Gemessen war das allein 35 ms pro Frame. */
/* ZWEITE MASKE + opacity (Hero-Vorlage, Regie-Notiz 13): links gedaempft,
   rechts voll — so tritt die Platine genau dort hervor, wo die Hero-Karte
   steht, und tritt unter der Textspalte zurueck. Die bestehende SENKRECHTE
   Maske (oben/unten ausblenden) bleibt unveraendert; beide werden per
   `mask-composite: intersect` multipliziert, statt dass die neue die
   gemessene alte ersetzt. `-webkit-mask-composite: source-in` ist dieselbe
   Rechnung in der alten WebKit-Schreibweise.
   Beide Aenderungen machen den Stapel nur DUNKLER — die gemessenen
   Kontrastwerte der Seite koennen dadurch nicht fallen. */
.pb-host {
  inset: 0; overflow: hidden; opacity: .85;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 76%, transparent 100%),
                      linear-gradient(100deg, rgba(0,0,0,.28) 0%, rgba(0,0,0,.42) 42%, #000 72%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 20%, #000 76%, transparent 100%),
                      linear-gradient(100deg, rgba(0,0,0,.28) 0%, rgba(0,0,0,.42) 42%, #000 72%);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
.pb-par  {              /* traegt den Scroll-Parallax (JS, translate3d)      */
  position: absolute; left: 50%; top: 0;
  transform: translate3d(-50%, 0, 0);
  will-change: transform;
}
.pb-cam  {              /* traegt die Kamerafahrt (CSS) — getrennt, weil     */
  transform-origin: top center;   /* zwei Transforms sonst kollidieren       */
  animation: pb-camera 52s ease-in-out infinite alternate;
}
.pb-cam svg { display: block; width: 100%; }

/* (3) NAEHE — grosse, stark unscharfe Kachel als vorderster Dunst.
   Sie bekommt bewusst KEINEN Scroll-Parallax mehr. Bei 210 % Kachelgroesse und
   4 px Weichzeichnung ist ihre Bewegung ohnehin nicht zu sehen; um sie wie die
   Ferne per transform zu bewegen, muesste das Element rund 6.000 px hoch sein
   (eine Hintergrund-Kachelhoehe Ueberstand je Seite) — das kostet mehr, als
   der unsichtbare Effekt wert ist. Die Tiefenwirkung traegt die Ferne. */
.pb-near {
  inset: -14px;
  background-image: var(--pb-tex);
  background-repeat: repeat;
  background-size: 210% auto;
  opacity: .14;
  filter: blur(4px);
}
.pb-ghost {                        /* leicht verschobenes, kuehleres Duplikat */
  position: absolute; inset: 0;
  background-image: var(--pb-tex);
  background-repeat: repeat;
  background-size: 210% auto;
  opacity: .5;
  filter: hue-rotate(-14deg) blur(1px);
}

/* (4) TILT-SHIFT, zweiter Teil — der Dunst-Schleier ueber den unscharfen
   Randzonen. Zusammen mit der Host-Maske oben ergibt das die Schaerfentiefe:
   Mittelband scharf und hell, oben/unten nur weichgezeichneter Dunst. */
.pb-tilt {
  inset: 0;
  background: linear-gradient(180deg,
    rgba(5,5,5,.55) 0%, rgba(5,5,5,0) 26%,
    rgba(5,5,5,0) 70%, rgba(5,5,5,.50) 100%);
}

/* (5) KEYLIGHT — wandernder Lichtfleck, gibt der Flaeche eine Lichtquelle. */
.pb-keylight {
  inset: -25%;
  background: radial-gradient(38% 34% at 30% 38%, rgba(255,235,232,.075), transparent 70%);
  animation: pb-keylight 34s ease-in-out infinite alternate;
}

/* (6) GLOW — der rote Grundschein in der Mitte. */
.pb-glow {
  inset: 0;
  background: radial-gradient(60% 46% at 50% 46%, rgba(255,58,52,.16), transparent 72%);
}

/* (7) STREAKS — zwei horizontale Lichtlinien, die unterschiedlich atmen. */
.pb-streak { left: -10%; right: -10%; height: 2px; }
.pb-streak.a { top: 22%; background: rgba(255,70,60,.55); filter: blur(5px); animation: pb-streak 11s ease-in-out infinite; }
.pb-streak.b { top: 63%; background: rgba(255,70,60,.42); filter: blur(7px); animation: pb-streak 17s ease-in-out infinite; animation-delay: -6s; }

/* (8) EMBER — der Seitenfuss glimmt in Markenrot. */
.pb-ember {
  left: 0; right: 0; bottom: 0; height: 34vh;
  background: linear-gradient(0deg, rgba(225,6,0,.20), transparent 100%);
  animation: pb-ember 13s ease-in-out infinite;
}

/* (9) SWEEP — der wandernde Lichtstreifen. Werte 1:1 aus dem alten Stand
   uebernommen: sein Helligkeits-Worst-Case ist dort analytisch durchgerechnet
   (0.97*c + 7.65) und in die Kontrast-Messung eingegangen. */
.pb-sweep {
  left: 0; right: 0; top: 0; height: 42%;
  background: linear-gradient(180deg,
    rgba(255,26,26,0)     0%,
    rgba(225,6,0,.05)    42%,
    rgba(255,255,255,.03) 50%,
    rgba(225,6,0,.05)    58%,
    rgba(255,26,26,0)   100%);
  will-change: transform;
  animation: pb-sweep 17s linear infinite;
}

/* (10) SCANLINES — feines Raster. Liegt HINTER dem Inhalt: ueber dem Inhalt
   sank der Fliesstext-Kontrast im schlechtesten Fall auf 3,06:1. */
.pb-scan {
  inset: 0;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,.55) 0 1px, rgba(0,0,0,0) 1px 4px);
  opacity: .55;
}

/* (11) KORN — bricht die Flaechigkeit, laeuft in 4 Stufen.
   OHNE `mix-blend-mode: overlay` (die Vorlage nutzt es): jeder Blend-Modus
   zwingt den Browser, den gesamten Stapel darunter — inklusive der 2.377
   SVG-Pfade — als Backdrop-Textur neu zu rastern, und zwar bei jedem der vier
   Korn-Schritte. Gemessen kostete allein das 46 ms pro Frame. Auf einem fast
   schwarzen Grund ist der Unterschied zu normalem Alpha nicht zu sehen; die
   Deckkraft ist dafuer leicht angehoben. */
.pb-grain {
  inset: -20%;
  opacity: .07;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  animation: pb-grain 1.6s steps(4) infinite;
}

/* (12) VIGNETTEN — zwei Elemente statt drei: die seitliche/radiale
   Randabdunklung und die beiden Kantenbaender liegen je in einem Element.
   Die Werte sind VIEWPORT-RELATIV, nicht in festen px wie in der Vorlage:
   `inset 0 0 190px 70px` frisst auf einem 1440er Fenster den Rand, auf einem
   390er die ganze Flaeche — gemessen war die Buehne mobil dadurch 25 % dunkler
   als auf Desktop, genau der Befund des Inhabers. `vmin`-Werte halten die
   Randabdunklung auf jeder Groesse gleich stark. */
.pb-vig  { inset: 0; box-shadow: inset 0 0 22vmin 8vmin rgba(5,5,5,.92); }
.pb-vig2 {
  inset: 0;
  background:
    radial-gradient(120% 90% at 50% 50%, transparent 46%, rgba(5,5,5,.58) 100%),
    linear-gradient(180deg, rgba(5,5,5,.85) 0, rgba(5,5,5,0) 9vh),
    linear-gradient(0deg,   rgba(5,5,5,.88) 0, rgba(5,5,5,0) 11vh);
}

/* --- Keyframes (aus der Vorlage; Namen mit pb- praefixiert, damit sie nicht
       mit shared.css kollidieren) ------------------------------------------- */
@keyframes pb-sweep   { 0% { transform: translateY(-150%); } 100% { transform: translateY(150%); } }
@keyframes pb-grain   { 0% { transform: translate3d(0,0,0); } 25% { transform: translate3d(-3%,2%,0); } 50% { transform: translate3d(2%,-3%,0); } 75% { transform: translate3d(-2%,-2%,0); } 100% { transform: translate3d(0,0,0); } }
@keyframes pb-streak  { 0%,100% { opacity: .12; transform: scaleX(.7); } 45% { opacity: .75; transform: scaleX(1.15); } }
@keyframes pb-ember   { 0%,100% { opacity: .35; } 50% { opacity: .8; } }
@keyframes pb-camera  { 0% { transform: scale(1.02) translate3d(0,0,0); } 100% { transform: scale(1.06) translate3d(-0.6%,-1.2%,0); } }
@keyframes pb-keylight{ 0% { transform: translate3d(-12%,0,0); } 100% { transform: translate3d(14%,4%,0); } }

/* --- Die Impulse in den Leiterbahnen. Die Klassen stehen IM SVG, die
       Keyframes hier. Alles auf #platine-buehne gescopt, damit generische
       Kuerzel wie .fl/.br nichts auf der Seite treffen. -------------------- */
#platine-buehne .fl { stroke-dasharray: 16 100; stroke-dashoffset: 116; animation-name: pb-flow;  animation-timing-function: linear; animation-iteration-count: infinite; }
#platine-buehne .rv { animation-name: pb-flowr; }
@keyframes pb-flow  { from { stroke-dashoffset: 116; }  to { stroke-dashoffset: -100; } }
@keyframes pb-flowr { from { stroke-dashoffset: -100; } to { stroke-dashoffset: 116; } }
#platine-buehne .br { animation-name: pb-breathe; animation-timing-function: ease-in-out; animation-iteration-count: infinite; }
@keyframes pb-breathe { 0%,100% { stroke-opacity: .28; } 45% { stroke-opacity: 1; } 70% { stroke-opacity: .5; } }
#platine-buehne .pd { animation-name: pb-pad; animation-timing-function: ease-in-out; animation-iteration-count: infinite; }
@keyframes pb-pad { 0%,100% { r: 2.2; fill-opacity: .5; } 50% { r: 4.8; fill-opacity: 1; } }
#platine-buehne .fk { stroke-opacity: 0; animation-name: pb-flick; animation-timing-function: linear; animation-iteration-count: infinite; }
@keyframes pb-flick { 0%,40% { stroke-opacity: 0; } 44% { stroke-opacity: .75; } 48% { stroke-opacity: 0; } 58% { stroke-opacity: .4; } 62%,100% { stroke-opacity: 0; } }

/* --- Bildraten-Waechter: Notbremse fuer schwache Geraete.
   Die ~450 animierten Pfade der Kachel zwingen den Browser, die Ebene in JEDEM
   Frame neu zu rastern — das ist der teuerste Posten des ganzen Rigs und er
   waechst mit der Fensterflaeche. Auf welchem Geraet das reicht, laesst sich
   hier nicht wissen, also misst die Seite es selbst (Skript am Seitenende):
   schafft sie keine ~30 fps, setzt sie NUR die Impulse in den Leiterbahnen
   still. Die Platine bleibt vollstaendig sichtbar, Kamerafahrt, Sweep,
   Streaks, Ember und Korn laufen weiter — die Seite wird ruhiger, nicht leer. */
#platine-buehne.pb-sparsam svg * { animation-play-state: paused !important; }

/* --- Reduzierte Bewegung: ALLES steht. Das Bild bleibt stehen, es
       verschwindet nicht — die Vorlage ignoriert reduced-motion, wir nicht.
       Der `*`-Selektor trifft auch die SVG-Elemente (fl/rv/br/pd/fk), deren
       Animation sonst aus dem style-Attribut weiterliefe. Das Parallax-JS
       schaltet sich zusaetzlich selbst ab. ---------------------------------- */
@media (prefers-reduced-motion: reduce) {
  #platine-buehne,
  #platine-buehne *,
  #platine-buehne svg * { animation: none !important; }
  .pb-cam   { transform: scale(1.03); }
  .pb-sweep { transform: translateY(30%); will-change: auto; }
  .pb-par   { will-change: auto; }
}

/* LESBARKEIT — zwei Nachzieher, die der Hintergrund noetig macht. */
body.seite-tuning {
  /* Frei stehender Mono-Kleintext (.section-marker .label, .footer h4,
     .footer-bottom; .crumbs und .stats-banner sind mit dem Hero-Umbau
     2026-08-03 entfallen) sitzt ohne Karte direkt auf
     der Platine. #7a7a7a fiel dort schon auf dem gedaempften Stapel auf 3,54:1;
     #8e8e8e trug ihn bis .78-Daempfung. Seit die Host-Ebene UNGEDAEMPFT laeuft,
     ist der hellste Pixel darunter heller — deshalb gilt jetzt auf ALLEN
     Breiten die Sekundaerfarbe #a8a8a8 (vorher nur mobil).
     Nachgemessen: _work/_bericht-kino.md §3. */
  --text-muted: #a8a8a8;

  /* .06-Hairlines verschwinden ueber der Platine optisch (Kanten-Kontrast
     1,26:1). Auf dieser Seite kraeftiger, damit Karten eine Kante behalten. */
  --border-1: rgba(255,255,255,.14);
  --border-2: rgba(255,255,255,.20);
}

/* ============================================================================
   DURCHSCHEINEN — die Sektionsflaechen geben den Blick auf die Platine frei
   ----------------------------------------------------------------------------
   Auftrag des Inhabers: die Platine soll durchgehend ueber die ganze Seite
   laufen. Ihre Deckkraft bleibt bei den gerechneten 22 % (der .78-Schleier
   oben ist unangetastet) — nur die Sektionen geben den Blick frei.
   KARTEN BLEIBEN DECKEND: .azb-card (frueher .svc) / .step / .showcase .img /
   .card tragen den
   Fliesstext und behalten ihre volle Flaeche. Angefasst sind ausschliesslich
   die grossflaechigen Verlaeufe HINTER den Karten.
   Restliche zwei Sektionsflaechen stehen als Inline-Style im Body (Ablauf, CTA).
   ========================================================================== */

/* Die Sektions-Marker ("01 —— TEILE & TECHNIK") sind der einzige freie
   Kleintext, der in den beiden VOLL transparenten Sektionen steht (Leistungen,
   Aus der Werkstatt) — genau dort, wo die Platine am hellsten durchlaeuft.
   Gemessen fiel die 12-px-Ziffer ueber einem hellen Leiterbahn-Knoten auf
   2,99:1 (ohne Rig 5,26:1). Statt die beiden Sektionen zu daempfen — sie sind
   die Referenz-Helligkeit der Seite — bekommt NUR diese eine Zeile einen
   weichen eigenen Grund. Auf dunklem Grund ist er unsichtbar, er faengt
   lediglich einen hellen Knoten ab, der zufaellig hinter der Zeile liegt.
   `position:absolute` ist Pflicht: als statisches ::before waere es ein
   Flex-Item und wuerde die Zeile auseinanderschieben. */
body.seite-tuning .section-marker { position: relative; isolation: isolate; }
body.seite-tuning .section-marker::before {
  /* Seitliche Ueberstaende bleiben UNTER dem 24-px-Innenabstand von .wrap —
     bei -28px ragte der Grund 4 px ueber den Viewport und erzeugte auf 390 px
     horizontalen Overflow (gemessen). */
  content: ''; position: absolute; inset: -12px -20px;
  z-index: -1; pointer-events: none;
  background: radial-gradient(ellipse 58% 150% at 38% 50%,
    rgba(5,5,5,.94) 0%, rgba(5,5,5,.78) 42%, rgba(5,5,5,0) 100%);
}

/* Der Footer ist der Abschluss der Seite und traegt viel 11-13-px-Kleintext
   (h4/Footer-Bottom in --text-muted). Deshalb die dichteste der angefassten
   Flaechen: oben .55, unten .72 — die Platine laeuft sichtbar hinein und
   verlischt nach unten, statt an einer harten Kante abzureissen. */
body.seite-tuning .footer {
  background: linear-gradient(180deg, rgba(5,5,5,.55), rgba(0,0,0,.72));
}

/* Hero-Stat-Grid: unter 520px brachen die Mono-Labels mitten im Wort — 2x2 statt 4 schmale Spalten */
@media (max-width: 520px) {
  .th-stats { grid-template-columns: repeat(2, 1fr) !important; }
}

/* ===== Offscreen-Standby fuer CSS-Dauerlaeufer (Review 20/6 R3) ==========
   14 `infinite`-Animationsgruppen liefen hier rund um die Uhr, unabhaengig
   davon, ob ihre Sektion im Bild stand — gemessen 1473 ms Main-Thread je 10 s
   ABSOLUTER Ruhe (mobil, CPU 4x). Ein IntersectionObserver (Skript am
   Seitenende) setzt diese Klasse, solange der Bereich NICHT im Bild ist.
   `animation-play-state` friert nur ein: beim Zurueckscrollen laeuft alles an
   derselben Stelle weiter.
   NICHT gegatet: die Platinen-Buehne (#platine-buehne ist `position: fixed;
   inset: 0` und damit IMMER im Viewport — ein Sicht-Gate haette dort nie
   ausgeloest; ihr Schutz ist und bleibt der Bildraten-Waechter `pb-sparsam`),
   sowie Nav und Footer (3D-Logo-Canvas, Mobile-Menue). */
.anim-standby,
.anim-standby *,
.anim-standby::before,
.anim-standby::after,
.anim-standby *::before,
.anim-standby *::after { animation-play-state: paused !important; }
