/* ==========================================================================
   Motion - Startzustaende, Masken, Laufband

   Alle Startzustaende haengen an .js und werden per Inline-Script im <head>
   gesetzt. Ohne JavaScript steht die Seite vollstaendig sichtbar da.
   ========================================================================== */

/* --- Zeilenmaske ---------------------------------------------------------
   Der Grundtrick der Referenz: ein Element mit overflow:hidden, der Inhalt
   sitzt darin um 110 % nach unten versetzt und faehrt hoch. Wirkt, als
   waere der Text hinter einer Kante hervorgeschoben worden. */
.js [data-hero-text] .line {
  display: block;
  overflow: hidden;
  /* Bei Zeilenhoehe 0.9 ragen g, j, p, y weit unter die Grundlinie.
     Ohne diesen Puffer schneidet die Maske sie ab.

     Regel fuer jede neue Maske: Der Puffer ist in em, also muss das
     maskierende Element selbst die Schriftgroesse tragen. Sitzt die
     Groesse erst im Kind, rechnet das em gegen die Elterngroesse und
     der Puffer ist zu klein. */
  padding-bottom: .28em;
  margin-bottom: -.28em;
  /* Dasselbe waagrecht: kursive Glyphen lehnen ueber ihre Laufweite
     hinaus nach rechts. "statt" steht rechtsbuendig direkt an der
     Spaltenkante - ohne diesen Puffer schnitt die Maske das letzte t
     halb ab und das Wort sah aus, als liefe es hinter Ruben.

     Padding und negative Margin gleichen sich aus: die Box waechst nach
     rechts, ihre Inhaltskante bleibt, wo sie war. Der Text verschiebt
     sich also nicht, er bekommt nur Luft innerhalb der Maske. */
  padding-right: .16em;
  margin-right: -.16em;
}
.js [data-hero-text] .line > * {
  display: inline-block;
  transform: translateY(110%);
  will-change: transform;
}

/* --- Aufgeteilte Ueberschriften ------------------------------------------
   [data-split] wird im JS zeilenweise in Masken zerlegt. Bis das passiert
   ist, bleibt der Text unsichtbar - aber nur, wenn JS wirklich laeuft. */
.js [data-split] { visibility: hidden; }
.js [data-split].is-ready { visibility: visible; }
.split-line {
  display: block;
  text-align: inherit;
  overflow: hidden;
  /* Wird im JS in die Ueberschrift selbst gehaengt, erbt also deren
     Schriftgroesse - das em stimmt hier von allein. */
  padding-bottom: .28em;
  margin-bottom: -.28em;
}
.split-line > span {
  display: inline-block;
  will-change: transform;
}

/* --- Bild-Reveal ---------------------------------------------------------
   Der Rahmen faehrt von unten auf, das Bild darin haelt mit einer
   Gegenbewegung dagegen. Dadurch wirkt es freigelegt statt eingeblendet. */
.js [data-media] { clip-path: inset(100% 0 0 0); }
.js [data-media] > img { transform: scale(1.28); will-change: transform; }

/* --- Hero ---------------------------------------------------------------- */
.js [data-hero-media] > img { transform: scale(1.18); will-change: transform; }
.js [data-hero-sig] { opacity: 0; }
.js [data-nav]      { opacity: 0; }

.hero__scroll {
  position: absolute;
  inset: auto 0 2.2em 0;
  z-index: var(--z-content);
  text-align: center;
  color: var(--color-gray-light);
}
.hero__scroll::after {
  content: "";
  display: block;
  width: 1px;
  height: 2.5em;
  margin: .75em auto 0;
  background: linear-gradient(to bottom, var(--color-gray-light), transparent);
  transform-origin: top;
  animation: scrollHint 2.4s var(--ease-smooth) infinite;
}
@keyframes scrollHint {
  0%   { transform: scaleY(0); opacity: 0; }
  35%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(2.5em); opacity: 0; }
}

/* --- Preloader ----------------------------------------------------------- */
.pageloader__inner {
  display: flex;
  align-items: baseline;
  gap: 1em;
}
.pageloader__count { color: var(--color-gray-mid); }
/* Der Loader faehrt als Vorhang nach oben weg statt einfach auszublenden. */
.pageloader {
  transition: transform 1s var(--ease-smooth), visibility 1s;
}
.pageloader.is-hidden {
  transform: translateY(-100%);
  visibility: hidden;
  opacity: 1;
}

/* --- Laufband ------------------------------------------------------------
   Zwei identische Saetze nebeneinander, der Track wird per JS endlos
   verschoben. Die Scrollrichtung dreht die Laufrichtung um. */
.ticker {
  overflow: hidden;
  padding: 1.5em 0;
  border-top: 1px solid var(--color-line);
  border-bottom: 1px solid var(--color-line);
  user-select: none;
}
.ticker__track {
  display: flex;
  width: max-content;
  will-change: transform;
}
.ticker__set {
  display: flex;
  align-items: center;
  gap: 1.5em;
  padding-right: 1.5em;
  white-space: nowrap;
  color: var(--color-gray-mid);
  font-size: var(--font-size-large-mono);
}
.ticker__set i { font-style: normal; color: var(--color-gray-dark); }
/* Ohne JS laeuft es als reine CSS-Animation weiter. */
.no-js .ticker__track,
.no-gsap .ticker__track { animation: tickerSlide 30s linear infinite; }
@keyframes tickerSlide { to { transform: translateX(-50%); } }

/* --- Magnetische Buttons -------------------------------------------------- */
[data-magnet] { will-change: transform; }

/* --- Cursor --------------------------------------------------------------
   difference laesst den Ring auf hellen wie dunklen Flaechen lesbar bleiben. */
.cursor { mix-blend-mode: difference; }

/* --- Bewegung reduzieren -------------------------------------------------
   Alle Startzustaende werden zurueckgenommen, damit ohne Animation
   nichts unsichtbar bleibt. */
@media (prefers-reduced-motion: reduce) {
  .js [data-hero-text] .line > *,
  .split-line > span            { transform: none !important; }
  .js [data-media]              { clip-path: none !important; }
  .js [data-media] > img,
  .js [data-hero-media] > img   { transform: none !important; }
  .js [data-hero-sig],
  .js [data-nav]                { opacity: 1 !important; }
  .js [data-split]              { visibility: visible !important; }
  .hero__scroll::after,
  .no-js .ticker__track         { animation: none; }
}

/* --------------------------------------------------------------------------
   Link-Hover: Zeilentausch

   Dasselbe Prinzip wie die Hero-Headline, nur klein: ein Element mit
   overflow:hidden, darin zwei identische Zeilen uebereinander. Beim Hover
   faehrt die obere heraus, die untere schiebt nach. Kein Strich, keine
   Farbe - die Seite hat ihre eigene Bewegung, und die reicht.

   Warum nicht handgezeichnet: zwei Anlaeufe scheiterten, der erste an der
   Verzerrung (feste viewBox auf die Wortbreite gequetscht), der zweite am
   Ton - Filzstift-Kringel unter eng getracktem Satoshi wirken wie ein
   Aufkleber auf einem Plakat.

   Die zweite Zeile wird im JS erzeugt (initSwap). Ohne JS bleibt der Link
   ein normaler Link, der Hover faellt weg - kein Schaden.

   Achtung Unterlaengen: der Kasten schneidet an der Padding-Kante ab, ein
   Puffer per padding-bottom wuerde die wartende zweite Zeile sichtbar
   machen. Die Luft fuer g, j, p muss deshalb aus der Zeilenhoehe kommen.
   -------------------------------------------------------------------------- */
[data-swap] {
  position: relative;
  display: inline-block;
  overflow: hidden;
  line-height: 1.45;
  vertical-align: bottom;
}

.swap { display: block; position: relative; }

.swap__a,
.swap__b {
  display: block;
  white-space: nowrap;
  transition: transform .5s var(--ease-smooth);
}
/* 104 % statt 100 %: bei krummen Zeilenhoehen bleibt sonst eine Haarlinie
   der wartenden Zeile am Rand stehen. */
.swap__b {
  position: absolute;
  inset: 0;
  transform: translateY(104%);
}

[data-swap]:hover .swap__a,
[data-swap]:focus-visible .swap__a { transform: translateY(-104%); }
[data-swap]:hover .swap__b,
[data-swap]:focus-visible .swap__b { transform: translateY(0); }

/* Ohne Bewegung bleibt nur der Farbwechsel, den die Links ohnehin haben. */
@media (prefers-reduced-motion: reduce) {
  .swap__a, .swap__b { transition: none; }
  [data-swap]:hover .swap__a,
  [data-swap]:focus-visible .swap__a { transform: none; }
  .swap__b { display: none; }
}

/* --------------------------------------------------------------------------
   Haltung: Wort fuer Wort

   Ein grosser Textblock wird ueberflogen, nicht gelesen. Deshalb starten
   alle Woerter gedimmt und leuchten beim Scrollen nacheinander auf. Das
   Auge folgt der Helligkeit und liest dadurch tatsaechlich mit.
   Ohne JavaScript steht der Text normal da.
   -------------------------------------------------------------------------- */
.js [data-stance] .word { opacity: .14; }
[data-stance] .word { display: inline-block; }
[data-stance] p + p { margin-top: .55em; }
[data-stance] .question .word { font-style: italic; }

@media (prefers-reduced-motion: reduce) {
  .js [data-stance] .word { opacity: 1 !important; }
}

/* --------------------------------------------------------------------------
   Unterschrift

   Sein SVG ist eine Outline-Nachzeichnung, keine Mittellinie. Ein echtes
   "wird geschrieben" braeuchte einen Pfad entlang des Stiftwegs. Der laesst
   sich aus einer Outline nicht zuverlaessig ableiten, und eine geratene
   Reihenfolge sieht falscher aus als gar keine.

   Deshalb ein Wisch entlang der Schreibrichtung: die Unterschrift steigt von
   links unten nach rechts oben, der Verlauf folgt diesem Winkel. Die weiche
   Kante laesst die Linie erscheinen, statt sie hart aufzudecken.
   -------------------------------------------------------------------------- */
.signature {
  width: 11.5em;
  height: auto;
  color: var(--color);
  opacity: .95;
}
@media (max-width: 991px) { .signature { width: 9.5em; } }

.js [data-sign] {
  -webkit-mask-image: linear-gradient(100deg, transparent 0 34%, #000 54% 100%);
          mask-image: linear-gradient(100deg, transparent 0 34%, #000 54% 100%);
  -webkit-mask-size: 260% 100%;
          mask-size: 260% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: 0% 0;
          mask-position: 0% 0;
}
.js [data-sign].is-signed {
  -webkit-mask-position: 100% 0;
          mask-position: 100% 0;
  transition: -webkit-mask-position 2.1s var(--ease-out-gentle);
  transition:         mask-position 2.1s var(--ease-out-gentle);
}

@media (prefers-reduced-motion: reduce) {
  .js [data-sign] { -webkit-mask-image: none; mask-image: none; }
}
