/* ============================================================
   VCI Design — Statement und grosser Kontakt-Link
   Direkt nach dem Hero, vor den Leistungen. Nur Startseite.

   Zwei Elemente, eine Sektion: das Statement setzt die Haltung,
   der Link ist die Konsequenz daraus. Getrennt waeren es zwei
   halbe Gedanken.

   Hier stand frueher, diese Sektion sei der Gegenpol zum Hero,
   weil der linksbuendig sei. Das stimmt nicht mehr: der Hero ist
   inzwischen ebenfalls zentriert, und sein Lead ist entfallen.

   Der Kontrast liegt jetzt woanders, und er traegt weiter:
   dunkle Flaeche gegen hellen Grund, ein gepinnter Zoom gegen
   voellige Ruhe, Eyebrow und Linie und Button gegen nichts als
   Text. Beide auf derselben Achse zu lesen, ist dabei kein
   Verlust, sondern haelt den Blick oben. Nach dem Zoom ist das
   die Atempause, bevor die Leistungen wieder Struktur aufbauen.
   ============================================================ */

.statement {
  /* --- Das Tempo der Sektion ------------------------------------
     Ein Faktor auf alle vier Takte: Satz, Farbe, Link, Linie. Die
     Dauern selbst kommen weiter aus den Tokens, hier steht nur,
     um wieviel sie in dieser Sektion gestreckt werden.

     Warum ueberhaupt: die Sektion ist die Atempause nach dem
     Hero-Zoom. Im Tempo der uebrigen Seite gelesen wirkte sie
     eilig, und der Satz ist der langsamste Moment der Startseite,
     nicht der schnellste.

     Hier drehen, wenn es schneller oder langsamer soll. 1 waere
     das Tempo des Rests der Seite. Gelesen wird der Wert von
     js/statement.js und von js/split-text.js, geschrieben steht
     er nur an dieser einen Stelle.
     -------------------------------------------------------------- */
  --statement-ruhe: 1.5;

  /* --- Die beiden Stellschrauben des Hovers ---------------------
     Hoehe des Abhebens, in em und nicht in Pixeln: der Link reicht
     von 59 bis 282px Schriftgrad, ein fester Wert waere oben ein
     Zucken und unten ein Sprung. Dieselbe Ueberlegung wie bei der
     Hoehe der Linie weiter unten.

     Ein Zehntel des Schriftgrads, also knapp das Dreifache der
     Linienstaerke darunter. Der Wert ist am Bild entschieden und
     nicht gerechnet: 0.08em waren als Abstand noch schwach
     abzulesen, ab 0.12em ruecken die Buchstaben dem Satz darueber
     auf die Pelle. Bei 1440px Fenster sind es 28 Pixel.

     Der Takt ist der zeitliche Abstand von Zeichen zu Zeichen.
     0.035s liegen in der Spanne, die auch js/split-text.js fuer
     seine wortweise Staffelung benutzt. Ueber neun Zeichen ergibt
     das 0,28s Vorlauf, zusammen mit --duration-short also rund
     0,53s fuer die ganze Welle.

     Der Rueckweg ist knapper als der Hinweg. Das Heben darf Zeit
     haben, das Zuruecksetzen soll der Maus nicht hinterherhinken.
     -------------------------------------------------------------- */
  --zeichen-hub: 0.1em;
  --zeichen-takt: 0.035s;
  --zeichen-rueckweg: 0.6;

  /* Grosszuegiger als der Standard-Sektionsabstand: die Sektion
     lebt vom Weissraum um sie herum, sonst klebt sie am Hero. */
  padding-block: var(--space-xxl);
  text-align: center;
}

.statement__inhalt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xl);
}

/* --- Statement ------------------------------------------------
   Groesse zwischen display-medium und display-large. Eine eigene
   clamp() statt eines Tokens, weil der Wert genau zwischen zwei
   Stufen der Skala liegt und nur hier gebraucht wird.

   max-width in ch statt in rem: begrenzt wird das Zeilenmass, und
   das haengt an der Zeichenbreite, nicht an der Fenstergroesse.
   Zusammen mit text-wrap: balance aus base.css ergibt das ruhige,
   etwa gleich lange Zeilen.
   ------------------------------------------------------------ */
.statement__text {
  /* Reicht das Tempo der Sektion an js/split-text.js weiter. Ohne
     diese Eigenschaft rechnet die Datei mit 1, so wie beim Hero. */
  --split-ruhe: var(--statement-ruhe);
  max-width: 22ch;
  font-size: clamp(2.5rem, 1.75rem + 3.25vw, 4.75rem);
  font-weight: var(--weight-regular);
  line-height: var(--leading-display);
  letter-spacing: var(--tracking-display);
}

/* --- Grosser Kontakt-Link -------------------------------------
   Fuellt fast die Containerbreite. Der Schriftgrad haengt deshalb
   an cqi, nicht an vw: gemeint ist ein Anteil des Containers, und
   der ist ab 1440px gedeckelt, waehrend das Fenster weiterwaechst.
   Mit vw liefe der Text ueber, sobald der Container nicht mehr
   mitwaechst. Dafuer traegt .statement__aktion container-type.

   Der Wert ist gemessen, nicht gerechnet, und er haengt an der
   Breite genau dieses Textes. Die Breite waechst linear mit dem
   Grad, die Laufweite steht in em, also genuegt eine Messung bei
   festem Grad: "Sie schon" ist in Playfair Black bei 100 Pixeln
   419,77 Pixel breit, in neun Kaesten gemessen. Daraus folgen
   20,96cqi, nachgemessen konstant von 320 bis 2560px Fenster und
   mit abgeschaltetem max-width, damit die Deckelung den Wert
   nicht verdeckt.

   Gefuellt werden bewusst 88 und nicht 95 Prozent. Der Text ist
   kein Ausruf mehr, sondern die Antwort auf den Satz darueber,
   und bei 95 Prozent nahm er dem Satz das Wort. 82 Prozent waren
   in der Gegenprobe schon zu zaghaft fuer den Weissraum ringsum.
   Am Bild entschieden, nicht am Zahlenwert.

   Gemessen wird am zerlegten Text, und das ist kein Detail: weil
   die Zeichen fuer den Hover einzeln in inline-blocks stehen,
   faellt die Unterschneidung zwischen ihnen weg. Hier kostet das
   fast nichts, 0,07 Pixel oder 0,02 Prozent. Bei "Abheben" waren
   es 0,52 Prozent. Verlassen sollte man sich darauf nicht, es
   haengt allein an den Buchstabenpaaren.

   Zur Geschichte, weil sie die Kopplung zeigt: "Abheben" stand
   zerlegt auf 24,12cqi bei 95 Prozent, "Weiterdenken" als ein
   Textlauf auf 15,43cqi. Der Platzhalter ganz am Anfang,
   "[Sag Hallo]", stand auf 19,5cqi, und mit dem laengeren Wort
   lief der Text ueber, bei 1280px Fenster um 195 Pixel.
   Kuerzerer Text heisst also groesserer Grad, nicht kleinerer.

   Die Obergrenze ist mit dem Text gewandert, von 20rem auf 18rem.
   Auf dem cqi-Weg greift sie nie: der breiteste Container misst
   1344 Pixel, das ergibt 281,7 Pixel Grad und damit 17,61rem.
   Gebraucht wird sie allein fuer die vw-Rueckfallebene, die mit
   dem Fenster weiterwaechst, waehrend der Container stehen
   bleibt. 18rem liegen knapp ueber dem cqi-Bedarf und schneiden
   dort deshalb nichts ab.

   ACHTUNG beim naechsten Textwechsel: neu messen, nicht schaetzen.
   Der Weg dahin ist eine Feinsuche auf die Zielfuellung, nicht
   eine Rechnung ueber die Zeichenzahl. Die negative Laufweite
   unten nimmt einem laengeren Text proportional mehr Breite als
   einem kurzen, deshalb geht die Rechnung nicht auf. Und die
   :nth-child-Zeilen weiter unten muessen zur Zeichenzahl passen.

   Die erste font-size ist die Rueckfallebene fuer Browser ohne
   Container-Queries, die zweite ueberschreibt sie ueberall sonst.
   Beide Werte gehoeren zusammen und wandern nur gemeinsam.
   ------------------------------------------------------------ */
.statement__aktion {
  width: 100%;
  container-type: inline-size;
}

.statement__link {
  display: block;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
  /* Eine Zeile, immer. Der Link ist eine Schlagzeile, kein Absatz. */
  white-space: nowrap;
  font-size: clamp(2.5rem, 18.6vw, 18rem);
  font-size: clamp(2.5rem, 20.96cqi, 18rem);
  font-weight: var(--weight-black);
  line-height: var(--leading-display);
  /* Bei diesem Grad laufen die Buchstaben sonst auseinander. */
  letter-spacing: -0.03em;
  text-decoration: none;
  color: var(--color-fg);
  transition: opacity var(--duration-short) var(--ease-base);
}

/* --- Hover: das Wort hebt von der Linie ab ---------------------
   Die cyanfarbene Linie darunter ist der Boden. Beim Ueberfahren
   loest sich das Wort davon, Buchstabe fuer Buchstabe von links
   nach rechts, und kommt geschlossen auf einer Hoehe zur Ruhe.
   Die Linie bleibt dabei vollkommen still. Nur deshalb ist der
   Abstand ueberhaupt als Abheben lesbar: bewegten sich beide,
   gaebe es kein Mass, gegen das man die Hoehe liest.

   Die Richtung ist nicht frei gewaehlt. Die Linie wird beim
   Einblenden von links nach rechts gezogen, siehe
   js/statement.js. Der Hover wiederholt diese Geste, statt eine
   zweite danebenzustellen.

   Warum ueberhaupt Buchstaben und nicht das ganze Wort am Stueck:
   gehoben wird so oder so. Erst die Staffelung macht daraus eine
   Bewegung mit Richtung und Dauer statt eines Versatzes. Am Ende
   stehen alle Buchstaben gleich hoch, ein gestaffelter
   Ruhezustand saehe nach schiefem Satz aus.

   Kein Ueberschwingen, bewusst. Ein Nachfedern gehoert zu einer
   Bewegung, die Schwung mitbringt, also zu Wischen und Werfen.
   Ein Zeiger, der ueber ein Wort faehrt, bringt keinen mit.
   Deshalb --ease-enter hin und --ease-exit zurueck: dieselbe
   Kurve, gespiegelt, damit Hin- und Rueckweg sich decken.

   Voraussetzungen der Regel, alle drei muessen gelten:
   feiner Zeiger, echtes Hover und volle Bewegung. Auf Touch
   bliebe ein :hover nach dem Tippen kleben, und bei reduzierter
   Bewegung hat sich hier nichts zu heben.
   --------------------------------------------------------------- */

/* inline-block ist die Voraussetzung fuer transform. Die Regel
   steht mit Absicht VOR jeder Media Query und ausserhalb von
   allen: einzelne inline-blocks verlieren die Unterschneidung
   zwischen den Buchstaben, und die Wortbreite haengt am
   cqi-Wert weiter oben. Sie muss in jedem Fall dieselbe sein,
   auch auf Touch und bei reduzierter Bewegung. */
.statement__zeichen {
  display: inline-block;
  /* Rueckfall, falls je ein Buchstabe ohne passende Regel unten
     dazukaeme: dann hebt er ohne Versatz mit, statt die ganze
     Staffelung ungueltig zu machen. */
  --zeichen-index: 0;
}

/* Die Platznummer je Zeichen, den Wortzwischenraum eingerechnet.
   Eine Zeile mehr, als der Text Zeichen hat, ist wirkungslos, eine
   zu wenig kostet dem letzten Zeichen seinen Versatz. Beim
   naechsten Textwechsel also mitzaehlen. Heute neun. */
.statement__zeichen:nth-child(1) { --zeichen-index: 0; }
.statement__zeichen:nth-child(2) { --zeichen-index: 1; }
.statement__zeichen:nth-child(3) { --zeichen-index: 2; }
.statement__zeichen:nth-child(4) { --zeichen-index: 3; }
.statement__zeichen:nth-child(5) { --zeichen-index: 4; }
.statement__zeichen:nth-child(6) { --zeichen-index: 5; }
.statement__zeichen:nth-child(7) { --zeichen-index: 6; }
.statement__zeichen:nth-child(8) { --zeichen-index: 7; }
.statement__zeichen:nth-child(9) { --zeichen-index: 8; }

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .statement__zeichen {
    transition: transform var(--duration-short) var(--ease-exit);
    /* Ruheweg. Wer zuerst gestiegen ist, setzt zuerst wieder auf:
       derselbe Laufsinn wie beim Heben, nur straffer. Genau diese
       Paarung haelt den Wechsel sauber, wenn jemand mitten in der
       Bewegung wieder herausfaehrt. Der Buchstabe, der schon oben
       ist, kommt dann sofort zurueck, und der, der noch gar nicht
       los ist, hat nichts zu tun. */
    transition-delay: calc(var(--zeichen-index) * var(--zeichen-takt) * var(--zeichen-rueckweg));
  }

  /* Tastatur bekommt dasselbe Bild wie die Maus. Der Fokus-Ring
     liegt aussen am Link, die Buchstaben bleiben auch gehoben
     innerhalb davon, nachgemessen. */
  .statement__link:hover .statement__zeichen,
  .statement__link:focus-visible .statement__zeichen {
    transform: translateY(calc(var(--zeichen-hub) * -1));
    transition-timing-function: var(--ease-enter);
    transition-delay: calc(var(--zeichen-index) * var(--zeichen-takt));
  }
}

/* --- Der Leuchtkreis am Zeiger --------------------------------
   Waehrend der Zeiger ueber dem Text laeuft, faerbt sich der Teil
   der Buchstaben in seiner Naehe in die Markenfarbe. Nur die
   Buchstaben, nie der Grund dazwischen: sichtbar wird der Kreis
   allein dort, wo Schrift steht.

   Gebaut als zweite, deckungsgleiche Lage ueber dem Text, die
   js/statement-leuchten.js anlegt und fuehrt. Sie traegt die
   Markenfarbe flaechig, und eine Maske schneidet aus ihr den
   Kreis um den Zeiger heraus. Die schwarze Schrift darunter
   bleibt unberuehrt, es wird nichts umgefaerbt, sondern etwas
   darueber sichtbar gemacht.

   Warum die Maske auf der Lage sitzt und nicht auf den einzelnen
   Zeichen: die Zeichen tragen im Hover ihren eigenen Versatz nach
   oben. Eine Maske je Zeichen wuerde mit dem Zeichen wandern, und
   der Kreis liefe beim Abheben mit nach oben davon. Die Lage
   selbst bewegt sich nicht, ihre Koordinaten bleiben deshalb
   stabil, und es ist ein Element zu fuehren statt neun.

   Die Lage entsteht im Skript und nicht im Markup. Ohne Zeiger
   gibt es nichts zu zeigen, und eine zweite Textkopie im Quelltext
   waere dann totes Gewicht. Faellt das Skript aus, fehlt genau
   dieser Effekt und sonst nichts.
   --------------------------------------------------------------- */
.statement__leuchten {
  position: absolute;
  inset: 0;
  /* Der Zeiger muss durch die Lage hindurchgreifen, sonst verloere
     der Link darunter sein Hover an die eigene Zutat. */
  pointer-events: none;
  color: var(--color-accent);

  /* --- Deckkraft: volle Marke, bewusste Ausnahme -------------
     tokens.css sagt zu --color-accent: "NIEMALS als Textfarbe".
     Hier steht sie deckend auf Buchstaben, ist also genau das.
     Die Ausnahme ist von Carl so entschieden und steht hier,
     damit sie niemand spaeter fuer ein Versehen haelt.

     Was sie kostet, der Vollstaendigkeit halber: die Buchstaben
     im Kreis liegen bei 1,50:1 gegen den Seitenhintergrund. Zum
     Vergleich die Zwischenstufen, gerechnet nach WCAG 2.1 ueber
     der schwarzen Schrift: 0,5 ergeben #057879 und 5,07:1, das
     waere der Kontrast von --color-accent-ink; 0,55 ergeben
     4,44:1 und damit den Bruch mit AA.

     Getragen wird die Entscheidung davon, dass der Kreis eine
     Zutat des Zeigers ist und nichts Ruhendes: der Text steht in
     jedem anderen Moment auf 18,97:1, betroffen ist nur die
     Stelle, auf die jemand gerade aktiv zeigt, und nur dort, wo
     ein feiner Zeiger und volle Bewegung zusammenkommen. Wer das
     zuruecknehmen will, dreht allein diesen Wert. */
  --leucht-deckkraft: 1;

  /* --- Groesse und Lage des Kreises --------------------------
     Der Radius steht in em und haengt damit am Schriftgrad, nicht
     am Fenster. 0.35em sind rund eine halbe Versalhoehe, der Kreis
     deckt also etwa einen bis anderthalb Buchstaben ab. Gross
     genug, um als Kreis lesbar zu sein, klein genug, um den Text
     nicht als Ganzes einzufaerben.

     Lage und Dehnung schreibt das Skript. Die Startwerte hier
     sorgen dafuer, dass die Maske auch vor dem ersten Frame
     gueltig ist; sichtbar wird davon nichts, --leucht-staerke
     steht auf 0. */
  --leucht-radius: 0.35em;
  --leucht-x: 50%;
  --leucht-y: 50%;
  --leucht-dehnung-x: 1;
  --leucht-dehnung-y: 1;
  --leucht-staerke: 0;

  opacity: calc(var(--leucht-deckkraft) * var(--leucht-staerke));

  /* --- Die Form: eine volle Scheibe --------------------------
     Hier standen zuvor Ringe, ein Kern mit abwechselnd duenneren
     und dichteren Baendern nach aussen. Jetzt ist es eine
     durchgehend gefuellte Flaeche.

     Die Werte sind Alpha der Maske, nicht Farbe. Voll bis 97
     Prozent, dann auf null. Die letzten drei Prozent sind keine
     weiche Kante, sondern die Rasterung: ein Sprung von 1 auf 0
     im selben Stopp laeuft als Treppe aus, weil der Verlauf nicht
     kantengeglaettet wird. Bei 282px Schriftgrad sind diese drei
     Prozent knapp drei Pixel, die Scheibe liest sich also als
     scharf begrenzt.

     Der aeusserste Stopp steht auf 0 und nicht auf einem kleinen
     Rest: sonst saesse um die Scheibe eine schwach gefaerbte
     Kante bis an den Rand der Lage. */
  mask-image: radial-gradient(
      calc(var(--leucht-radius) * var(--leucht-dehnung-x))
      calc(var(--leucht-radius) * var(--leucht-dehnung-y))
      at var(--leucht-x) var(--leucht-y),
      rgb(0 0 0 / 1) 0%,
      rgb(0 0 0 / 1) 97%,
      rgb(0 0 0 / 0) 100%);
  mask-repeat: no-repeat;
}

/* Die Zeichen der Leuchtlage tragen ihren Buchstaben im Attribut
   statt als Text, siehe js/statement-leuchten.js. Gezeichnet wird
   er hier. user-select zusaetzlich abgeschaltet: der Inhalt eines
   Pseudoelements ist ohnehin nicht markierbar, aber die Regel
   sagt es an der Stelle, an der jemand danach sucht. */
.statement__leuchten .statement__zeichen::before {
  content: attr(data-zeichen);
}

.statement__leuchten .statement__zeichen {
  user-select: none;
}

/* --- Rueckfall ohne Bewegung ----------------------------------
   Reduzierte Bewegung heisst nicht, dass der Zeiger keine Antwort
   bekommt, sondern dass die Antwort nicht durch den Raum laeuft.
   Deckkraft bleibt dafuer zulaessig, und es ist genau der
   Zustand, den der Link vorher hatte.
   --------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: reduce) {
  .statement__link:hover {
    opacity: 0.55;
  }
}

/* Die Antwort auf das Druecken, und auf Touch die einzige, die es
   gibt. Sie sitzt auf dem Link und nimmt die Linie mit: gemeint
   ist hier nicht das Abheben, sondern die Quittung. */
.statement__link:active {
  opacity: 0.55;
}

/* Der Fokus-Ring aus base.css liegt bei diesem Schriftgrad sehr
   eng am Text. Etwas mehr Abstand, damit er als Rahmen lesbar
   bleibt und nicht wie eine Unterstreichung wirkt. */
.statement__link:focus-visible {
  outline-offset: 0.15em;
}

/* --- Markenfarbe im Satz --------------------------------------
   Ein Wort, nicht mehr. "verdient" ist das Scharnier des Satzes,
   und ein einzelnes farbiges Wort liest sich als Entscheidung,
   waehrend zwei schon als Auszeichnung durchgehen.

   --color-accent-ink und nicht --color-accent: das reine Cyan
   erreicht auf dem Seitenhintergrund nur 1,50:1 und ist damit als
   Textfarbe ausgeschlossen. Die textfaehige Variante desselben
   Farbtons kommt auf 5,07:1.

   Die Farbe traegt keine Bedeutung, die der Satz ohne sie
   verloere. WCAG 1.4.1 ist damit nicht beruehrt, es ist Betonung
   und keine Information.

   Das span steht im Markup. Ohne JavaScript und bei reduzierter
   Bewegung ist die Farbe deshalb von der ersten Sekunde an da.
   ------------------------------------------------------------ */
.statement__akzent {
  color: var(--color-accent-ink);
  /* Der einzige Farbwechsel der Seite. Er ist ein Paint und kein
     Transform, also eine bewusste Ausnahme von der Projektregel,
     dieselbe Abwaegung wie bei den Hero-Ecken. Er betrifft ein
     Wort und laeuft genau einmal. */
  transition: color calc(var(--duration-long) * var(--statement-ruhe)) var(--ease-enter);
}

/* Die Wartestellung setzt js/statement.js und nimmt sie zurueck,
   sobald der Satz vollstaendig steht. Sie existiert nur, wenn
   auch jemand da ist, der sie wieder aufloest. */
.statement__text--akzent-wartet .statement__akzent {
  color: inherit;
}

/* --- Die Linie unter dem Wort ---------------------------------
   Der letzte Takt der Sektion: erst steigt der Satz auf, dann
   kommt der Link, dann zieht sich die Linie. Die Markenfarbe ist
   damit die Interpunktion der Sequenz und nicht ihr Schmuck.

   Reines Cyan ist hier richtig, denn es ist Grafik und kein Text.
   Die Regel setzt fort, was der Hero schon fuehrt: .hero__rule
   unter dem Eyebrow, 2px und in derselben Farbe. Aus der Mitte
   dieser Linie faellt ausserdem das Lot der Leistungen darunter,
   siehe css/leistungen.css. Wer die Linie verschiebt oder den
   Aussenabstand dieser Sektion aendert, prueft dort nach.

   Hoehe in em statt in Pixeln, weil der Link von 53 bis 208px
   Schriftgrad reicht. Eine feste 2px-Linie waere unter dem
   grossen Wort ein Haar und unter dem kleinen ein Balken.
   ------------------------------------------------------------ */
.statement__link {
  position: relative;
}

.statement__linie {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 0.035em;
  background-color: var(--color-accent);
  /* Ruhezustand ist die gezogene Linie. Den Startwert setzt allein
     js/statement.js, sonst bliebe sie ohne Skript unsichtbar. */
  transform-origin: left center;
}
