/* ============================================================
   VOSSEM — Bewegung und Feinschliff
   ------------------------------------------------------------
   Alles hier laeuft ueber scrollgesteuerte CSS-Animationen
   (animation-timeline). Kein Scroll-Listener, keine Bibliothek,
   kein Arbeitsanteil auf dem Hauptthread: der Compositor erledigt
   das. Browser ohne Unterstuetzung bekommen den fertigen Zustand,
   nichts ist je unsichtbar.

   Regeln, an die sich alles hier haelt:
   · nur transform und opacity, nie width/height/top
   · Parallaxe nur auf dekorative Ebenen, nie auf Fliesstext
   · Ausgang schneller als Eingang
   · prefers-reduced-motion schaltet Bewegung ab, nicht Inhalt
   ============================================================ */

/* ── 1. Feines Korn gegen die flache Schwarzflaeche ──────────
   Ein statisches SVG-Rauschen als Datei-URI, 2 KB, kein Request.
   Dark Mode ohne Textur wirkt tot; das Korn gibt Tiefe. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
html.light-mode body::before { opacity: .02; mix-blend-mode: multiply; }

/* ── 2. Scroll-Fortschritt im Kopf ──────────────────────────
   Zwei Pixel, die zeigen, wie weit die Seite noch geht. */
@supports (animation-timeline: scroll()) {
  #siteHeader::after {
    content: '';
    position: absolute;
    left: 0; right: 0; bottom: -1px;
    height: 2px;
    background: var(--neon);
    transform-origin: 0 50%;
    transform: scaleX(0);
    animation: vFortschritt linear both;
    animation-timeline: scroll(root block);
  }
}
@keyframes vFortschritt { to { transform: scaleX(1); } }

/* ── 3. Abschnitte kommen mit dem Scrollen herein ────────────
   view() bindet den Fortschritt an die Position im Bildfenster.
   entry 0% bis cover 22% heisst: fertig, kurz nachdem das
   Element vollstaendig sichtbar ist. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    .v-sh, .v-mat-head, .v-proc-head, .v-ai, .v-info-section > h2,
    .v-cst-partner > h2, .v-cst-partner > .v-cst-lede,
    .v-pt-koop-in > h2, .v-team-grid, .v-equip-cards,
    .v-cst-koop-grid, .v-cst-facts, .v-rx-list {
      animation: vAuftritt linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 18%;
    }

    /* Karten treten versetzt auf. Kein JS-Stagger: jede Karte hat
       ihre eigene Zeitachse, der Versatz entsteht durch die
       Position im Raster. */
    .v-mat-card, .v-cst-product-card, .v-team-card,
    .v-equip-card, .v-proc-step, .v-cst-koop-card, .v-pt-koop-card {
      animation: vAuftrittKarte linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 20%;
    }

    /* Bilder werden freigelegt statt eingeblendet. */
    .v-mat-card .v-mat-bg,
    .v-team-photo {
      animation: vFreilegen linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 24%;
    }

    /* Parallaxe nur auf dem Heldenbild, 8 Prozent Versatz.
       Der Text darueber bleibt bewusst unbewegt. */
    .v-slide.active img {
      animation: vParallaxe linear both;
      animation-timeline: view(block);
      animation-range: exit 0% exit 100%;
    }

    /* Bannerbild driftet langsamer als die Seite, der Text darueber
       bleibt stehen. Zwoelf Prozent Vergroesserung, damit der Versatz
       nie den Rand freilegt. */
    .v-cst-banner-bg {
      animation: vBanner linear both;
      animation-timeline: view();
      animation-range: cover 0% cover 100%;
    }
    /* Logo und Rolle treten auf, wenn das Banner ins Bild kommt */
    .v-cst-banner-in > * {
      animation: vAuftritt linear both;
      animation-timeline: view();
      animation-range: entry 25% entry 100%;
    }
    /* Produktbilder legen sich frei */
    .v-cst-shot {
      animation: vFreilegen linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 26%;
    }

    /* Trust-Kacheln: nur heben, nicht einblenden.
       Sie stehen dicht unter dem Helden und sind beim Laden auf schmalen
       Geraeten halb im Bild. Eine halb durchsichtige Kachel faellt durch
       jede Kontrastpruefung (gemessen 1,3:1 bei 14 % Deckkraft), also
       bewegt sich hier nur die Position. */
    .v-cst-trust-item {
      animation: vAuftrittRuhig linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 16%;
    }
  }
}

@keyframes vAuftritt {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}
@keyframes vAuftrittRuhig {
  from { transform: translateY(30px); }
  to   { transform: none; }
}
@keyframes vAuftrittKarte {
  from { opacity: 0; transform: translateY(34px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
@keyframes vFreilegen {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}
/* Leicht vergroessert, damit der Versatz nie den Rand freilegt.
   Bewusst knapp: jedes Prozent Vergroesserung beschneidet das Motiv,
   und bei den Partnerbannern ist genau das Motiv der Punkt. */
@keyframes vBanner {
  from { transform: scale(1.06) translateY(-1.6%); }
  to   { transform: scale(1.06) translateY(1.6%); }
}
@keyframes vParallaxe {
  from { transform: scale(1.08) translateY(-2.6%); }
  to   { transform: scale(1.08) translateY(2.6%); }
}

/* ── 4. Ueberschriften werden aufgedeckt ─────────────────────
   Zeile fuer Zeile hinter einer Maske hervor. Der Text steht im
   Markup ganz normal da, nur die Sichtbarkeit wird gesteuert. */
/* Unterlaengen von Bebas Neue duerfen nicht abgeschnitten werden:
   etwas Luft nach unten, oben wieder zurueckgeholt. */
/* Der Rahmen schneidet die Zeile beim Aufdecken ab. Unten war dafuer Platz
   geschaffen, oben nicht - bei Zeilenhoehe 0,9 lagen die Punkte von Ae, Oe
   und Ue ueber dem Zeilenkasten und wurden weggeschnitten. Auf der
   Startseite stand deshalb "FUR DETAILS" statt "FÜR DETAILS"
   (gesehen 06.09.2026). Die negative Auszenkante haelt das Layout gleich. */
.v-aufdecken { display: block; overflow: hidden;
  padding-block: .16em .12em; margin-block: -.16em -.12em; }
.v-aufdecken > span { display: block; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .v-aufdecken > span {
      animation: vZeile cubic-bezier(.23,1,.32,1) both;
      animation-timeline: view();
      animation-range: entry 0% cover 15%;
    }
  }
}
/* ── 4b. Die Prozesslinie zeichnet sich beim Scrollen ────────
   Die vorhandene Verbindungslinie bleibt als blasse Spur stehen,
   darueber laeuft eine zweite in voller Farbe mit. */
.v-proc-steps::after {
  content: '';
  position: absolute;
  top: 24px;
  left: 12.5%;
  right: 12.5%;
  height: 1px;
  background: var(--neon);
  transform-origin: 0 50%;
  transform: scaleX(1);
  pointer-events: none;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .v-proc-steps::after {
      transform: scaleX(0);
      animation: vLinie linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 35%;
    }
    /* Die Ziffernkreise fuellen sich nacheinander */
    .v-proc-circle {
      animation: vKreis linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 30%;
    }
  }
}
@media (max-width:1024px){ .v-proc-steps::after{ display:none } }
@keyframes vLinie { to { transform: scaleX(1); } }
@keyframes vKreis {
  from { border-color: rgba(255,255,255,.10); }
  to   { border-color: var(--neon); }
}

@keyframes vZeile {
  from { transform: translateY(105%); }
  to   { transform: translateY(0); }
}

/* ── 5. Zeiger-Feinheiten ────────────────────────────────────
   Nur mit echtem Zeiger, nie auf Touch. */
@media (hover: hover) and (pointer: fine) {

  /* Der primaere Knopf folgt dem Zeiger ein Stueck weit.
     --mx/--my setzt js/bewegung.js, Standardwert ist 0. */
  .v-btn, .nav-cta-btn, .v-cst-koop-go, .v-pt-koop-go {
    transform: translate(calc(var(--mx, 0) * 5px), calc(var(--my, 0) * 4px));
    transition: transform .25s cubic-bezier(.23,1,.32,1), background .2s ease, box-shadow .2s ease;
  }
  .v-btn:active, .nav-cta-btn:active { transform: scale(.97); }

  /* Karten kippen minimal in Richtung Zeiger. Zwei Grad, mehr
     wirkt wie ein Spielzeug. */
  .v-mat-card, .v-cst-product-card, .v-cst-koop-card, .v-team-card {
    transition: transform .35s cubic-bezier(.23,1,.32,1), border-color .25s ease;
    transform-style: preserve-3d;
  }
  .v-mat-card:hover, .v-cst-product-card:hover, .v-cst-koop-card:hover {
    transform: perspective(900px)
               rotateX(calc(var(--my, 0) * -2deg))
               rotateY(calc(var(--mx, 0) * 2deg))
               translateY(-3px);
  }

  /* Beim Ueberfahren tritt die Spezifikationszeile hervor */
  .v-mat-spec { transition: color .25s ease, letter-spacing .3s cubic-bezier(.23,1,.32,1); }
  .v-mat-card:hover .v-mat-spec { color: #fff; letter-spacing: 3.6px; }

  /* Produktbild wird beim Ueberfahren freigewischt */
  .v-shop-card-img img, .v-pc-img img {
    transition: transform .6s cubic-bezier(.23,1,.32,1);
  }
  .v-shop-card:hover .v-shop-card-img img { transform: scale(1.03); }

  /* Unterstreichung waechst aus der Mitte statt zu blinken */
  .v-info-nav a::after, .v-cst-link::after { transition: transform .28s cubic-bezier(.23,1,.32,1); }
}

/* ── 7. Zahlen, die hochlaufen ───────────────────────────────
   js/bewegung.js zaehlt; hier nur die Ziffernbreite fixieren,
   damit beim Zaehlen nichts springt. */
.v-stat-box-num { font-variant-numeric: tabular-nums; }

/* ── 8. Bewegung aus ─────────────────────────────────────────
   Alles oben steht in @media (prefers-reduced-motion: no-preference).
   Hier nur noch die Zeiger-Feinheiten zuruecknehmen. */
@media (prefers-reduced-motion: reduce) {
  .v-btn, .nav-cta-btn, .v-cst-koop-go, .v-pt-koop-go,
  .v-mat-card, .v-cst-product-card, .v-cst-koop-card, .v-team-card { transform: none !important; }
}
