/* Bewegungssprache.

   Grundregeln:
   - Nur transform und opacity animieren. Beides läuft auf dem Compositor
     und ruckelt auch auf schwachen Geräten nicht.
   - Eingänge kommen von unten und werden heller — nie von der Seite,
     das lenkt zu stark ab.
   - Kurz bleiben: unter 400 ms wirkt reaktionsschnell, darüber träge.
   - Alles hier respektiert prefers-reduced-motion (siehe tokens.css). */

/* ── Eingänge ────────────────────────────────────────────── */

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

@keyframes rise-scale {
  from { opacity: 0; transform: translateY(8px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}

@keyframes appear {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.rise       { animation: rise var(--dur) var(--ease) both; }
.rise-scale { animation: rise-scale var(--dur) var(--ease) both; }
.appear     { animation: appear var(--dur) var(--ease) both; }

/* ── Gestaffeltes Erscheinen ─────────────────────────────────
   Karten und Listenzeilen laufen nacheinander ein statt alle auf einmal.
   Das Auge folgt der Reihenfolge und die Seite wirkt aufgebaut statt
   hingeworfen. Ab dem zehnten Element ohne weitere Verzögerung — sonst
   wartet man bei langen Listen spürbar. */

.stagger > * {
  animation: rise var(--dur) var(--ease) both;
}
.stagger > *:nth-child(1) { animation-delay: 0ms; }
.stagger > *:nth-child(2) { animation-delay: 45ms; }
.stagger > *:nth-child(3) { animation-delay: 90ms; }
.stagger > *:nth-child(4) { animation-delay: 135ms; }
.stagger > *:nth-child(5) { animation-delay: 180ms; }
.stagger > *:nth-child(6) { animation-delay: 225ms; }
.stagger > *:nth-child(7) { animation-delay: 270ms; }
.stagger > *:nth-child(8) { animation-delay: 300ms; }
.stagger > *:nth-child(n+9) { animation-delay: 330ms; }

/* ── Diagramme ───────────────────────────────────────────────
   Die Linie zeichnet sich von links nach rechts. Umgesetzt über
   stroke-dasharray: die Strichlänge entspricht der Pfadlänge, der Versatz
   wandert auf null. */

@keyframes draw-line {
  from { stroke-dashoffset: var(--path-length, 1000); }
  to   { stroke-dashoffset: 0; }
}

@keyframes fill-area {
  from { opacity: 0; transform: scaleY(0.6); }
  to   { opacity: 1; transform: none; }
}

@keyframes pop-dot {
  from { opacity: 0; transform: scale(0); }
  60%  { transform: scale(1.35); }
  to   { opacity: 1; transform: scale(1); }
}

.chart-line {
  stroke-dasharray: var(--path-length, 1000);
  animation: draw-line 1.1s var(--ease) both;
}

.chart-area {
  transform-origin: bottom;
  animation: fill-area 0.9s var(--ease) 0.2s both;
}

/* Punkte erscheinen nach der Linie, in Leserichtung. */
.chart-dot { animation: pop-dot 0.32s var(--ease) both; }

/* ── Balken ──────────────────────────────────────────────── */

@keyframes grow-bar {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.bar-fill {
  transform-origin: left;
  animation: grow-bar 0.7s var(--ease) both;
}

/* ── Zahlen ──────────────────────────────────────────────────
   Kennzahlen erscheinen leicht vergrößert und setzen sich — dadurch wirken
   sie wie eingerastet statt eingeblendet. */

@keyframes settle {
  from { opacity: 0; transform: translateY(6px) scale(1.06); }
  to   { opacity: 1; transform: none; }
}

.stat-value { animation: settle 0.42s var(--ease) both; }

/* ── Rückmeldung auf Eingaben ────────────────────────────── */

@keyframes press {
  50% { transform: scale(0.96); }
}

@keyframes shake {
  20%, 60% { transform: translateX(-4px); }
  40%, 80% { transform: translateX(4px); }
}

.shake { animation: shake 0.4s var(--ease); }

/* Erfolgshaken zeichnet sich statt einfach aufzutauchen. */
@keyframes draw-check {
  from { stroke-dashoffset: 30; }
  to   { stroke-dashoffset: 0; }
}
.check-draw {
  stroke-dasharray: 30;
  animation: draw-check 0.4s var(--ease) both;
}

/* ── Schimmern beim Laden ────────────────────────────────────
   Platzhalter in Inhaltsform statt kreisendem Spinner: Der Nutzer sieht
   schon, wie das Ergebnis aussehen wird, und die Seite springt beim
   Eintreffen der Daten nicht. */

.skeleton-line {
  height: 12px;
  border-radius: 6px;
  background: linear-gradient(90deg,
    var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s ease-in-out infinite;
}
.skeleton-line + .skeleton-line { margin-top: var(--sp-2); }
.skeleton-line.short { width: 45%; }
.skeleton-line.tall  { height: 26px; }

/* ── Übergänge zwischen Bereichen ────────────────────────── */

.section.active { animation: rise 0.26s var(--ease); }

/* ── Schwebende Elemente ─────────────────────────────────── */

@keyframes float-in {
  from { opacity: 0; transform: translateY(16px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
.float-in { animation: float-in 0.3s var(--ease) both; }

/* ── Interaktion ─────────────────────────────────────────────
   Anheben beim Überfahren, Einsinken beim Drücken. Der Unterschied macht
   Flächen erst als anfassbar erkennbar. */

.btn, .quick-card, .choice-card, .hook-card, .slot-card, .style-card, .thumb {
  will-change: transform;
}
.btn:active { animation: press 0.18s var(--ease); }

/* Nach der Animation wieder freigeben — dauerhaftes will-change kostet
   Speicher auf jeder Ebene. */
.stagger > *, .stat-value, .chart-line, .bar-fill {
  will-change: auto;
}
