/* ------------------------------------------------------------------
   Aurasec, Bewegungsebene
   Liegt als eigene Datei ueber dem fertigen Build. Kein Build noetig.

   Grundsatz: Jede Animation braucht einen Zweck. Reine Zierde bei
   Elementen, die oft gesehen werden, ist weggelassen.
   ------------------------------------------------------------------ */

:root{
  /* Kraeftige Kurven. Die eingebauten CSS-Easings sind zu schwach. */
  --as-ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --as-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* Tailwinds Standardeasing war cubic-bezier(.4,0,.2,1).
     Diese Variable speist alle 58 bestehenden Uebergaenge der Seite,
     eine Zeile wertet sie also samt Navigation und Links mit auf. */
  --default-transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
}

/* ------------------------------------------------------------------
   1. "transition: all" eingrenzen
   17 Elemente animierten pauschal alles, auch Layout-Eigenschaften.
   Das erzwingt Layout und Paint statt nur Compositing.
   ------------------------------------------------------------------ */
.transition-all{
  transition-property: color, background-color, border-color, box-shadow,
                       transform, opacity, filter;
}

/* ------------------------------------------------------------------
   2. Druckfeedback auf Schaltflaechen
   Zweck: Rueckmeldung. Die Oberflaeche bestaetigt, dass sie den
   Klick gehoert hat. Alle Handlungsaufrufe sind echte <button>.
   ------------------------------------------------------------------ */
/* Eine Dauer fuer alle Eigenschaften. Getrennte Listen fuer Eigenschaft
   und Dauer rotieren sonst gegeneinander, sobald .transition-all mit
   hoeherer Spezifitaet mehr Eigenschaften beisteuert als hier Dauern
   stehen. 150 ms liegt im Band fuer Druckfeedback. */
button{
  transition-property: color, background-color, border-color, box-shadow,
                       transform, opacity, filter;
  transition-duration: 150ms;
  transition-timing-function: var(--as-ease-out);
}
button:active{ transform: scale(0.97); }

/* Navigationsknoepfe im Kopf sind reine Textlinks, dort waere
   Skalieren zu viel. Nur Farbe, wie gehabt. */
header button:active,
[class*="fixed top-0"] button:active{ transform: none; }
[class*="fixed top-0"] button[class*="bg-[#c9a84c]"]:active{ transform: scale(0.97); }

/* ------------------------------------------------------------------
   3. Karten
   Zweck: Affordanz. 13 Leistungskarten, dezentes Anheben zeigt,
   dass sie zusammengehoerige Einheiten sind.
   Nur auf Geraeten mit echtem Zeiger, sonst loest Tippen es aus.
   ------------------------------------------------------------------ */
@media (hover: hover) and (pointer: fine){
  .rounded-xl[class*="bg-card"]{
    transition: transform 200ms var(--as-ease-out),
                box-shadow 200ms var(--as-ease-out),
                border-color 200ms var(--as-ease-out);
    will-change: transform;
  }
  .rounded-xl[class*="bg-card"]:hover{
    transform: translateY(-3px);
  }
}

/* ------------------------------------------------------------------
   4. Kopfleiste schrumpft beim Scrollen
   Zweck: funktional, nicht dekorativ. Die Leiste ist 152 px hoch und
   nimmt auf einem Notebook rund ein Viertel der Hoehe weg. Beim
   Scrollen gibt sie 52 px zurueck.
   Bewegung auf dem Bildschirm, also ease-in-out.
   Die Hoehen stehen als Inline-Stil im Build, daher !important.
   ------------------------------------------------------------------ */
[data-as-kopf]{
  transition: height 260ms var(--as-ease-in-out);
}
[data-as-kopf] img{
  transition: width 260ms var(--as-ease-in-out),
              height 260ms var(--as-ease-in-out);
}
[data-as-kopf] > div:last-child,
[data-as-kopf] [class*="text-xl"],
[data-as-kopf] p{
  transition: font-size 260ms var(--as-ease-in-out),
              opacity 200ms var(--as-ease-out),
              height 260ms var(--as-ease-in-out),
              margin 260ms var(--as-ease-in-out);
}

[data-as-kopf][data-as-geschrumpft="true"]{ height: 6.25rem !important; }
[data-as-kopf][data-as-geschrumpft="true"] img{
  width: 7.5rem !important;
  height: 4.1rem !important;
}
[data-as-kopf][data-as-geschrumpft="true"] p{
  opacity: 0;
  /* Nicht nur unsichtbar, sondern auch ohne Platzbedarf. Sonst behaelt die
     Beschriftung ihre 14 px und der groessere Adler laeuft oben und unten
     aus der Leiste heraus. Gemessen: 105 px Inhalt in 96 px Leiste. */
  height: 0;
  margin: 0;
  overflow: hidden;
}

/* ------------------------------------------------------------------
   5. Abschnitte beim Hereinscrollen
   Zweck: Rhythmus auf einer 6900 px langen Seite. Inhalte sollen
   nicht schlagartig da sein, sondern beim Erreichen ankommen.
   Einmalig, nicht bei jedem Scrollen erneut.

   Wichtig: Die Startwerte setzt erst das Skript ueber [data-as-reveal].
   Ohne JavaScript bleibt alles sichtbar, nichts geht verloren.
   ------------------------------------------------------------------ */
[data-as-reveal]{
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 520ms var(--as-ease-out),
              transform 520ms var(--as-ease-out);
}
[data-as-reveal][data-as-sichtbar="true"]{
  opacity: 1;
  transform: none;
}

/* Bei einem grossen Sprung ueber die Navigation soll der Zielabschnitt
   sofort dastehen, ohne Einblenden. Setzt das Skript fuer einen Frame. */
[data-as-sofort] [data-as-reveal]{
  transition: none !important;
  transition-delay: 0ms !important;
}

/* Karten innerhalb eines Abschnitts gestaffelt, 55 ms Abstand.
   Kurz halten, lange Staffeln lassen die Seite traege wirken. */
[data-as-reveal] .rounded-xl[class*="bg-card"]{
  transition-delay: 0ms;
}
[data-as-stagger] > *:nth-child(1){ transition-delay: 0ms; }
[data-as-stagger] > *:nth-child(2){ transition-delay: 55ms; }
[data-as-stagger] > *:nth-child(3){ transition-delay: 110ms; }
[data-as-stagger] > *:nth-child(4){ transition-delay: 165ms; }
[data-as-stagger] > *:nth-child(5){ transition-delay: 220ms; }
[data-as-stagger] > *:nth-child(6){ transition-delay: 275ms; }

/* ------------------------------------------------------------------
   6. Formularfelder
   Zweck: Rueckmeldung, wo der Fokus sitzt.
   ------------------------------------------------------------------ */
input, select, textarea{
  transition: border-color 150ms var(--as-ease-out),
              box-shadow 150ms var(--as-ease-out);
}

/* ------------------------------------------------------------------
   7. Reduzierte Bewegung
   Weniger und sanfter, nicht null. Deckkraft bleibt, weil sie beim
   Verstehen hilft. Jede Ortsveraenderung faellt weg.
   ------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce){
  [data-as-reveal]{
    transform: none;
    transition: opacity 240ms ease;
  }
  [data-as-reveal][data-as-sichtbar="true"]{ transform: none; }
  [data-as-stagger] > *{ transition-delay: 0ms !important; }

  button:active{ transform: none; }

  @media (hover: hover) and (pointer: fine){
    .rounded-xl[class*="bg-card"]:hover{ transform: none; }
  }

  [data-as-kopf],
  [data-as-kopf] img,
  [data-as-kopf] p{ transition: none; }
}

/* ------------------------------------------------------------------
   4b. Das Logo ist ueberall anklickbar und fuehrt zur Startseite
   Betrifft alle Vorkommen: Kopfleiste, Abzeichen unter "Ueber uns",
   Fussbereich und Impressum-Kopf. Das Attribut setzt das Fix-Skript.
   Der Zeiger ist reine Kosmetik. Faellt dieses Stylesheet aus, bleibt
   der Klick trotzdem bedienbar, das Verhalten haengt am Fix-Skript.
   ------------------------------------------------------------------ */
[data-as-logo]{ cursor: pointer; }
[data-as-logo]:focus-visible{
  outline: 2px solid #c9a84c;
  outline-offset: 4px;
  border-radius: 4px;
}

/* ------------------------------------------------------------------
   5. Kennzahlen als Laufband

   Die Leiste unter dem Hero wird nach dem Hochzaehlen zu einem endlos
   laufenden Band. Die Spur enthaelt den Satz zweimal hintereinander,
   deshalb ist die Schleife bei genau -50 Prozent nahtlos.

   Umgebaut wird nur, wenn das Steuerskript laeuft. Faellt es aus,
   bleibt das urspruengliche Raster stehen und alles ist lesbar.

   Das display muss "!important" tragen, weil Tailwind auf demselben
   Element "grid" setzt.
   ------------------------------------------------------------------ */
[data-as-band]{
  display: block !important;
  overflow: hidden;
  /* Ein- und Ausblenden an den Raendern, damit nichts hart abreisst */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
}

[data-as-spur]{
  display: flex;
  width: max-content;
  animation: as-band 34s linear infinite;
  will-change: transform;
}

[data-as-spur] > *{
  flex: 0 0 auto;
  padding: 0 2.75rem;
}

/* Anhalten, solange jemand mit dem Zeiger draufbleibt oder per Tastatur
   hineinnavigiert. Wer lesen will, soll lesen koennen. */
[data-as-band]:hover [data-as-spur],
[data-as-band]:focus-within [data-as-spur]{
  animation-play-state: paused;
}

@keyframes as-band{
  from{ transform: translate3d(0, 0, 0); }
  to  { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce){
  [data-as-spur]{ animation: none; }
}

/* ------------------------------------------------------------------
   5b. Fluegelschlag des Adlers beim Aufruf

   Zweck: Aufmerksamkeit in der ersten Sekunde, einmalig. Kein Kreisen,
   kein Pulsieren, kein Dauerlaeufer. Nach dem letzten Schlag nimmt das
   Steuerskript das Attribut wieder ab, danach ist es ein gewoehnliches
   Bild.

   Die Bewegung: die Fluegel schwingen kraeftig nach vorn, dann nach
   hinten, dann steht der Adler still. Der Schwanz faechert dabei mit,
   und zum Schluss wendet der Kopf kurz zur Kamera.

   ---- Aufbau, fuenf Ebenen ohne ein einziges neues Element ----

   Ein Element in den Aufbau der App einzuhaengen waere riskant, die App
   entfernt es beim naechsten Zeichnen moeglicherweise wieder. Deshalb
   ausschliesslich Pseudo-Elemente, die stehen nicht im DOM. Zwei gibt es
   pro Element, gebraucht werden vier, also liefert der Wortmarken-Block
   darunter die beiden weiteren.

     Fluegel links   Logo-Block ::before
     Fluegel rechts  Logo-Block ::after
     Rumpf           das Originalbild selbst, beschnitten
     Schwanz         Wortmarken-Block ::before
     Kopf            Wortmarken-Block ::after

   ---- Schnitte, alle aus dem Alphakanal gemessen ----

   Bild 352 x 192. Geschnitten wird jeweils an der schmalsten Stelle,
   dort haengt am wenigsten Material zusammen:

     Fluegel   x = 136 und 216, also 38.6 % und 61.4 %
               Verbindung dort nur 12 px hoch
     Hals      y = 68, also 35.4 %
               Deckung im Mittelband 28 px statt 81 px
     Schwanz   y = 138, also 71.9 %
               Deckung 39 px statt 73 px

   ---- Warum nach vorn und nicht hoch und runter ----

   Die Fluegel drehen um die senkrechte Achse durch die Schulter, und
   diese Achse IST die Schnittkante. Punkte auf der Drehachse bewegen
   sich nicht, deshalb kann sich die Naht nicht oeffnen, auch bei 72 Grad
   nicht. Beim Heben und Senken wandert die Kante mit, dort rissen im
   Versuch bei grossen Winkeln Splitter auf.

   Der Kopf bleibt still. Er war im zehnten Durchgang bewegt und wendete
   sich zum Schluss zur Kamera; das ist raus. Seine Ebene bleibt bestehen,
   weil sie den Kopf ueberhaupt erst zeichnet.

   ---- Warum 8500 ms ----

   Der zehnte Durchgang lief in 1700 ms. Das war als Blickfang in der
   ersten Sekunde gedacht und schlug dafuer zu hart zu: bei dieser Dauer
   liest sich der Ausschlag von 72 Grad als Zucken. Fuenfmal so lang
   gedehnt wird aus demselben Weg ein getragener Zug. Die Winkel und die
   Kurven sind unveraendert, allein die Dauer ist eine andere.

   Das hat zwei Folgen im Steuerskript, beide dort behandelt: das
   Aufraeumen darf nicht mehr am Ende der Kopfwendung haengen, und das
   Sicherheitsnetz von vier Sekunden lag mitten im Schlag.

   Groesse und Lage der Ebenen kommen aus Werten, die das Steuerskript
   misst und bei jedem Bild nachfuehrt. Fest eingetragene Werte waeren
   falsch, sobald die Kopfleiste beim Scrollen von 152 auf 100 px
   schrumpft.

   background-size ist "contain", nicht "100% 100%": das Bild traegt
   object-fit contain und wird bei 192 x 104 seitlich um 0.67 px
   eingerueckt. Gestreckt waeren die Ebenen um 0.7 Prozent zu breit, und
   an den Schnitten stuende eine Haarlinie.
   ------------------------------------------------------------------ */
[data-as-schwingen]{ position: relative; }

/* Rumpf: das Originalbild, beschnitten auf die Mitte zwischen Hals und
   Schwanzansatz. Ueber den Fluegeln, unter Kopf und Schwanz. */
[data-as-schwingen] > img{
  position: relative;
  z-index: 2;
  clip-path: inset(35.4% 38.6% 28.1% 38.6%);
}

/* Die vier bewegten Ebenen, deckungsgleich ueber dem Bild. */
[data-as-schwingen]::before,
[data-as-schwingen]::after,
[data-as-schwingen] > div:last-child::before,
[data-as-schwingen] > div:last-child::after{
  content: "";
  position: absolute;
  top: var(--as-adler-o, 0px);
  left: 50%;
  width: var(--as-adler-b, 12rem);
  height: var(--as-adler-h, 6.5rem);
  margin-left: calc(var(--as-adler-b, 12rem) / -2);
  background: url(/bilder/aurasec-adler.png) no-repeat center / contain;
  pointer-events: none;
  backface-visibility: hidden;
  z-index: 1;
}

[data-as-schwingen]::before{
  clip-path: inset(0 61.4% 0 0);
  transform-origin: 38.6% 52%;
  animation: as-fluegel-links 8500ms both;
}
[data-as-schwingen]::after{
  clip-path: inset(0 0 0 61.4%);
  transform-origin: 61.4% 52%;
  animation: as-fluegel-rechts 8500ms both;
}
[data-as-schwingen] > div:last-child::before{
  clip-path: inset(71.9% 38.6% 0 38.6%);
  transform-origin: 50% 71.9%;
  z-index: 3;
  animation: as-schwanz 8500ms both;
}

/* Der Kopf bewegt sich nicht. Die Ebene bleibt trotzdem stehen, denn der
   Rumpf ist oben bei 35,4 Prozent beschnitten: alles darüber zeichnet
   allein diese Ebene. Wer sie entfernt, nimmt dem Adler den Kopf. */
[data-as-schwingen] > div:last-child::after{
  clip-path: inset(0 38.6% 63% 38.6%);
  transform-origin: 49% 35.4%;
  z-index: 4;
}

/* Vorn schnell, zurueck gelassener, kurzes Ausschwingen, dann still.
   Die Kurve steht in den Keyframes selbst, damit jeder Abschnitt sein
   eigenes Tempo hat. Eine Kurve fuer die ganze Animation wuerde den
   Rhythmus des Schlags glattbuegeln. */
/* ---- Warum 900 px Perspektive und nicht 520 ----

   Bei 520 px ragten die Fluegel oben aus der Kopfleiste heraus und wurden
   vom Bildschirmrand gekappt. Gemessen: 8 px Ueberstand, verfuegbar sind
   5 (das Bild sitzt 4 px unter der Leistenkante, darin 1 px Luft bis zum
   ersten goldenen Pixel).

   Die Ursache ist nicht der Winkel, sondern die Vergroesserung durch die
   Perspektive. Ein Fluegel kommt beim Schwung rund 70 px nach vorn, das
   vergroessert die vordere Kante um 520/(520-70) = 1,156. Die Ebene ragt
   54 px ueber ihren Drehpunkt hinaus, mal 1,156 sind 62 px, also 8 mehr.

   Bei 900 px sind es 900/(900-70) = 1,084, macht 4 px Ueberstand. Passt
   mit 1 px Reserve. Die Verkuerzung der Fluegel bleibt dabei fast gleich:
   engste Spannweite 91 statt 95 px, bei 187 px in Ruhe. Der Charakter der
   Bewegung aendert sich also nicht, nur das Herauswachsen.

   Bei einer Aenderung der Bildgroesse oder der Leistenhoehe neu messen,
   die 5 px Spielraum sind kein Naturgesetz. ---- */
@keyframes as-fluegel-links{
  0%   { transform: perspective(900px) rotateY(0deg);   animation-timing-function: cubic-bezier(0.28, 0, 0.32, 1); }
  28%  { transform: perspective(900px) rotateY(72deg);  animation-timing-function: cubic-bezier(0.42, 0, 0.38, 1); }
  62%  { transform: perspective(900px) rotateY(-50deg); animation-timing-function: cubic-bezier(0.4, 0, 0.5, 1); }
  86%  { transform: perspective(900px) rotateY(12deg);  animation-timing-function: ease-out; }
  100% { transform: perspective(900px) rotateY(0deg); }
}
@keyframes as-fluegel-rechts{
  0%   { transform: perspective(900px) rotateY(0deg);    animation-timing-function: cubic-bezier(0.28, 0, 0.32, 1); }
  28%  { transform: perspective(900px) rotateY(-72deg);  animation-timing-function: cubic-bezier(0.42, 0, 0.38, 1); }
  62%  { transform: perspective(900px) rotateY(50deg);   animation-timing-function: cubic-bezier(0.4, 0, 0.5, 1); }
  86%  { transform: perspective(900px) rotateY(-12deg);  animation-timing-function: ease-out; }
  100% { transform: perspective(900px) rotateY(0deg); }
}

/* Der Schwanz faechert beim Vorschwung auf und legt sich beim
   Rueckschwung zusammen. scaleX ist das Auffaechern, rotateX das
   Kippen in die Tiefe. */
@keyframes as-schwanz{
  0%   { transform: perspective(420px) scaleX(1)    rotateX(0deg);   animation-timing-function: cubic-bezier(0.28, 0, 0.32, 1); }
  28%  { transform: perspective(420px) scaleX(1.16) rotateX(-13deg); animation-timing-function: cubic-bezier(0.42, 0, 0.38, 1); }
  62%  { transform: perspective(420px) scaleX(0.92) rotateX(9deg);   animation-timing-function: cubic-bezier(0.4, 0, 0.5, 1); }
  86%  { transform: perspective(420px) scaleX(1.05) rotateX(-4deg);  animation-timing-function: ease-out; }
  100% { transform: perspective(420px) scaleX(1)    rotateX(0deg); }
}

/* Eine Kopfwendung gab es im zehnten Durchgang, sie ist auf Wunsch raus.
   Der Kopf bleibt still, die Keyframes dafuer sind entfernt statt nur
   abgehaengt: ungenutzte Regeln laden sonst jeder Besucher mit. Wer sie
   zurueckholen will, findet den Stand in _upload-backup-vor-elftem/. */

/* Ohne Bewegung kein Schlag. Das Skript setzt das Attribut dann schon
   nicht, diese Regeln sind der zweite Riegel, falls es doch dazu kommt.
   Wichtig: auch der Beschnitt muss weg, sonst fehlte der Adler in
   Teilen. */
@media (prefers-reduced-motion: reduce){
  [data-as-schwingen] > img{ clip-path: none; }
  [data-as-schwingen]::before,
  [data-as-schwingen]::after,
  [data-as-schwingen] > div:last-child::before,
  [data-as-schwingen] > div:last-child::after{ content: none; }
}

/* ------------------------------------------------------------------
   6. Standanzeige in der Kopfleiste

   Zweck: Orientierung. Auf einer Seite von rund 6900 px zeigt das Menue,
   in welchem Abschnitt man gerade liest.

   Die Farbe kommt ausschliesslich von hier, nicht mehr aus der App. Die
   App setzt ihren goldenen Stand nur beim Klick und behaelt ihn beim
   Weiterscrollen, deshalb wird er mit "!important" ueberschrieben. Sonst
   leuchteten zwei Punkte: der angeklickte und der erreichte.

   Das Attribut setzt das Steuerskript. Faellt es aus, bleibt der Stand
   der App sichtbar, also das Verhalten von vorher.

   Kein Uebergang noetig: die Regel fuer button traegt bereits 150 ms auf
   der Farbe. Reduzierte Bewegung ist nicht betroffen, ein Farbwechsel
   bewegt nichts.
   ------------------------------------------------------------------ */
[data-as-nav]{ color: rgba(255, 255, 255, 0.8) !important; }

@media (hover: hover) and (pointer: fine){
  [data-as-nav]:hover{ color: #ffffff !important; }
}

/* Zuletzt, damit der Stand den Zeigerzustand schlaegt. Beide Regeln haben
   dieselbe Spezifitaet, hier entscheidet die Reihenfolge. */
[data-as-nav][data-as-stand="true"],
[data-as-nav][data-as-stand="true"]:hover{ color: #c9a84c !important; }

[data-as-nav]:focus-visible{
  outline: 2px solid #c9a84c;
  outline-offset: 4px;
  border-radius: 4px;
}

/* Strich unter dem erreichten Punkt.
   Zweck: der Stand ist auf einen Blick lesbar, ohne zwei Goldtoene
   vergleichen zu muessen. Farbe allein trennt schwach, Farbe und Form
   zusammen tragen die Aussage auch bei schlechtem Bildschirmwinkel und
   bei Rot-Gruen-Schwaeche.

   Nur ab 768 px, dort zeigt die App das waagerechte Menue. Darunter ist
   es eine aufgeklappte Liste, ein Strich ueber die ganze Zeilenbreite
   waere dort ein Trennstrich, kein Hinweis.

   Der Balken liegt immer im Aufbau und wird nur in der Breite geschaltet.
   Ein Balken, der erst beim Wechsel entsteht, verschiebt sonst das Menue.
   Aus der Mitte heraus, nicht von links: beim Zurueckscrollen wandert der
   Stand nach oben, eine Richtung waere dann die falsche. */
@media (min-width: 768px){
  [data-as-nav]{ position: relative; }

  [data-as-nav]::after{
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -0.5rem;
    height: 2px;
    border-radius: 1px;
    background: #c9a84c;
    transform: scaleX(0);
    transform-origin: center;
    transition: transform 260ms var(--as-ease-out);
    pointer-events: none;
  }

  [data-as-nav][data-as-stand="true"]::after{ transform: scaleX(1); }

  /* Der Zeiger bekommt bewusst keinen angedeuteten Strich. Ein halber
     Balken unter dem Punkt, auf dem die Maus liegt, liest sich wie ein
     zweiter Stand. Im ersten Entwurf war er drin und hat beim Nachsehen
     genau das getan. Fuer den Zeiger genuegt der Wechsel auf Weiss. */

  /* Ohne Bewegung erscheint der Strich schlicht, statt zu wachsen. */
  @media (prefers-reduced-motion: reduce){
    [data-as-nav]::after{
      transition: opacity 200ms ease;
      transform: scaleX(1);
      opacity: 0;
    }
    [data-as-nav][data-as-stand="true"]::after{ opacity: 1; }
  }
}
