/* ==========================================================================
   Seasonal theme overlays.

   Purely additive. With no `theme-*` class on <body> nothing in this file
   applies, so the site renders exactly as it always has — this is the "all
   themes off" state. When a season is active (admin panel -> Themes) the body
   gains e.g. `theme-winter` and views/partials/theme_overlay.ejs injects a
   single #seasonfx node holding the particles. The drifting particles live in
   that node; the settled "pile-ups" are ::before overlays on a couple of the
   standard page sections (below). Everything is keyed off the body class, so
   the whole effect is one removable layer with no markup changes.

   #seasonfx is fixed, pointer-events:none (never blocks a click) and sits at
   z-index 50: above the page panels, but below the fixed top bar (1000) and the
   chat popups (99), so the controls stay clear.
   ========================================================================== */

#seasonfx {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
  overflow: hidden;
  contain: strict;          /* isolate the layer's paint/layout from the page */
}

/* Ambient seasonal wash — a soft edge vignette that tints only the margins, so
   the centre content stays clean. No animation, so it survives reduced-motion. */
#seasonfx::before {
  content: "";
  position: absolute;
  inset: 0;
}
body.theme-winter #seasonfx::before {
  background: radial-gradient(ellipse 78% 62% at 50% 34%, transparent 56%, rgba(150,190,235,.20));
}
body.theme-spring #seasonfx::before {
  background: radial-gradient(ellipse 78% 62% at 50% 34%, transparent 58%, rgba(240,170,200,.16));
}
body.theme-summer #seasonfx::before {
  background: radial-gradient(ellipse 92% 74% at 50% 2%, rgba(255,205,90,.14), transparent 55%);
}
body.theme-fall #seasonfx::before {
  background: radial-gradient(ellipse 78% 62% at 50% 34%, transparent 56%, rgba(200,110,40,.18));
}

/* ---- particles ---------------------------------------------------------- */
/* Per-particle knobs are set inline by theme_overlay.ejs:
   --x start column, --t duration, --d (negative) delay, --s scale,
   --k / --k2 opposing horizontal sways (px), --rot tumble degrees,
   --spin tumble direction, --c colour. */
.sf {
  position: absolute;
  top: -6%;
  left: var(--x);
  width: calc(6px * var(--s));
  height: calc(6px * var(--s));
  will-change: transform, opacity;
}

/* Winter — snow: round, soft, slow gentle sway (no tumble). */
.sf-snow {
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff, var(--c));
  box-shadow: 0 0 4px rgba(220,235,255,.7);
  animation: sf-fall-snow var(--t) linear var(--d) infinite;
}

/* Spring — cherry-blossom petal: teardrop shape, slow flutter + rotation. */
.sf-petal {
  width: calc(11px * var(--s));
  height: calc(8px * var(--s));
  background: radial-gradient(circle at 30% 30%, rgba(255,255,255,.55), var(--c));
  border-radius: 100% 0 100% 0;
  animation: sf-fall-petal var(--t) linear var(--d) infinite;
}

/* Fall — autumn leaf: leaf shape, wide erratic sway, uneven tumble. The
   ease-in-out timing gives each leaf an organic flutter rather than a constant
   glide. */
.sf-leaf {
  width: calc(12px * var(--s));
  height: calc(12px * var(--s));
  background: linear-gradient(135deg, var(--c), #5a3818);
  border-radius: 0 100% 0 100%;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.18);
  animation: sf-fall-leaf var(--t) ease-in-out var(--d) infinite;
}

/* Summer — firefly: small glowing mote that rises through the dark. */
.sf-mote {
  top: auto;
  bottom: -6%;
  width: calc(5px * var(--s));
  height: calc(5px * var(--s));
  border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 6px 2px rgba(255,210,74,.6), 0 0 13px 4px rgba(255,160,40,.25);
  animation: sf-rise-mote var(--t) ease-in-out var(--d) infinite;
}

/* Gentle, slow snowfall: a soft side-to-side drift, never a straight drop. */
@keyframes sf-fall-snow {
  0%   { transform: translate3d(0, -12vh, 0); opacity: 0; }
  8%   { opacity: .9; }
  30%  { transform: translate3d(calc(var(--k) * 1px), 22vh, 0); }
  55%  { transform: translate3d(calc(var(--k) * -0.6px), 52vh, 0); }
  80%  { transform: translate3d(calc(var(--k) * 0.8px), 82vh, 0); }
  92%  { opacity: .9; }
  100% { transform: translate3d(0, 116vh, 0); opacity: 0; }
}

@keyframes sf-fall-petal {
  0%   { transform: translate3d(0, -12vh, 0) rotate(0deg); opacity: 0; }
  10%  { opacity: .95; }
  30%  { transform: translate3d(calc(var(--k) * 1px), 22vh, 0) rotate(calc(var(--spin) * 120deg)); }
  60%  { transform: translate3d(calc(var(--k) * -1px), 58vh, 0) rotate(calc(var(--spin) * 240deg)); }
  90%  { opacity: .95; }
  100% { transform: translate3d(calc(var(--k) * 0.5px), 116vh, 0) rotate(calc(var(--spin) * 400deg)); opacity: 0; }
}

/* Erratic leaf-fall: the two sways (--k right, --k2 left) have independent
   magnitudes and opposite signs, so the path zig-zags unevenly; --rot varies
   the tumble per leaf. Together with per-leaf duration this reads as fluttering
   rather than a uniform fall. */
@keyframes sf-fall-leaf {
  0%   { transform: translate3d(0, -12vh, 0) rotate(0deg); opacity: 0; }
  10%  { opacity: 1; }
  22%  { transform: translate3d(calc(var(--k) * 1px),   20vh, 0) rotate(calc(var(--spin) * var(--rot) * 0.20deg)); }
  40%  { transform: translate3d(calc(var(--k2) * 1px),  40vh, 0) rotate(calc(var(--spin) * var(--rot) * 0.42deg)); }
  58%  { transform: translate3d(calc(var(--k) * 0.6px), 60vh, 0) rotate(calc(var(--spin) * var(--rot) * 0.60deg)); }
  76%  { transform: translate3d(calc(var(--k2) * 0.7px),80vh, 0) rotate(calc(var(--spin) * var(--rot) * 0.82deg)); }
  90%  { opacity: 1; }
  100% { transform: translate3d(0, 116vh, 0) rotate(calc(var(--spin) * var(--rot) * 1deg)); opacity: 0; }
}

@keyframes sf-rise-mote {
  0%   { transform: translate3d(0, 0, 0); opacity: 0; }
  15%  { opacity: .9; }
  50%  { transform: translate3d(calc(var(--k) * 1px), -55vh, 0); opacity: .45; }
  80%  { opacity: .8; }
  100% { transform: translate3d(calc(var(--k) * -1px), -118vh, 0); opacity: 0; }
}

/* ---- settled pile-ups (scattered clumps) -------------------------------- */
/* js/season.js drops discrete clumps of snow/leaves onto the top rims of a
   random subset of the page's content sections and positions each one in
   document coordinates inside this one layer. The layer sits above the page
   panels (z-index 3) but still below the falling particles (#seasonfx, 50), so
   snow/leaves keep drifting in front of the settled clumps. Removing the layer
   removes the whole effect — no page markup is touched. */
#seasonpiles {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 0;
  z-index: 3;
  pointer-events: none;
}
.seasonpile {
  position: absolute;
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: 100% 100%;
  pointer-events: none;
}
body.theme-winter .seasonpile { filter: drop-shadow(0 2px 1px rgba(40,60,90,.30)); }
body.theme-fall   .seasonpile { filter: drop-shadow(0 2px 1px rgba(0,0,0,.32)); }

/* Thin the falling field on small screens — the effect stays, at a lighter
   density. The pile-ups are left intact. */
@media screen and (max-width: 1099px) {
  #seasonfx .sf:nth-child(2n) { display: none; }
}

/* Respect a visitor's reduced-motion preference: drop the moving particles but
   keep the still ambient tint and the settled pile-ups, so the season still
   reads. */
@media (prefers-reduced-motion: reduce) {
  #seasonfx .sf { display: none; }
}
