/* ============================================================
   animations.css — All Keyframe Animations & Transitions
   ============================================================

   This file contains every keyframe animation used in the
   birthday surprise website. Each animation is named
   semantically and scoped to its purpose.

   ============================================================ */

/* ============================================================
   1. GIFT BOX — Pulse / Gentle wiggle animation
   ============================================================ */

@keyframes pulse-gentle {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); }
}

@keyframes wiggle {
  0%, 100% { transform: rotate(0deg); }
  25%      { transform: rotate(-3deg); }
  75%      { transform: rotate(3deg); }
}

/* ============================================================
   2. SCREEN TRANSITION — Fade out landing, fade in main
   ============================================================ */

@keyframes fadeScreenOut {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.03); }
}

@keyframes fadeScreenIn {
  from { opacity: 0; transform: scale(0.97); }
  to   { opacity: 1; transform: scale(1); }
}

/* ============================================================
   3. TYPING EFFECT — Character reveal with blinking cursor
   ============================================================ */

@keyframes typing-cursor {
  0%, 100% { border-right-color: var(--color-rose-gold); }
  50%      { border-right-color: transparent; }
}

/* ============================================================
   4. FIRE — Candle flame layers
   Each .fuego layer scales/fades on its own timing so the
   combined result reads as a live, flickering flame.
   ============================================================ */

@keyframes fuego {
  0%, 100% {
    background: rgba(254, 248, 97, 0.5);
    box-shadow: 0 0 40px 10px rgba(248, 233, 209, 0.2);
    transform: translateY(0) scale(1);
  }
  50% {
    background: rgba(255, 50, 0, 0.1);
    box-shadow: 0 0 40px 20px rgba(248, 233, 209, 0.2);
    transform: translateY(-20px) scale(0);
  }
}

/* Candle drops in from above once the cake has finished drawing */
@keyframes candle-in {
  to { transform: translateY(0); }
}

/* Soft pulsing halo behind the landing-screen gift box */
@keyframes soft-glow {
  0%, 100% { opacity: 0.3; transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: 0.6; transform: translate(-50%, -50%) scale(1.15); }
}

/* ============================================================
   5. SMOKE — Thin smoke wisps after candle blow
   ============================================================ */

@keyframes smoke-rise {
  0%   { opacity: 0.7; transform: translateY(0) translateX(0) scale(1); }
  50%  { opacity: 0.4; transform: translateY(-30px) translateX(8px) scale(1.5); }
  100% { opacity: 0; transform: translateY(-70px) translateX(-5px) scale(2.2); }
}

@keyframes smoke-rise-alt {
  0%   { opacity: 0.6; transform: translateY(0) translateX(0) scale(0.8); }
  50%  { opacity: 0.3; transform: translateY(-25px) translateX(-10px) scale(1.8); }
  100% { opacity: 0; transform: translateY(-60px) translateX(10px) scale(2.5); }
}

/* ============================================================
   6. CONFETTI — Burst particles from center
   ============================================================ */

@keyframes confetti-burst {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--cx), var(--cy)) rotate(var(--rot)); opacity: 0; }
}

/* ============================================================
   7. SAKURA PETALS — Falling cherry blossom / rose petals
   ============================================================ */

@keyframes petal-fall {
  0% {
    transform: translateY(-20px) translateX(0) rotate(0deg);
    opacity: 0;
  }
  10% { opacity: 1; }
  25% {
    transform: translateY(25vh) translateX(var(--sway-x)) rotate(120deg);
  }
  50% {
    transform: translateY(50vh) translateX(calc(var(--sway-x) * -0.5)) rotate(240deg);
    opacity: 0.8;
  }
  75% {
    transform: translateY(75vh) translateX(var(--sway-x)) rotate(360deg);
  }
  90% { opacity: 0.5; }
  100% {
    transform: translateY(105vh) translateX(calc(var(--sway-x) * -0.3)) rotate(480deg);
    opacity: 0;
  }
}

/* ============================================================
   7b. SAKURA CORNER TREES — canopy sway + petals shed from branches
   ============================================================ */

/* Whole-tree bend. Kept tiny (≈1.2°) — a decorative element that moves
   much more than this reads as a glitch rather than a breeze. */
@keyframes sakura-sway {
  0%, 100% { transform: rotate(0deg)     skewX(0deg); }
  35%      { transform: rotate(1.2deg)   skewX(-1deg); }
  70%      { transform: rotate(-0.8deg)  skewX(0.6deg); }
}

/* A petal shed by a corner tree: falls from wherever it left the canopy
   down past the bottom edge, drifting sideways as it goes.
   --fall  = distance to the bottom of the viewport, measured in JS. The
             canopy sits only a few hundred px up, so a vh-based drop
             would send petals far below the fold.
   --drift = horizontal travel, signed per side so each tree blows its
             petals toward the middle of the page. */
@keyframes tree-petal-fall {
  0% {
    transform: translate(0, 0) rotate(0deg);
    opacity: 0;
  }
  8%  { opacity: var(--peak-opacity, 0.85); }
  30% {
    transform: translate(calc(var(--drift) * 0.35), calc(var(--fall) * 0.28)) rotate(140deg);
  }
  55% {
    transform: translate(calc(var(--drift) * 0.6), calc(var(--fall) * 0.52)) rotate(280deg);
    opacity: var(--peak-opacity, 0.85);
  }
  80% {
    transform: translate(calc(var(--drift) * 0.85), calc(var(--fall) * 0.78)) rotate(400deg);
    opacity: 0.45;
  }
  100% {
    transform: translate(var(--drift), var(--fall)) rotate(520deg);
    opacity: 0;
  }
}

/* ============================================================
   8. REVEAL — Sections appear after candle blow
   ============================================================ */

@keyframes reveal-up {
  from {
    opacity: 0;
    transform: translateY(40px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes reveal-scale {
  from {
    opacity: 0;
    transform: scale(0.85) rotate(-2deg);
  }
  to {
    opacity: 1;
    transform: scale(1) rotate(0deg);
  }
}

/* ============================================================
   9. POLAROID — Gentle hover float effect
   ============================================================ */

@keyframes float-polaroid {
  0%, 100% { transform: translateY(0) rotate(var(--polaroid-rotation, -4deg)); }
  50%      { transform: translateY(-8px) rotate(var(--polaroid-rotation, -4deg)); }
}

/* ============================================================
   10. GIFT OPEN — Box opening animation
   ============================================================ */

@keyframes gift-open-up {
  from { transform: translateY(0) rotate(0deg); }
  to   { transform: translateY(-120px) rotate(15deg); opacity: 0; }
}

@keyframes gift-glow-out {
  from { opacity: 0; transform: scale(0.5); }
  50%  { opacity: 1; transform: scale(1.1); }
  to   { opacity: 0; transform: scale(2); }
}

/* ============================================================
   10b. ENVELOPE — Heartbeat & floating hearts
   ============================================================ */

@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  15%      { transform: scale(1.2); }
  30%      { transform: scale(1); }
  45%      { transform: scale(1.15); }
  60%      { transform: scale(1); }
}

@keyframes float-heart-anim {
  0% {
    opacity: 0;
    transform: translate(0, 0) scale(0.5);
  }
  20% {
    opacity: 0.8;
  }
  100% {
    opacity: 0;
    transform: translate(var(--fh-x), var(--fh-y)) scale(1.2);
  }
}

@keyframes envelope-shake {
  0%, 100% { transform: rotate(0deg); }
  20%      { transform: rotate(-5deg); }
  40%      { transform: rotate(5deg); }
  60%      { transform: rotate(-3deg); }
  80%      { transform: rotate(3deg); }
}

/* Hati-hati melayang keluar dari amplop saat dibuka.
   Dipakai oleh .a1 / .a2 / .a3 di components.css — animasi `top`
   (bukan translate) supaya `transform: scale()` pada .aN tetap utuh. */
@keyframes heart-float-up {
  0%   { top: 0; }
  100% { top: -600px; }
}

/* Goyangan menyamping supaya lintasan hati tidak lurus */
@keyframes heart-side-sway {
  0%   { margin-left: 0px; }
  100% { margin-left: 50px; }
}

/* ============================================================
   10c. PORTRAIT FRAME — Rotating ring, glow, floating charms
   ============================================================ */

/* Dashed ring slowly circles the photo */
@keyframes portrait-ring-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Photo frame scales in from slightly smaller */
@keyframes portrait-in {
  from {
    opacity: 0;
    transform: scale(0.8);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* Soft halo breathing behind the frame */
@keyframes portrait-glow-pulse {
  0%, 100% { opacity: 0.45; transform: scale(1); }
  50%      { opacity: 0.75; transform: scale(1.06); }
}

/* Each charm bobs in place. The charm's position around the ring is
   handled by its own transform in components.css, so this animation
   only nudges it along its local axis via translate on top of that. */
@keyframes portrait-charm-bob {
  0%, 100% { translate: 0 0; }
  50%      { translate: 0 -6px; }
}

/* ============================================================
   11. SPARKLE — Small twinkling star bursts
   ============================================================ */

@keyframes sparkle {
  0%, 100% { opacity: 0; transform: scale(0) rotate(0deg); }
  50%      { opacity: 1; transform: scale(1) rotate(180deg); }
}

/* ============================================================
   12. WELCOME — Main screen entrance
   ============================================================ */

@keyframes welcome-entrance {
  from {
    opacity: 0;
    transform: translateY(60px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* ============================================================
   13. CELEBRATION EMOJI — Floating & Swaying Animation
   ============================================================ */

.celebration-emoji {
  position: absolute;
  pointer-events: none;
  z-index: 9998;
  opacity: 0;
  transform: translate(0, 0) scale(0.6);
  animation-name: emoji-float-up;
  animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  animation-fill-mode: forwards;
}

@keyframes emoji-float-up {
  0% {
    opacity: 0;
    transform: translate(0, 0) scale(0.6) rotate(0deg);
  }
  15% {
    opacity: 1;
    transform: translate(calc(var(--drift-x) * 0.15), -5vh) scale(1.1) rotate(15deg);
  }
  50% {
    transform: translate(calc(var(--drift-x) * 0.5), -25vh) scale(1) rotate(-15deg);
  }
  100% {
    opacity: 0;
    transform: translate(var(--drift-x), -60vh) scale(0.8) rotate(30deg);
  }
}

/* ============================================================
   14. WISH CARD — Confirmation flash after a wish is emailed
   ============================================================ */

/* A soft pink glow washes over the card, then fades. Deliberately gentle:
   the status line already says what happened, this just marks the beat. */
@keyframes wish-sent {
  0%   { box-shadow: 0 0 0 0 rgba(183, 110, 121, 0); }
  20%  { box-shadow: 0 0 40px 6px rgba(255, 182, 193, 0.7); }
  60%  { box-shadow: 0 0 30px 3px rgba(255, 182, 193, 0.4); }
  100% { box-shadow: 0 0 0 0 rgba(183, 110, 121, 0); }
}

/* ============================================================
   15. FINALE — Last Celebrate button & heart of photos
   ============================================================ */

/* Gradient drifts across the button so it never sits still */
@keyframes finale-shimmer {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

/* Glow breathes outward — reads as "press me" without moving the button.
   Deliberately box-shadow only: animating transform here would override
   the :hover / :active transforms, since a running animation beats a
   plain declaration in the cascade. */
@keyframes finale-pulse {
  0%, 100% { box-shadow: 0 8px 30px rgba(255, 107, 158, 0.45); }
  50%      { box-shadow: 0 12px 46px rgba(255, 107, 158, 0.75); }
}

/* Each photo tile pops into its own point on the curve. JS sets the resting
   spot on left/top and the stagger on animation-delay, so the tiles land one
   after another and the heart traces itself into being.

   The translate(-50%, -50%) is what centres a tile on its curve point, and it
   has to be repeated in every frame: an animated transform replaces the
   element's transform outright, so omitting it in any keyframe would jump the
   tile down-right by half its size for that frame.
   --tilt gives each tile a slightly different resting angle. */
@keyframes heart-tile-in {
  0% {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.2) rotate(-40deg);
  }
  60% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.18) rotate(calc(var(--tilt, 0deg) * 1.4));
  }
  100% {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1) rotate(var(--tilt, 0deg));
  }
}

/* Whole heart pulses once assembled — a real heartbeat, two quick
   squeezes then rest, rather than a single sine breath. */
@keyframes heart-beat {
  0%, 100% { transform: scale(1); }
  14%      { transform: scale(1.06); }
  28%      { transform: scale(1); }
  42%      { transform: scale(1.04); }
  56%      { transform: scale(1); }
}

/* Caption fades up after the tiles have landed */
@keyframes heart-caption-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}
