/* ═══════════════════════════════════════════════════════════════════════
   Ö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 ═══════════════════
   ⚠ Die Klasse heisst `oe-laufband`, NICHT `oe-band`. `oe-band` ist seit
     dem ersten Tag der Abschnitt (ein waagerechtes Band der SEITE) und
     steht auf gut zwanzig Seiten. Haette das Laufband denselben Namen,
     laege auf jedem Abschnitt eine Randmaske und `overflow: hidden` —
     genau das war beim Rebranding zwei Schritte lang der Fall.
   ⚠ 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-laufband {
  --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-laufband > .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-laufband.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-laufband.sponsoren       > .spur { --tempo: var(--band-sponsoren); }
.oe-laufband.sponsoren-2     > .spur { --tempo: var(--band-sponsoren-2); }
.oe-laufband.sponsoren-3     > .spur { --tempo: var(--band-sponsoren-3); --richtung: reverse; }
.oe-laufband.competitions    > .spur { --tempo: var(--band-competitions); }
.oe-laufband.erfolge-vor     > .spur { --tempo: var(--band-erfolge-vor); }
.oe-laufband.erfolge-zurueck > .spur { --tempo: var(--band-erfolge-zurueck); --richtung: reverse; }
.oe-laufband.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-laufband:hover > .spur,
.oe-laufband: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. */
/* ⚠ Die Schrittweite rechnet der Browser aus `--stationen`, sie steht NICHT
     mehr in den Keyframes. Vorher waren dort fünf feste Stufen (−20 %,
     −40 %, …) verdrahtet. Mit vier Stationen landete jeder Schritt
     zwischen zwei Eintraegen, und die letzte Stufe (−100 %) schob die Spur
     ganz aus dem Fenster — der Roller zeigte die halbe Runde nichts. Genau
     so sah es auf der LAN-Kachel aus.
   ⚠ `steps()` statt einer Kurve: Ein Roller SOLL springen und dann stehen.
     Eine Kurve liesse sich nur mit festen Keyframes bauen — und damit
     waere die Anzahl wieder fest verdrahtet. */
.oe-roller { overflow: hidden; height: var(--roller-h, 3.4rem); }
/* ⚠ `display: block` ist hier KEINE Kosmetik, sondern die Bedingung dafuer,
     dass sich ueberhaupt etwas bewegt: Auf ein nicht ersetztes INLINE-
     Element wirkt `transform` nicht. Die Spur ist ein `<span>`; ohne diese
     Zeile lief die Animation sauber durch (der Browser meldete sie als
     „running"), und auf dem Bildschirm stand alles still. Das Laufband
     hatte das Problem nie — dessen Spur ist `display: flex`. */
.oe-roller > .stationen {
  display: block;
  --stationen: 1;
  --tempo: 12s;
  animation: oe-roller-lauf var(--tempo) steps(var(--stationen)) infinite;
}
/* Eine Station allein bewegt sich nicht — sonst schoebe der Roller den
   einzigen Eintrag aus dem Bild und zeigte dann nichts. */
.oe-roller > .stationen[style*="--stationen: 1"] { animation: none; }
@keyframes oe-roller-lauf { to { transform: translateY(-100%); } }

/* ═══════════════ DIE LEISEN REAKTIONEN ══════════════════════════════
   ⚠ Eigene Zeiten, nicht `--dauer-schnell` (.14s) geliehen: Die Token sind
     fuer Zustandswechsel gedacht (Knopf gedrueckt, Feld aktiv) und dafuer
     richtig knapp. Eine Linie, die unter einem Wort entlangwaechst, soll
     man SEHEN — bei .14s ist sie schon da, bevor der Blick ankommt.
     Stehen sie hier eigen, laesst sich das Tempo der Website aendern,
     ohne die Bedienzeiten mit zu verschieben. */
:root {
  --dauer-reaktion: .3s;   /* Unterlinie, Kante, Pfeil */
  --dauer-einlauf:  .55s;  /* ein einzelner Punkt / eine Zeile */
  --takt-einlauf:   .12s;  /* Abstand von Element zu Element */
}

   Was auf JEDER Seite greift, weil es an gemeinsamen Bausteinen haengt.
   Nichts davon bewegt sich von allein — alles antwortet auf jemanden.

   ⚠ Das ist der Teil, der eine Seite „lebendig" macht, ohne dass etwas
     flimmert: Bewegung nur dort, wo der Besucher gerade hinzeigt. Darum
     steht hier kein `infinite`. */

/* Ein Link im Fliesstext bekommt eine Unterlinie, die von links waechst.
   ⚠ Angehaengt an das, was es WIRKLICH gibt: Absaetze und Listen im
     `<main>`, der Beitragsrumpf und die Rechtstexte. Ein erster Versuch
     hing an `.oe-text` und `.oe-lesetext` — beide Klassen existieren im
     Projekt nicht, die Regel traf also nirgends. Nachgesehen statt
     angenommen.
   ⚠ Knoepfe, Weiter-Links und Chips sind ausgenommen: Dort ist der ganze
     Kasten das Ziel, und eine Linie darunter waere Unruhe. */
main :is(p, li, dd) > a:not(.oe-knopf):not(.oe-weiter):not(.oe-chip),
.pn-beitrag .inhalt a:not(.oe-knopf),
.pn-recht a:not(.oe-knopf) {
  background-image: linear-gradient(var(--red), var(--red));
  background-size: 0% 1px; background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size var(--dauer-reaktion) var(--kurve);
  text-decoration: none;
}
main :is(p, li, dd) > a:not(.oe-knopf):not(.oe-weiter):not(.oe-chip):hover,
main :is(p, li, dd) > a:not(.oe-knopf):not(.oe-weiter):not(.oe-chip):focus-visible,
.pn-beitrag .inhalt a:not(.oe-knopf):hover,
.pn-beitrag .inhalt a:not(.oe-knopf):focus-visible,
.pn-recht a:not(.oe-knopf):hover,
.pn-recht a:not(.oe-knopf):focus-visible { background-size: 100% 1px; }

/* Eine Zeile in einer Liste: eine rote Kante faehrt von oben herein.
   Sie liegt auf einem `::before`, damit die Zeile nicht springt. */
.oe-linien > a { position: relative; }
.oe-linien > a::before {
  content: ''; position: absolute; inset: 0 auto 0 0; width: 2px;
  background: var(--red); transform: scaleY(0); transform-origin: center top;
  transition: transform var(--dauer-reaktion) var(--kurve);
  pointer-events: none;
}
.oe-linien > a:hover::before,
.oe-linien > a:focus-visible::before { transform: scaleY(1); }

/* ⚠ Den Pfeil bei `.oe-weiter` bewegt `oe-bausteine.css` schon selbst —
     hier steht deshalb NUR, was dort fehlt: Wer mit der Tastatur
     ankommt, bekommt dieselbe Rueckmeldung wie mit der Maus. Eine zweite
     Regel fuer dasselbe waere nur eine Stelle mehr, die auseinanderlaeuft. */
.oe-weiter:focus-visible::after { transform: translateX(3px); }

/* Der Fokusring zieht auf, statt zu erscheinen. Er bleibt dabei immer
   sichtbar — wer mit der Tastatur navigiert, darf nicht auf eine
   Animation warten muessen. */
:where(a, button, [tabindex]):focus-visible {
  animation: oe-fokus-auf .26s var(--kurve);
}
@keyframes oe-fokus-auf {
  from { outline-offset: 6px; }
  to   { outline-offset: 2px; }
}

/* ═══════════════ EINLAUF — der Moment, der genau einmal läuft ═══════
   Zwei Formen, beide gestaffelt über `--i` (die Zahl setzt `marke.js`):

     `.oe-einlauf.punkte`  Die Formkurve baut sich von links auf.
     `.oe-einlauf.zeile`   Ein roter Durchlauf von oben nach unten.

   ⚠ Beide starten vom FERTIGEN Zustand. Die Formkurve geht nie auf
     `opacity: 0`, sondern von .35 auf 1 — wer in dem Moment hinsieht,
     sieht eine Kurve, die sich füllt, nie ein Loch. Der Durchlauf färbt
     nur kurz ein und nimmt nichts weg.
   ⚠ Ohne die Klasse `.lauf` (die `marke.js` beim ersten Sichtkontakt
     setzt) passiert gar nichts. Ohne JavaScript steht alles still und
     vollständig da — der Einlauf ist Zugabe, kein Zustand. */

/* Die Formkurve: Punkt für Punkt von links. */
.oe-einlauf.punkte.lauf > * {
  animation: oe-punkt-ein var(--dauer-einlauf) var(--kurve) both;
  animation-delay: calc(var(--i, 0) * var(--takt-einlauf));
}
@keyframes oe-punkt-ein {
  from { transform: scale(.45); opacity: .35; }
  to   { transform: none;       opacity: 1; }
}

/* Der Durchlauf: eine rote Kante wandert die Liste hinunter. Sie liegt
   auf einem `::before`, nicht auf dem Rahmen der Zeile — so verschiebt
   sich beim Laufen nichts. */
.oe-einlauf.zeile > * { position: relative; }
.oe-einlauf.zeile > *::before {
  content: ''; position: absolute; inset: 0 auto 0 0;
  width: 2px; background: var(--red);
  transform: scaleY(0); transform-origin: top;
  pointer-events: none;
}
.oe-einlauf.zeile.lauf > *::before {
  animation: oe-zeile-durch calc(var(--dauer-einlauf) * 1.4) var(--kurve) both;
  animation-delay: calc(var(--i, 0) * var(--takt-einlauf) * 1.5);
}
.oe-einlauf.zeile.lauf > * {
  animation: oe-zeile-ton calc(var(--dauer-einlauf) * 1.4) var(--kurve) both;
  animation-delay: calc(var(--i, 0) * var(--takt-einlauf) * 1.5);
}
@keyframes oe-zeile-durch {
  0%        { transform: scaleY(0); transform-origin: top; }
  45%       { transform: scaleY(1); transform-origin: top; }
  55%       { transform: scaleY(1); transform-origin: bottom; }
  100%      { transform: scaleY(0); transform-origin: bottom; }
}
@keyframes oe-zeile-ton {
  0%, 100%  { background: transparent; }
  45%, 55%  { background: color-mix(in srgb, var(--red) 9%, transparent); }
}

/* ═══════════════ 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. */
/* ⚠ Die Verzoegerung steht als `--i` am Element. `:nth-child` taugt hier
     nicht: Vor den Zeilen kann eine Kanalzeile stehen, und dann zaehlt der
     Selektor falsch — beide Zeilen liefen gleichzeitig, und der Ausschnitt
     war fast die halbe Runde leer.
   ⚠ Die Fenster UEBERLAPPEN sich bewusst (4–54 % und 51–101 %): Ein
     Chat-Ausschnitt, in dem zwischendurch gar nichts steht, sieht aus wie
     ein Ladefehler, nicht wie eine Unterhaltung. */
.oe-chat > .zeile {
  animation: oe-chat-ein 13s var(--kurve-chat) infinite;
  animation-delay: calc(13s * .47 * var(--i, 0));
  opacity: 0;
}
@keyframes oe-chat-ein {
  0%        { opacity: 0; transform: translateY(8px); }
  4%, 50%   { opacity: 1; transform: none; }
  58%, 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); } }

/* ── Der Fortschrittsbalken, der beim EIGENEN Wert endet ──────────────

   ⚠ WARUM NICHT `.rule`
     `.rule` endet bei `scaleX(1)`, also IMMER bei voller Breite. Als
     Trennlinie, die sich zeichnet, ist das genau richtig. Als
     Fortschrittsbalken ist es falsch — und es war falsch: Auf
     `/crossfire/team/<slug>` stand `style="transform: scaleX(0.889)"`,
     gerechnet wurde `scaleX(1)`. Eine Animation schlaegt den Inline-Stil
     fuer die animierte Eigenschaft. Jedes Team zeigte seit dem Rebranding
     einen vollen Balken, auch das letzte der Division.

   ⚠ WARUM BREITE UND NICHT `transform`
     Dieselbe Entscheidung wie beim Hub-Balken (`.ah-balken` mit
     `ah-grow`): Ein skalierter abgerundeter Balken bekommt an der Kante
     eine gequetschte Rundung. Bei 4–8px Hoehe mit `--r-full` sieht man
     das. „Nur `transform` und `opacity`" zielt auf Dauerbewegung — hier
     laeuft es einmal beim Hereinscrollen.

   ⚠ Der Wert steht als `--anteil` im Markup (`0%`–`100%`), NICHT als
     Inline-`width`. Nur so kann der Endzustand der Animation ihn
     uebernehmen — und nur so steht der richtige Wert auch dann da, wenn
     keine Animation laeuft (reduzierte Bewegung, kein JS, alter Browser). */
.oe-fuellt { width: var(--anteil, 100%); }

@supports (animation-timeline: view()) {
  .oe-fuellt {
    animation: oe-fuellt linear both;
    animation-timeline: view();
    animation-range: entry 4% entry 56%;
  }
}
html.aufbau-js .oe-fuellt { width: 0; transition: width .6s var(--kurve-hover); }
html.aufbau-js .oe-fuellt.da { width: var(--anteil, 100%); }

@keyframes oe-fuellt { from { width: 0; } to { width: var(--anteil, 100%); } }

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

/* 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-fuellt` steht hier BEWUSST nicht bei `.rise, .rule`:
     `transform: none` hiesse dort volle Breite, und ein
     Fortschrittsbalken, der bei abgeschalteter Bewegung 100% zeigt,
     sagt etwas Falsches ueber die Daten. Er behaelt seinen Wert. */
  .oe-fuellt, html.aufbau-js .oe-fuellt {
    width: var(--anteil, 100%) !important;
    transition: none !important;
  }
  .oe-laufband > .spur, .oe-roller > .stationen { transform: none !important; }
  /* Der Einlauf ist reine Zugabe — hier faellt er ersatzlos weg, und zwar
     im FERTIGEN Zustand: volle Deckkraft, keine rote Kante. */
  .oe-einlauf > *, .oe-einlauf > *::before { animation: none !important; }
  /* Die leisen Reaktionen bleiben SICHTBAR, nur ohne Weg: Die Unterlinie
     steht sofort, die Kante auch. Wer Bewegung abstellt, soll nicht die
     Rueckmeldung verlieren. */
  main :is(p, li, dd) > a:not(.oe-knopf):not(.oe-weiter):not(.oe-chip):hover,
  .pn-beitrag .inhalt a:not(.oe-knopf):hover,
  .pn-recht a:not(.oe-knopf):hover { background-size: 100% 1px; }
  .oe-linien > a:hover::before { transform: scaleY(1); }
  :where(a, button, [tabindex]):focus-visible { animation: none !important; }
  .oe-einlauf.punkte > * { opacity: 1 !important; transform: none !important; }
  .oe-einlauf.zeile > *::before { transform: scaleY(0) !important; }
  /* Ein Laufband ohne Lauf ist eine Liste — und die darf umbrechen, statt
     hinter der Maske zu verschwinden. */
  .oe-laufband { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
  .oe-laufband > .spur { width: auto; flex-wrap: wrap; }
  .oe-wechsel > img:last-child { display: none; }
  .oe-schreibt { border-right: 0; width: auto !important; }
  .topbar { display: none; }
}

}
