/* ==========================================================================
   Wortmarke, drei Druckplatten.

   Cyan, Papier und Orange liegen als drei deckungsgleiche SVG uebereinander.
   Den Fehldruck macht dieses Stylesheet, nicht die Datei — nur so laesst er
   sich bewegen.

   Die Ausgangswerte sind aus der Vorlage gemessen, bezogen auf die
   Papierplatte (SVG-Einheiten bei einer 1856 breiten, 129.74 hohen Platte):

     Cyan    -6.95 / -2.90
     Orange  +4.97 / +6.57

   Umgerechnet auf Prozent der Plattengroesse stehen sie unten als top/left.
   Die Container-Hoehe deckt beide Versaetze mit ab: 129.74 + 2.90 + 6.57.
   ========================================================================== */
.lh-wordmark{
  position:relative;
  /* Pfad der Maske einmal hier, damit die Stoerschicht ihn nicht doppelt
     fuehrt. Relativ zu DIESER Datei, also aus assets/css/ heraus. */
  --lh-mask:url("../wordmark-plate-paper.svg");
  width:100%;

  /* Seitliche Reserve. Die Orangeplatte steht bis zu 17px rechts des
     Rahmens und die Maus schiebt sie um weitere 16px — zusammen mehr als
     der Rinnenrand hergibt, der bei 32px endet. Ist der Ausschlag groesser
     als der Rand, rueckt der Rahmen entsprechend ein statt ueberzulaufen. */
  --lh-wm-ausschlag:calc(min(0.8990%, 17px) + min(0.8%, 16px) + 6px);
  max-width:calc(100% - 2 * max(var(--lh-gutter), var(--lh-wm-ausschlag)));
  margin-inline:auto;
  /* ⚠ 1872 / 146.55, nicht 1856 / 139.2. Der alte viewBox der Platten war
     zu klein fuer ihren eigenen Inhalt: die Buchstaben reichten bis 1869.86,
     die Zeichenflaeche endete bei 1856.018 — das S war IN DER DATEI glatt
     abgeschert, und kein Eingriff am Layout konnte das heilen. Gemessen mit
     getBBox ueber alle Pfade, nicht geschaetzt.

     Der viewBox ist jetzt 0 -5 1872 142 und deckt den Inhalt aller drei
     Platten ab (links 2.05, rechts 1869.86, oben -3.67, unten 135.32).
     Alles, was an der alten Zahl hing, zieht mit: die Hoehe hier, die
     Abstaende unten, --lh-wordmark-h in tokens.css und die Maskenmasse der
     Stoerschicht. Die Buchstaben stehen danach auf demselben Fleck wie
     vorher, das S ist nur vollstaendig. */
  aspect-ratio:1872 / 156.9;

  /* Richtung des Lichteinfalls, -1 bis 1. Ohne Skript bleibt sie auf 0 und
     die Platten stehen auf ihren gemessenen Ausgangswerten. */
  --lh-ray-x:0;
  --lh-ray-y:0;
}

.lh-plate{
  position:absolute;left:0;
  width:100%;height:auto;display:block;
}

/* Ausgangslage, aus der Vorlage gemessen. */
/* ⚠ Der Versatz steckt SCHON in den Dateien: jede Platte zeichnet ihre
   Buchstaben an leicht anderer Stelle (paper liegt 6.955/2.904 Einheiten
   links-oben von cyan, orange 11.923/9.473). Nur steht er dort in der
   falschen Richtung — orange saesse oben, cyan unten.

   Das CSS muss ihn also DOPPELT aufbringen: einmal um die Bake-Richtung
   umzudrehen, einmal um den eigentlichen Fehldruck zu erzeugen. Vorher
   stand hier der einfache Betrag, und damit hoben sich Datei und CSS exakt
   auf — die drei Platten lagen deckungsgleich, uebrig blieb ein duenner
   Saum statt eines Fehldrucks. An gerenderten Pixeln gemessen: in der
   Vorlage steht Cyan 9px ueber Orange bei 126px Buchstabenhoehe (7.1 %),
   bei uns waren an derselben Spalte gar keine Cyan-Pixel.

   Doppelter Betrag in Einheiten: paper 13.910/5.808, orange 23.846/18.946.
   Umgerechnet auf die Rahmenmasse 1872 breit, 156.9 hoch. */
/* ⚠ Gedeckelt. In der Vorlage war der Versatz ein FESTER Pixelwert (top
   2.9036px, 9.4731px im Original-CSS), er wuchs nicht mit dem Fenster. Als
   reiner Anteil waere er auf einem 3440er-Schirm dreimal so gross wie
   gedacht und liefe ueber den Rand. min() nimmt unter etwa 1900px den
   Anteil, darueber den Festwert. */
.lh-plate--cyan  { top:-3.200%; margin-left:calc(-1 * min(0.3747%,  7px)) }
.lh-plate--paper { top:calc(-3.200% + min(3.702%,  6px)); margin-left:min(0.3684%,  7px) }
.lh-plate--orange{ top:calc(-3.200% + min(12.075%,19px)); margin-left:min(0.8990%, 17px) }

/* --- Lichteinfall ---------------------------------------------------------
   Die beiden Farbplatten wandern gegenlaeufig zum Zeiger, als saesse die
   Lichtquelle dort. Papier bleibt stehen: es ist die Grundplatte, gegen die
   der Passerfehler sichtbar wird.

   Die Faktoren sind unterschiedlich, weil Prozent sich auf die jeweilige
   Achse der Platte beziehen: 0.8 Prozent der Breite (1856) sind rund 15px,
   dieselben 15px sind 11 Prozent der Hoehe (129.74).
   -------------------------------------------------------------------- */
@media (hover:hover) and (prefers-reduced-motion:no-preference){
  .lh-plate--cyan,
  .lh-plate--orange{
    transition:translate .45s cubic-bezier(.16,1,.3,1);
  }
  /* ⚠ Der seitliche Ausschlag ist gedeckelt. 0.8 % waechst mit der Breite,
     der Rinnenrand nicht: er endet bei 32px (tokens.css). Auf einem
     3440px-Schirm haette die Orangeplatte 27px Ausschlag plus 9px
     Grundversatz gehabt und waere ueber die Kante gelaufen. Bis rund
     2000px greift der Deckel nicht, dort sind 0.8 % noch unter 16px.

     Senkrecht braucht es das nicht: der Kopfraum in shell.css ist selbst
     ein Anteil derselben Hoehe und waechst mit. */
  .lh-plate--cyan{
    translate:calc(var(--lh-ray-x) * -1 * min(0.8%, 16px)) calc(var(--lh-ray-y) * -11%);
  }
  .lh-plate--orange{
    translate:calc(var(--lh-ray-x) *      min(0.8%, 16px)) calc(var(--lh-ray-y) *  11%);
  }
}

@media (prefers-reduced-motion:no-preference){
  .lh-wordmark--home{
    animation:lhRiseIn .9s cubic-bezier(.16,1,.3,1) both .15s;
  }
  @keyframes lhRiseIn{from{opacity:0;transform:translateY(42px)}to{opacity:1;transform:none}}
}

/* --- Fehlkontakt -----------------------------------------------------------
   Die beiden Farbplatten zucken gelegentlich, wie ein Roehrenbildschirm mit
   schlechter Masse. Kurze harte Spruenge statt weicher Bewegung: deshalb
   steps(1,end), jedes Bild steht, nichts wird interpoliert.

   ⚠ Der Versatz laeuft ueber `transform`, NICHT ueber `translate`. Die
   Mausrichtung sitzt bereits auf `translate`; die beiden Eigenschaften
   verketten sich, eine Animation auf `translate` haette sie ueberschrieben
   und der Lichteinfall waere tot gewesen.

   Die Platten laufen versetzt (negative Verzoegerung), damit Cyan und Orange
   nie im selben Bild zucken — sonst sieht es nach Wackeln aus, nicht nach
   Stoerung. Papier bleibt ruhig: es ist die Grundplatte.
   -------------------------------------------------------------------- */
@media (prefers-reduced-motion:no-preference){
  /* 6.0 gegen 7.5 Sekunden. Der gemeinsame Nenner liegt bei 30 Sekunden —
     das ist Absicht, siehe den Doppelstoss unten. Ungleiche Laufzeiten sind
     weiter noetig, damit das Auge keinen Takt lernt. */
  .lh-plate--cyan  { animation:lhBuzzCyan   6.0s steps(1,end) infinite }
  .lh-plate--orange{ animation:lhBuzzOrange 7.5s steps(1,end) infinite }
}

/* Ein Schritt dauert 30ms, vier Stoesse je Umlauf. Zusammen faellt damit
   rund alle 0.9 Sekunden etwas aus dem Tritt, kurz genug, dass es zuckt
   und nicht wackelt.

   ⚠ Der Doppelstoss: Cyan bei 80 % von 6.0s und Orange bei 64 % von 7.5s
   liegen beide exakt bei 4800ms. Orange steht um 0.9 % spaeter, also rund
   68ms — knapp genug, dass man es als einen Fehler sieht, weit genug, dass
   die Platten nacheinander springen. Wegen des gemeinsamen Nenners trifft
   sich dieses Paar alle 30 Sekunden wieder.

   ⚠ Der Versatz laeuft ueber `transform`, NICHT ueber `translate`. Dort
   sitzt die Mausrichtung; eine Animation darauf haette sie ueberschrieben.

   ⚠ Die Deckkraft faellt nur bis rund 0.75. Tiefer scheint das Papier durch
   die Orangeplatte und der Schriftzug wirkt rosa ausgewaschen statt
   gestoert. Die Arbeit machen Versatz und Ausfall, nicht das Verblassen. */
@keyframes lhBuzzCyan{
  0%, 8%       { transform:none; opacity:1; clip-path:none }
  8.5%         { transform:translate3d(-.42%, -.8%, 0); opacity:.78 }
  9%           { transform:translate3d( .28%,  .5%, 0); opacity:1 }
  9.5%, 31%    { transform:none }
  31.5%        { transform:translate3d( .55%, 0, 0); opacity:.74 }
  32%          { transform:translate3d(-.2%, .35%, 0); opacity:1 }
  32.5%, 57%   { transform:none }
  57.5%        { transform:translate3d(-.3%, .6%, 0); opacity:.8 }
  58%, 80%     { transform:none; opacity:1 }

  /* 80 % von 6.0s = 4800ms. Hier trifft sich der Doppelstoss. */
  80.5%        { transform:translate3d(-.6%, -.9%, 0); opacity:.76;
                 clip-path:inset(0 0 41% 0) }
  81%          { transform:translate3d( .34%, .55%, 0); opacity:1 }
  81.5%        { transform:translate3d(-.14%, 0, 0); clip-path:none }
  82%, 100%    { transform:none; opacity:1; clip-path:none }
}

@keyframes lhBuzzOrange{
  0%, 14%      { transform:none; opacity:1; clip-path:none }
  14.4%        { transform:translate3d( .4%,  .7%, 0); opacity:.76 }
  14.8%        { transform:translate3d(-.26%, -.4%, 0); opacity:1 }
  15.2%, 41%   { transform:none }
  41.4%        { transform:translate3d(-.5%, 0, 0); opacity:.78 }
  41.8%        { transform:translate3d( .2%, -.3%, 0); opacity:1 }
  42.2%, 64.9% { transform:none }

  /* 64.9 % von 7.5s = 4868ms, also 68ms nach der Cyanplatte. */
  65.3%        { transform:translate3d( .62%, .85%, 0); opacity:.74;
                 clip-path:inset(34% 0 0 0) }
  65.7%        { transform:translate3d(-.3%, -.45%, 0); opacity:1; clip-path:none }
  66.1%, 88%   { transform:none }
  88.4%        { transform:translate3d( .34%, -.5%, 0); opacity:.8 }
  88.8%, 100%  { transform:none; opacity:1; clip-path:none }
}

/* Der Schriftzug als Rueckweg auf Unterseiten. Er ist ein Blockelement, der
   Link darf ihn weder einruecken noch in der Breite beschneiden. */
.lh-wordmark-home{ display:block; text-decoration:none }
.lh-wordmark-home:focus-visible{ outline:2px solid var(--lh-accent); outline-offset:4px }

/* --- Stoerschicht ----------------------------------------------------------
   Baender und Rauschen liegen ueber den Platten, sind aber mit der
   Papierplatte maskiert: sichtbar wird nur, was INNERHALB der Buchstaben
   liegt. Ohne die Maske waeren es Rechtecke ueber dem Foto, mit ihr sieht
   es aus, als risse der Druck selbst auf.

   Die Maskenmasse sind gerechnet, nicht geraten: die Platte ist
   1856 : 129.743, der Rahmen 1856 : 139.2. Also ist die Platte
   142 / 156.9 = 90.50 % so hoch wie der Rahmen, und die Papierplatte
   sitzt bei 0.502 % — dieselben Werte wie oben.
   -------------------------------------------------------------------- */
.lh-glitch{
  position:absolute; inset:0;
  pointer-events:none;
  /* Ueber den Platten, aber unter allem, was der Besucher bedienen kann. */
  z-index:1;

  /* ⚠ Die Baender werden zur Laufzeit seitlich verschoben und gedehnt
     (scaleX bis 1.14). Ohne Deckel schoben sie die Seite um rund 64px in
     die Breite, es erschien ein waagerechter Rollbalken und der Schriftzug
     stand rechts angeschnitten da.

     clip statt hidden: hidden erzeugt einen Rollbereich, und ein
     Rollbereich in der Kette friert scroll-getriebene Animationen ein.
     Sichtbar geht nichts verloren — die Maske beschraenkt die Baender
     ohnehin auf die Buchstaben, und die liegen innerhalb. */
  overflow:clip;
}

.lh-glitch__band,
.lh-glitch__noise{
  position:absolute; inset:0;
  display:block;
  opacity:0;                       /* Ruhezustand: nichts zu sehen */

          mask-image:var(--lh-mask); mask-size:100% 93.21%;
          mask-position:0 2.083%;   mask-repeat:no-repeat;
  -webkit-mask-image:var(--lh-mask); -webkit-mask-size:100% 90.50%;
  -webkit-mask-position:0 0.502%;   -webkit-mask-repeat:no-repeat;
}

/* Die Baender tragen zur Laufzeit einen Bildausschnitt, den glitch.js setzt. */
.lh-glitch__band{
  background-position:50% 50%;
  background-size:cover;
  background-repeat:no-repeat;
  mix-blend-mode:screen;
}

/* Grobes Pixelrauschen. feTurbulence liefert den Zufall, background-size
   macht daraus Bloecke statt Korn — 3px sieht nach kaputtem Signal aus,
   1px nur nach Filmkorn. */
.lh-glitch__noise{
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='discrete' tableValues='0 1'/%3E%3CfeFuncG type='discrete' tableValues='0 1'/%3E%3CfeFuncB type='discrete' tableValues='0 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='40' height='40' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:3px 3px;
  mix-blend-mode:overlay;
}

@media (prefers-reduced-motion:reduce){
  .lh-glitch{ display:none }
}
