/* =====================================================================
   Squish Season - Christmas scenery and decorations (every page).
   Snowfall backdrop, string lights, swaying fir, pine tree line, wreath,
   waving snowman, gifts, candy canes, snow drifts, Santa's sleigh and the
   present cursor. Everything here is decorative: aria-hidden in the markup,
   pointer-events: none, clipped so it can never cause sideways scrolling,
   and still under prefers-reduced-motion.
   ===================================================================== */

/* ---------- Snowfall backdrop ---------- */
.xm-scene {
  position: fixed; inset: 0;
  z-index: var(--z-scene);
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(95% 60% at 50% -12%, #379a82 0%, transparent 62%),
    radial-gradient(75% 45% at 0% 100%, #1a5346 0%, transparent 62%),
    radial-gradient(60% 40% at 100% 88%, #2e8270 0%, transparent 60%);
}
/* ---------- Northern lights ----------
   Six ribbons drifting across the sky behind the whole site, each a different colour --
   teal, ocean, indigo, plum, pine and ice -- fading in and out on its own long clock, so
   the colour of the sky keeps moving and never settles.

   WHY THERE IS NO mix-blend-mode HERE. An earlier version used `mix-blend-mode: multiply`
   to guarantee the ribbons could only darken. It banded badly -- the owner's words were
   "pixely and not smooth" -- because a blend mode forces the element to be painted against
   its backdrop instead of being promoted to its own layer, so the low-alpha gradient steps
   showed as hard stripes AND the blur that would have hidden them could not be afforded.

   Plain alpha compositing does the same job. Every ribbon colour below is darker than the
   page green (#256e5d, luminance 0.1234), so painting one over the page at any opacity can
   only ever deepen it -- measured worst case anywhere on the site is 4.86:1 against the
   gold links, better than the 4.59:1 of the bare page. That matters: gold clears AA by only
   0.09, so anything that LIGHTENS the background behind text fails. Keep new ribbons darker
   than the page and this stays true.

   With the blend mode gone each ribbon is its own composited layer, so the blur that makes
   them smooth is rasterised once and the drift is pure transform and opacity after that --
   nothing repaints frame to frame. */
.xm-aurora { position: absolute; inset: -22% -14% auto -14%; height: 104%; }
.xm-aurora i {
  position: absolute; left: 0; right: 0; height: 62%;
  border-radius: 50%;
  opacity: 0;
  filter: blur(46px);
  will-change: transform, opacity;
}
.xm-aurora i:nth-child(1) {
  top: -6%;
  background: linear-gradient(97deg, transparent 2%, rgb(6 64 58 / 0.78) 26%, rgb(11 53 80 / 0.6) 52%, rgb(6 64 58 / 0.4) 74%, transparent 98%);
  animation: aurora-a 38s ease-in-out infinite;
}
.xm-aurora i:nth-child(2) {
  top: 10%;
  background: linear-gradient(83deg, transparent 2%, rgb(11 53 80 / 0.72) 28%, rgb(36 28 78 / 0.55) 56%, transparent 98%);
  animation: aurora-b 53s ease-in-out -9s infinite;
}
.xm-aurora i:nth-child(3) {
  top: 26%;
  background: linear-gradient(110deg, transparent 2%, rgb(36 28 78 / 0.66) 30%, rgb(8 66 47 / 0.5) 62%, transparent 98%);
  animation: aurora-c 67s ease-in-out -24s infinite;
}
.xm-aurora i:nth-child(4) {
  top: 4%;
  background: linear-gradient(72deg, transparent 2%, rgb(61 27 68 / 0.6) 34%, rgb(19 56 77 / 0.46) 66%, transparent 98%);
  animation: aurora-d 83s ease-in-out -47s infinite;
}
.xm-aurora i:nth-child(5) {
  top: 20%;
  background: linear-gradient(124deg, transparent 2%, rgb(8 66 47 / 0.68) 28%, rgb(36 28 78 / 0.46) 60%, transparent 98%);
  animation: aurora-e 97s ease-in-out -61s infinite;
}
.xm-aurora i:nth-child(6) {
  top: 34%;
  background: linear-gradient(91deg, transparent 2%, rgb(19 56 77 / 0.6) 32%, rgb(61 27 68 / 0.44) 64%, transparent 98%);
  animation: aurora-f 113s ease-in-out -83s infinite;
}
/* Drift only: no scaleY. Scaling a blurred layer makes the browser re-rasterise the
   blur, which is the one thing that would make this expensive again. */
@keyframes aurora-a {
  0%, 100% { transform: translate3d(-9%, 2%, 0);  opacity: 0.18; }
  30%      { transform: translate3d(5%, 7%, 0);   opacity: 0.9; }
  62%      { transform: translate3d(11%, -4%, 0); opacity: 0.45; }
}
@keyframes aurora-b {
  0%, 100% { transform: translate3d(8%, -3%, 0);  opacity: 0.12; }
  26%      { transform: translate3d(-5%, 5%, 0);  opacity: 0.82; }
  58%      { transform: translate3d(-10%, 2%, 0); opacity: 0.34; }
}
@keyframes aurora-c {
  0%, 100% { transform: translate3d(-7%, 5%, 0);  opacity: 0.1; }
  34%      { transform: translate3d(9%, -3%, 0);  opacity: 0.78; }
  70%      { transform: translate3d(3%, 6%, 0);   opacity: 0.28; }
}
@keyframes aurora-d {
  0%, 100% { transform: translate3d(10%, 1%, 0);  opacity: 0.07; }
  40%      { transform: translate3d(-8%, 6%, 0);  opacity: 0.72; }
  74%      { transform: translate3d(-2%, -4%, 0); opacity: 0.24; }
}
@keyframes aurora-e {
  0%, 100% { transform: translate3d(-11%, -2%, 0); opacity: 0.08; }
  36%      { transform: translate3d(7%, 4%, 0);    opacity: 0.74; }
  68%      { transform: translate3d(12%, 7%, 0);   opacity: 0.26; }
}
@keyframes aurora-f {
  0%, 100% { transform: translate3d(4%, 6%, 0);    opacity: 0.06; }
  44%      { transform: translate3d(-9%, -3%, 0);  opacity: 0.68; }
  78%      { transform: translate3d(-3%, 4%, 0);   opacity: 0.22; }
}

/* ---------- Elves on an errand ----------
   Two elves cross the sky carrying a present. Each loop is over a minute long and the
   elf is only on screen for a few seconds of it, so one drifts past about once a minute
   and it never turns into wallpaper. */
.xm-elf {
  position: absolute; left: 0;
  width: clamp(44px, 5vw, 64px);
  opacity: 0;
  will-change: transform, opacity;
}
.xm-elf svg { width: 100%; height: auto; display: block; filter: drop-shadow(0 6px 10px rgb(0 0 0 / 0.35)); }
.xm-elf--a { top: 16%; animation: elf-cross 70s linear infinite; }
.xm-elf--b { top: 58%; animation: elf-cross-back 95s linear -38s infinite; }
@keyframes elf-cross {
  0%      { transform: translate3d(-12vw, 0, 0) rotate(-4deg);  opacity: 0; }
  3%      { opacity: 0.92; }
  4%      { transform: translate3d(14vw, -3vh, 0) rotate(3deg); }
  6%      { transform: translate3d(48vw, 2vh, 0) rotate(-3deg); }
  9%      { opacity: 0.92; }
  11%     { transform: translate3d(108vw, -2vh, 0) rotate(2deg); opacity: 0; }
  100%    { transform: translate3d(108vw, -2vh, 0); opacity: 0; }
}
@keyframes elf-cross-back {
  0%      { transform: translate3d(104vw, 0, 0) scaleX(-1) rotate(4deg); opacity: 0; }
  2%      { opacity: 0.85; }
  4%      { transform: translate3d(62vw, 3vh, 0) scaleX(-1) rotate(-3deg); }
  6%      { transform: translate3d(26vw, -2vh, 0) scaleX(-1) rotate(3deg); }
  7.5%    { opacity: 0.85; }
  9%      { transform: translate3d(-14vw, 1vh, 0) scaleX(-1) rotate(-2deg); opacity: 0; }
  100%    { transform: translate3d(-14vw, 1vh, 0) scaleX(-1); opacity: 0; }
}
.elf-legs { animation: elf-kick 0.7s ease-in-out infinite; transform-origin: 50% 0; }
@keyframes elf-kick { 0%, 100% { transform: rotate(-7deg); } 50% { transform: rotate(7deg); } }
.elf-scarf { animation: elf-scarf 1.1s ease-in-out infinite; transform-origin: 30% 50%; }
@keyframes elf-scarf { 0%, 100% { transform: skewX(0deg); } 50% { transform: skewX(-9deg); } }

.xm-snow { position: absolute; inset: 0; }
.xm-snow i {
  position: absolute; top: -14px; left: var(--x);
  width: var(--s); height: var(--s);
  border-radius: 50%;
  background: var(--snow);
  opacity: var(--o);
  will-change: transform;
  animation: xm-fall var(--d) linear var(--delay) infinite;
}
@keyframes xm-fall { to { transform: translate3d(var(--sway), 108vh, 0); } }

/* ---------- String lights under the header ---------- */
.xm-lights {
  position: relative; z-index: var(--z-content);
  height: var(--lights-h); overflow: hidden;
  margin-top: -1px;
  pointer-events: none;
}
.xm-lights svg { width: 100%; height: 100%; display: block; }
.bulb { animation: xm-glow 3.8s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.41s); }
.bulb--flicker { animation: xm-flicker 6.5s steps(1, end) infinite; animation-delay: calc(var(--i, 0) * -0.9s); }
@keyframes xm-glow {
  0%, 100% { opacity: 1; }
  40% { opacity: 0.62; }
  55% { opacity: 0.95; }
  72% { opacity: 0.78; }
}
@keyframes xm-flicker {
  0%, 100% { opacity: 1; }
  46% { opacity: 0.35; }
  48% { opacity: 1; }
  51% { opacity: 0.5; }
  53% { opacity: 1; }
  78% { opacity: 0.7; }
  80% { opacity: 1; }
}

/* ---------- Fraser fir ---------- */
.xm-tree {
  width: min(62%, 300px); height: auto;
  transform-origin: 50% 100%;
  animation: xm-sway 8s ease-in-out infinite;
  filter: drop-shadow(0 18px 24px rgb(0 0 0 / 0.35));
}
@keyframes xm-sway { 0%, 100% { transform: rotate(-1.2deg); } 50% { transform: rotate(1.2deg); } }
.orn { animation: xm-twinkle 4.2s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.7s); }
@keyframes xm-twinkle { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.xm-star { animation: xm-twinkle 3s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }

/* ---------- Pine tree line that closes a section ---------- */
.treeline {
  position: relative; z-index: var(--z-content);
  height: clamp(110px, 14vw, 190px);
  margin-bottom: -1px;
  overflow: hidden; pointer-events: none;
}
.treeline svg { width: 100%; height: 100%; display: block; }
.tl-front { animation: tl-sway 9s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.8s); transform-box: fill-box; transform-origin: 50% 100%; }
.tl-back { animation: tl-sway 12s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -1.1s); transform-box: fill-box; transform-origin: 50% 100%; }
@keyframes tl-sway { 0%, 100% { transform: rotate(-0.7deg); } 50% { transform: rotate(0.7deg); } }
.tl-light { animation: xm-twinkle 3.4s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.44s); transform-box: fill-box; transform-origin: center; }

/* ---------- Snow drift above the footer ---------- */
.snowline {
  position: relative; z-index: var(--z-content);
  height: clamp(42px, 6vw, 72px); margin-bottom: -1px;
  overflow: hidden; pointer-events: none;
}
.snowline svg { width: 100%; height: 100%; display: block; }

/* ---------- Wreath ---------- */
.wreath-wrap { display: grid; place-items: center; pointer-events: none; }
.wreath { width: clamp(76px, 11vw, 124px); height: auto; filter: drop-shadow(0 10px 16px rgb(0 0 0 / 0.3)); }
.wreath__ring { animation: wreath-turn 34s linear infinite; transform-box: fill-box; transform-origin: 50% 46.7%; }
@keyframes wreath-turn { to { transform: rotate(360deg); } }
.wreath__bow { animation: bow-wiggle 5s ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 20%; }
@keyframes bow-wiggle { 0%, 100% { transform: rotate(-3deg); } 50% { transform: rotate(3deg); } }
.berry { animation: xm-twinkle 3.6s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.5s); transform-box: fill-box; transform-origin: center; }

/* ---------- Waving snowman ---------- */
.snowman-wrap { pointer-events: none; }
.snowman { width: clamp(92px, 13vw, 168px); height: auto; filter: drop-shadow(0 14px 20px rgb(0 0 0 / 0.32)); animation: snowman-bob 6s ease-in-out infinite; }
@keyframes snowman-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.snowman__wave { animation: wave 2.4s ease-in-out infinite; transform-box: fill-box; transform-origin: 8% 92%; }
@keyframes wave { 0%, 60%, 100% { transform: rotate(0); } 70% { transform: rotate(-22deg); } 80% { transform: rotate(6deg); } 90% { transform: rotate(-16deg); } }
.snowman__scarf { animation: scarf 4.5s ease-in-out infinite; transform-box: fill-box; transform-origin: 40% 10%; }
@keyframes scarf { 0%, 100% { transform: rotate(-1.5deg); } 50% { transform: rotate(3deg); } }

/* ---------- Gifts ---------- */
.gifts-wrap { pointer-events: none; }
.gifts { width: clamp(120px, 17vw, 230px); height: auto; filter: drop-shadow(0 14px 20px rgb(0 0 0 / 0.32)); }
.gift { animation: gift-pop 5.5s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -1.3s); transform-box: fill-box; transform-origin: 50% 100%; }
@keyframes gift-pop { 0%, 82%, 100% { transform: translateY(0) scale(1); } 88% { transform: translateY(-4px) scale(1.03, 0.97); } 94% { transform: translateY(0) scale(0.99, 1.01); } }
.gift__bow { animation: bow-wiggle 4.2s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -0.9s); transform-box: fill-box; transform-origin: 50% 100%; }

/* ---------- Candy cane ---------- */
.cane-wrap { pointer-events: none; }
.cane { width: clamp(38px, 5vw, 62px); height: auto; filter: drop-shadow(0 8px 12px rgb(0 0 0 / 0.3)); animation: cane-sway 7s ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 100%; }
@keyframes cane-sway { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(5deg); } }

/* ---------- Santa's sleigh: flies across as the section scrolls ---------- */
.sky-ride {
  position: relative; overflow: hidden; container-type: inline-size;
  height: clamp(120px, 20vw, 210px); margin-bottom: 0.5rem;
  view-timeline: --ride block;
  pointer-events: none;
}
.sky-ride__moon {
  position: absolute; right: 7%; top: 8%;
  width: clamp(48px, 8vw, 96px); aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle at 36% 34%, #fff8e1, #f2d98c 62%, #e6c26a);
  box-shadow: 0 0 46px 14px rgb(242 217 140 / 0.22);
}
.sleigh {
  position: absolute; left: 0; top: 6%;
  width: clamp(230px, 52cqw, 560px); height: auto;
  filter: drop-shadow(0 10px 18px rgb(0 0 0 / 0.4));
  animation: sleigh-fly 18s linear infinite;       /* fallback: keeps flying on a timer */
}
@supports (animation-timeline: view()) {
  .sleigh { animation: sleigh-ride linear both; animation-timeline: --ride; animation-range: entry 0% exit 100%; }
}
@keyframes sleigh-fly {
  from { transform: translateX(-115%) translateY(18%); }
  to { transform: translateX(calc(100cqw + 15%)) translateY(-12%); }
}
@keyframes sleigh-ride {
  from { transform: translateX(-115%) translateY(22%); }
  to { transform: translateX(calc(100cqw + 15%)) translateY(-14%); }
}
.sleigh__all { animation: sleigh-bob 1.6s ease-in-out infinite; }
@keyframes sleigh-bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.leg { transform-box: fill-box; transform-origin: top center; animation: gallop 0.5s ease-in-out infinite alternate; }
.leg--b, .leg--d { animation-delay: -0.25s; }
@keyframes gallop { from { transform: rotate(-22deg); } to { transform: rotate(22deg); } }
.nose--rudolph, .nose-glow { animation: nose-pulse 1.2s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes nose-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.55; transform: scale(1.25); } }
.nose-glow { animation-name: glow-pulse; }
@keyframes glow-pulse { 0%, 100% { opacity: 0.35; transform: scale(1); } 50% { opacity: 0.12; transform: scale(1.5); } }
.trail path { animation: xm-twinkle 1.8s ease-in-out infinite; }
.trail path:nth-child(2) { animation-delay: -0.6s; }
.trail path:nth-child(3) { animation-delay: -1.2s; }
.trail path:nth-child(4) { animation-delay: -0.3s; }

/* ---------- Wrapped-present cursor (desktop pointers only) ----------
   Matches the logo and the favicon: every icon on the site is the same present. */
@media (hover: hover) and (pointer: fine) {
  html {
    cursor: url("../img/cursor-gift.png") 3 3, auto;
    cursor: -webkit-image-set(url("../img/cursor-gift.png") 1x, url("../img/cursor-gift@2x.png") 2x) 3 3, auto;
    cursor: image-set(url("../img/cursor-gift.png") 1x, url("../img/cursor-gift@2x.png") 2x) 3 3, auto;
  }
  :is(a, button, summary, label, [role="button"]) {
    cursor: url("../img/cursor-gift.png") 3 3, pointer;
    cursor: -webkit-image-set(url("../img/cursor-gift.png") 1x, url("../img/cursor-gift@2x.png") 2x) 3 3, pointer;
    cursor: image-set(url("../img/cursor-gift.png") 1x, url("../img/cursor-gift@2x.png") 2x) 3 3, pointer;
  }
  :is(input:not([type="checkbox"]):not([type="radio"]), textarea, select) { cursor: text; }
  [disabled] { cursor: not-allowed; }
}

/* ---------- Motion safety ---------- */
@media (prefers-reduced-motion: reduce) {
  .xm-snow i { display: none; }
  .bulb, .bulb--flicker, .orn, .xm-star, .xm-tree,
  .tl-front, .tl-back, .tl-light,
  .wreath__ring, .wreath__bow, .berry,
  .snowman, .snowman__wave, .snowman__scarf,
  .gift, .gift__bow, .cane,
  .sleigh__all, .leg, .nose--rudolph, .nose-glow, .trail path { animation: none; }
  .sleigh { animation: none; transform: translateX(25cqw); }
  /* the aurora holds still rather than disappearing: it is colour, not motion */
  .xm-aurora i { animation: none; }
  .xm-aurora { opacity: 0.4; }
  /* the elves stay away entirely under reduced motion: they only exist as movement */
  .xm-elf { display: none; }
}

/* ---------- Page transition ----------
   Clicking a product plays this, then the next page loads. Santa's sleigh sweeps
   across while a sheet of snow wipes the screen.

   Leaving runs 0.4s and arriving 0.36s. An earlier version was 0.26s/0.24s and the
   owner found it too quick to see, so it was slowed down. Measured click-to-next-page
   is about 0.41s, still inside the half second they originally asked for once the page
   fetch is counted. Skipped under reduced motion, where links just go. */
.page-wipe {
  position: fixed; inset: 0;
  z-index: calc(var(--z-toast) + 2);
  pointer-events: none;
  visibility: hidden;
  contain: strict;
}
.page-wipe.is-leaving, .page-wipe.is-arriving { visibility: visible; }

.page-wipe__sheet {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 80% at 10% 0%, #ffffff 0%, #f6f1e6 48%, #e6f0ea 100%);
  transform: translate3d(-102%, 0, 0) skewX(-7deg);
  transform-origin: left center;
}
.page-wipe.is-leaving .page-wipe__sheet { animation: wipe-in 0.38s cubic-bezier(0.55, 0, 0.3, 1) forwards; }
.page-wipe.is-arriving .page-wipe__sheet { animation: wipe-out 0.36s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
@keyframes wipe-in  { from { transform: translate3d(-102%, 0, 0) skewX(-7deg); } to { transform: translate3d(0, 0, 0) skewX(0deg); } }
@keyframes wipe-out { from { transform: translate3d(0, 0, 0) skewX(0deg); }     to { transform: translate3d(102%, 0, 0) skewX(7deg); } }

/* the sleigh runs just ahead of the snow, so it looks like it drags the sheet across */
.page-wipe__ride { position: absolute; left: 0; top: 24%; width: clamp(190px, 26vw, 340px); opacity: 0; }
.page-wipe__ride svg { width: 100%; height: auto; display: block; }
.page-wipe.is-leaving .page-wipe__ride  { animation: wipe-ride 0.4s cubic-bezier(0.4, 0, 0.3, 1) forwards; }
.page-wipe.is-arriving .page-wipe__ride { animation: wipe-ride-out 0.36s ease-in forwards; }
@keyframes wipe-ride {
  0%   { transform: translate3d(-40vw, 6vh, 0) rotate(-5deg); opacity: 0; }
  18%  { opacity: 1; }
  100% { transform: translate3d(104vw, -5vh, 0) rotate(4deg); opacity: 1; }
}
@keyframes wipe-ride-out {
  0%   { transform: translate3d(40vw, 0, 0) rotate(2deg); opacity: 1; }
  100% { transform: translate3d(126vw, -6vh, 0) rotate(5deg); opacity: 0; }
}

.page-wipe__flakes { position: absolute; inset: 0; overflow: hidden; }
.page-wipe__flakes i {
  position: absolute; top: -8%; left: var(--x);
  width: var(--s); height: var(--s); border-radius: 50%;
  background: #ffffff; opacity: 0;
  box-shadow: 0 0 6px rgb(255 255 255 / 0.9);
}
.page-wipe.is-leaving .page-wipe__flakes i { animation: wipe-flake 0.4s linear var(--delay) forwards; }
@keyframes wipe-flake {
  0%   { opacity: 0;    transform: translate3d(0, 0, 0); }
  25%  { opacity: 0.95; }
  100% { opacity: 0;    transform: translate3d(var(--sway), 116vh, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .page-wipe { display: none; }
}
