/* ============================================================
   ARKADE 3.0 — Motion
   Gemeinsame Animations-Bibliothek. Bisher war Bewegung über base.css,
   components.css, games.css, farm.css und ~20 JS-Dateien verstreut, jede
   mit eigenen @keyframes für im Grunde dieselben vier Dinge (auftauchen,
   aufmerksam machen, belohnen, laden). Hier steht das EINMAL, als Klassen
   zum Draufwerfen — neue Screens/Spiele müssen keine Keyframes mehr erfinden.

   Konventionen:
     .anim-*      Einmal-Animationen (Auftritt, Belohnung)
     .loop-*      Endlosschleifen (nur Deko — werden bei Low-Power abgeschaltet)
     .fx-*        Zustands-/Interaktions-Effekte (Hover, Druck, 3D-Neigung)
   Alle Dauern hängen an den --dur-*-Tokens, damit der Bewegungs-reduzieren-
   Schalter (tokens.css) global greift.
   ============================================================ */

/* ---------- 1. Auftritt ---------- */
.anim-rise { animation: mRise var(--dur-slow) var(--ease-out) both; }
@keyframes mRise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }

.anim-drop { animation: mDrop var(--dur-slow) var(--ease-out) both; }
@keyframes mDrop { from { opacity: 0; transform: translateY(-16px); } to { opacity: 1; transform: none; } }

.anim-fade { animation: mFade var(--dur) var(--ease) both; }
@keyframes mFade { from { opacity: 0; } to { opacity: 1; } }

/* Der Standard-Auftritt für Karten/Kacheln: kommt leicht aus der Tiefe nach vorn. */
.anim-pop { animation: mPop var(--dur) var(--ease-spring) both; }
@keyframes mPop { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: scale(1); } }

.anim-slide-l { animation: mSlideL var(--dur) var(--ease-out) both; }
@keyframes mSlideL { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: none; } }
.anim-slide-r { animation: mSlideR var(--dur) var(--ease-out) both; }
@keyframes mSlideR { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: none; } }

/* Verzögerungen zum Staffeln einzelner Elemente ohne :nth-child-Regeln. */
.anim-d1 { animation-delay: calc(var(--stagger) * 1); }
.anim-d2 { animation-delay: calc(var(--stagger) * 2); }
.anim-d3 { animation-delay: calc(var(--stagger) * 3); }
.anim-d4 { animation-delay: calc(var(--stagger) * 4); }
.anim-d5 { animation-delay: calc(var(--stagger) * 5); }
.anim-d6 { animation-delay: calc(var(--stagger) * 6); }

/* ---------- 2. Aufmerksamkeit ---------- */
/* Glanzstreifen, der einmal über eine Fläche wandert — für "neu"/"freigeschaltet".
   Braucht position:relative + overflow:hidden am Elternelement. */
.anim-shine { position: relative; overflow: hidden; }
.anim-shine::after {
  content: ''; position: absolute; top: 0; left: -60%; width: 45%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-18deg); animation: mShine 2.4s var(--ease-out) infinite;
  pointer-events: none;
}
@keyframes mShine { 0% { left: -60%; } 55%, 100% { left: 125%; } }

.loop-float { animation: mFloat 3.2s ease-in-out infinite; }
@keyframes mFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }

.loop-breathe { animation: mBreathe 2.8s ease-in-out infinite; }
@keyframes mBreathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.05); } }

/* Ausbreitender Ring — markiert etwas, das angetippt werden will. */
.loop-ring { position: relative; }
.loop-ring::before {
  content: ''; position: absolute; inset: -4px; border-radius: inherit; pointer-events: none;
  border: 2px solid var(--accent); animation: mRing 1.8s var(--ease-out) infinite;
}
@keyframes mRing { 0% { opacity: .7; transform: scale(1); } 100% { opacity: 0; transform: scale(1.35); } }

.anim-wiggle { animation: mWiggle .5s var(--ease-bounce); }
@keyframes mWiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-6deg); } 60% { transform: rotate(4deg); } }

.anim-shake { animation: mShake .4s var(--ease-bounce); }
@keyframes mShake { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-8px); } 45% { transform: translateX(7px); } 70% { transform: translateX(-4px); } }

/* ---------- 3. Belohnung ---------- */
/* Große Zahl/Icon, die beim Gewinnen aufploppt und wieder verschwindet. */
.anim-reward { animation: mReward 1.1s var(--ease-spring) both; }
@keyframes mReward {
  0% { opacity: 0; transform: scale(.4) translateY(10px); }
  35% { opacity: 1; transform: scale(1.15) translateY(-6px); }
  60% { transform: scale(1) translateY(-8px); }
  100% { opacity: 0; transform: scale(1) translateY(-34px); }
}

/* Kurzes Aufleuchten der ganzen Fläche (Levelaufstieg, Freischaltung). */
.anim-flash { animation: mFlash .7s var(--ease-out); }
@keyframes mFlash {
  0% { box-shadow: 0 0 0 0 var(--accent-glow); }
  40% { box-shadow: 0 0 40px 8px var(--accent-glow); }
  100% { box-shadow: 0 0 0 0 transparent; }
}

/* Zähler/Fortschritt, der gerade hochgezählt wurde. */
.anim-count { animation: mCount .45s var(--ease-spring); }
@keyframes mCount { 0% { transform: scale(1); } 45% { transform: scale(1.28); color: var(--accent-2); } 100% { transform: scale(1); } }

/* ---------- 4. Lootbox / Kiste ---------- */
/* Dreistufig: erst zittern (Spannung), dann aufspringen, dann Lichtstoß.
   Wird in Welle 9 zusätzlich von einer echten 3D-Kiste überlagert — diese
   CSS-Stufe bleibt als Rückfallebene für Geräte ohne WebGL. */
.fx-box-shake { animation: mBoxShake 1.1s var(--ease-in-out, ease-in-out); }
@keyframes mBoxShake {
  0%, 100% { transform: rotate(0) scale(1); }
  15% { transform: rotate(-5deg) scale(1.02); }
  30% { transform: rotate(5deg) scale(1.04); }
  45% { transform: rotate(-7deg) scale(1.06); }
  60% { transform: rotate(7deg) scale(1.08); }
  80% { transform: rotate(-3deg) scale(1.12); }
}
.fx-box-open { animation: mBoxOpen .6s var(--ease-spring) both; }
@keyframes mBoxOpen {
  0% { transform: scale(1.12); }
  40% { transform: scale(1.35) translateY(-8px); }
  100% { opacity: 0; transform: scale(1.8) translateY(-20px); }
}
/* Lichtstoß hinter der Kiste — Farbe kommt über --burst-color je Seltenheit. */
.fx-burst { position: relative; }
.fx-burst::after {
  content: ''; position: absolute; inset: -40%; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, var(--burst-color, var(--accent)) 0%, transparent 62%);
  animation: mBurst .85s var(--ease-out) forwards;
}
@keyframes mBurst { 0% { opacity: 0; transform: scale(.3); } 35% { opacity: .85; } 100% { opacity: 0; transform: scale(1.6); } }

/* Strahlenkranz für seltene Funde. */
.fx-rays::before {
  content: ''; position: absolute; inset: -60%; pointer-events: none; z-index: -1;
  background: conic-gradient(from 0deg, transparent 0deg, var(--burst-color, var(--accent)) 6deg, transparent 12deg,
              transparent 30deg, var(--burst-color, var(--accent)) 36deg, transparent 42deg,
              transparent 60deg, var(--burst-color, var(--accent)) 66deg, transparent 72deg);
  opacity: .28; animation: mRays 9s linear infinite;
}
@keyframes mRays { to { transform: rotate(360deg); } }

/* ---------- 5. 3D-Interaktion ---------- */
/* Neigung zur Maus — die eigentlichen Winkel setzt JS über --rx/--ry.
   Gibt 2D-Karten im neuen Look räumliche Reaktion, passend zu den echten
   3D-Ansichten (Charakter/Boxen/Hof). */
.fx-tilt {
  transform: perspective(700px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateZ(0);
  transition: transform .18s var(--ease-out);
  transform-style: preserve-3d;
}
.fx-tilt-deep { perspective: 900px; }

/* Hebt beim Hover senkrecht ab — dasselbe Modell wie .btn/.panel, als Utility
   für alles, was keine dieser Klassen hat. */
.fx-lift { transition: transform .18s var(--ease-out), box-shadow .18s var(--ease-out); }
.fx-lift:hover { transform: translateY(-3px); box-shadow: var(--sh-lg), var(--lift-strong); }

/* Drückt sich beim Antippen sichtbar ein (Touch-Feedback ohne :hover). */
.fx-press:active { transform: scale(.96); transition-duration: .06s; }

/* ---------- 6. Laden ---------- */
.skel {
  background: linear-gradient(100deg, var(--surface-hi) 30%, var(--surface-2) 50%, var(--surface-hi) 70%);
  background-size: 220% 100%; animation: mSkel 1.3s linear infinite; border-radius: var(--r-sm);
  color: transparent !important;
}
@keyframes mSkel { to { background-position: -120% 0; } }

.loop-spin { animation: mSpin 1s linear infinite; }
@keyframes mSpin { to { transform: rotate(360deg); } }

/* ---------- 7a. Sticker-Teile (Arkade 3.0) ----------
   Die eigenen animierten Sticker (js/data/stickerArt.js) sind Inline-SVGs, deren EINZELNE
   Teile sich bewegen (Arm winkt, Auge blinzelt, Träne fällt, Flamme flackert). Die Keyframes
   stehen bewusst EINMAL hier statt in jedem SVG: sonst würde jede Chat-Nachricht mit Sticker
   dieselben Keyframes erneut mitschleppen.
   `transform-box: fill-box` ist bei SVG-Teilen zwingend — ohne das bezieht sich
   transform-origin auf das gesamte SVG-Koordinatensystem und die Teile "wandern" beim
   Drehen/Skalieren aus dem Bild heraus. */
.stk { display: block; overflow: visible; }
.stk [class^="stk-"], .stk [class*=" stk-"] { transform-box: fill-box; transform-origin: center; }

.stk-bob { animation: stkBob 2.4s ease-in-out infinite; }
@keyframes stkBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }

.stk-laugh { animation: stkLaugh .7s ease-in-out infinite; }
@keyframes stkLaugh { 0%, 100% { transform: translateY(0) rotate(-3deg); } 50% { transform: translateY(-6px) rotate(3deg); } }

/* Blinzeln: lange offen, kurz zu — deshalb passiert fast alles am Ende der Schleife. */
.stk-blink { animation: stkBlink 3.6s infinite; }
@keyframes stkBlink { 0%, 92%, 100% { transform: scaleY(1); } 96% { transform: scaleY(.1); } }

.stk-wave { animation: stkWave .9s ease-in-out infinite; transform-origin: top center; }
@keyframes stkWave { 0%, 100% { transform: rotate(-18deg); } 50% { transform: rotate(22deg); } }

.stk-mouth { animation: stkMouth .7s ease-in-out infinite; }
@keyframes stkMouth { 0%, 100% { transform: scaleY(.6); } 50% { transform: scaleY(1.15); } }

.stk-tear { animation: stkTear 2.2s ease-in infinite; }
@keyframes stkTear { 0% { transform: translateY(0); opacity: 0; } 20% { opacity: 1; } 100% { transform: translateY(26px); opacity: 0; } }

.stk-float1 { animation: stkFloat 2.6s ease-in-out infinite; }
.stk-float2 { animation: stkFloat 2.6s ease-in-out .8s infinite; }
@keyframes stkFloat { 0% { transform: translateY(6px) scale(.7); opacity: 0; } 30% { opacity: 1; } 100% { transform: translateY(-14px) scale(1.05); opacity: 0; } }

.stk-shine { animation: stkShine 2.6s ease-in-out infinite; }
@keyframes stkShine { 0%, 100% { transform: translateX(-4px); opacity: 0; } 45% { opacity: .8; } 70% { transform: translateX(30px); opacity: 0; } }

.stk-flick { animation: stkFlick .45s ease-in-out infinite alternate; }
@keyframes stkFlick { from { transform: scale(1) skewX(-2deg); } to { transform: scale(1.09, .94) skewX(3deg); } }

.stk-pulse { animation: stkPulse 1.1s ease-in-out infinite; }
@keyframes stkPulse { 0%, 100% { transform: scale(.85); opacity: .7; } 50% { transform: scale(1.15); opacity: 1; } }

.stk-pop { animation: stkPop 1.4s var(--ease-spring) infinite; }
@keyframes stkPop { 0%, 70%, 100% { transform: scale(1); } 12% { transform: scale(1.16); } 26% { transform: scale(.96); } }

.stk-shakeit { animation: stkShakeIt 1.8s ease-in-out infinite; }
@keyframes stkShakeIt { 0%, 60%, 100% { transform: rotate(0); } 68% { transform: rotate(-9deg); } 78% { transform: rotate(8deg); } 88% { transform: rotate(-4deg); } }

.stk-spin { animation: stkSpin 7s linear infinite; }
@keyframes stkSpin { to { transform: rotate(360deg); } }

/* ---------- 7b. Sticker als Ganzes ---------- */
.sticker-in { animation: mStickerIn .5s var(--ease-spring) both; }
@keyframes mStickerIn { 0% { opacity: 0; transform: scale(.3) rotate(-12deg); } 60% { transform: scale(1.12) rotate(4deg); } 100% { opacity: 1; transform: scale(1) rotate(0); } }
.sticker-idle { animation: mStickerIdle 2.6s ease-in-out infinite; transform-origin: 50% 90%; }
@keyframes mStickerIdle { 0%, 100% { transform: rotate(-3deg) translateY(0); } 50% { transform: rotate(3deg) translateY(-4px); } }

/* ---------- 8. Sparsamkeit ----------
   Endlosschleifen sind reine Deko: auf schwachen Geräten und in inaktiven Tabs
   werden sie abgeschaltet (Hover/Klick/Übergänge bleiben immer erhalten).
   Gleiche Logik wie in tokens.css für die bestehenden Dauerschleifen. */
html.low-power .loop-float, html.tab-hidden .loop-float,
html.low-power .loop-breathe, html.tab-hidden .loop-breathe,
html.low-power .loop-spin, html.tab-hidden .loop-spin,
html.low-power .sticker-idle, html.tab-hidden .sticker-idle,
html.low-power .anim-shine::after, html.tab-hidden .anim-shine::after,
html.low-power .loop-ring::before, html.tab-hidden .loop-ring::before,
html.low-power .fx-rays::before, html.tab-hidden .fx-rays::before,
html.low-power .skel, html.tab-hidden .skel { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .anim-shine::after, .loop-ring::before, .fx-rays::before, .loop-float, .loop-breathe, .sticker-idle { animation: none; }
  .fx-tilt { transform: none; }
}
