/* ═══════════════════════════════════════════════════════════════════════
   ÖFFENTLICH · 07 — BEWEGUNG
   Die Animations-Bibliothek des Rebrandings (Design-Guide, Kapitel
   „Bewegung"). Sie steht in der LETZTEN Ebene, damit der Abschalter für
   `prefers-reduced-motion` jede Animation schlagen kann, die eine frühere
   Ebene gesetzt hat.

   ── ZWEI FAMILIEN ─────────────────────────────────────────────────────
   **Dauerbewegung** läuft immer und zeigt Gegenwart: Laufbänder, Roller,
   Equalizer, Puls. Sie braucht keinen Besucher.
   **Scroll-Aufbau** reagiert auf den Besucher: `.rise`, `.rule`, `.topbar`.
   An die Scroll-POSITION gekoppelt, nicht an einen Timer — wer
   zurückscrollt, baut den Inhalt wieder ab.

   ── DER WICHTIGSTE GRUNDSATZ ──────────────────────────────────────────
   ⚠ **Nichts darf nur in einer Animation existieren.** Jede Regel hier
     beginnt mit dem fertigen, sichtbaren Zustand und animiert von dort —
     nie umgekehrt. Ohne JavaScript, ohne Scroll-Timeline und mit
     `prefers-reduced-motion: reduce` steht jede Seite vollständig da.
     Das ist kein Nice-to-have: Ein Laufband, dessen Inhalt in `opacity: 0`
     beginnt, ist für Vorlesegeräte und Suchmaschinen eine leere Seite.

   ── WAS VERBOTEN IST ──────────────────────────────────────────────────
   Laserstrahlen und Scanlines über Inhalten. Glows. Schräge
   Clip-Path-Kanten. Parallax. Animationen, die beim Zurückscrollen
   stehenbleiben. Automatische Karussells ohne Stopp. Bewegung ohne echten
   Inhalt dahinter — ein Laufband ohne Daten ist Flimmern.
   ═════════════════════════════════════════════════════════════════════ */

@layer oe-bewegung {

/* ═══════════════ LAUFBAND — das wichtigste Muster ═══════════════════
   ⚠ Der Inhalt wird DOPPELT gerendert. Nur dann schliesst `translateX(-50%)`
     nahtlos: Nach der halben Strecke steht die zweite Kopie exakt dort, wo
     die erste begann. Mit nur einer Kopie springt das Band bei jedem
     Durchlauf sichtbar zurück.
   ⚠ Die Maske an beiden Rändern ist Pflicht. Ohne sie schneidet die Kante
     hart ab, und das Band sieht aus wie ein Fehler statt wie Bewegung. */
.oe-band {
  --tempo: 30s;
  --richtung: normal;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}
.oe-band > .spur {
  display: flex;
  width: max-content;
  align-items: center;
  gap: var(--s-7);
  animation: oe-band-lauf var(--tempo) linear infinite var(--richtung);
  will-change: transform;
}
.oe-band.zurueck > .spur { --richtung: reverse; }
@keyframes oe-band-lauf { to { transform: translateX(-50%); } }

/* Mehrere Spuren übereinander laufen gegenläufig und verschieden schnell —
   gleiche Tempi wirken mechanisch (Guide). */
.oe-band.sponsoren       > .spur { --tempo: var(--band-sponsoren); }
.oe-band.sponsoren-2     > .spur { --tempo: var(--band-sponsoren-2); }
.oe-band.sponsoren-3     > .spur { --tempo: var(--band-sponsoren-3); --richtung: reverse; }
.oe-band.competitions    > .spur { --tempo: var(--band-competitions); }
.oe-band.erfolge-vor     > .spur { --tempo: var(--band-erfolge-vor); }
.oe-band.erfolge-zurueck > .spur { --tempo: var(--band-erfolge-zurueck); --richtung: reverse; }
.oe-band.claim           > .spur { --tempo: var(--band-claim); --richtung: reverse; }

/* Ein Band hält an, solange jemand mit der Maus darauf steht oder mit der
   Tastatur hineingeht. Der Guide verbietet Karussells, die man nicht
   anhalten kann — für ein Laufband gilt dasselbe. */
.oe-band:hover > .spur,
.oe-band:focus-within > .spur { animation-play-state: paused; }

/* ═══════════════ VERTIKALER ROLLER MIT HALTEPHASEN ══════════════════
   Für Inhalte, die GELESEN werden sollen: jede Station steht rund zwei
   Sekunden, dann rutscht die nächste nach. Ein gleichmässig laufendes Band
   wäre hier falsch — man käme nie zu Ende. */
.oe-roller { overflow: hidden; height: var(--roller-h, 3.4rem); }
.oe-roller > .stationen {
  --stationen: 5;
  --tempo: 12s;
  animation: oe-roller-lauf var(--tempo) var(--kurve-roller) infinite;
}
@keyframes oe-roller-lauf {
  0%,   16% { transform: translateY(0); }
  20%,  36% { transform: translateY(-20%); }
  40%,  56% { transform: translateY(-40%); }
  60%,  76% { transform: translateY(-60%); }
  80%,  96% { transform: translateY(-80%); }
  100%      { transform: translateY(-100%); }
}

/* ═══════════════ EQUALIZER ══════════════════════════════════════════
   Sechs Balken, 0.9s, Versatz 0.12s je Balken (Guide). Der Versatz ist der
   ganze Trick: Gleichzeitig wäre es ein Blinken, versetzt ist es ein Ton. */
.oe-eq { display: flex; align-items: flex-end; gap: 3px; height: 2.2rem; }
.oe-eq > i {
  display: block; width: 4px; border-radius: 1px; background: var(--red);
  transform-origin: bottom;
  animation: oe-eq-schlag .9s ease-in-out infinite alternate;
}
.oe-eq > i:nth-child(1) { height: 42%; animation-delay: 0s; }
.oe-eq > i:nth-child(2) { height: 78%; animation-delay: .12s; }
.oe-eq > i:nth-child(3) { height: 54%; animation-delay: .24s; }
.oe-eq > i:nth-child(4) { height: 96%; animation-delay: .36s; }
.oe-eq > i:nth-child(5) { height: 62%; animation-delay: .48s; }
.oe-eq > i:nth-child(6) { height: 34%; animation-delay: .60s; }
@keyframes oe-eq-schlag { from { transform: scaleY(.35); } to { transform: scaleY(1); } }

/* ═══════════════ LIVE-PULS ══════════════════════════════════════════ */
.oe-puls {
  position: relative; display: inline-block; flex: none;
  width: 8px; height: 8px; border-radius: var(--r-full); background: var(--red);
}
.oe-puls::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: inherit; animation: oe-puls-welle 1.4s ease-in-out infinite;
}
@keyframes oe-puls-welle {
  0%   { transform: scale(1);   opacity: .7; }
  70%  { transform: scale(2.6); opacity: 0; }
  100% { transform: scale(2.6); opacity: 0; }
}

/* ═══════════════ WECHSELBILD (Shop: Home/Away) ══════════════════════
   Zwei Bilder, dieselbe Schleife, das zweite mit halbem Versatz. */
.oe-wechsel { position: relative; }
.oe-wechsel > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
                    animation: oe-wechsel-blende 7s ease-in-out infinite; }
.oe-wechsel > img:last-child { animation-delay: -3.5s; }
@keyframes oe-wechsel-blende {
  0%, 44%  { opacity: 1; }
  50%, 94% { opacity: 0; }
  100%     { opacity: 1; }
}

/* ═══════════════ CHAT UND SCHREIBMASCHINE ═══════════════════════════
   ⚠ Alle Nachrichten teilen EINE Schleife und haben eigene Einsätze
     (7% und 42%). Mit je eigener Dauer liefen sie nach wenigen Minuten
     auseinander, und der Chat zeigte zwei Nachrichten übereinander. */
.oe-chat > .zeile {
  animation: oe-chat-ein 13s var(--kurve-chat) infinite;
  opacity: 0;
}
.oe-chat > .zeile:nth-child(1) { animation-delay: calc(13s * .07); }
.oe-chat > .zeile:nth-child(2) { animation-delay: calc(13s * .42); }
@keyframes oe-chat-ein {
  0%        { opacity: 0; transform: translateY(8px); }
  4%, 46%   { opacity: 1; transform: none; }
  54%, 100% { opacity: 0; transform: none; }
}
.oe-tippt { display: inline-flex; gap: 3px; align-items: center; }
.oe-tippt > i { width: 4px; height: 4px; border-radius: var(--r-full); background: var(--text-3);
                animation: oe-tippt-hub 1.3s ease-in-out infinite; }
.oe-tippt > i:nth-child(2) { animation-delay: .16s; }
.oe-tippt > i:nth-child(3) { animation-delay: .32s; }
@keyframes oe-tippt-hub { 0%, 60%, 100% { transform: none; opacity: .45; } 30% { transform: translateY(-3px); opacity: 1; } }

/* ⚠ Die Eingabezeile tippt sich über die BREITE, nicht über den
   Textinhalt. Eine Animation auf `width` schneidet sauber ab; eine auf
   dem Text selbst bräuchte JavaScript und bräche bei jeder Übersetzung. */
.oe-schreibt {
  display: inline-block; overflow: hidden; white-space: nowrap;
  border-right: 2px solid var(--red);
  animation: oe-schreibt-breite 13s steps(21) infinite;
}
@keyframes oe-schreibt-breite {
  0%, 4%    { width: 0; }
  26%, 92%  { width: 100%; }
  100%      { width: 0; }
}

/* ═══════════════ SCROLL-AUFBAU ══════════════════════════════════════
   ⚠ Der Grundzustand ist SICHTBAR. Erst wenn eine der beiden Mechaniken
     wirklich da ist, wird daraus eine Animation. Umgekehrt — erst
     ausblenden, dann hoffentlich einblenden — ist der Fehler, der eine
     Seite ohne JavaScript leer lässt. */
.rise, .rule { opacity: 1; transform: none; }

/* ① Der saubere Weg: Scroll-Timeline im Browser. Rückwärtsscrollen baut
      von selbst wieder ab, ohne eine Zeile JavaScript. */
@supports (animation-timeline: view()) {
  .rise {
    animation: oe-rise linear both;
    animation-timeline: view();
    animation-range: entry 2% entry 42%;
  }
  .rule {
    animation: oe-rule linear both;
    animation-timeline: view();
    animation-range: entry 4% entry 56%;
  }
  .topbar {
    transform-origin: 0 50%;
    animation: oe-topbar linear both;
    animation-timeline: scroll(root block);
  }
}
/* ② Der Rückfall: `js/marke.js` setzt `aufbau-js` NUR, wenn ① fehlt, und
      schaltet `.da` beim Hinein- und Hinausscrollen. */
html.aufbau-js .rise { opacity: 0; transform: translateY(18px);
                       transition: opacity .5s var(--kurve-hover), transform .5s var(--kurve-hover); }
html.aufbau-js .rise.da { opacity: 1; transform: none; }
html.aufbau-js .rule { transform: scaleX(0); transform-origin: 0 50%;
                       transition: transform .6s var(--kurve-hover); }
html.aufbau-js .rule.da { transform: scaleX(1); }
html.aufbau-js .topbar { transform: scaleX(var(--fortschritt, 0)); transform-origin: 0 50%; }

@keyframes oe-rise   { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes oe-rule   { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes oe-topbar { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Gestaffelt: Kacheln einer Reihe kommen nacheinander, nicht als Block. */
.rise-staffel > * { animation-delay: calc(var(--i, 0) * .06s); }
html.aufbau-js .rise-staffel > * { transition-delay: calc(var(--i, 0) * .06s); }

/* Der Lesefortschritt: 2px über die ganze Seite. */
.topbar {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  height: 2px; background: var(--red); transform: scaleX(0);
}

/* ═══════════════ HOVER ══════════════════════════════════════════════
   Karten 4px in 0.35s, Buttons 2px und 7% heller. Mehr nicht — kein
   Skalieren, kein Schatten, der aufpoppt (Guide). */
@media (hover: hover) {
  .oe-hebt { transition: transform var(--dauer-hover) var(--kurve-hover),
                         border-color var(--dauer-hover) var(--kurve-hover); }
  .oe-hebt:hover, .oe-hebt:focus-within { transform: translateY(-4px); border-color: var(--line); }
  .oe-knopf { transition: transform var(--dauer-hover) var(--kurve-hover), filter var(--dauer-hover); }
  .oe-knopf:hover { transform: translateY(-2px); filter: brightness(1.07); }
}

/* ═══════════════ PFLICHT: prefers-reduced-motion ════════════════════
   ⚠ Schaltet JEDE Animation ab, auch die Dauerschleifen — und lässt alle
     Inhalte dabei vollständig sichtbar. Deshalb werden hier nicht nur
     Animationen gestoppt, sondern die Zustände ausdrücklich
     zurückgesetzt: Ein angehaltenes `opacity: 0` wäre unsichtbarer Text. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .rise, .rule, .oe-chat > .zeile,
  html.aufbau-js .rise, html.aufbau-js .rule {
    opacity: 1 !important; transform: none !important;
  }
  .oe-band > .spur, .oe-roller > .stationen { transform: none !important; }
  /* Ein Laufband ohne Lauf ist eine Liste — und die darf umbrechen, statt
     hinter der Maske zu verschwinden. */
  .oe-band { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
  .oe-band > .spur { width: auto; flex-wrap: wrap; }
  .oe-wechsel > img:last-child { display: none; }
  .oe-schreibt { border-right: 0; width: auto !important; }
  .topbar { display: none; }
}

}
