/* ==========================================================================
   ANIMASI & MICRO-INTERACTIONS — NihongoDo
   Semua keyframe dan kelas animasi dipusatkan di sini supaya aturan
   reduced-motion di bawah otomatis berlaku untuk seluruhnya.
   ========================================================================== */

/* ─── KEYFRAMES ──────────────────────────────────────────── */

/* Jawaban benar: flash hijau + scale ringan */
@keyframes kfAnswerCorrect {
  0% {
    transform: scale(1);
    background-color: inherit;
    box-shadow: none;
  }
  20% {
    transform: scale(1.05);
    background-color: var(--jade-ghost);
    box-shadow: 0 0 0 3px var(--jade);
  }
  60% {
    transform: scale(1.02);
    background-color: var(--jade-ghost);
    box-shadow: 0 0 0 2px var(--jade-dim);
  }
  100% {
    transform: scale(1);
    background-color: inherit;
    box-shadow: none;
  }
}

/* Jawaban salah: goyangan horisontal + flash merah */
@keyframes kfAnswerWrong {
  0% {
    transform: translateX(0);
    background-color: inherit;
  }
  15% {
    transform: translateX(-8px);
    background-color: var(--shu-ghost);
  }
  30% {
    transform: translateX(7px);
    background-color: var(--shu-ghost);
  }
  45% {
    transform: translateX(-5px);
  }
  60% {
    transform: translateX(4px);
  }
  75% {
    transform: translateX(-2px);
  }
  100% {
    transform: translateX(0);
    background-color: inherit;
  }
}

/* Flash latar hijau (untuk wrapper soal/panel) */
@keyframes kfFlashCorrect {
  0% {
    box-shadow: 0 0 0 0 rgba(47, 139, 99, 0);
  }
  30% {
    box-shadow: 0 0 0 4px rgba(47, 139, 99, 0.5);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(47, 139, 99, 0);
  }
}

/* Flash latar merah */
@keyframes kfFlashWrong {
  0% {
    box-shadow: 0 0 0 0 rgba(200, 69, 46, 0);
  }
  30% {
    box-shadow: 0 0 0 4px rgba(200, 69, 46, 0.55);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(200, 69, 46, 0);
  }
}

/* Naik level: pop besar + rotasi ringan */
@keyframes kfLevelUp {
  0% {
    transform: scale(1) rotate(0deg);
  }
  25% {
    transform: scale(1.18) rotate(-3deg);
  }
  50% {
    transform: scale(1.22) rotate(2deg);
  }
  70% {
    transform: scale(1.1) rotate(-1deg);
  }
  100% {
    transform: scale(1) rotate(0deg);
  }
}

/* Unlock pencapaian: bouncing masuk dari atas */
@keyframes kfAchievement {
  0% {
    opacity: 0;
    transform: translateY(-24px) scale(0.9);
  }
  50% {
    opacity: 1;
    transform: translateY(4px) scale(1.04);
  }
  70% {
    transform: translateY(-3px) scale(0.98);
  }
  85% {
    transform: translateY(2px) scale(1.01);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Streak tersimpan: denyut hangat */
@keyframes kfStreakSaved {
  0% {
    box-shadow: 0 0 0 0 rgba(200, 69, 46, 0);
  }
  40% {
    box-shadow: 0 0 0 8px rgba(200, 69, 46, 0.35);
  }
  100% {
    box-shadow: 0 0 0 18px rgba(200, 69, 46, 0);
  }
}

/* Masuk dari bawah (fade-in-up): untuk kartu & daftar */
@keyframes kfFadeInUp {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Masuk dari kanan: untuk Toast/notifikasi */
@keyframes kfSlideInRight {
  from {
    opacity: 0;
    transform: translateX(28px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

/* Masuk dari atas: untuk menu/dropdown/sheet */
@keyframes kfSlideInDown {
  from {
    opacity: 0;
    transform: translateY(-12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Pop cepat: feedback klik/toggle */
@keyframes kfScalePop {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.12);
  }
  100% {
    transform: scale(1);
  }
}

/* Denyut cincin glow (untuk ikon achievement/XP) */
@keyframes kfPulseGlow {
  0%,
  100% {
    box-shadow: var(--shadow-glow-gold);
  }
  50% {
    box-shadow: 0 0 24px rgba(203, 161, 53, 0.55);
  }
}

/* Partikel confetti */
@keyframes kfConfettiA {
  0% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(var(--cx, 40px), var(--cy, 80px)) rotate(var(--cr, 300deg)) scale(0.5);
  }
}
@keyframes kfConfettiB {
  0% {
    opacity: 1;
    transform: translate(0, 0) rotate(0deg) scale(1);
  }
  100% {
    opacity: 0;
    transform: translate(var(--cx, -50px), var(--cy, 70px)) rotate(var(--cr, -270deg)) scale(0.4);
  }
}

/* Perhatian (wiggle) */
@keyframes kfWiggle {
  0%,
  100% {
    transform: rotate(0deg);
  }
  20% {
    transform: rotate(-4deg);
  }
  40% {
    transform: rotate(4deg);
  }
  60% {
    transform: rotate(-3deg);
  }
  80% {
    transform: rotate(2deg);
  }
}

/* Shimmer skeleton loader */
@keyframes kfShimmer {
  from {
    background-position: -400px 0;
  }
  to {
    background-position: 400px 0;
  }
}

/* Shimmer teks (judul hero) — gradasi warna berjalan halus */
@keyframes kfShimmerText {
  to {
    background-position: -250% center;
  }
}

/* Sapuan cahaya diagonal (shine) untuk kartu saat hover */
@keyframes kfShine {
  from {
    transform: translateX(-120%) rotate(8deg);
  }
  to {
    transform: translateX(220%) rotate(8deg);
  }
}

/* Ikon "swap": putar + sedikit membesar saat hover */
@keyframes kfIconSwap {
  0% {
    transform: rotate(0deg) scale(1);
  }
  50% {
    transform: rotate(-14deg) scale(1.18);
  }
  100% {
    transform: rotate(0deg) scale(1.08);
  }
}

/* Garis bawah nav tumbuh dari tengah */
@keyframes kfUnderlineGrow {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

/* Denyut lembut untuk badge/nomor saat konten baru masuk */
@keyframes kfSoftPulse {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.06);
  }
}

/* ─── KELAS ANIMASI ──────────────────────────────────────── */

.anim-answer-correct {
  animation: kfAnswerCorrect 0.55s var(--ease) forwards;
}
.anim-answer-wrong {
  animation: kfAnswerWrong 0.5s var(--ease) forwards;
}
.anim-flash-correct {
  animation: kfFlashCorrect 0.6s var(--ease) forwards;
}
.anim-flash-wrong {
  animation: kfFlashWrong 0.6s var(--ease) forwards;
}
.anim-level-up {
  animation: kfLevelUp 0.65s var(--ease) forwards;
}
.anim-achievement {
  animation: kfAchievement 0.55s var(--ease) both;
}
.anim-streak-saved {
  animation: kfStreakSaved 0.8s var(--ease) forwards;
}
.anim-fade-in-up {
  animation: kfFadeInUp var(--dur-med) var(--ease) both;
}
.anim-slide-in-right {
  animation: kfSlideInRight var(--dur-med) var(--ease) both;
}
.anim-slide-in-down {
  animation: kfSlideInDown var(--dur-med) var(--ease) both;
}
.anim-scale-pop {
  animation: kfScalePop 0.25s var(--ease) forwards;
}
.anim-pulse-glow {
  animation: kfPulseGlow 2s ease-in-out infinite;
}
.anim-wiggle {
  animation: kfWiggle 0.6s var(--ease) forwards;
}

/* Staggered list: set --stagger-i (0,1,2…) pada elemen anak */
.anim-stagger > * {
  opacity: 0;
  animation: kfFadeInUp var(--dur-med) var(--ease) both;
  animation-delay: calc(var(--stagger-i, 0) * 60ms);
}

/* ─── SCROLL REVEAL (dipasang oleh js/modules/scroll-reveal.js) ───────────
   Aman-default: hanya "disembunyikan" jika <html> punya kelas .js-reveal
   (ditambahkan oleh JS setelah observer berhasil dipasang). Jika JS gagal
   atau dimatikan, konten tetap terlihat normal — tidak pernah nge-blank. */
.js-reveal .reveal-pending {
  opacity: 0;
}
.js-reveal .reveal-pending.is-revealed {
  animation: kfFadeInUp 0.6s var(--ease) both;
  animation-delay: calc(var(--stagger-i, 0) * 70ms);
}

/* ─── ICON SWAP (hover) ─────────────────────────────────────────────────
   Tempel di ikon/emoji dalam kartu aksi, modul, atau item lesson. */
.icon-swap {
  display: inline-block;
  transition: transform var(--dur-fast) var(--ease);
}
.action-card:hover .icon-swap,
.module-card:hover .icon-swap,
.lesson-item:hover .icon-swap,
a:hover > .icon-swap {
  animation: kfIconSwap 0.45s var(--ease) forwards;
}

/* ─── CARD SHINE (sapuan cahaya saat hover) ────────────────────────────── */
.card-shine {
  position: relative;
  overflow: hidden;
}
.card-shine::before {
  content: "";
  position: absolute;
  top: -50%;
  left: -10%;
  width: 40%;
  height: 200%;
  background: linear-gradient(100deg, transparent, rgba(245, 240, 228, 0.1), transparent);
  transform: translateX(-120%) rotate(8deg);
  pointer-events: none;
}
.card-shine:hover::before {
  animation: kfShine 0.85s ease;
}

/* ─── TEKS SHIMMER (judul hero) ───────────────────────────────────────── */
.text-shimmer {
  background: linear-gradient(
    100deg,
    var(--indigo-light) 15%,
    var(--gold-light) 40%,
    var(--shu-light) 55%,
    var(--indigo-light) 80%
  );
  background-size: 250% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: kfShimmerText 7s linear infinite;
}

/* ─── UNDERLINE HOVER (nav / link teks) ───────────────────────────────── */
.nav-underline {
  position: relative;
}
.nav-underline::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--dur-fast) var(--ease);
}
.nav-underline:hover::after,
.nav-underline.active::after {
  transform: scaleX(1);
}

/* Skeleton loader */
.skeleton {
  background: linear-gradient(90deg, var(--ink-3) 25%, var(--ink-4) 50%, var(--ink-3) 75%);
  background-size: 800px 100%;
  animation: kfShimmer 1.4s ease-in-out infinite;
  border-radius: var(--radius-sm);
}

/* Confetti burst — elemen .confetti-particle dibuat via JS */
.confetti-burst {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-toast);
  overflow: hidden;
}
.confetti-particle {
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  animation: kfConfettiA 0.9s var(--ease) forwards;
}
.confetti-particle:nth-child(even) {
  animation-name: kfConfettiB;
  border-radius: 50%;
}

/* ─── REDUCED MOTION (WCAG 2.1) ─────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
