/* ==========================================================================
   ILLUMOR DESIGN SYSTEM — effects.css
   --------------------------------------------------------------------------
   Der Röhren-Effekt, Elevation, Radius und Bewegung.

   KERNPRINZIP
   Jede Klasse hier ist theme-unabhängig. .fx-tube-text bleibt
   .fx-tube-text — im Dark Mode löst der Token zu Glow auf, im Light Mode
   zu Relief. Dieselben SVGs, dasselbe Markup, kein zweiter Asset-Satz.

   HARTE REGELN
   1. LESBARKEIT — Röhren-Effekt nur auf Display-Typo, Logo, Icons und
      Akzente. Niemals auf Fließtext, Labels, Rechtstexte oder alles
      unter 20px. Glow ist dekorativ, nie Bedeutungsträger.
   2. PERFORMANCE — Animiert wird ausschließlich opacity und transform,
      niemals Shadow-Werte: Shadow-Interpolation erzwingt einen Repaint
      pro Frame. Höchstens 4 Layer bei text-shadow (wenige Elemente),
      höchstens 3 bei box-shadow und filter (Flächen).
   ========================================================================== */

/* ==========================================================================
   1 · TEXT — text-shadow
   ========================================================================== */
.fx-tube-text     { text-shadow: var(--tube-text-md); }
.fx-tube-text--sm { text-shadow: var(--tube-text-sm); }
.fx-tube-text--lg { text-shadow: var(--tube-text-lg); }

/* Idle-Atmen: eine deckungsgleiche Glow-Kopie hinter dem Text, deren
   opacity pulsiert. Der Text selbst bleibt zu 100 % deckend — ein
   pulsierender Fließtext wäre unlesbar.
   Voraussetzung: data-text spiegelt den Textinhalt.
   <h1 class="fx-tube-text fx-tube-breathe" data-text="Illuminate">Illuminate</h1> */
.fx-tube-breathe {
  position: relative;
  isolation: isolate;
}
.fx-tube-breathe::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  z-index: -1;
  color: transparent;            /* nur der Schatten wird sichtbar */
  text-shadow: var(--tube-text-lg);
  pointer-events: none;
  animation: tube-breathe 4.5s var(--ease-in-out) infinite;
}

/* Zündung: das Anflackern einer echten Röhre beim Einschalten.
   Animiert die opacity des ganzen Elements — genau das tut eine echte
   Röhre auch, und es läuft rein auf dem Compositor. */
.fx-tube-ignite {
  animation: tube-ignite var(--d-ignite) var(--ease-out) both;
}
.fx-tube-ignite--delay-1 { animation-delay: 160ms; }
.fx-tube-ignite--delay-2 { animation-delay: 340ms; }
.fx-tube-ignite--delay-3 { animation-delay: 520ms; }

/* ==========================================================================
   2 · KANTE — box-shadow
   Outline-Pills, Inputs, glühende Karten-Kanten.
   ========================================================================== */
.fx-tube-edge     { box-shadow: var(--tube-edge-md); }
.fx-tube-edge--sm { box-shadow: var(--tube-edge-sm); }
.fx-tube-edge--lg { box-shadow: var(--tube-edge-lg); }

/* ==========================================================================
   3 · LINIE — filter, für SVG-Strokes
   Logo, Icons, Deko-Linienkunst. Wirkt auf jedes currentColor-SVG.
   ========================================================================== */
.fx-tube-stroke     { filter: var(--tube-stroke-md); }
.fx-tube-stroke--sm { filter: var(--tube-stroke-sm); }
.fx-tube-stroke--lg { filter: var(--tube-stroke-lg); }

/* ==========================================================================
   4 · PRIMITIVE — glühende Hairline und Knoten
   ========================================================================== */
.fx-tube-hairline {
  height: 1px;
  border: 0;
  background: var(--tube-core);
  opacity: 0.55;
  box-shadow: 0 0 6px rgb(var(--c-glow-tint) / 0.55),
              0 0 16px rgb(var(--c-glow-tint) / 0.28);
}
[data-theme="light"] .fx-tube-hairline {
  opacity: 0.9;
  box-shadow: 0 1px 0 rgb(255 255 255 / 0.9),
              0 2px 5px rgb(var(--c-shade-tint) / 0.18);
}

.fx-tube-dot {
  width: 0.75rem;
  aspect-ratio: 1;
  border-radius: var(--r-pill);
  background: var(--tube-core);
  box-shadow: var(--tube-edge-md);
}

/* ==========================================================================
   5 · ELEVATION & RADIUS
   ========================================================================== */
.e-0 { box-shadow: none; }
.e-1 { box-shadow: var(--e-1); }
.e-2 { box-shadow: var(--e-2); }
.e-3 { box-shadow: var(--e-3); }
.e-4 { box-shadow: var(--e-4); }
.e-inset { box-shadow: var(--e-inset); }

.r-xs  { border-radius: var(--r-xs); }
.r-sm  { border-radius: var(--r-sm); }
.r-md  { border-radius: var(--r-md); }
.r-lg  { border-radius: var(--r-lg); }
.r-xl  { border-radius: var(--r-xl); }
.r-2xl { border-radius: var(--r-2xl); }
.r-pill { border-radius: var(--r-pill); }

/* ==========================================================================
   6 · SCROLL-REVEAL
   Startzustand nur setzen, wenn JS tatsächlich läuft — sonst bleibt bei
   deaktiviertem JavaScript alles unsichtbar.
   ========================================================================== */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity var(--d-slow) var(--ease-out),
              transform var(--d-slow) var(--ease-out);
}
.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1; transform: none; }
}

/* ==========================================================================
   7 · KEYFRAMES
   ========================================================================== */
@keyframes tube-ignite {
  0%   { opacity: 0;    }
  8%   { opacity: 0.85; }
  12%  { opacity: 0.12; }
  20%  { opacity: 0.95; }
  26%  { opacity: 0.30; }
  34%  { opacity: 1;    }
  42%  { opacity: 0.55; }
  100% { opacity: 1;    }
}

@keyframes tube-breathe {
  0%, 100% { opacity: 0.82; }
  50%      { opacity: 1;    }
}

@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ==========================================================================
   8 · REDUCED MOTION — Endzustand statt Bewegung
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .fx-tube-ignite { animation: none; opacity: 1; }
  .fx-tube-breathe::after { animation: none; opacity: 0.92; }
}

/* ==========================================================================
   9 · RÖHREN-ELEMENTE — dekorative Leuchtrohre
   --------------------------------------------------------------------------
   Zwei getrennte Strichgewichts-Haushalte im System:

     Icons  1.5 auf 24er Raster  → die Linie ist ein STRICH
     Deko   6–14 im eigenen Raster → die Linie ist ein ROHR

   Das ist keine Inkonsequenz, sondern die Bedingung dafür, dass der Effekt
   funktioniert: unter dem Glow liest sich eine dünne Linie als leuchtendes
   Haar, erst eine echt dicke Kontur mit runden Enden als Leuchtstoffröhre.
   ========================================================================== */
.fx-deco {
  position: absolute;
  z-index: var(--z-deco);
  color: var(--tube-core);
  opacity: var(--deco-opacity, 0.85);
  pointer-events: none;
  filter: var(--tube-stroke-lg);
}
/* Im Light Mode ist das Rohr ein schwarzer Körper und muss zurücktreten,
   sonst dominiert es den Text. */
[data-theme="light"] .fx-deco,
.theme-light .fx-deco { opacity: var(--deco-opacity-light, 0.22); }

.fx-deco > svg { width: 100%; height: auto; }

/* Deko-Fläche: begrenzt die absolut positionierten Rohre und schneidet
   den Überhang ab, damit die Seite nie seitlich scrollt. */
.deco-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  z-index: var(--z-deco);
  pointer-events: none;
}

/* ==========================================================================
   10 · TEXT-SCRIM — die Trennung von Schrift und Rohr
   --------------------------------------------------------------------------
   HARTE REGEL: Kein Textkörper liegt jemals direkt vor einer Röhre.
   Ein Rohr ist eine Lichtquelle mit hohem Eigenkontrast; Schrift davor
   verliert ihre Kanten und fällt unter jede brauchbare Kontrastschwelle —
   im Dark Mode blendet sie, im Light Mode zerfällt sie.

   Zwei Maßnahmen, immer beide:

   A · PLATZIERUNG — Rohre gehören in die äußeren Ränder, hinter den Fold
       oder in die freie Hälfte einer Sektion. Nie durch die Textspalte.
   B · SCRIM — .deco-scrim legt einen Verlauf der Flächenfarbe zwischen
       Deko-Ebene und Inhalt. Er greift auch dann, wenn ein Rohr durch eine
       andere Viewport-Breite doch in die Textspalte wandert. Damit ist die
       Regel nicht nur Disziplin, sondern strukturell abgesichert.
   ========================================================================== */
.deco-scrim {
  position: absolute;
  inset: 0;
  z-index: calc(var(--z-content) - 1);   /* über der Deko, unter dem Text */
  pointer-events: none;
  background: linear-gradient(
    var(--scrim-angle, 100deg),
    rgb(var(--surface-base-rgb))            0%,
    rgb(var(--surface-base-rgb))            var(--scrim-solid, 34%),
    rgb(var(--surface-base-rgb) / 0.55)     var(--scrim-mid, 52%),
    rgb(var(--surface-base-rgb) / 0)        var(--scrim-end, 72%)
  );
}
/* Für zentrierte Sektionen: Scrim von unten statt von der Seite. */
.deco-scrim--up {
  --scrim-angle: 0deg;
  --scrim-solid: 22%;
  --scrim-mid: 46%;
  --scrim-end: 78%;
}
/* Für Textblöcke, die unvermeidlich über einem Rohr sitzen (Karten auf
   Bildstrecken): weiche Insel statt Verlauf. */
.deco-scrim--island {
  background: radial-gradient(
    ellipse at var(--scrim-x, 30%) var(--scrim-y, 50%),
    rgb(var(--surface-base-rgb)) 0%,
    rgb(var(--surface-base-rgb) / 0.82) 42%,
    rgb(var(--surface-base-rgb) / 0) 76%
  );
}

/* ==========================================================================
   11 · SELBSTZEICHNENDE RÖHRE
   --------------------------------------------------------------------------
   Alle Deko-Assets tragen pathLength="1" — die Kontur ist damit auf die
   Länge 1 normiert und stroke-dashoffset lässt sich in CSS animieren, ohne
   die echte Pfadlänge zu kennen.

   AUSNAHME ZUR PERFORMANCE-REGEL: stroke-dashoffset läuft nicht auf dem
   Compositor. Das ist hier vertretbar, weil die Animation einmalig ist, auf
   höchstens zwei Konturen läuft und nach 1.4 s endet. Für alles Dauerhafte
   oder Wiederholte bleibt die Regel: nur opacity und transform.
   ========================================================================== */
.fx-tube-draw :is(path, circle, rect, ellipse, line, polyline) {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: tube-draw var(--draw-d, 1400ms) var(--ease-out) var(--draw-delay, 0ms) forwards;
}
@keyframes tube-draw { to { stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce) {
  .fx-tube-draw :is(path, circle, rect, ellipse, line, polyline) {
    animation: none;
    stroke-dashoffset: 0;
  }
}
