/* ============================================================================
   ITSLORU DESIGN-SYSTEM  ·  zentrale Quelle fuer das Site-Design
   ----------------------------------------------------------------------------
   ZWECK: Eine Aenderung HIER wirkt auf jede Seite, die dieses File laedt.
   Vorher definierten 47 Dateien ihre Tokens selbst — jede Farbaenderung
   musste 47x nachgezogen werden und driftete auseinander.

   AUFBAU (zwei Schichten):
     1. TOKEN-SCHICHT  — ueberschreibt die :root-Variablen der Seiten.
        Wirkt SOFORT ueberall, weil alle Seiten dieselben Var-Namen nutzen
        (--violet, --sans, --bg ...). Der :root:root-Trick verdoppelt die
        Spezifitaet, damit diese Werte unabhaengig von der Ladereihenfolge
        gegen die seiteneigenen :root-Bloecke gewinnen.
     2. KOMPONENTEN-SCHICHT — Opt-in-Klassen mit ds-*-Praefix (Kicker,
        Akzentwort, Marker, Karte). Wirken erst, wenn eine Seite das Markup
        umstellt. Dadurch ist dieses File DEPLOY-INERT: solange keine Seite
        es verlinkt bzw. die Klassen nutzt, aendert sich live nichts.

   EINBINDEN (pro Seite, im <head> NACH den Seiten-Styles):
     <link rel="stylesheet" href="/design-system.css?v=YYYYMMDD" />
   Bei JEDER Aenderung an diesem File den ?v=-Parameter bumpen —
   Cloudflare cached statische Files am Edge (siehe CLAUDE.md).

   Fuer den Marker-Wisch braucht die Seite zusaetzlich das kleine
   Head-Script, das html.js-anim setzt (FOUC-Guard, siehe unten).
   ========================================================================== */

/* ===== SCHRIFTEN (lokal gehostet, DSGVO — kein Remote-Google-Fonts) ====== */
@font-face {
  font-family: 'Archivo';
  src: url('/fonts/archivo-variable-latin.woff2') format('woff2');
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+2122;
}
@font-face {
  font-family: 'Archivo';
  src: url('/fonts/archivo-variable-latin-ext.woff2') format('woff2');
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF;
}

/* ===== 1) TOKEN-SCHICHT ==================================================
   Nur Werte, die sich vom Alt-Bestand UNTERSCHEIDEN. Was hier nicht steht,
   behaelt seinen Wert aus der Seite (bewusst: --bg bleibt blau-schwarz,
   --violet bleibt Twitch-Lila — Betreiber-Entscheidung Juli 2026). */
:root:root {
  /* Schrift: Archivo (variable, mit Breiten-Achse) statt Geist */
  --sans: 'Archivo', -apple-system, system-ui, sans-serif;

  /* Mono + Serif ebenfalls hier verankern (Juli 2026).
     Vorher standen sie nur im :root der Startseite. Alle anderen Seiten
     fielen deshalb auf Systemschriften zurueck: --mono wurde zu
     "ui-monospace", --serif zu "Times New Roman". Sichtbar wurde das
     ueberall dort, wo Mono traegt — Kicker, Leitsystem, Preis- und
     Zahlenangaben. Die Schriftdateien selbst waren laengst geladen
     (fonts.css), nur die Tokens zeigten nicht darauf.
     Serif bleibt gesetzt, wird aber fuer Akzentwoerter bewusst auf --sans
     umgebogen (siehe Legacy-Override weiter unten). */
  --mono:  'JetBrains Mono', ui-monospace, Menlo, monospace;
  --serif: 'Instrument Serif', Georgia, serif;

  /* Nebenfarben: aufeinander abgestimmt statt roher Tailwind-Defaults.
     Das Lila bleibt der einzige "laute" Ton der Marke. */
  --green:  #7ac74f;   /* statt #22c55e (tailwind green-500) */
  --orange: #ff7043;   /* statt #f59e0b (amber-500)          */
  --pink:   #e05263;   /* statt #ec4899 (pink-500)           */
  --blue:   #4a9dad;   /* statt #3b82f6 (blue-500)           */
  --cyan:   #2fb6a8;   /* statt #06b6d4 (cyan-500)           */

  /* Easing-Kurven (neu 25.07.2026). Die eingebauten CSS-Easings sind zu
     weich: sie starten und stoppen traege und lassen jede Interaktion
     unentschieden wirken. Diese beiden ziehen deutlich schaerfer an.
     --ease-out fuer alles, was eintritt oder auf eine Eingabe antwortet,
     --ease-in-out fuer Bewegung von A nach B. Konstante Bewegung
     (Laufband, Fortschrittsbalken) bleibt linear.
     Reine Zusatz-Tokens: sie aendern nichts, solange sie niemand nutzt. */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}

/* ===== 2) KOMPONENTEN-SCHICHT (Opt-in via ds-*-Klassen) ================== */

/* --- Kicker: Nummer · Text · auslaufende Linie ---------------------------
   Ersetzt die Badge-Pille (border-radius:999px + Punkt + getoenter Kasten).
   Markup:  <span class="ds-kicker">01 · Einsendungen</span>
   Zentriert (Linie beidseitig): class="ds-kicker ds-kicker--center"       */
.ds-kicker {
  display: inline-flex; align-items: center; gap: 14px;
  font-family: var(--mono, ui-monospace, monospace);
  font-size: 13px; font-weight: 700;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--fg);
}
.ds-kicker::after {
  content: '';
  width: 46px; height: 2px;
  background: linear-gradient(90deg, var(--violet), rgba(145,70,255,0.12));
}
.ds-kicker--center::before {
  content: '';
  width: 46px; height: 2px;
  background: linear-gradient(90deg, rgba(145,70,255,0.12), var(--violet));
}

/* --- Akzentwort: schmal + extrafett statt kursiver Serif -----------------
   Markup:  <span class="ds-accent">Lieblings-Clip ein.</span>              */
.ds-accent {
  font-family: var(--sans);
  font-style: normal;
  font-weight: 800;
  font-stretch: 78%;
  letter-spacing: -0.01em;
  color: var(--violet-2, #a87bff);
}

/* --- Textmarker hinter dem Akzentwort ------------------------------------
   Markup:  <span class="ds-accent ds-mark">…</span>
   Wisch-Animation ausloesen: Klasse .is-wipe setzen (JS), z.B. per
   IntersectionObserver beim Reinscrollen. Deckkraft .18 ist gemessen:
   5,68:1 Kontrast fuer #a87bff-Text — volles Lila waere 1,53:1, unlesbar. */
.ds-mark {
  width: fit-content;
  background-image: linear-gradient(rgba(145,70,255,.18), rgba(145,70,255,.18));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  /* em-Polster skaliert mit der Schriftgroesse (px war bei 63px-H2 zu knapp).
     Links minimal mehr: Versalien haben kaum Vorbreite, das gleicht optisch. */
  padding: 0.10em 0.20em 0.14em 0.22em;
  margin-left: -0.22em;
  border-radius: 4px;
}
@keyframes ds-mark-wipe {
  from { background-size: 0% 100%; }
  to   { background-size: 100% 100%; }
}
.ds-mark.is-wipe {
  animation: ds-mark-wipe .85s cubic-bezier(.5,0,.1,1) .35s both;
}
/* FOUC-Guard: Seite setzt html.js-anim synchron im <head>:
     <script>try{if(!matchMedia('(prefers-reduced-motion: reduce)').matches)
       document.documentElement.classList.add('js-anim')}catch(e){}</script>
   Dann startet der Marker versteckt statt voll aufzublitzen.
   Ohne JS bleibt die Klasse aus -> Marker voll sichtbar (Sicherheitsnetz). */
html.js-anim .ds-mark:not(.is-wipe) { background-size: 0% 100%; }

@media (prefers-reduced-motion: reduce) {
  .ds-mark, .ds-mark.is-wipe { animation: none; background-size: 100% 100%; }
}

/* --- Werkzeug-Karte: flach + kantig + Akzentkante -------------------------
   Ersetzt die Glaskarte (Gradient + 14px-Radius + 40px-Weichschatten).
   Markup:  <div class="ds-card">…</div>                                    */
.ds-card {
  background: var(--surface);
  border: 1px solid var(--border-2, var(--border));
  border-left: 3px solid var(--violet);
  border-radius: 3px;
  box-shadow: 4px 4px 0 rgba(0,0,0,0.55);
  transition: transform .25s cubic-bezier(.6,0,.2,1), box-shadow .25s;
}
.ds-card:hover {
  transform: translate(-2px,-2px);
  box-shadow: 7px 7px 0 rgba(0,0,0,0.6);
}
:root[data-theme="light"] .ds-card {
  background: #fffdf8;
  box-shadow: 4px 4px 0 rgba(0,0,0,0.14);
}
:root[data-theme="light"] .ds-card:hover {
  box-shadow: 7px 7px 0 rgba(0,0,0,0.18);
}

/* --- Legacy-Override: alte .serif-Akzente umerziehen ----------------------
   Die frozen CSS-Bundles der Raw-Pages (mediaplayer.*.css, schnittkurs.*.css)
   stylen <span class="serif"> als KURSIVE SERIF — mit [data-astro-cid]-
   Attributen, also hoher Spezifitaet, und die Bundles sind nicht neu baubar.
   Deshalb hier per !important (Iron Law 10): Typografie auf das neue
   Akzent-Muster zwingen. Die FARBE bleibt bewusst der Seite ueberlassen —
   manche Akzente sind dort violet-2, manche gradient, das soll so bleiben.
   Wirkt auf JEDER Seite, die dieses File laedt — Markup muss nicht angefasst
   werden. */
h1 .serif, h2 .serif, h3 .serif, .hero .serif, .sk-hero .serif {
  font-family: var(--sans) !important;
  font-style: normal !important;
  font-weight: 800 !important;
  font-stretch: 78% !important;
  letter-spacing: -0.01em !important;
}

/* --- Seiten-Adapter: Marker fuer Hero-Akzente der Raw-Pages ---------------
   Die Raw-Pages koennen keine ds-mark-Klassen im Markup tragen: ihre
   data-i18n-html-Ueberschriften werden von den frozen JS-Bundles zur
   Laufzeit NEU GESCHRIEBEN (Iron Law 9) — Klassen im HTML wuerden beim
   Sprachwechsel verschwinden. Deshalb hier per Selektor, ohne Markup-
   Abhaengigkeit. Wird das h1 neu geschrieben, greift der Selektor auf den
   neuen Span einfach wieder (die Wipe-Animation startet dann erneut —
   erwuenscht). Marker nur auf HERO-Ebene, wie auf der Startseite
   entschieden (Sections bewusst ohne). */
.sk-hero h1 .serif {
  /* display:inline ist der Kern: Als block malte der Browser bei Zeilen-
     umbruch EINEN grossen Kasten um den ganzen Block — inklusive der Leere
     rechts neben kuerzeren Zeilen. Inline + box-decoration-break:clone gibt
     JEDER Zeile ihren eigenen, eng anliegenden Marker (wie mit einem echten
     Textmarker gezogen). !important noetig: die frozen Bundle-Regel setzt
     display:block mit [data-astro-cid]-Spezifitaet. */
  display: inline !important;
  background-image: linear-gradient(rgba(145,70,255,.18), rgba(145,70,255,.18));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  /* Vertikal knapper als beim Block-Marker: Inline-Zeilenboxen zweier
     markierter Zeilen ueberlappen sonst sichtbar (Leading < Polster). */
  padding: 0.06em 0.20em 0.10em 0.22em;
  margin-left: -0.22em;
  border-radius: 4px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
html.js-anim .sk-hero h1 .serif {
  animation: ds-mark-wipe .85s cubic-bezier(.5,0,.1,1) .35s both;
}
@media (prefers-reduced-motion: reduce) {
  html.js-anim .sk-hero h1 .serif { animation: none; background-size: 100% 100%; }
}

/* --- Adapter: Einsendungen-Hero -------------------------------------------
   Die frozen page-title-Regel setzt die GANZE H1 in kursivnaher Serif
   (weight 400) mit kursivem <em> — das alte Muster in Reinform. Hier auf
   das neue System gezogen: Grundschrift Archivo, das <em> wird zum
   Akzentwort mit Marker (Hero-Ebene, gleiche Phrase wie der Startseiten-
   Hero — "Lieblings-Clip ein." soll auf beiden Seiten identisch wirken). */
.page-title {
  font-family: var(--sans) !important;
  font-weight: 700 !important;
  letter-spacing: -0.03em !important;
}
.page-title em {
  font-style: normal !important;
  font-weight: 800 !important;
  font-stretch: 78% !important;
  letter-spacing: -0.01em !important;
  display: inline !important;
  background-image: linear-gradient(rgba(145,70,255,.18), rgba(145,70,255,.18));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  padding: 0.06em 0.20em 0.10em 0.22em;
  margin-left: -0.22em;
  border-radius: 4px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
html.js-anim .page-title em {
  animation: ds-mark-wipe .85s cubic-bezier(.5,0,.1,1) .35s both;
}

/* --- Adapter: Portfolio-Hero ----------------------------------------------
   .pf-pill ist die alte Badge-Pille (Kasten + Punkt) — wird zum Kicker.
   Der Marker haengt am i18n-Key-Attribut, weil das h1 dort keine Klasse
   traegt; der Key ist stabil (nur Seiten, die dieses File laden, betroffen —
   aktuell allein Portfolio). */
/* Vereinheitlicht fuer ALLE Deko-Pillen der Seiten: Portfolio (.pf-pill),
   Schnittkurs (.sk-pill), MediaChest (.pill). !important schlaegt auch die
   INLINE-Styles der MediaChest-Pille (amber-Kasten + Puls-Punkt) — Inline
   verliert gegen !important im Stylesheet. Die .user-pill der Nav ist ein
   BEDIENELEMENT und bleibt bewusst unangetastet. Der Punkt wird zur
   auslaufenden Linie — ausser bei Status-Anzeigen (siehe .pill-stat). */
.pf-pill, .sk-pill, .pill {
  background: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
  gap: 14px !important;
  font-family: var(--mono, ui-monospace, monospace) !important;
  font-size: 13px !important;
  font-weight: 700 !important;
  letter-spacing: 0.22em !important;
  text-transform: uppercase !important;
  color: var(--fg) !important;
}
.pf-pill .dot, .sk-pill .dot, .pill .dot {
  width: 46px !important; height: 2px !important;
  border-radius: 0 !important; box-shadow: none !important;
  background: linear-gradient(90deg, var(--violet), rgba(145,70,255,0.12)) !important;
  animation: none !important;
}

/* .eyebrow ist dieselbe alte Badge-Pille im page-head vieler raw-pages
   (einsendungen, datum-suche, browse, profil, …) und einiger Astro-Pages
   (cookies, widerruf, twitch-commands). Gleicher Kicker-Look wie oben.
   Der Inline-SVG-Pfeil verschwindet (die Legacy-i18n-Bundles ersetzen ihn
   beim innerHTML-Rewrite ohnehin); die auslaufende Linie kommt als ::after,
   damit sie jeden Runtime-Rewrite ueberlebt. */
.eyebrow {
  background: none !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
  gap: 14px !important;
  font-family: var(--mono, ui-monospace, monospace) !important;
  font-size: 13px !important;
  font-weight: 700 !important;
  letter-spacing: 0.22em !important;
  text-transform: uppercase !important;
  color: var(--fg) !important;
}
.eyebrow svg { display: none !important; }
.eyebrow::after {
  content: "";
  display: inline-block;
  width: 46px; height: 2px;
  background: linear-gradient(90deg, var(--violet), rgba(145,70,255,0.12));
}

/* Einsendungen .pill-stat ist ein LIVE-STATUS (der #apiDot wechselt per JS
   die Farbe: gruen/orange/rot). Der Punkt MUSS Punkt bleiben — er ist das
   Signal. Nur die Pillenform wird kantig (ds-chip-Look). */
.pill-stat {
  border-radius: 3px !important;
  border-left-width: 2px !important;
}
h1[data-i18n-html="hero.title"] .serif {
  display: inline !important;
  background-image: linear-gradient(rgba(145,70,255,.18), rgba(145,70,255,.18));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  padding: 0.06em 0.20em 0.10em 0.22em;
  margin-left: -0.22em;
  border-radius: 4px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
html.js-anim h1[data-i18n-html="hero.title"] .serif {
  animation: ds-mark-wipe .85s cubic-bezier(.5,0,.1,1) .35s both;
}
@media (prefers-reduced-motion: reduce) {
  html.js-anim .page-title em,
  html.js-anim h1[data-i18n-html="hero.title"] .serif {
    animation: none; background-size: 100% 100%;
  }
}

/* --- Status-Chip: kantig statt Pille --------------------------------------
   Fuer echte Status-Abzeichen ("Bald verfuegbar") — inhaltlich ein Chip,
   nur die Pillenform ist raus.                                             */
.ds-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  background: rgba(255,112,67,0.1);
  border: 1px solid rgba(255,112,67,0.3);
  border-left: 2px solid var(--orange);
  border-radius: 2px;
  font-size: 10px; font-family: var(--mono, ui-monospace, monospace);
  font-weight: 600; color: var(--orange);
  letter-spacing: 0.06em; text-transform: uppercase;
}

/* ===== 3) INTERAKTIONS-SCHICHT (neu 25.07.2026) ==========================
   ACHTUNG, das ist der Unterschied zu den Schichten 1 und 2: diese Regeln
   sind NICHT opt-in. Sie wirken auf jeder Seite, die dieses File laedt,
   ohne dass am Markup etwas geaendert wird. Der Kopfkommentar oben nennt
   das File "deploy-inert" - fuer diesen Block gilt das nicht mehr.

   Herkunft: dieselben Handgriffe, die die Startseite bekommen hat. Rail
   und Hoehepunkt bleiben dort exklusiv, weil sie eine gegliederte
   Sektionsstruktur brauchen; das Handwerk hier ist strukturunabhaengig.
   ======================================================================== */

/* --- Tastatur-Fokus ------------------------------------------------------
   36 Stellen im Bestand setzen `outline: none` und machen den Fokus fuer
   Tastaturnutzer unsichtbar. Die stehen fast alle auf Basis-Regeln
   (z.B. `.inp { outline: none }`, Spezifitaet 0,1,0). Ein Selektor mit
   Pseudoklasse liegt bei 0,1,1 und gewinnt - deshalb kommt dieser Block
   OHNE !important aus und laesst bewusst gestaltete Fokus-Stile in Ruhe,
   solange sie ebenfalls mit :focus-visible arbeiten und spaeter geladen
   werden.
   :focus-visible statt :focus: Mausklicks loesen keinen Ring aus, nur
   Tastatur- und Hilfsmittel-Navigation. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--violet-2, #a87bff);
  outline-offset: 3px;
}

/* --- Druckfeedback -------------------------------------------------------
   Ohne Rueckmeldung beim Druecken fuehlt sich eine Oberflaeche taub an.

   Zwei bewusste Entscheidungen:
   1) `scale` als EIGENSTAENDIGE Eigenschaft, nicht `transform: scale()`.
      Mehrere Seiten (Startseite, MediaChest) bewegen Buttons per GSAP und
      schreiben dabei ein inline `transform`. Ein CSS-`transform` hier
      waere davon ueberschrieben und wirkungslos. `scale` wird vom Browser
      mit dem transform verrechnet, beide Effekte koexistieren.
   2) Die Transition steht in :where() und hat damit Spezifitaet 0.
      Jede vorhandene Seiten-Transition gewinnt. Seiten mit
      `transition: all .15s` animieren die Skalierung ueber ihre eigene
      Dauer mit; Seiten ohne passende Transition schalten hart um. Beides
      ist richtig - nur duerfen wir ihre Transition nicht ueberschreiben,
      sonst kippen dort Farb- und Rahmenuebergaenge weg. */
:where(button, .btn, [role="button"], input[type="submit"], input[type="button"]) {
  transition: scale 140ms var(--ease-out, ease-out);
}
button:active,
.btn:active,
[role="button"]:active,
input[type="submit"]:active,
input[type="button"]:active {
  scale: 0.97;
}
/* Deaktivierte Schaltflaechen duerfen nicht so tun, als haetten sie
   reagiert. */
button:disabled:active,
.btn:disabled:active,
button[aria-disabled="true"]:active,
.btn[aria-disabled="true"]:active {
  scale: 1;
}

/* --- Zeilenumbruch -------------------------------------------------------
   `balance` verteilt Ueberschriften gleichmaessig statt stur umzubrechen
   und verhindert die einzelne Waise in der letzten Zeile. `pretty` macht
   dasselbe fuer Fliesstext, aber nur fuer die letzten Zeilen, damit lange
   Absaetze nicht neu durchgerechnet werden muessen.
   Elementselektoren mit Spezifitaet 0,0,1: jede Seitenregel gewinnt. */
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }

/* --- Bewegung abbestellen ------------------------------------------------
   Wer Bewegung reduziert haben will, bekommt auch hier keine. Betrifft
   ausdruecklich nur die Schicht oben; Seiten-Animationen regeln ihre
   eigenen Media-Queries. */
@media (prefers-reduced-motion: reduce) {
  :where(button, .btn, [role="button"], input[type="submit"], input[type="button"]) {
    transition: none;
  }
  button:active, .btn:active, [role="button"]:active,
  input[type="submit"]:active, input[type="button"]:active { scale: 1; }
}

/* ===== 4) SCROLL-EINBLENDUNGEN (Opt-in via data-reveal) ==================
   Gegenstueck zu /ds-motion.js. Bringt die Ruhe-vor-der-Bewegung der
   Startseite auf die uebrigen Seiten, ohne dort GSAP zu laden.

   Markup:
     <section data-reveal>…</section>            ganzer Block blendet ein
     <div data-reveal="stagger">…</div>          direkte Kinder nacheinander

   Bewusst dezent: 14px Versatz statt grosser Spruenge — auf langen
   Marketing-Seiten wird staerkere Bewegung beim Scrollen schnell unruhig.
   Der Startzustand haengt an html.js-anim, damit ohne JavaScript nichts
   unsichtbar bleibt (derselbe FOUC-Guard wie beim Marker).                */
html.js-anim [data-reveal]:not(.is-revealed),
html.js-anim [data-reveal="stagger"]:not(.is-revealed) > * {
  opacity: 0;
  transform: translateY(14px);
}
[data-reveal],
[data-reveal="stagger"] > * {
  transition: opacity .6s var(--ease-out, cubic-bezier(.23,1,.32,1)),
              transform .6s var(--ease-out, cubic-bezier(.23,1,.32,1));
}
[data-reveal].is-revealed,
[data-reveal="stagger"] > .is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html.js-anim [data-reveal]:not(.is-revealed),
  html.js-anim [data-reveal="stagger"]:not(.is-revealed) > * {
    opacity: 1;
    transform: none;
  }
  [data-reveal], [data-reveal="stagger"] > * { transition: none; }
}

/* Notschalter: setzt ds-motion.js, wenn Einblendungen in dieser Umgebung
   nachweislich nicht greifen. Dann zählt nur noch, dass der Inhalt da ist —
   ohne Übergang, ohne Versatz, ohne Ausnahme. */
html.ds-motion-off [data-reveal],
html.ds-motion-off [data-reveal] > *,
html.ds-motion-off [data-reveal="stagger"] > * {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}

/* ===== 5) LEITSYSTEM (Scroll-Rail) ======================================
   Dieselbe Rail wie auf der Startseite, hier als wiederverwendbarer
   Baustein: /ds-rail.js baut sie zur Laufzeit aus allen Abschnitten, die
   ein data-rail="Name" tragen. Die Seite selbst braucht kein Markup.

   Erst ab 1240px — darunter ist der Seitenrand zu schmal und die Rail käme
   dem Inhalt in die Quere.                                              */
.ds-rail { display: none; }
@media (min-width: 1240px) {
  .ds-rail {
    display: flex; flex-direction: column; gap: 18px;
    position: fixed; left: 30px; top: 50%;
    transform: translateY(-50%);
    z-index: 40;
    padding-left: 16px;
    opacity: 0; visibility: hidden;
    transition: opacity 320ms var(--ease-out, cubic-bezier(.23,1,.32,1)), visibility 320ms;
  }
  /* Erscheint erst, wenn der Kopfbereich durch ist. */
  .ds-rail.is-visible { opacity: 1; visibility: visible; }

  .ds-rail__line {
    position: absolute; left: 0; top: 4px; bottom: 4px;
    width: 2px; background: var(--border-2); overflow: hidden;
  }
  /* Gefüllter Anteil wächst per scaleY — läuft auf der GPU, anders als eine
     Höhen-Animation. */
  .ds-rail__fill {
    display: block; width: 100%; height: 100%;
    background: linear-gradient(180deg, var(--violet), var(--violet-2));
    transform: scaleY(0); transform-origin: top;
    transition: transform 420ms var(--ease-out, cubic-bezier(.23,1,.32,1));
  }

  .ds-rail__item {
    display: flex; align-items: center; gap: 10px;
    font-family: var(--mono, ui-monospace, monospace);
    font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
    color: var(--fg-dim); text-decoration: none;
    transition: color 180ms var(--ease-out, cubic-bezier(.23,1,.32,1));
  }
  .ds-rail__item:hover { color: var(--fg); }
  .ds-rail__item:focus-visible {
    outline: 2px solid var(--violet-2); outline-offset: 4px; border-radius: 2px;
  }
  .ds-rail__item.is-active { color: var(--violet-2); }

  /* Der Name erscheint nur beim Überfahren oder bei Tastaturfokus — sonst
     trägt die Nummer allein, damit die Rail am Rand nicht mitliest. */
  .ds-rail__name {
    text-transform: uppercase; white-space: nowrap;
    opacity: 0; translate: -6px 0;
    transition: opacity 200ms var(--ease-out, cubic-bezier(.23,1,.32,1)),
                translate 200ms var(--ease-out, cubic-bezier(.23,1,.32,1));
  }
  .ds-rail:hover .ds-rail__name,
  .ds-rail__item:focus-visible .ds-rail__name { opacity: 1; translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ds-rail, .ds-rail__fill, .ds-rail__name, .ds-rail__item { transition: none; }
}

/* ===== 6) LAUFSCHRIFT ANGLEICHEN =========================================
   Die Laufschrift-Bänder auf MediaChest, Schnittkurs und Portfolio zogen
   ihre Schrift aus eingefrorenen Seiten-Bundles: `var(--serif) italic`.
   Solange --serif nicht gesetzt war, lief das auf Times New Roman hinaus;
   seit das Token verankert ist, auf kursive Instrument Serif. Beides passt
   nicht zur Startseite, die hier schmales, fettes Archivo verwendet.

   `!important` ist nötig: Die Bundle-Regeln tragen die Astro-Scope-Attribute
   (.marquee-item[data-astro-cid-…]) und sind damit spezifischer als jeder
   normale Selektor hier.                                                 */
.marquee-item {
  font-family: var(--sans) !important;
  font-style: normal !important;
  font-weight: 800 !important;
  font-stretch: 78% !important;
  letter-spacing: -0.01em !important;
}

/* ===== 7) SERIF-RESTBESTAND SITE-WEIT ABLOESEN ===========================
   Der Legacy-Override oben fasst nur <span class="serif"> in Ueberschriften.
   Ein Scan ueber alle Seiten-Stylesheets (inkl. der eingefrorenen Bundles)
   fand 58 weitere Stellen, die `var(--serif) italic` setzen — Laufschriften,
   Kapitelnummern, Titel, Kennzahlen. Solange --serif nicht verankert war,
   fiel das auf Times New Roman; seit der Verankerung auf kursive Instrument
   Serif. Beides passt nicht zur Startseite.

   Zwei Gruppen, bewusst unterschiedlich behandelt:
     A) Akzent-Traeger (Laufschrift, Nummern, Kennzahlen) bekommen den vollen
        Akzent-Schnitt der Startseite: schmal + extrafett.
     B) Titel und Ueberschriften bekommen nur Schriftart und aufrechten
        Schnitt. Gewicht und Breite bleiben der Seite ueberlassen, sonst
        wuerde die Groessenhierarchie der jeweiligen Seite platt gebuegelt.

   `!important` ist Pflicht: die Bundle-Regeln tragen [data-astro-cid]-
   Attribute und sind damit spezifischer als jeder normale Selektor.       */

/* --- A) Akzent-Traeger: schmal + extrafett ------------------------------ */
/* <em> in Ueberschriften ist auf diesen Seiten ein Akzentwort, keine
   Betonung im Fliesstext — deshalb derselbe Schnitt wie .serif. Bewusst NUR
   in h1/h2/h3: ein <em> im Absatz soll seine Kursive behalten. */
h1 em, h2 em, h3 em,
.sk-marquee-item,
.sk-mnum,
.pf-process-num,
.lb-rank,
.pf-chip-avatar,
.pf-trust-avatar.is-fallback,
.pf-acc-thumb.is-gradient span,
.stat-num, .kpi-num, .profile-stat-num, .lb-stat-num,
.sk-about-stat .n {
  font-family: var(--sans) !important;
  font-style: normal !important;
  font-weight: 800 !important;
  font-stretch: 78% !important;
  letter-spacing: -0.01em !important;
}

/* --- B) Titel und Ueberschriften: nur Schrift + aufrecht ---------------- */
.page-title, .card-title, .modal-title, .empty-title,
.profile-name, .profile-section-title,
.chat-vod-header, .result-head-date,
.yt-card-title, .yt-result-head-title,
.prose h3, .legal h2,
.sk-hero h1, .sk-shead h2, .sk-feat h3,
.sk-about-text h2, .sk-cta-final h2, .sk-about-name h3,
.hero h1, .feature-card h3, .section-head h2, .cta-final h2,
.pf-about-name h3 {
  font-family: var(--sans) !important;
  font-style: normal !important;
}
