/* ==========================================================================
   assets/css/festive.css — Christmas and New Year effects (performance build).

   Only loaded when an admin has switched a season on (Settings → Holiday
   effects), so on an ordinary day the site pays nothing for any of this.

   Performance rules followed throughout this file:
     • CSS animations only change opacity and transform. Those run on the
       graphics chip; anything else (box-shadow, filter, background-position)
       repaints on the main thread every frame and is what causes lag.
     • No blur (backdrop-filter) over anything that moves. A blur on top of a
       moving canvas is recalculated every single frame.
     • festive.js puts one of .fx-low / .fx-mid / .fx-high on <html> after
       measuring the device, and the rules at the bottom trim effects to suit.

   Layering, from back to front:
     z -1     .fx-fireworks   behind the content, over the ember background
     z 1040   .fx-snow        in front of the content, behind the navbar
     z 1045   .fx-greeting    the small card in the bottom-right corner
     z 1060   .fx-sleigh      flies across under the navbar
     z 1090   .fx-lights      hangs from the bottom edge of the navbar
     z 1095   .fx-confetti    the one-off burst
   ========================================================================== */

:root {
  --fx-red:   #E0384B;
  --fx-green: #2FB36A;
  --fx-gold:  #F2C94C;
  --fx-ice:   #BFE3FF;
  --fx-plum:  #C77DFF;
}

.fx-layer {
  position: fixed;
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   1. CANVASES — size and top offset are set by festive.js
   ------------------------------------------------------------------------ */
.fx-snow,
.fx-fireworks,
.fx-confetti {
  left: 0;
  top: 0;
  /* Own compositor layer: the page underneath is never repainted because a
     canvas above or below it changed. */
  transform: translateZ(0);
  contain: strict;
}
.fx-snow      { z-index: 1040; }
.fx-fireworks { z-index: -1; opacity: .9; }
.fx-confetti  { z-index: 1095; }

/* ---------------------------------------------------------------------------
   2. CHRISTMAS LIGHTS
   ------------------------------------------------------------------------ */
.fx-lights {
  top: var(--nav-h, 76px);
  left: 0;
  right: 0;
  height: 40px;
  z-index: 1090;
  overflow: hidden;
  contain: strict;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='40' viewBox='0 0 64 40'%3E%3Cpath d='M0 2 Q32 22 64 2' fill='none' stroke='%23262a1e' stroke-width='2.2'/%3E%3Cpath d='M0 2 Q32 22 64 2' fill='none' stroke='%23556b2f' stroke-opacity='.45' stroke-width='.8'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-size: 64px 40px;
}

.fx-bulb {
  position: absolute;
  top: 11px;
  width: 9px;
  height: 15px;
  margin-left: -4.5px;
  border-radius: 50% 50% 46% 46% / 40% 40% 60% 60%;
  background: var(--c);
  /* The glow is painted ONCE. Twinkling fades the whole bulb (glow included)
     with opacity, which the graphics chip does for free. */
  box-shadow:
    0 0 6px 1px var(--c),
    0 0 16px 4px color-mix(in srgb, var(--c) 45%, transparent);
  will-change: opacity;
  animation: fx-twinkle var(--t, 2.4s) ease-in-out var(--d, 0s) infinite;
}
.fx-bulb.is-still { animation: none; will-change: auto; }

.fx-bulb::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 1.5px;
  width: 6px;
  height: 5px;
  border-radius: 1.5px;
  background: #2b2f24;
}
.fx-bulb::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 2px;
  width: 2.5px;
  height: 5px;
  border-radius: 2px;
  background: rgba(255, 255, 255, .55);
}

@keyframes fx-twinkle {
  0%, 100% { opacity: 1; }
  50%      { opacity: .5; }
}

.fx-lights.is-chasing .fx-bulb {
  animation: fx-chase 1.1s ease-in-out calc(var(--i) * 45ms) 2;
}
@keyframes fx-chase {
  0%, 100% { opacity: .35; transform: scale(.9); }
  50%      { opacity: 1;   transform: scale(1.25); }
}

/* ---------------------------------------------------------------------------
   3. SANTA'S SLEIGH
   ------------------------------------------------------------------------ */
.fx-sleigh {
  top: calc(var(--nav-h, 76px) + 46px);
  left: 0;
  width: 220px;
  height: 70px;
  z-index: 1060;
  opacity: 0;
  visibility: hidden;      /* not painted at all between flights */
  contain: layout paint;
}
.fx-sleigh svg { width: 100%; height: 100%; display: block; overflow: visible; }

.fx-sleigh.is-flying {
  visibility: visible;
  will-change: transform, opacity;
  animation: fx-fly var(--fly, 14s) linear forwards;
}

@keyframes fx-fly {
  0%   { opacity: 0; transform: translate3d(calc(100vw + 40px), 30px, 0) rotate(-4deg); }
  6%   { opacity: .95; }
  25%  { transform: translate3d(70vw, 0, 0) rotate(-2deg); }
  50%  { transform: translate3d(40vw, 26px, 0) rotate(1deg); }
  75%  { transform: translate3d(10vw, -6px, 0) rotate(-3deg); }
  94%  { opacity: .95; }
  100% { opacity: 0; transform: translate3d(-260px, 14px, 0) rotate(-4deg); }
}

/* The galloping legs and glinting trail only run while it is on screen. */
.fx-sleigh.is-flying .leg   { transform-box: fill-box; transform-origin: top center; animation: fx-gallop .45s ease-in-out infinite alternate; }
.fx-sleigh.is-flying .leg.b { animation-delay: -.22s; }
@keyframes fx-gallop { from { transform: rotate(-22deg); } to { transform: rotate(18deg); } }

.fx-sleigh.is-flying .trail circle { animation: fx-glint 1.2s ease-in-out infinite; }
.fx-sleigh.is-flying .trail circle:nth-child(2) { animation-delay: .2s; }
.fx-sleigh.is-flying .trail circle:nth-child(3) { animation-delay: .4s; }
.fx-sleigh.is-flying .trail circle:nth-child(4) { animation-delay: .6s; }
.fx-sleigh.is-flying .trail circle:nth-child(5) { animation-delay: .8s; }
@keyframes fx-glint { 0%, 100% { opacity: .15; } 50% { opacity: 1; } }

/* ---------------------------------------------------------------------------
   4. GREETING CARD
   ------------------------------------------------------------------------ */
.fx-greeting {
  position: fixed;
  right: 18px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: 1045;
  width: min(300px, calc(100vw - 110px));
  padding: 14px 40px 14px 16px;
  border-radius: 18px;
  /* Nearly opaque instead of a blur: snow falls behind this card, and a blur
     would have to be recalculated on every frame of it. */
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(224, 56, 75, .22), transparent 55%),
    radial-gradient(120% 140% at 100% 100%, rgba(47, 179, 106, .18), transparent 55%),
    rgba(16, 16, 16, .96);
  border: 1px solid rgba(212, 175, 55, .45);
  box-shadow: 0 18px 40px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .06);
  color: #F3EEDF;
  cursor: pointer;
  contain: layout paint;
  animation: fx-greet-in .8s cubic-bezier(.2, 1.3, .4, 1) .6s both;
}
.fx-greeting.is-newyear-only {
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(242, 201, 76, .22), transparent 55%),
    radial-gradient(120% 140% at 100% 100%, rgba(199, 125, 255, .2), transparent 55%),
    rgba(16, 16, 16, .96);
}
.fx-greeting.is-leaving { animation: fx-greet-out .35s ease-in forwards; }

@keyframes fx-greet-in  { from { opacity: 0; transform: translateY(24px) scale(.94); } to { opacity: 1; transform: none; } }
@keyframes fx-greet-out { to   { opacity: 0; transform: translateY(18px) scale(.96); } }

.fx-greeting:focus-visible { outline: 2px solid var(--fx-gold); outline-offset: 3px; }

.fx-greet-line {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: "Cormorant Garamond", Georgia, serif;
  font-size: 1.2rem;
  font-weight: 600;
  line-height: 1.2;
}
.fx-greet-line + .fx-greet-line { margin-top: 8px; }

.fx-greet-icon {
  flex: 0 0 auto;
  display: inline-block;
  font-size: 1.35rem;
  line-height: 1;
  animation: fx-bob 2.6s ease-in-out infinite;
}
@keyframes fx-bob { 0%, 100% { transform: translateY(0) rotate(-6deg); } 50% { transform: translateY(-3px) rotate(6deg); } }

/* The gold shine sweeps three times when the card appears, then holds still.
   (Moving a gradient repaints the text, so it is not left running forever.) */
.fx-greet-text {
  background: linear-gradient(90deg, #F7E7A9, #D4AF37 40%, #FFF3C4 50%, #D4AF37 60%, #F7E7A9);
  background-size: 250% 100%;
  background-position: 0 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: fx-shine 3s linear 1.2s 3;
}
@keyframes fx-shine { from { background-position: 100% 0; } to { background-position: -150% 0; } }

.fx-countdown {
  display: block;
  margin-top: 4px;
  font-family: Poppins, system-ui, sans-serif;
  font-size: .78rem;
  font-weight: 500;
  color: #C9C2AE;
  font-variant-numeric: tabular-nums;
}
.fx-countdown b { color: var(--fx-gold); font-weight: 600; }

.fx-hint {
  display: block;
  margin-top: 8px;
  font-family: Poppins, system-ui, sans-serif;
  font-size: .68rem;
  color: #8E887A;
}

.fx-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 0;
  background: transparent;
  color: #9A9384;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: color .2s, background .2s;
}
.fx-close:hover,
.fx-close:focus-visible { color: var(--fx-gold); background: rgba(255, 255, 255, .06); outline: none; }

@media (max-width: 480px) {
  .fx-greeting {
    right: 12px;
    bottom: calc(78px + env(safe-area-inset-bottom, 0px));
    width: min(280px, calc(100vw - 24px));
  }
  .fx-greet-line { font-size: 1.08rem; }
  .fx-lights { height: 34px; }
  .fx-sleigh { width: 160px; height: 52px; }
}

/* ---------------------------------------------------------------------------
   5. DEVICE TIERS (classes set on <html> by festive.js)
   ------------------------------------------------------------------------ */

/* LOW + MID: frosted-glass panels (Messenger button, cart drawer) become solid
   while the effects run, because snow moving behind a blur makes the browser
   recalculate that blur every frame. HIGH keeps the glass. */
.fx-low .glass,
.fx-mid .glass,
.fx-minimal .glass {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  background: rgba(20, 20, 20, .94);
}

/* LOW: the festive effects replace the site's own moving background for the
   season, so the device is not running both at once. The gradient stays. */
.fx-low .bg-embers,
.fx-minimal .bg-embers { display: none !important; }
.fx-low .bg-aurora,
.fx-low .bg-mesh,
.fx-low .bg-beams,
.fx-low .bg-orbs i,
.fx-minimal .bg-aurora,
.fx-minimal .bg-mesh,
.fx-minimal .bg-beams,
.fx-minimal .bg-orbs i { animation: none !important; }
.fx-low .bg-grain,
.fx-minimal .bg-grain { display: none !important; }

.fx-low .fx-sleigh.is-flying .leg,
.fx-low .fx-sleigh.is-flying .trail circle { animation: none; }
.fx-low .fx-greet-text { animation: none; }
.fx-low .fx-greet-icon { animation: none; }
.fx-low .fx-bulb { box-shadow: 0 0 6px 1px var(--c); }   /* one shadow, not two */

/* MINIMAL: the device was still struggling on LOW, so only still decorations
   remain. */
.fx-minimal .fx-bulb { animation: none !important; will-change: auto; }
.fx-minimal .fx-sleigh { display: none !important; }

/* ---------------------------------------------------------------------------
   6. ACCESSIBILITY + PRINT
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .fx-bulb, .fx-greet-icon, .fx-greet-text { animation: none !important; will-change: auto; }
  .fx-greeting { animation: none; }
}

@media print {
  .fx-layer, .fx-greeting { display: none !important; }
}
