/* ==========================================================================
   Bewegung & Micro-Interactions
   Wird in inc/header.php und admin/_head.php eingebunden.

   Regeln:
     - animiert wird ausschliesslich transform / opacity / box-shadow /
       border-color  (laeuft im Compositor, kein Layout-Reflow)
     - Entrance-Animationen laufen nur, wenn <html class="motion-ready">
       gesetzt ist. Das macht motion.js. Ohne JS ist alles sofort sichtbar.
     - ganz unten steht der prefers-reduced-motion-Block.
   ========================================================================== */

:root{
  --e-bounce: cubic-bezier(.34, 1.56, .64, 1);   /* federt ~6 % ueber das Ziel */
  --e-out:    cubic-bezier(.22, 1, .36, 1);      /* schnell raus, weich rein */
  --t-fast:   .14s;
  --t-mid:    .28s;
}

/* --------------------------------------------------------------------------
   0) Hintergrundschleier
   Gehoert zu body::before in inc/header.php. Sehr langsam, damit eine
   dauerhaft laufende Animation nicht staendig Rechenzeit zieht.
   -------------------------------------------------------------------------- */

@keyframes mo-drift{
  from{ transform: translate3d(-2%, -1%, 0) scale(1.04) }
  to  { transform: translate3d( 2%,  1%, 0) scale(1.10) }
}

/* Wanderndes Glanzlicht auf Kanten und Flaechen. */
@keyframes mo-sheen{
  from{ transform: translateX(-130%) }
  to  { transform: translateX( 130%) }
}

/* Ruhiges Pulsieren, benutzt vom Farbring hinter dem Logo (index.php). */
@keyframes mo-breathe{
  from{ transform: translateY(-50%) scale(.94); opacity:.75 }
  to  { transform: translateY(-50%) scale(1.08); opacity:1 }
}

/* --------------------------------------------------------------------------
   1) Micro-Interactions
   -------------------------------------------------------------------------- */

/* Kacheln auf der Startseite - anklickbar, darf am deutlichsten reagieren */
.tile{
  position: relative;
  overflow: hidden;
  transition: transform var(--t-mid) var(--e-bounce),
              border-color var(--t-fast) ease,
              box-shadow var(--t-mid) var(--e-out);
}
.tile:hover,
.tile:focus-visible{
  transform: translateY(-6px) scale(1.02);
  border-color: transparent;
  box-shadow: var(--elev, 0 18px 44px rgba(0,0,0,.5)),
              0 0 0 1px rgba(106,166,255,.45),
              0 0 26px -6px rgba(106,166,255,.5);
}
.tile:active{
  transform: translateY(-2px) scale(.985);
  transition: transform var(--t-fast) linear;   /* Druck ohne Nachfedern */
}

/* Glanzlicht, das beim Ueberfahren einmal quer ueber die Kachel laeuft.
   Liegt ueber der Kachel, faengt aber keine Klicks ab. */
.tile::after{
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 45%;
  pointer-events: none;
  background: linear-gradient(100deg, transparent,
              rgba(255,255,255,.09) 45%, transparent);
  transform: translateX(-130%);
}
.motion-ready .tile:hover::after,
.motion-ready .tile:focus-visible::after{
  animation: mo-sheen .85s var(--e-out);
}

/* Das Symbol bekommt beim Ueberfahren einen eigenen Takt. */
.tile .ico{
  display: inline-block;
  transition: transform var(--t-mid) var(--e-bounce);
}
.tile:hover .ico,
.tile:focus-visible .ico{
  transform: translateY(-3px) rotate(-7deg) scale(1.16);
}

/* Karten und Statistik-Felder sind nicht anklickbar -> nur dezent anheben */
.card,
.stat{
  transition: transform var(--t-mid) var(--e-out),
              border-color var(--t-fast) ease,
              box-shadow var(--t-mid) var(--e-out);
}
.card:hover,
.stat:hover{
  transform: translateY(-3px);
  border-color: rgba(106,166,255,.30);
  box-shadow: 0 14px 32px rgba(0,0,0,.42);
}

/* Schaltflaechen */
.btn{
  transition: transform var(--t-mid) var(--e-bounce),
              border-color var(--t-fast) ease,
              box-shadow var(--t-mid) var(--e-out);
}
.btn:hover,
.btn:focus-visible{
  transform: translateY(-2px) scale(1.03);
}
.btn:active{
  transform: translateY(0) scale(.97);
  transition: transform var(--t-fast) linear;
}
/* die Hauptaktion leuchtet zusaetzlich auf */
.btn.pri:hover,
.btn.pri:focus-visible,
.btn.primary:hover,
.btn.primary:focus-visible{
  box-shadow: 0 8px 26px rgba(106,166,255,.45),
              0 0 0 1px rgba(106,166,255,.35);
}

/* Kleine Bedienelemente der Werkzeugseiten: Segmentschalter, Reiter,
   Voreinstellungs-Plaettchen, Animationsauswahl. Definiert sind die Klassen
   in den jeweiligen Seiten, die Druckbestaetigung steht hier, damit sie
   ueberall gleich ausfaellt.

   Absichtlich knapp: diese Knoepfe werden waehrend einer Sitzung dutzendfach
   gedrueckt. Deshalb --e-out statt --e-bounce - Nachfedern bei jedem Klick
   liest sich als Verzoegerung. Und nur der Druck, kein Hover-Effekt: die
   Dinger sitzen dicht an dicht, da wandert die Maus staendig drueber.

   button.chip und nicht .chip: im Preflight-Bericht des PDF-Werkzeugs ist
   .chip ein <span>-Etikett, kein Bedienelement. */
.seg button,
.anims button,
.tabs button,
button.chip{
  transition: transform var(--t-fast) var(--e-out);
}
.seg button:active,
.anims button:active,
.tabs button:active,
button.chip:active{
  transform: scale(.97);
  transition: transform var(--t-fast) linear;
}

/* --------------------------------------------------------------------------
   2) Gestaffelter Auftritt
   Container bekommt class="stagger", die direkten Kinder laufen versetzt ein.
   Ab dem 13. Kind ohne Verzoegerung, damit lange Listen nicht ewig brauchen.
   -------------------------------------------------------------------------- */

@keyframes mo-fade-up{
  from{ opacity:0; transform: translateY(14px) }
  to  { opacity:1; transform: none }
}

.motion-ready .stagger > *{
  animation: mo-fade-up .5s var(--e-out) both;
}

.motion-ready .stagger > :nth-child(1){ animation-delay:  0ms }
.motion-ready .stagger > :nth-child(2){ animation-delay: 40ms }
.motion-ready .stagger > :nth-child(3){ animation-delay: 80ms }
.motion-ready .stagger > :nth-child(4){ animation-delay:120ms }
.motion-ready .stagger > :nth-child(5){ animation-delay:160ms }
.motion-ready .stagger > :nth-child(6){ animation-delay:200ms }
.motion-ready .stagger > :nth-child(7){ animation-delay:240ms }
.motion-ready .stagger > :nth-child(8){ animation-delay:280ms }
.motion-ready .stagger > :nth-child(9){ animation-delay:320ms }
.motion-ready .stagger > :nth-child(10){ animation-delay:360ms }
.motion-ready .stagger > :nth-child(11){ animation-delay:400ms }
.motion-ready .stagger > :nth-child(12){ animation-delay:440ms }

/* Waehrend der Einblendung nicht gleichzeitig hovern lassen - sonst kaempfen
   Animation und Transition um dieselbe transform-Eigenschaft. */
.motion-ready .stagger > *:hover{ animation-play-state: running }

/* Menue-Kategorien in der Seitenleiste.
   Die Hoehe schiebt motion.js (Motion.disclosure), hier steht nur, was die
   CSS allein nicht hinbekommt: der Pfeil muss beim Zuklappen sofort
   zurueckdrehen. Die vorhandene Regel in inc/header.php haengt an [open],
   und open faellt erst, wenn die Animation durch ist. */
.sb-cat.mo-closing > summary .sb-arrow{ transform: none; opacity: .6 }

/* Kurze Rueckmeldung auf ein Ereignis - angenommen bzw. abgelehnt.
   Ohne fill-mode: das Element steht danach wieder auf seinem Normalwert und
   spaetere :hover-Transitions bleiben unbehelligt. */

@keyframes mo-took{                  /* angenommen: einmal kurz atmen */
  0%, 100%{ transform: none }
  45%     { transform: scale(1.015) }
}

@keyframes mo-nope{                  /* abgelehnt: Kopfschuetteln */
  20%{ transform: translateX(-5px) }
  40%{ transform: translateX( 5px) }
  60%{ transform: translateX(-3px) }
  80%{ transform: translateX( 3px) }
}

.motion-ready .mo-took{ animation: mo-took .26s var(--e-out) }
.motion-ready .mo-nope{ animation: mo-nope .34s var(--e-out) }

/* Auftritt fuer Elemente, die erst zur Laufzeit entstehen.
   Wird von motion.js (Motion.enter) gesetzt, Verzoegerung kommt inline.
   Warum nicht .stagger: die Regel oben zaehlt per nth-child und hoert bei 12
   auf - Ergebnisgitter koennen aber Hunderte Kacheln haben. */
.motion-ready .mo-in{
  animation: mo-fade-up .34s var(--e-out) both;
}

/* Dialoge (<dialog> mit showModal).
   Kein fill-mode: der Endzustand ist ohnehin der Normalzustand. So bleibt
   nach der Animation kein Wert am Element haengen.

   Der Dialog bleibt mittig und waechst nicht aus dem ausloesenden Knopf -
   ein modaler Dialog gehoert der ganzen Seite, nicht der Stelle, an der
   er angefordert wurde.

   Nur der Auftritt. Fuers Schliessen muesste close() verzoegert werden,
   bis eine Ausblendung durch ist - das haengt an der Aufrufstelle und
   waere hier nicht mehr gebuendelt. */

@keyframes mo-pop{
  from{ opacity: 0; transform: translateY(8px) scale(.98) }
  to  { opacity: 1; transform: none }
}
@keyframes mo-fade{
  from{ opacity: 0 }
  to  { opacity: 1 }
}

.motion-ready dialog[open]           { animation: mo-pop  .2s var(--e-out) }
.motion-ready dialog[open]::backdrop { animation: mo-fade .2s ease }

/* --------------------------------------------------------------------------
   3) Zaehler
   -------------------------------------------------------------------------- */

[data-count]{
  font-variant-numeric: tabular-nums;   /* Ziffern springen beim Zaehlen nicht */
}

/* --------------------------------------------------------------------------
   4) Wartezustand
   Formular mit data-pending="Text" bekommt beim Absenden einen unbestimmten
   Laufbalken. Unbestimmt, weil der Server nicht meldet, wie weit er ist -
   der Balken sagt nur "laeuft noch", nicht "zu 40 % fertig".

   Laeuft bewusst OHNE die Klasse motion-ready: das hier ist Rueckmeldung,
   keine Zierde. Wer weniger Bewegung eingestellt hat, braucht sie genauso -
   nur eben als stehender Balken, siehe Block 6.
   -------------------------------------------------------------------------- */

@keyframes mo-indet{
  from{ transform: translateX(-110%) }
  to  { transform: translateX( 410%) }
}

.mo-track{
  height: 2px;
  margin-top: 10px;
  border-radius: 2px;
  background: var(--line);
  overflow: hidden;
  opacity: 0;                       /* belegt schon Platz, damit nichts springt */
  transition: opacity var(--t-fast) var(--e-out);
}
.mo-track.on{ opacity: 1 }

.mo-track > i{
  display: block;
  height: 100%;
  width: 25%;                       /* statisch - animiert wird nur transform */
  background: var(--acc);
  transform: translateX(-110%);
}
.mo-track.on > i{
  animation: mo-indet 1.1s linear infinite;
}

/* Der gesperrte Knopf muss auch gesperrt aussehen - die Seiten hier haben
   teils eigene .btn-Regeln ohne :disabled-Zustand. */
form[data-mo-busy] button[disabled]{
  opacity: .6;
  cursor: default;
}

/* Fortschrittsbalken.
   Fuellung laeuft ueber scaleX statt ueber width - width ist eine
   Layout-Eigenschaft und zwingt den Browser in jedem Frame zum Neuberechnen.

   --mo-bar-dur stellt die Dauer auf den Takt der Datenquelle ein: wer alle
   400 ms einen neuen Wert bekommt, braucht auch ~400 ms Weg dorthin, sonst
   ruckelt der Balken von Haltepunkt zu Haltepunkt. */
.mo-bar{
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--mo-bar-dur, .2s) linear;
}

/* Unbestimmte Phase: der Balken parkt auf seinem letzten Wert, ein Streifen
   wandert darueber. Nur so ist zu sehen, dass der Server noch arbeitet -
   der meldet naemlich zwischendurch gar nichts. */
.mo-wait{ position: relative }
.mo-wait::after{
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: 35%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.30), transparent);
  transform: translateX(-110%);
  animation: mo-indet 1.2s linear infinite;
}

/* --------------------------------------------------------------------------
   5) Rueckfallebene: Nutzer moechte weniger Bewegung
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* Hover bleibt erkennbar, aber ohne Bewegung */
  .tile:hover, .tile:focus-visible,
  .card:hover, .stat:hover,
  .btn:hover, .btn:focus-visible,
  .tile:active, .btn:active,
  .seg button:active, .anims button:active,
  .tabs button:active, button.chip:active{
    transform: none;
  }

  /* Der Hintergrundschleier steht still. Er bleibt sichtbar - er ist Teil
     des Aussehens, nur eben ohne Wanderung. Ebenso das Glanzlicht auf den
     Kacheln, das gar nicht erst anlaeuft. */
  body::before{ animation: none !important }
  .tile::after{ animation: none !important; opacity: 0 }

  /* Dialoge stehen sofort da. Die .motion-ready-Regel greift hier ohnehin
     nicht, das ist der Guertel zum Hosentraeger. */
  dialog[open], dialog[open]::backdrop{
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  /* Nachtraeglich eingefuegte Elemente erscheinen sofort statt einzulaufen.
     motion.js setzt die Klasse in dem Fall ohnehin nicht - das hier ist der
     Guertel zum Hosentraeger, falls die Klasse doch mal im Markup landet. */
  .mo-in{
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }

  /* Wartebalken (Block 4): steht still, bleibt aber sichtbar. Ohne diese
     Ausnahme wuerde die .01ms-Regel oben den Balken faktisch ausknipsen -
     und dann fehlt die Rueckmeldung, dass ueberhaupt etwas laeuft. */
  .mo-track.on > i{
    animation: none !important;
    transform: none;
    width: 100%;
    opacity: .55;
  }

  /* Fortschritt springt jetzt ohne Zwischenweg auf den neuen Wert. Der
     Wanderstreifen wird zur ruhigen Aufhellung - immer noch erkennbar
     "hier laeuft was", nur ohne Bewegung. */
  .mo-wait::after{
    animation: none !important;
    transform: none;
    width: 100%;
    opacity: .5;
  }
}
