/**
 * Snowfall CSS
 * ------------
 * This stylesheet supports a lightweight, professional snowfall overlay:
 * - Uses a dynamic viewport height variable to behave well on mobile browsers
 * - Each flake "settles" exactly on the bottom edge (size-aware)
 * - Fade-out happens while stationary (no visible sliding)
 * - Horizontal drift is handled by the OUTER wrapper (fall animation)
 * - Cursor push + scale are handled by the INNER element (transform)
 *
 * Variables expected from snow.js:
 * - --size     (0..1)    : controls flake diameter
 * - --opacity  (0..1)    : per-flake opacity target
 * - --drift    (px)      : per-flake horizontal drift distance
 * - --scale    (~0.9..1.1): subtle visual scale (inner only)
 * - --push     (px)      : cursor push (inner only)
 */

/* Prevent horizontal scrollbars if drift/push crosses viewport edge */
html,
body {
  overflow-x: hidden;
}

/* ============================================================
 * Viewport height handling (mobile-safe)
 * ============================================================
 * Some mobile browsers have dynamic address bars that make 100vh
 * unreliable; 100dvh tracks the "dynamic viewport height" where
 * supported. We store the chosen value in --snow-vh for reuse.
 */
:root {
  --snow-vh: 100vh;
}

@supports (height: 100dvh) {
  :root {
    --snow-vh: 100dvh;
  }
}

/* ============================================================
 * Outer flake wrapper (movement layer)
 * ============================================================
 * The OUTER element:
 * - Is position:fixed so it floats above the page content
 * - Owns the "fall" animation (Y movement) and drift (X movement)
 * - Defines the flake's bounding box size (used for correct settling)
 */
.snowflake {
  position: fixed;
  top: -12px; /* start slightly above the viewport */
  left: 0;

  /* Single source of truth for flake diameter:
     - --size comes from JS (0..1)
     - diameter becomes ~6px to ~16px
     - used to calculate the exact settle position at the bottom edge
  */
  --flake-d: calc(6px + (10px * var(--size, 0.5)));

  width: var(--flake-d);
  height: var(--flake-d);

  /* Ensure flakes never block clicks/selection */
  pointer-events: none;
  user-select: none;

  /* Keep above most UI; adjust if you have modals/menus that must sit on top */
  z-index: 99999;

  /* The fall animation runs forever */
  animation-name: fall;
  animation-timing-function: linear;
  animation-iteration-count: infinite;

  /* Performance hint: the element animates via transform */
  will-change: transform;
}

/* ============================================================
 * Inner flake (visual layer)
 * ============================================================
 * The INNER element:
 * - Draws the snow circle (background + border-radius)
 * - Handles cursor push and visual scale (X-only + scale)
 * - Handles opacity animation (fade in/out)
 *
 * Important: we do NOT animate vertical movement here, so scaling
 * never affects "how far" the flake falls (prevents floating issues).
 */
.snowflake__inner {
  width: 100%;
  height: 100%;
  background-color: #ffffff;
  border-radius: 50%;

  /* Start invisible until fade-in begins */
  opacity: 0;

  /* Cursor push is horizontal only; scale provides subtle depth */
  transform: translateX(var(--push, 0px)) scale(var(--scale, 1));

  /* Optional polish: makes cursor push feel smooth and professional */
  transition: transform 0.12s ease-out;

  /* Opacity animation (separate from movement animation) */
  animation-name: flakeOpacity;
  animation-timing-function: linear;
  animation-iteration-count: infinite;

  /* Performance hint: transform + opacity change frequently */
  will-change: transform, opacity;
}

/* ============================================================
 * Fall keyframes (movement only)
 * ============================================================
 * Goals:
 * 1) Flake reaches the bottom edge and pauses ("settles").
 * 2) Settling is size-aware so the *bottom of the circle* touches
 *    the bottom edge (small flakes do NOT float above).
 * 3) During fade-out, the flake stays perfectly still.
 * 4) At 100% it jumps off-screen (while invisible) to reset cleanly.
 *
 * Settle Y formula:
 *   var(--snow-vh)           -> viewport height
 * + 12px                     -> compensates for top:-12px start offset
 * - var(--flake-d)           -> ensures bottom of flake aligns to bottom edge
 */
@keyframes fall {
  0% {
    /* Start from just above viewport (top:-12px already applied) */
    transform: translate3d(0, 0, 0);
  }

  /* Arrive at bottom edge (size-aware) */
  65% {
    transform: translate3d(
      var(--drift, 0px),
      calc(var(--snow-vh) + 12px - var(--flake-d)),
      0
    );
  }

  /* Hold / settle in place */
  99% {
    transform: translate3d(
      var(--drift, 0px),
      calc(var(--snow-vh) + 12px - var(--flake-d)),
      0
    );
  }

  /* Jump out of view ONLY when fully invisible (prevents visible sliding) */
  100% {
    transform: translate3d(
      var(--drift, 0px),
      calc(var(--snow-vh) + 12px - var(--flake-d) + 48px),
      0
    );
  }
}

/* ============================================================
 * Opacity keyframes (fade only)
 * ============================================================
 * Fade is timed so that:
 * - Flake is visible during the settle pause
 * - Flake fades to 0 BEFORE the 100% position jump
 *   (no visible sliding at the end)
 */
@keyframes flakeOpacity {
  0% {
    opacity: 0;
  }

  /* Fade in early */
  8% {
    opacity: var(--opacity, 0.85);
  }

  /* Stay visible while settled */
  90% {
    opacity: var(--opacity, 0.85);
  }

  /* Fade out while perfectly still */
  98% {
    opacity: 0;
  }

  100% {
    opacity: 0;
  }
}