/* =============================================================================
 * ff-design/animations.css — Tempo, Keyframes, Tap-Feedback (Design-Reset)
 * -----------------------------------------------------------------------------
 * Grundregel: Animation darf niemals Aufmerksamkeit verlangen. Sie dient
 * dem Verstaendnis (Zustand hat sich geaendert, hier ist der neue Wert),
 * nicht dem Eindruck. Siehe 05-design-tokens.md Abschnitt "Animations-
 * Patterns" und docs/prompts/design-reset.md.
 *
 * Reduced-Motion-Override schaltet alle Dauer-Variablen auf 0ms.
 * ===========================================================================*/

:root {
  --ff-anim-duration-quick:  120ms;  /* Tap-Feedback */
  --ff-anim-duration-medium: 220ms;  /* Drawer-Slide, Modal-Fade */
  --ff-anim-duration-long:   400ms;  /* Number-Roll */
  --ff-anim-easing:          cubic-bezier(0.22, 1, 0.36, 1);
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --ff-anim-duration-quick:  0ms;
    --ff-anim-duration-medium: 0ms;
    --ff-anim-duration-long:   0ms;
  }
}

/* ---------------------------------------------------------------------------
 * Tap-Feedback — Scale-down + Glut-Wash beim pointerdown.
 *
 * Zwei Wege ins gleiche Verhalten:
 *   - via x-tap-feedback: setzt .ff-tap-active per JS (Pointer-Events).
 *     Bleibt erhalten fuer Sonderfaelle (frueher das einzige Mittel) und fuer
 *     Touch-Geraete, die :active nicht zuverlaessig halten.
 *   - via globalen :active-Selektor unten ("Haptik durchgaengig"): greift auf
 *     allen Buttons/Links/Listen-Zeilen ohne x-tap-feedback-Attribut. Macht
 *     die Anwendung beim Klicken ueberall "fuehlbar".
 *
 * Beide Wege landen visuell beim gleichen Scale-Effekt; .ff-tap-active toppt
 * zusaetzlich mit dem Glut-Wash, weil das semantisch ein "ich-fuehl-dich"-
 * Signal fuer wichtige Buttons ist.
 * ------------------------------------------------------------------------- */
.ff-tap-active {
  transform: scale(0.97);
  background-color: var(--ff-accent-subtle) !important;
  transition: transform var(--ff-anim-duration-quick) var(--ff-anim-easing),
              background-color var(--ff-anim-duration-quick) var(--ff-anim-easing);
}

/* ---------------------------------------------------------------------------
 * Haptik durchgaengig — globaler Pressed-State fuer alle Interaktiven.
 *
 * Was es macht: scale(0.97) beim :active. Ueberall, wo etwas klickbar ist —
 * Buttons, Sidebar-Links, Listen-Zeilen, Aktion-Buttons. Reicht voellig fuer
 * "ich hab deinen Klick gehoert" (Spec 05-design-tokens.md Tap-Feedback).
 *
 * Was es NICHT macht: Glut-Wash. Der gehoert nur an die spezifischen Tap-
 * Feedback-Elemente (.ff-tap-active per JS), weil sonst neutrale Listen-
 * Hover unangenehm in Glut leuchten.
 *
 * Reduced-Motion-Override unten schaltet beide Effekte ab.
 * ------------------------------------------------------------------------- */
.ff-clickable,
.ff-btn,
.ff-sidebar__link,
.ff-sidebar__foot-btn,
.ff-sidebar__theme-btn,
.ff-uebersicht-row__action,
.ff-uebersicht-karte__link,
.ff-statusbar__action {
  transition: transform 80ms cubic-bezier(0.3, 0, 0.2, 1),
              background-color 120ms ease,
              border-color 120ms ease,
              color 120ms ease;
  user-select: none;
}

.ff-clickable:active:not(:disabled),
.ff-btn:active:not(:disabled),
.ff-sidebar__link:active,
.ff-sidebar__foot-btn:active:not(:disabled),
.ff-sidebar__theme-btn:active:not(:disabled),
.ff-uebersicht-row__action:active,
.ff-uebersicht-karte__link:active,
.ff-statusbar__action:active {
  transform: scale(0.97);
}

/* Glut-Buttons zusaetzlich leicht abgedunkelter Hintergrund beim Pressed-
 * State — das gibt mehr Materialitaet bei den primaeren Aktionen. */
.ff-btn--primary:active:not(:disabled),
.ff-btn--accent:active:not(:disabled) {
  background: color-mix(in oklab, var(--accent) 85%, black);
  border-color: color-mix(in oklab, var(--accent) 85%, black);
}

@media (prefers-reduced-motion: reduce) {
  .ff-clickable, .ff-btn, .ff-sidebar__link, .ff-sidebar__foot-btn,
  .ff-sidebar__theme-btn, .ff-uebersicht-row__action,
  .ff-uebersicht-karte__link, .ff-statusbar__action {
    transition: none;
  }
  .ff-clickable:active, .ff-btn:active, .ff-sidebar__link:active,
  .ff-sidebar__foot-btn:active, .ff-sidebar__theme-btn:active,
  .ff-uebersicht-row__action:active, .ff-uebersicht-karte__link:active,
  .ff-statusbar__action:active {
    transform: none;
  }
}

/* ---------------------------------------------------------------------------
 * Toast — Fade + Slide-Up. Toast-Fragment bleibt fuer System-Fehler-Hinweise.
 * ------------------------------------------------------------------------- */
@keyframes ff-toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0);   }
}
.ff-toast {
  animation: ff-toast-in var(--ff-anim-duration-medium) var(--ff-anim-easing) both;
}

/* ---------------------------------------------------------------------------
 * Number-Roll — Stellenweise Split-Flap-Animation.
 * Jede geaenderte Stelle "rollt" durch steps(4, end) auf die neue Ziffer.
 * Delay-Versatz pro Position kommt aus JS (animation-delay als Inline-Style).
 *
 * Markup wird von animations.js erzeugt:
 *   <span class="ff-number-roll">
 *     <span class="ff-digit">,</span>                          (statisch)
 *     <span class="ff-digit ff-digit-rolling">                 (rollt)
 *       <span class="ff-digit-stack"><span>4</span><span>6</span></span>
 *     </span>
 *     <span class="ff-digit ff-digit-suffix"> EUR</span>       (optional)
 *   </span>
 * ------------------------------------------------------------------------- */
.ff-number-roll {
  display: inline-flex;
  align-items: baseline;
  font-variant-numeric: tabular-nums slashed-zero;
  font-feature-settings: var(--ff-numeric-feature-settings);
}

.ff-digit {
  display: inline-block;
  height: 1em;
  line-height: 1;
  overflow: hidden;
  vertical-align: baseline;
}
.ff-digit-stack {
  display: block;
}
.ff-digit-stack > span {
  display: block;
  height: 1em;
  line-height: 1;
}
.ff-digit-suffix {
  margin-left: 0.05em;
}

@keyframes ff-digit-roll-kf {
  from { transform: translateY(0); }
  to   { transform: translateY(-1em); }
}
.ff-digit-rolling .ff-digit-stack {
  animation: ff-digit-roll-kf 240ms steps(4, end) forwards;
}

@media (prefers-reduced-motion: reduce) {
  .ff-digit-rolling .ff-digit-stack {
    animation: none;
    transform: translateY(-1em);
  }
}

/* ---------------------------------------------------------------------------
 * State-Puls — Erfolgs- und Fehler-Feedback am ausloesenden Element.
 * Ersetzt Toast-Notifications fuer "Buchung erfolgreich", "Aktion
 * fehlgeschlagen". Inset-Box-Shadow als Overlay, damit der Hintergrund
 * der Kachel kurz in state-ok/state-err aufleuchtet, ohne dass Layout-
 * Reflows entstehen.
 *
 * Verwendung via window.ffPulse(element, 'ok' | 'err') aus animations.js.
 * Kommt automatisch zum Einsatz, wenn nach Server-Redirect ein
 * personId/produktId/buchungId/produktIds Query-Param in der URL steht.
 * ------------------------------------------------------------------------- */
@keyframes ff-pulse-ok-kf {
  0%   { box-shadow: inset 0 0 0 0 transparent; }
  50%  { box-shadow: inset 0 0 0 999px color-mix(in oklab,
                                                 var(--state-ok) 18%,
                                                 transparent); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
.ff-pulse-ok {
  animation: ff-pulse-ok-kf 600ms ease-out;
}

@keyframes ff-pulse-err-kf {
  0%   { box-shadow: inset 0 0 0 0 transparent; }
  50%  { box-shadow: inset 0 0 0 999px color-mix(in oklab,
                                                 var(--state-err) 18%,
                                                 transparent); }
  100% { box-shadow: inset 0 0 0 0 transparent; }
}
.ff-pulse-err {
  animation: ff-pulse-err-kf 600ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .ff-pulse-ok,
  .ff-pulse-err {
    animation: none;
  }
}
