/* ============================================================
   Seasonal decorations — self-switching, no deploy needed.
   A tiny <head> script sets html[data-season] from the current
   date in America/Denver; everything below is scoped to that.
   Seasons: halloween | fall | thanksgiving | blackfriday | smallbiz
            | winter | nye | newyear
   (absent = plain site)

   !! VERSIONED FILENAME ON PURPOSE. Cloudflare ignores ?v= query
      strings, so editing this file in place leaves returning visitors
      on a cached copy. When you change it, rename to seasonal.v20.css
      and update the link in tools/season.py.

   Nothing here changes layout. The scene is fixed, behind a
   pointer-events:none shell, and every animation touches only
   transform/opacity so it stays on the compositor.
   ============================================================ */

.sn { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 3; contain: strict; }
.sn > div { display: none; }
html[data-season="halloween"]    .sn-halloween    { display: block; }
html[data-season="fall"]         .sn-fall         { display: block; }
html[data-season="thanksgiving"] .sn-fall         { display: block; }
html[data-season="blackfriday"]  .sn-fall         { display: block; }   /* leaves keep falling */
html[data-season="blackfriday"]  .sn-blackfriday  { display: block; }
html[data-season="smallbiz"]     .sn-fall         { display: block; }   /* leaves keep falling */
html[data-season="smallbiz"]     .sn-smallbiz     { display: block; }
.sn-greet-wrap { display: none; }
html[data-season="halloween"]    .sn-greet-hw { display: inline-flex; }
html[data-greet~="thanksgiving"] .sn-greet-tg  { display: inline-flex; }
html[data-greet~="tgweek"]       .sn-greet-tw  { display: inline-flex; }
html[data-greet~="tgweek"]       .sn-greet-binw { display: inline-flex; }
html[data-greet~="blackfriday"]  .sn-greet-bf   { display: inline-flex; }
html[data-greet~="blackfriday"]  .sn-greet-bint { display: inline-flex; }
html[data-greet~="smallbiz"]     .sn-greet-sb   { display: inline-flex; }

/* ---------- shared greeting chip ---------- */
.sn-greet {
  align-items: center; gap: 8px;
  margin: 2px 0 4px; padding: 7px 15px 7px 13px;
  border-radius: 999px;
  font-family: var(--font-head); font-weight: 700;
  font-size: 0.82rem; letter-spacing: 0.1em; text-transform: uppercase;
}
.sn-greet-hw { background: #4a2d5e; color: #f8ecd0; box-shadow: 0 2px 10px rgba(74, 45, 94, 0.28); }
.sn-greet-tg { background: #8a4b1c; color: #fbeed6; box-shadow: 0 2px 10px rgba(138, 75, 28, 0.26); }
.sn-greet-tw { background: #8a4b1c; color: #fbeed6; box-shadow: 0 2px 10px rgba(138, 75, 28, 0.26); }
/* Black Friday is the only day of the year this site goes near-black.
   Gold on charcoal reads as Black Friday without darkening the page. */
.sn-greet-bf { background: #241f1a; color: #e8c87a; box-shadow: 0 2px 12px rgba(36, 31, 26, 0.34); }
/* brick red, distinct from the purple, brown, blue, green, olive and
   near-black chips already in use */
.sn-greet-sb { background: #9c3b30; color: #fbeade; box-shadow: 0 2px 10px rgba(156, 59, 48, 0.28); }
/* the bin-day chip is a LINK to the Trash & Recycling page, so it is an
   <a> and has to shed the default underline and inherit the chip colour */
.sn-greet-bin {
  background: #3f5c45; color: #eef3e2; text-decoration: none;
  box-shadow: 0 2px 10px rgba(63, 92, 69, 0.26);
  transition: background 0.18s ease, transform 0.18s ease;
}
.sn-greet-bin:hover, .sn-greet-bin:focus-visible { background: #35503b; transform: translateY(-1px); }
.sn-greet-bin:focus-visible { outline: 2px solid #8a4b1c; outline-offset: 2px; }
.sn-greet .ic { font-size: 1.05rem; display: inline-block; animation: sn-bob 2.6s ease-in-out infinite; }
@keyframes sn-bob { 0%,100% { transform: translateY(0) rotate(-6deg); } 50% { transform: translateY(-3px) rotate(6deg); } }

/* =================== HALLOWEEN =================== */
.sn-web { position: absolute; top: 0; width: 132px; height: 132px; opacity: 0.4; color: #5a4a2f; }
.sn-web.l { left: 0; }
.sn-web.r { right: 0; transform: scaleX(-1); }

.sn-bat {
  position: absolute; width: 34px; height: 34px; color: #2f2a3d; opacity: 0.62;
  will-change: transform; animation: sn-fly linear infinite;
}
.sn-bat .wing { transform-origin: 50% 46%; animation: sn-flap 0.34s ease-in-out infinite alternate; }
.sn-bat.b1 { top: 13%; animation-duration: 21s; animation-delay: -2s; }
.sn-bat.b2 { top: 27%; animation-duration: 27s; animation-delay: -11s; width: 24px; height: 24px; opacity: 0.45; }
.sn-bat.b3 { top: 56%; animation-duration: 33s; animation-delay: -6s; width: 28px; height: 28px; opacity: 0.5; }
.sn-bat.b4 { top: 73%; animation-duration: 24s; animation-delay: -17s; width: 20px; height: 20px; opacity: 0.38; }
@keyframes sn-fly {
  0%   { transform: translate3d(-12vw, 0, 0) rotate(-4deg); }
  25%  { transform: translate3d(22vw, -26px, 0) rotate(3deg); }
  50%  { transform: translate3d(56vw, 14px, 0) rotate(-3deg); }
  75%  { transform: translate3d(84vw, -18px, 0) rotate(4deg); }
  100% { transform: translate3d(114vw, 0, 0) rotate(-4deg); }
}
@keyframes sn-flap { from { transform: scaleY(1); } to { transform: scaleY(0.42); } }

.sn-ghost {
  position: absolute; width: 46px; height: 58px; opacity: 0; color: #fdfbf2;
  will-change: transform, opacity; animation: sn-drift ease-in-out infinite;
  filter: drop-shadow(0 2px 6px rgba(58, 48, 30, 0.18));
}
.sn-ghost.g1 { left: 6%; animation-duration: 17s; animation-delay: -3s; }
.sn-ghost.g2 { right: 8%; animation-duration: 23s; animation-delay: -12s; width: 34px; height: 44px; }
@keyframes sn-drift {
  0%   { transform: translate3d(0, 24vh, 0) scale(0.92); opacity: 0; }
  18%  { opacity: 0.5; }
  50%  { transform: translate3d(26px, -12vh, 0) scale(1); opacity: 0.6; }
  82%  { opacity: 0.4; }
  100% { transform: translate3d(-10px, -46vh, 0) scale(0.95); opacity: 0; }
}

.sn-spider-wrap {
  position: absolute; top: 0; right: 17%;
  display: flex; flex-direction: column; align-items: center;
  transform-origin: 50% 0; will-change: transform;
  animation: sn-dangle 5.5s ease-in-out infinite;
}
.sn-thread { width: 1px; height: 94px; background: linear-gradient(180deg, rgba(90,74,47,0) 0%, rgba(90,74,47,0.55) 45%); }
.sn-spider { width: 26px; height: 26px; color: #2f2a3d; opacity: 0.72; margin-top: -2px; }
@keyframes sn-dangle {
  0%,100% { transform: translateY(-10px) rotate(-2.5deg); }
  50%     { transform: translateY(14px) rotate(2.5deg); }
}

html[data-season="halloween"] .hero .kicker::before { color: #d2691e; }
html[data-season="halloween"] .hero h1.has-script::after {
  background: linear-gradient(90deg, #d2691e 0%, #d2691e 55%, rgba(210, 105, 30, 0) 100%);
}
html[data-season="halloween"] .notice-bar .tag { background: #4a2d5e; color: #f7e9c9; }

/* =================== FALL / THANKSGIVING =================== */
.sn-leaf {
  position: absolute; top: -8vh; width: 26px; height: 26px;
  will-change: transform, opacity; opacity: 0;
  animation: sn-fall linear infinite;
}
.sn-leaf.l1 { left: 7%;  animation-duration: 15s; animation-delay: -1s;  color: #b4521f; }
.sn-leaf.l2 { left: 21%; animation-duration: 19s; animation-delay: -7s;  color: #8a6a1c; width: 20px; height: 20px; }
.sn-leaf.l3 { left: 38%; animation-duration: 23s; animation-delay: -13s; color: #9c3f14; width: 23px; height: 23px; }
.sn-leaf.l4 { left: 54%; animation-duration: 17s; animation-delay: -4s;  color: #c07a22; }
.sn-leaf.l5 { left: 69%; animation-duration: 21s; animation-delay: -16s; color: #7d4a16; width: 19px; height: 19px; }
.sn-leaf.l6 { left: 83%; animation-duration: 25s; animation-delay: -9s;  color: #a85a1d; width: 24px; height: 24px; }
.sn-leaf.l7 { left: 93%; animation-duration: 18s; animation-delay: -20s; color: #8f6324; width: 18px; height: 18px; }

@keyframes sn-fall {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg); opacity: 0; }
  8%   { opacity: 0.72; }
  25%  { transform: translate3d(32px, 28vh, 0) rotate(110deg); }
  50%  { transform: translate3d(-22px, 56vh, 0) rotate(210deg); }
  75%  { transform: translate3d(28px, 84vh, 0) rotate(320deg); }
  92%  { opacity: 0.6; }
  100% { transform: translate3d(-10px, 116vh, 0) rotate(430deg); opacity: 0; }
}

/* a few acorns drift more slowly and spin less */
.sn-acorn { position: absolute; top: -6vh; width: 17px; height: 17px; color: #6b4a22; opacity: 0; animation: sn-fall linear infinite; }
.sn-acorn.a1 { left: 29%; animation-duration: 27s; animation-delay: -11s; }
.sn-acorn.a2 { left: 62%; animation-duration: 31s; animation-delay: -22s; }

/* warm accents */
html[data-season="fall"] .hero .kicker::before,
html[data-season="thanksgiving"] .hero .kicker::before { color: #b4521f; }
html[data-season="fall"] .hero h1.has-script::after,
html[data-season="thanksgiving"] .hero h1.has-script::after {
  background: linear-gradient(90deg, #b4521f 0%, #b4521f 58%, rgba(180, 82, 31, 0) 100%);
}
html[data-season="thanksgiving"] .notice-bar .tag { background: #8a4b1c; color: #fbeed6; }

@media (max-width: 620px) {
  .sn-web { width: 88px; height: 88px; }
  .sn-ghost.g1, .sn-ghost.g2 { display: none; }
  .sn-spider-wrap { right: 8%; }
  .sn-leaf.l3, .sn-leaf.l5, .sn-leaf.l7, .sn-acorn.a2 { display: none; }
  .sn-greet { font-size: 0.72rem; letter-spacing: 0.07em; }
}

/* Keep the art, stop the motion. */
@media (prefers-reduced-motion: reduce) {
  .sn-bat, .sn-bat .wing, .sn-ghost, .sn-spider-wrap, .sn-greet .ic, .sn-leaf, .sn-acorn { animation: none; }
  .sn-bat.b1 { transform: translate3d(14vw, 0, 0); }
  .sn-bat.b2 { transform: translate3d(42vw, 0, 0); }
  .sn-bat.b3 { transform: translate3d(68vw, 0, 0); }
  .sn-bat.b4 { transform: translate3d(88vw, 0, 0); }
  .sn-ghost { opacity: 0.45; transform: translate3d(0, 6vh, 0); }
  .sn-leaf, .sn-acorn { opacity: 0.6; top: auto; }
  .sn-leaf.l1 { top: 12%; } .sn-leaf.l2 { top: 34%; } .sn-leaf.l3 { top: 58%; }
  .sn-leaf.l4 { top: 21%; } .sn-leaf.l5 { top: 70%; } .sn-leaf.l6 { top: 44%; }
  .sn-leaf.l7 { top: 80%; } .sn-acorn.a1 { top: 27%; } .sn-acorn.a2 { top: 63%; }
}

/* =================== WINTER / DECEMBER =================== */
/* Scene = season (data-season). Greetings = independent tokens
   (data-greet, space separated) so Hanukkah, Christmas and New Year
   can coexist when their dates overlap. */

.sn-snow { position: absolute; top: -6vh; border-radius: 50%; background: #fff; opacity: 0; animation: sn-fall linear infinite; }
.sn-snow.s1 { left: 5%;  width: 9px;  height: 9px;  animation-duration: 19s; animation-delay: -2s; }
.sn-snow.s2 { left: 17%; width: 6px;  height: 6px;  animation-duration: 25s; animation-delay: -9s; }
.sn-snow.s3 { left: 31%; width: 11px; height: 11px; animation-duration: 22s; animation-delay: -15s; }
.sn-snow.s4 { left: 44%; width: 7px;  height: 7px;  animation-duration: 28s; animation-delay: -5s; }
.sn-snow.s5 { left: 58%; width: 10px; height: 10px; animation-duration: 20s; animation-delay: -18s; }
.sn-snow.s6 { left: 71%; width: 6px;  height: 6px;  animation-duration: 26s; animation-delay: -11s; }
.sn-snow.s7 { left: 84%; width: 9px;  height: 9px;  animation-duration: 23s; animation-delay: -3s; }
.sn-snow.s8 { left: 95%; width: 7px;  height: 7px;  animation-duration: 30s; animation-delay: -21s; }

.sn-sprig { position: absolute; top: -6px; width: 150px; height: 150px; color: #2f4a33; opacity: 0.5; }
.sn-sprig.l { left: -14px; }
.sn-sprig.r { right: -14px; transform: scaleX(-1); }

/* confetti for the New Year windows */
.sn-conf { position: absolute; top: -6vh; width: 8px; height: 13px; border-radius: 1px; opacity: 0; animation: sn-fall linear infinite; }
.sn-conf.c1 { left: 8%;  background: #c6a04a; animation-duration: 13s; animation-delay: -1s; }
.sn-conf.c2 { left: 19%; background: #9aa7b5; animation-duration: 17s; animation-delay: -6s; }
.sn-conf.c3 { left: 29%; background: #b4521f; animation-duration: 15s; animation-delay: -11s; }
.sn-conf.c4 { left: 41%; background: #c6a04a; animation-duration: 19s; animation-delay: -3s; }
.sn-conf.c5 { left: 52%; background: #5f7f66; animation-duration: 14s; animation-delay: -16s; }
.sn-conf.c6 { left: 63%; background: #9aa7b5; animation-duration: 18s; animation-delay: -8s; }
.sn-conf.c7 { left: 75%; background: #c6a04a; animation-duration: 16s; animation-delay: -13s; }
.sn-conf.c8 { left: 86%; background: #b4521f; animation-duration: 20s; animation-delay: -4s; }
.sn-conf.c9 { left: 94%; background: #5f7f66; animation-duration: 15s; animation-delay: -19s; }

/* menorah: sits still, lights the correct number of candles for the night */
.sn-menorah { position: absolute; right: 26px; bottom: 18px; width: 126px; height: 104px; color: #4a5a7a; opacity: 0.9; }
.sn-menorah .fl { opacity: 0; transform-origin: 50% 100%; }
.sn-menorah .sh { opacity: 1; animation: sn-flicker 1.5s ease-in-out infinite; }
html[data-hnight="1"] .sn-menorah :is(.f1),
html[data-hnight="2"] .sn-menorah :is(.f1,.f2),
html[data-hnight="3"] .sn-menorah :is(.f1,.f2,.f3),
html[data-hnight="4"] .sn-menorah :is(.f1,.f2,.f3,.f4),
html[data-hnight="5"] .sn-menorah :is(.f1,.f2,.f3,.f4,.f5),
html[data-hnight="6"] .sn-menorah :is(.f1,.f2,.f3,.f4,.f5,.f6),
html[data-hnight="7"] .sn-menorah :is(.f1,.f2,.f3,.f4,.f5,.f6,.f7),
html[data-hnight="8"] .sn-menorah :is(.f1,.f2,.f3,.f4,.f5,.f6,.f7,.f8) {
  opacity: 1;
  animation: sn-lightin 0.4s ease-out var(--d, 0s) backwards,
             sn-flicker 1.7s ease-in-out calc(var(--d, 0s) + 0.4s) infinite;
}
@keyframes sn-flicker { 0%,100% { transform: scaleY(1); opacity: 1; } 50% { transform: scaleY(0.82); opacity: 0.78; } }

/* which scene shows */
html[data-season="winter"]  .sn-winter  { display: block; }
html[data-season="nye"]     .sn-newyear { display: block; }
html[data-season="newyear"] .sn-newyear { display: block; }
.sn-menorah { display: none; }
html[data-greet~="hanukkah"] .sn-menorah { display: block; }

/* which greeting chips show (tokens can combine) */
html[data-greet~="hanukkah"]  .sn-greet-hk { display: inline-flex; }
html[data-greet~="christmas"] .sn-greet-xm { display: inline-flex; }
html[data-greet~="nye"]       .sn-greet-ny { display: inline-flex; }
html[data-greet~="newyear"]   .sn-greet-hy { display: inline-flex; }
.sn-greet-hk { background: #27406b; color: #e8f0fb; box-shadow: 0 2px 10px rgba(39, 64, 107, 0.28); }
.sn-greet-xm { background: #1f4d2e; color: #f1f7ed; box-shadow: 0 2px 10px rgba(31, 77, 46, 0.26); }
.sn-greet-ny,
.sn-greet-hy { background: #6b5415; color: #fbf1d4; box-shadow: 0 2px 10px rgba(107, 84, 21, 0.26); }

/* chips stack neatly when more than one applies (e.g. Hanukkah + Christmas) */
.sn-greet-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 6px; }
.sn-greet-row .sn-greet { margin: 0; }

/* accents */
html[data-season="winter"] .hero .kicker::before { color: #1f4d2e; }
html[data-season="winter"] .hero h1.has-script::after {
  background: linear-gradient(90deg, #1f4d2e 0%, #1f4d2e 40%, #8c2f22 70%, rgba(140, 47, 34, 0) 100%);
}
html[data-season="winter"] .notice-bar .tag { background: #1f4d2e; color: #f1f7ed; }
html[data-season="nye"] .hero .kicker::before,
html[data-season="newyear"] .hero .kicker::before { color: #a8872c; }
html[data-season="nye"] .hero h1.has-script::after,
html[data-season="newyear"] .hero h1.has-script::after {
  background: linear-gradient(90deg, #a8872c 0%, #a8872c 58%, rgba(168, 135, 44, 0) 100%);
}
html[data-season="nye"] .notice-bar .tag,
html[data-season="newyear"] .notice-bar .tag { background: #6b5415; color: #fbf1d4; }

@media (max-width: 620px) {
  .sn-menorah { display: none !important; }
  .sn-sprig { width: 96px; height: 96px; }
  .sn-snow.s3, .sn-snow.s6, .sn-conf.c3, .sn-conf.c6, .sn-conf.c9 { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sn-snow, .sn-conf, .sn-menorah .fl, .sn-menorah .sh { animation: none; }
  .sn-snow, .sn-conf { opacity: 0.6; top: auto; }
  .sn-snow.s1 { top: 14%; } .sn-snow.s2 { top: 32%; } .sn-snow.s3 { top: 51%; } .sn-snow.s4 { top: 68%; }
  .sn-snow.s5 { top: 24%; } .sn-snow.s6 { top: 44%; } .sn-snow.s7 { top: 61%; } .sn-snow.s8 { top: 78%; }
  .sn-conf.c1 { top: 18%; } .sn-conf.c2 { top: 36%; } .sn-conf.c3 { top: 55%; } .sn-conf.c4 { top: 72%; }
  .sn-conf.c5 { top: 27%; } .sn-conf.c6 { top: 47%; } .sn-conf.c7 { top: 64%; } .sn-conf.c8 { top: 81%; }
  .sn-conf.c9 { top: 40%; }
}

/* =================== ARRIVAL BURST ===================
   Plays ONCE on load, then gets out of the way. Every burst
   animation is `1 both` with an opacity-0 end state, so after a
   few seconds the ambient scene is all that remains. No JS. */

.sn-burst { position: absolute; inset: 0; }
.sn-burst > * { position: absolute; opacity: 0; will-change: transform, opacity; }

/* falling debris: leaves, snow, confetti */
.sn-burst .bst {
  top: -12vh;
  animation: sn-bfall var(--dur, 3.4s) cubic-bezier(0.32, 0.5, 0.45, 1) var(--d, 0s) 1 both;
}
@keyframes sn-bfall {
  0%   { transform: translate3d(0, 0, 0) rotate(0deg) scale(1.15); opacity: 0; }
  7%   { opacity: 0.95; }
  80%  { opacity: 0.8; }
  100% { transform: translate3d(var(--dx, 24px), 128vh, 0) rotate(var(--rot, 540deg)) scale(0.9); opacity: 0; }
}

/* bats sweeping the full width, fast, once */
.sn-burst .bstfly {
  animation: sn-bfly var(--dur, 3.2s) cubic-bezier(0.25, 0.6, 0.4, 1) var(--d, 0s) 1 both;
}
.sn-burst .bstfly .wing { transform-origin: 50% 46%; animation: sn-flap 0.22s ease-in-out infinite alternate; }
@keyframes sn-bfly {
  0%   { transform: translate3d(-22vw, 0, 0) rotate(-6deg); opacity: 0; }
  8%   { opacity: 0.9; }
  50%  { transform: translate3d(48vw, -7vh, 0) rotate(5deg); }
  85%  { opacity: 0.65; }
  100% { transform: translate3d(124vw, 2vh, 0) rotate(-5deg); opacity: 0; }
}

/* the greeting chip arrives with a small pop */
.sn-greet { animation: sn-pop 0.62s cubic-bezier(0.2, 1.35, 0.4, 1) 0.3s both; }
@keyframes sn-pop {
  0%   { transform: scale(0.62) translateY(12px); opacity: 0; }
  100% { transform: none; opacity: 1; }
}

/* menorah: candles light one at a time on arrival, right to left */
.sn-menorah .f1 { --d: 0.45s; } .sn-menorah .f2 { --d: 0.75s; }
.sn-menorah .f3 { --d: 1.05s; } .sn-menorah .f4 { --d: 1.35s; }
.sn-menorah .f5 { --d: 1.65s; } .sn-menorah .f6 { --d: 1.95s; }
.sn-menorah .f7 { --d: 2.25s; } .sn-menorah .f8 { --d: 2.55s; }
.sn-menorah .sh { animation: sn-lightin 0.4s ease-out 0.15s backwards, sn-flicker 1.5s ease-in-out 0.55s infinite; }
@keyframes sn-lightin { from { opacity: 0; transform: scaleY(0.2); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .sn-burst { display: none; }
  .sn-greet { animation: none; }
  html[data-hnight] .sn-menorah :is(.f1,.f2,.f3,.f4,.f5,.f6,.f7,.f8),
  .sn-menorah .sh { animation: none; }
}

/* Burst particles have no .l1/.s1/.c1 class, so size and colour must be
   given here or they render at 0x0 / transparent. */
.sn-burst svg.bst { width: 26px; height: 26px; color: #b4521f; }
.sn-burst svg.bst:nth-child(3n)   { color: #8a6a1c; width: 21px; height: 21px; }
.sn-burst svg.bst:nth-child(3n+1) { color: #9c3f14; width: 24px; height: 24px; }
.sn-burst .bst.sn-snow { width: 12px; height: 12px; background: #fff; }
.sn-burst .bst.sn-snow:nth-child(3n)   { width: 8px;  height: 8px; }
.sn-burst .bst.sn-snow:nth-child(4n+1) { width: 15px; height: 15px; }
.sn-burst .bst.sn-conf { width: 9px; height: 15px; background: #c6a04a; }
.sn-burst .bst.sn-conf:nth-child(3n)   { background: #9aa7b5; }
.sn-burst .bst.sn-conf:nth-child(3n+1) { background: #b4521f; }
.sn-burst .bst.sn-conf:nth-child(5n)   { background: #5f7f66; }

/* =================== FIREWORKS (nye + newyear) ===================
   Two layers: .fw-boom plays ONCE on arrival across the page, then
   .fw-amb keeps popping near the top on a long loop so it stays
   festive without competing with the content below. Pure CSS. */

.fw { position: absolute; width: 0; height: 0; }
.fw .r {                                  /* the shell climbing */
  position: absolute; left: -1px; top: 0; width: 3px; height: 13px;
  border-radius: 2px; background: currentColor; opacity: 0;
  box-shadow: 0 0 7px currentColor;
}
.fw .p {                                  /* a spark from the explosion */
  position: absolute; left: -2.5px; top: -2.5px; width: 5px; height: 5px;
  border-radius: 50%; background: currentColor; opacity: 0;
  box-shadow: 0 0 7px currentColor, 0 0 14px currentColor;
}

@keyframes fw-rise {
  0%   { transform: translateY(var(--rise, 52vh)) scaleY(1.8); opacity: 0; }
  12%  { opacity: 0.95; }
  86%  { opacity: 0.95; }
  100% { transform: translateY(0) scaleY(0.5); opacity: 0; }
}
@keyframes fw-pop {
  0%   { transform: translate(0, 0) scale(0.4); opacity: 0; }
  7%   { transform: translate(0, 0) scale(1.25); opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) scale(0.2); opacity: 0; }
}
/* looping variants hold invisible for the rest of the cycle, which is the gap */
@keyframes fw-rise-loop {
  0%   { transform: translateY(var(--rise, 30vh)) scaleY(1.8); opacity: 0; }
  2%   { opacity: 0.95; }
  13%  { transform: translateY(0) scaleY(0.5); opacity: 0; }
  100% { opacity: 0; }
}
@keyframes fw-pop-loop {
  0%   { transform: translate(0, 0) scale(0.4); opacity: 0; }
  14%  { transform: translate(0, 0) scale(1.25); opacity: 1; }
  34%  { transform: translate(var(--tx), var(--ty)) scale(0.2); opacity: 0; }
  100% { transform: translate(var(--tx), var(--ty)) scale(0.2); opacity: 0; }
}

.fw-boom .r { animation: fw-rise var(--rd, 0.95s) ease-out var(--d, 0s) 1 both; }
.fw-boom .p { animation: fw-pop var(--pd, 1.8s) cubic-bezier(0.15, 0.7, 0.35, 1)
                         calc(var(--d, 0s) + var(--rd, 0.95s)) 1 both; }
.fw-amb .r  { animation: fw-rise-loop var(--cyc, 8s) ease-out var(--d, 0s) infinite; }
.fw-amb .p  { animation: fw-pop-loop  var(--cyc, 8s) cubic-bezier(0.15, 0.7, 0.35, 1)
                         calc(var(--d, 0s) + var(--rd, 0.95s)) infinite; }

@media (max-width: 620px) {
  .fw-boom:nth-of-type(n+4), .fw-amb:nth-of-type(n+3) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .fw-boom { display: none; }
  .fw-amb .r { animation: none; opacity: 0; }
  .fw-amb .p { animation: none; opacity: 0.5; transform: translate(var(--tx), var(--ty)) scale(0.6); }
}

/* --- make the fireworks actually read on a cream page ---
   Light sparks vanish against #f3ead3. Two fixes: a brief night-sky
   wash behind the arrival show, and a bright flash at each burst. */

.sn-sky {
  position: absolute; left: 0; right: 0; top: 0; height: 62vh;
  background: linear-gradient(180deg, rgba(14, 18, 38, 0.72) 0%, rgba(18, 22, 44, 0.52) 48%, rgba(24, 28, 50, 0) 100%);
  opacity: 0; animation: sn-sky 7.4s ease-in-out 0.1s 1 both;
}
@keyframes sn-sky {
  0%   { opacity: 0; }
  7%   { opacity: 1; }
  62%  { opacity: 1; }
  100% { opacity: 0; }
}
/* while the sky is up, lift the hero text so it stays readable */
.sn-newyear ~ * .hero h1, html[data-season="nye"] .hero h1, html[data-season="newyear"] .hero h1 { position: relative; z-index: 4; }

.fw .fl {                                  /* the flash of the shell bursting */
  position: absolute; left: -9px; top: -9px; width: 18px; height: 18px;
  border-radius: 50%; background: radial-gradient(circle, #fff 0%, currentColor 45%, rgba(255,255,255,0) 72%);
  opacity: 0;
}
.fw-boom .fl { animation: fw-flash 0.75s ease-out calc(var(--d, 0s) + var(--rd, 0.95s)) 1 both; }
.fw-amb  .fl { animation: fw-flash-loop var(--cyc, 8s) ease-out calc(var(--d, 0s) + var(--rd, 0.95s)) infinite; }
@keyframes fw-flash {
  0%   { transform: scale(0.2); opacity: 0; }
  18%  { transform: scale(2.6); opacity: 1; }
  100% { transform: scale(5.2); opacity: 0; }
}
@keyframes fw-flash-loop {
  0%   { transform: scale(0.2); opacity: 0; }
  5%   { transform: scale(2.4); opacity: 0.95; }
  26%  { transform: scale(4.6); opacity: 0; }
  100% { transform: scale(4.6); opacity: 0; }
}

/* bigger, brighter sparks */
.fw .p { width: 6px; height: 6px; left: -3px; top: -3px; box-shadow: 0 0 8px currentColor, 0 0 18px currentColor; }
.fw .r { height: 15px; box-shadow: 0 0 9px currentColor; }

@media (prefers-reduced-motion: reduce) {
  .sn-sky { display: none; }
  .fw .fl { animation: none; opacity: 0; }
}

/* The 0.72 wash made the hero text muddy for 7s. Lighter sky: the sparks
   carry their own glow, so they still read, and the page stays legible. */
.sn-sky {
  background: linear-gradient(180deg, rgba(16, 20, 40, 0.46) 0%, rgba(20, 24, 46, 0.30) 46%, rgba(24, 28, 50, 0) 100%);
  height: 56vh;
}
/* keep the wordmark and nav clearly above the wash */
html[data-season="nye"] .hero .container,
html[data-season="newyear"] .hero .container { position: relative; z-index: 4; }

/* =================== THEME PREVIEW PICKER ===================
   Deliberately near-invisible until hovered or focused. It only
   changes what THIS browser renders; nothing is saved or shared. */

.sn-pickbtn {
  position: fixed; right: 9px; bottom: 9px; z-index: 70;
  width: 20px; height: 20px; padding: 0; border-radius: 50%;
  border: 1px solid rgba(90, 74, 47, 0.3); background: rgba(253, 248, 232, 0.45);
  color: #6b5f45; font: 600 10px/1 var(--font-head, sans-serif); cursor: pointer;
  opacity: 0.12; transition: opacity 0.18s ease, transform 0.18s ease;
}
.sn-pickbtn:hover, .sn-pickbtn:focus-visible { opacity: 0.96; transform: scale(1.15); }
.sn-pickbtn:focus-visible { outline: 2px solid var(--gold-deep, #8f6d1f); outline-offset: 2px; }

.sn-pick {
  position: fixed; right: 9px; bottom: 36px; z-index: 71; width: 236px;
  display: none; padding: 13px 13px 11px;
  background: #fdf8e8; border: 1px solid #d9cfae; border-radius: 13px;
  box-shadow: 0 10px 30px rgba(58, 48, 30, 0.24);
  font-family: var(--font-body, system-ui, sans-serif); color: #4a4330;
}
.sn-pick[data-open] { display: block; }
.sn-pick h4 {
  margin: 0 0 2px; font: 700 0.76rem/1.2 var(--font-head, sans-serif);
  letter-spacing: 0.1em; text-transform: uppercase; color: #6b5f45;
}
.sn-pick .hint { margin: 0 0 9px; font-size: 0.68rem; color: #8a8068; line-height: 1.35; }
.sn-pick label { display: block; font-size: 0.68rem; color: #6b5f45; margin: 0 0 3px; }
.sn-pick input[type="date"], .sn-pick select {
  width: 100%; box-sizing: border-box; padding: 5px 7px; margin-bottom: 9px;
  border: 1px solid #cfc5a4; border-radius: 7px; background: #fff;
  font: inherit; font-size: 0.78rem; color: #4a4330;
}
.sn-pick .row { display: flex; flex-wrap: wrap; gap: 5px; }
.sn-pick .row button {
  flex: 1 1 auto; padding: 5px 8px; border-radius: 999px; cursor: pointer;
  border: 1px solid #cfc5a4; background: #fffdf4; color: #4a4330;
  font: 500 0.7rem/1.2 var(--font-body, sans-serif); white-space: nowrap;
}
.sn-pick .row button:hover { background: #f3ead3; border-color: #b9ad86; }
.sn-pick .row button[aria-pressed="true"] { background: #4f5638; border-color: #4f5638; color: #fdf8e8; }
.sn-pick .now { margin: 9px 0 0; font-size: 0.68rem; color: #6b5f45; }
.sn-pick .now b { color: #3b3625; }
.sn-pick .close {
  position: absolute; top: 6px; right: 8px; width: 20px; height: 20px; padding: 0;
  border: 0; background: none; color: #8a8068; font-size: 15px; line-height: 1; cursor: pointer;
}
@media (max-width: 620px) { .sn-pick { width: calc(100vw - 28px); right: 14px; } }
@media print { .sn-pickbtn, .sn-pick { display: none !important; } }

/* --- arrival burst: MUCH larger than the ambient scene --- */
.sn-burst svg.bst            { width: 58px; height: 58px; }
.sn-burst svg.bst:nth-child(3n)   { width: 46px; height: 46px; }
.sn-burst svg.bst:nth-child(3n+1) { width: 68px; height: 68px; }
.sn-burst .bst.sn-snow            { width: 26px; height: 26px; }
.sn-burst .bst.sn-snow:nth-child(3n)   { width: 18px; height: 18px; }
.sn-burst .bst.sn-snow:nth-child(4n+1) { width: 34px; height: 34px; }
.sn-burst .bst.sn-conf { width: 15px; height: 26px; }

/* big ghosts that swoop up through the page on arrival */
.sn-burst .bstghost {
  color: #fdfbf2;
  filter: drop-shadow(0 5px 16px rgba(58, 48, 30, 0.28));
  animation: sn-bghost var(--dur, 3.8s) cubic-bezier(0.3, 0.5, 0.4, 1) var(--d, 0s) 1 both;
}
@keyframes sn-bghost {
  0%   { transform: translate3d(0, 36vh, 0) scale(0.6) rotate(-5deg); opacity: 0; }
  14%  { opacity: 0.92; }
  55%  { transform: translate3d(var(--dx, 40px), -4vh, 0) scale(1.12) rotate(4deg); opacity: 0.88; }
  100% { transform: translate3d(var(--dx2, -30px), -56vh, 0) scale(0.92) rotate(-3deg); opacity: 0; }
}

/* fireworks a touch bigger too */
.fw .p { width: 7px; height: 7px; left: -3.5px; top: -3.5px; }

@media (max-width: 620px) {
  /* a phone should not be swamped */
  .sn-burst svg.bst,
  .sn-burst svg.bst:nth-child(3n),
  .sn-burst svg.bst:nth-child(3n+1) { width: 36px; height: 36px; }
  .sn-burst .bst.sn-snow,
  .sn-burst .bst.sn-snow:nth-child(3n),
  .sn-burst .bst.sn-snow:nth-child(4n+1) { width: 18px; height: 18px; }
  .sn-burst .bstghost { width: 70px !important; height: 88px !important; }
  .sn-burst .bstfly { transform: scale(0.62); transform-origin: center; }
}
@media (prefers-reduced-motion: reduce) { .sn-burst .bstghost { animation: none; opacity: 0; } }

/* =================== BIGGER ARRIVAL FIREWORKS =================== */
.fw-boom .p { width: 11px; height: 11px; left: -5.5px; top: -5.5px;
              box-shadow: 0 0 12px currentColor, 0 0 26px currentColor; }
.fw-boom .r { width: 4px; height: 22px; left: -2px; box-shadow: 0 0 12px currentColor; }
.fw-boom .fl { left: -16px; top: -16px; width: 32px; height: 32px; }
@keyframes fw-flash { 0% { transform: scale(0.2); opacity: 0; }
                      18% { transform: scale(3.4); opacity: 1; }
                      100% { transform: scale(7); opacity: 0; } }

/* =================== CHRISTMAS: LIGHTS + TREES =================== */
.sn-lights { position: absolute; inset: 0; display: none; }
html[data-greet~="christmas"] .sn-lights { display: block; }
.sn-lights .wire {
  position: absolute; inset: 7px; border: 2px solid rgba(58, 44, 22, 0.38);
  border-radius: 4px;
}
.sn-lights b {                                  /* one bulb */
  position: absolute; width: 11px; height: 16px; border-radius: 50% 50% 46% 46%;
  background: currentColor; box-shadow: 0 0 9px currentColor, 0 0 20px currentColor;
  animation: sn-twinkle var(--tw, 2.4s) ease-in-out var(--d, 0s) infinite;
}
.sn-lights b::after {                           /* the little cap */
  content: ""; position: absolute; left: 3px; top: -4px; width: 5px; height: 5px;
  border-radius: 1px; background: rgba(58, 44, 22, 0.6);
}
@keyframes sn-twinkle {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.32; transform: scale(0.88); }
}

.sn-tree { position: absolute; bottom: 0; display: none; }
html[data-greet~="christmas"] .sn-tree { display: block; }
.sn-tree .bulb { animation: sn-twinkle var(--tw, 2s) ease-in-out var(--d, 0s) infinite; }

/* =================== THANKSGIVING: TURKEY + TABLE =================== */
.sn-feast, .sn-turkey { position: absolute; bottom: 0; display: none; }
html[data-season="thanksgiving"] .sn-feast,
html[data-season="thanksgiving"] .sn-turkey { display: block; }
.sn-feast { left: 50%; transform: translateX(-50%); width: min(860px, 94vw); opacity: 0.92; }
.sn-turkey { left: 22px; width: 190px; opacity: 0.95; }
.sn-steam { animation: sn-steam 3.4s ease-in-out infinite; transform-origin: 50% 100%; }
@keyframes sn-steam {
  0%, 100% { opacity: 0.15; transform: translateY(0) scaleY(1); }
  50%      { opacity: 0.5;  transform: translateY(-7px) scaleY(1.18); }
}

@media (max-width: 760px) {
  .sn-turkey { display: none !important; }
  .sn-feast { width: 100vw; opacity: 0.85; }
  .sn-lights b { width: 8px; height: 12px; }
  .sn-tree.t2 { display: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  .sn-lights b, .sn-tree .bulb, .sn-steam { animation: none; }
}

/* --- size the scenery so it frames the page instead of covering it ---
   These are fixed overlays, so whatever sits at the bottom of the
   viewport is underneath them. Keep them short and slightly sheer. */
.sn-feast { width: min(520px, 62vw); opacity: 0.82; bottom: -8px; }
.sn-turkey { width: 124px; left: 16px; bottom: -6px; opacity: 0.9; }
.sn-tree.t1 { width: 150px !important; height: 214px !important; left: 2px; opacity: 0.92; }
.sn-tree.t2 { width: 124px !important; height: 178px !important; right: 4px; opacity: 0.88; }

@media (max-width: 980px) {
  .sn-feast { width: min(430px, 70vw); }
  .sn-tree.t1 { width: 112px !important; height: 160px !important; }
}
@media (max-height: 720px) {
  /* short windows: the bottom band would eat the fold */
  .sn-feast { width: min(400px, 52vw); opacity: 0.7; }
  .sn-turkey { display: none !important; }
  .sn-tree.t1 { width: 112px !important; height: 160px !important; }
  .sn-tree.t2 { width: 92px !important; height: 132px !important; }
}

/* --- trees pulled in from the edges ---
   NB: the tree SVGs carry inline left/right, so these need !important.
   The menorah is a fixed 126px box at right:26px (so it reaches 152px in
   from the right). When Hanukkah and Christmas overlap - which happens for
   real on 2027-12-25 - the right tree has to clear that entirely. */
.sn-tree.t1 { left: 7% !important; }
.sn-tree.t2 { right: 7% !important; }

@media (min-width: 621px) {
  html[data-greet~="hanukkah"] .sn-tree.t2 { right: 196px !important; }
}
@media (max-width: 980px) {
  .sn-tree.t1 { left: 4% !important; }
  .sn-tree.t2 { right: 4% !important; }
}
@media (max-width: 620px) {
  /* menorah is hidden at this width, so no clearance needed */
  html[data-greet~="hanukkah"] .sn-tree.t2 { right: 4% !important; }
}

/* =================== THANKSGIVING: THREE FAMILY TABLES ===================
   Replaces the single silhouette scene. Three separate families at three
   tables placed around the foot of the page. Inline SVG, so no extra
   network requests and nothing downloaded outside the Thanksgiving window. */
.sn-feast, .sn-turkey { display: none !important; }   /* superseded */

.sn-tgscene { position: absolute; bottom: -6px; display: none; }
html[data-season="thanksgiving"] .sn-tgscene { display: block; }
.sn-tgscene.a { left: -12px; width: 420px;  opacity: 0.96; }
.sn-tgscene.b { left: 50%; transform: translateX(-50%); width: 376px; opacity: 0.9; }
.sn-tgscene.c { right: -10px; width: 392px; opacity: 0.96; }

@media (max-width: 1240px) { .sn-tgscene.b { display: none !important; } }
@media (max-width: 900px) {
  .sn-tgscene.a { width: 310px; }
  .sn-tgscene.c { width: 290px; }
}
@media (max-width: 620px) {
  .sn-tgscene.c { display: none !important; }
  .sn-tgscene.a { left: 50%; transform: translateX(-50%); width: 320px; opacity: 0.88; }
}
@media (max-height: 720px) {
  .sn-tgscene.b { display: none !important; }
  .sn-tgscene.a { width: 300px; }
  .sn-tgscene.c { width: 282px; }
}

/* trim the tables so they read as a border along the foot of the page
   rather than sitting on top of the stat cards */
.sn-tgscene.a { width: 352px; opacity: 0.93; }
.sn-tgscene.b { width: 312px; opacity: 0.86; }
.sn-tgscene.c { width: 330px; opacity: 0.93; }
@media (max-width: 900px)  { .sn-tgscene.a { width: 286px; } .sn-tgscene.c { width: 268px; } }
@media (max-height: 820px) { .sn-tgscene.b { display: none !important; }
                             .sn-tgscene.a { width: 288px; } .sn-tgscene.c { width: 272px; } }

/* =============== THANKSGIVING DAY: THE PHOTOGRAPHS ===============
   Licensed for ONE DAY A YEAR, so they are gated behind
   html[data-tgday="1"], which the head script sets only on the fourth
   Thursday of November. Every other day of the Thanksgiving window the
   drawn tables above still show, and the rest of the year nothing does.

   The photos are CSS background-images, never <img> tags, on purpose:
   a background declared inside a selector that nothing matches is never
   fetched, so these cost returning visitors zero bytes for the other
   364 days. Do not "simplify" this into <img src>.

   !! THE ASPECT RATIO IS LOAD-BEARING. The sources are cropped to
      700x412 (1.70) - a window running from the diners' faces down
      THROUGH the near edge of the table, so the food is visible. Each
      frame is given that same ratio, because background-size: cover
      crops to fill: a frame WIDER than 1.70 has its top and bottom
      sliced off and the table disappears, which was the original bug.
      If you change the frame proportions, re-crop the sources to match
      (scratchpad recrop_tg.py). Never cap these frames with max-height
      for the same reason - shrink the WIDTH and the height follows.

   !! POSITION BY CENTRE, NEVER BY transform: translateX(-50%). The
      arrival animation ends on `transform: none` with fill-mode both,
      which silently beats any positioning transform - it did, and the
      centre frames sat half a frame to the right. Hence --cx (the
      frame's centre as a % of the viewport) plus a negative margin of
      half --w. No transform anywhere in the layout. */

html[data-tgday="1"] .sn-tgscene { display: none !important; }   /* photos replace the drawings */

.sn-tgband { position: absolute; left: 0; right: 0; bottom: 0; height: 0; display: none; }
html[data-tgday="1"] .sn-tgband { display: block; }

.sn-tgpic {
  --w: clamp(210px, 23vw, 336px);
  position: absolute;
  width: var(--w);
  left: var(--cx);
  margin-left: calc(var(--w) / -2);
  aspect-ratio: 700 / 412;              /* == the crop, so cover never cuts twice */
  background-size: cover;
  background-position: center;
  border-radius: 10px;
  filter: saturate(0.94) contrast(1.02) sepia(0.06);
  -webkit-mask-image:
      linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%),
      linear-gradient(to top, #000 58%, rgba(0,0,0,0.5) 84%, transparent 100%);
          mask-image:
      linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%),
      linear-gradient(to top, #000 58%, rgba(0,0,0,0.5) 84%, transparent 100%);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
  opacity: 0;
  animation: sn-tgphotoin 1.4s cubic-bezier(.2,.7,.3,1) var(--d, 0s) both;
}
/* cream veil so the top edge settles into the page colour */
.sn-tgpic::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(to top,
      rgba(253, 251, 242, 0) 60%,
      rgba(253, 251, 242, 0.34) 100%);
}

@keyframes sn-tgphotoin {
  from { opacity: 0; transform: translateY(26px) scale(0.99); }
  to   { opacity: var(--o, 0.94); transform: none; }
}

/* four frames, centres evenly spaced across the viewport */
.sn-tgpic.p1 { --cx: 12.5%; bottom: -14px; --o: 0.96; --d: 0.15s;
               background-image: url("../images/seasonal/tg-table-1.webp"); }
.sn-tgpic.p2 { --cx: 37.5%; bottom: -24px; --o: 0.9;  --d: 0.42s;
               background-image: url("../images/seasonal/tg-table-2.webp"); }
.sn-tgpic.p3 { --cx: 62.5%; bottom: -12px; --o: 0.96; --d: 0.28s;
               background-image: url("../images/seasonal/tg-table-3.webp"); }
.sn-tgpic.p4 { --cx: 87.5%; bottom: -22px; --o: 0.91; --d: 0.55s;
               background-image: url("../images/seasonal/tg-table-4.webp"); }

/* fewer frames as the page narrows, so each stays big enough to read a table */
@media (max-width: 1180px) {
  .sn-tgpic { --w: clamp(210px, 28vw, 330px); }
  .sn-tgpic.p2 { display: none; }
  .sn-tgpic.p1 { --cx: 16.7%; }
  .sn-tgpic.p3 { --cx: 50%; }
  .sn-tgpic.p4 { --cx: 83.3%; }
}
@media (max-width: 790px) {
  .sn-tgpic { --w: clamp(236px, 45vw, 330px); }
  .sn-tgpic.p3 { display: none; }
  .sn-tgpic.p1 { --cx: 26%; }
  .sn-tgpic.p4 { --cx: 74%; }
}
@media (max-width: 540px) {
  .sn-tgpic { --w: min(92vw, 400px); }
  .sn-tgpic.p4 { display: none; }
  .sn-tgpic.p1 { --cx: 50%; bottom: -12px; --o: 0.93; }
}

/* Short DESKTOP windows only - scoped above 540px so a tall phone is
   never treated as a short window (it was, and the photo came out
   half size on mobile). Shrink the width; the height follows the
   locked ratio, so the table is never cropped. */
@media (min-width: 541px) and (max-height: 760px) {
  .sn-tgpic { --w: clamp(188px, 19vw, 272px); }
}
@media (min-width: 541px) and (max-width: 1180px) and (max-height: 760px) {
  .sn-tgpic { --w: clamp(188px, 24vw, 272px); }
}
@media (min-width: 541px) and (max-width: 790px) and (max-height: 760px) {
  .sn-tgpic { --w: clamp(210px, 38vw, 290px); }
}
@media (min-width: 541px) and (max-height: 620px) {
  .sn-tgpic { --w: clamp(164px, 16vw, 228px); }
  .sn-tgpic.p2 { display: none; }
  .sn-tgpic.p1 { --cx: 16.7%; }
  .sn-tgpic.p3 { --cx: 50%; }
  .sn-tgpic.p4 { --cx: 83.3%; }
}

/* The band is deep enough to reach the hero's stat chips and whatever
   else sits at the foot of the viewport, and washed-out body text on a
   public site is not acceptable. So on this one day the page's own text
   containers are lifted ABOVE the decoration layer (.sn is z-index 3).
   Only the text wrappers are lifted, never the <section> elements -
   .section.alt and .photo-band carry opaque backgrounds and would blank
   the band out as they scrolled past, making the photos flicker in and
   out. The notice bar and footer ARE lifted whole, because their pale
   text needs their own dark backgrounds behind it.

   The run-up week gets the same treatment: the cornucopia is 240px
   wide and was landing across the hero's stat chips. Harvest shapes
   passing BEHIND the chips is strictly better than over them. */
html[data-tgday="1"] .hero .container,
html[data-tgday="1"] .section .container,
html[data-tgday="1"] .notice-bar,
html[data-tgday="1"] .site-footer,
html[data-tgcount] .hero .container,
html[data-tgcount] .section .container,
html[data-tgcount] .notice-bar,
html[data-tgcount] .site-footer { position: relative; z-index: 4; }

@media (prefers-reduced-motion: reduce) {
  .sn-tgpic { animation: none; opacity: var(--o, 0.94); }
}

/* ============ THANKSGIVING WEEK: THE HARVEST (the run-up) ============
   Shown on html[data-tgcount], which the head script sets on the Friday
   before Thanksgiving through the Wednesday before, counting down. The
   idea is preparation versus arrival: the week is harvest and getting
   ready, the Thursday is the gathering. So the drawn family tables are
   deliberately NOT shown during the week - the bottom of the page cannot
   hold a harvest border and three table scenes at once, and showing the
   feast all week would spend the photographs' moment early.

   The drawn tables are still the documented fallback for the day and
   stay reachable at ?season=tgtables.

   !! Arrival animation is OPACITY ONLY. Two of these items are mirrored
      with transform: scaleX(-1), and a keyframe ending on `transform:
      none` with fill-mode both would silently un-mirror them, the same
      way it defeated translateX(-50%) on the photo frames. */

html[data-tgcount] .sn-tgscene { display: none !important; }

/* !! These three scene blocks live INSIDE .sn-fall in the markup, not as
   siblings of it, so `.sn > div { display: none }` does NOT reach them -
   it only matches direct children of .sn. Each one therefore needs its
   own explicit default of none, or it inherits .sn-fall's visibility and
   renders on every fall day in November. That is exactly what happened
   to the Black Friday and Small Business Saturday blocks on first wiring:
   parcels and a shopfront showed up all month. Any future scene added
   inside .sn-fall needs the same line. */
.sn-harvest,
.sn-blackfriday,
.sn-smallbiz { display: none; }
html[data-tgcount] .sn-harvest { display: block; }

.sn-hv {
  position: absolute;
  opacity: 0;
  /* the hero already carries pale feathergrass artwork along its foot, and
     a straw-coloured sheaf laid straight on top of it disappeared. A soft
     shadow lifts every harvest piece off that background without making
     them look like stickers. */
  filter: drop-shadow(0 1px 2px rgba(74, 58, 32, 0.22));
  animation: sn-hvin 1.1s ease-out var(--d, 0s) both;
}
@keyframes sn-hvin { from { opacity: 0; } to { opacity: var(--o, 0.95); } }

/* Two clusters pinned to the left and right EDGES in pixels, not in
   percentages. Percentages with fixed pixel widths look fine at 1440 and
   then collapse: measured at 900px the gourd sat 34px inside the pumpkin
   and the sheaf 24px inside that. Pixel offsets keep each cluster's
   internal spacing identical at every width, and the clusters simply
   drift apart as the page widens. The small overlaps below are
   deliberate - a pumpkin tucked against the base of a sheaf reads as
   arranged, where a tidy row reads as clip art. */
.sn-hv.sheaf-l { left: 14px;   bottom: -6px; width: 92px;  --d: 0.10s; --o: 0.95; }
.sn-hv.pump-a  { left: 98px;   bottom: -4px; width: 86px;  --d: 0.26s; --o: 0.96; }
.sn-hv.gourd-a { left: 176px;  bottom: -2px; width: 62px;  --d: 0.38s; --o: 0.94; }
.sn-hv.corn-a  { left: 230px;  bottom: -2px; width: 50px;  --d: 0.58s; --o: 0.94; }
.sn-hv.gourd-b { right: 166px; bottom: -3px; width: 66px;  --d: 0.44s; --o: 0.94;
                 transform: scaleX(-1); }
.sn-hv.pump-b  { right: 98px;  bottom: -4px; width: 76px;  --d: 0.32s; --o: 0.96; }
.sn-hv.sheaf-r { right: 14px;  bottom: -6px; width: 92px;  --d: 0.16s; --o: 0.95;
                 transform: scaleX(-1); }
/* the cornucopia is the showpiece, so it is placed by percentage in the
   clear gap to the right of the hero's stat chips rather than behind them */
.sn-hv.cornu   { left: 54%;    bottom: -6px; width: 240px; --d: 0.50s; --o: 0.95; }
/* hung clear of the sticky top bar, over the grass artwork on the right */
.sn-hv.wreath  { top: 100px;   right: 3.5%;  width: 116px; --d: 0.66s; --o: 0.9; }

@media (max-width: 1180px) {
  .sn-hv.cornu  { left: 52%; width: 200px; }
  .sn-hv.wreath { width: 96px; top: 92px; }
}
@media (max-width: 900px) {
  .sn-hv.cornu, .sn-hv.wreath { display: none; }
}
@media (max-width: 620px) {
  .sn-hv.gourd-a, .sn-hv.gourd-b, .sn-hv.corn-a { display: none; }
  .sn-hv.sheaf-l, .sn-hv.sheaf-r { width: 74px; }
  .sn-hv.sheaf-l { left: 8px; }
  .sn-hv.sheaf-r { right: 8px; }
  .sn-hv.pump-a  { left: 76px;  width: 68px; }
  .sn-hv.pump-b  { right: 76px; width: 62px; }
}
@media (max-height: 700px) {
  .sn-hv.wreath { display: none; }
  .sn-hv.sheaf-l, .sn-hv.sheaf-r { width: 74px; }
  .sn-hv.cornu { width: 186px; }
}

@media (prefers-reduced-motion: reduce) {
  .sn-hv { animation: none; opacity: var(--o, 0.95); }
}

/* =================== BLACK FRIDAY (the Friday after) ===================
   One day a year, on html[data-season="blackfriday"]. Read as "the
   holiday deliveries begin" rather than as retail advertising: an HOA
   page has no business running a sale. The falling leaves continue
   underneath, because it is still late November.

   !! Same two traps as the harvest. Clusters are pinned to the page
      edges in PIXELS, not percentages, so their internal spacing cannot
      collapse as the page narrows. And the arrival animation here is
      opacity only, because parcels-r is mirrored with scaleX(-1) and a
      keyframe ending on `transform: none` would silently un-mirror it. */

.sn-bf {
  position: absolute;
  opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(36, 31, 26, 0.2));
  animation: sn-hvin 1.1s ease-out var(--d, 0s) both;
}
.sn-bf.parcels-l { left: 18px;   bottom: -4px; width: 112px; --d: 0.12s; --o: 0.96; }
.sn-bf.tote      { left: 124px;  bottom: -2px; width: 78px;  --d: 0.30s; --o: 0.95; }
.sn-bf.parcels-r { right: 18px;  bottom: -4px; width: 96px;  --d: 0.20s; --o: 0.94;
                   transform: scaleX(-1); }

/* price tags drift down like the leaves, but a tag on a string sways -
   it does not tumble end over end the way a leaf does, so these get
   their own gentler keyframe instead of reusing sn-fall */
.sn-bftag {
  position: absolute; top: -8vh; width: 30px; opacity: 0;
  will-change: transform, opacity;
  animation: sn-bffall linear infinite;
}
.sn-bftag.t1 { left: 12%; animation-duration: 19s; animation-delay: -2s;  width: 26px; }
.sn-bftag.t2 { left: 34%; animation-duration: 24s; animation-delay: -11s; }
.sn-bftag.t3 { left: 61%; animation-duration: 21s; animation-delay: -6s;  width: 24px; }
.sn-bftag.t4 { left: 86%; animation-duration: 26s; animation-delay: -17s; width: 28px; }

@keyframes sn-bffall {
  0%   { transform: translate3d(0, 0, 0) rotate(-8deg); opacity: 0; }
  8%   { opacity: 0.8; }
  30%  { transform: translate3d(26px, 32vh, 0) rotate(9deg); }
  60%  { transform: translate3d(-20px, 64vh, 0) rotate(-10deg); }
  88%  { opacity: 0.62; }
  100% { transform: translate3d(14px, 116vh, 0) rotate(7deg); opacity: 0; }
}

@media (max-width: 760px) {
  .sn-bf.tote { display: none; }
  .sn-bf.parcels-l { width: 92px; left: 10px; }
  .sn-bf.parcels-r { width: 80px; right: 10px; }
  .sn-bftag.t2 { display: none; }
}
@media (max-height: 700px) {
  .sn-bf.parcels-l { width: 92px; }
  .sn-bf.parcels-r { width: 80px; }
  .sn-bf.tote { width: 66px; left: 104px; }
}

/* the parcels sit low and sparse, but the chips and any content at the
   foot of the viewport still win, same rule as the other two themes */
html[data-season="blackfriday"] .hero .container,
html[data-season="blackfriday"] .section .container,
html[data-season="blackfriday"] .notice-bar,
html[data-season="blackfriday"] .site-footer { position: relative; z-index: 4; }

@media (prefers-reduced-motion: reduce) {
  .sn-bf { animation: none; opacity: var(--o, 0.95); }
  .sn-bftag { animation: none; opacity: 0.6; top: auto; bottom: 22vh; }
}

/* ============ SMALL BUSINESS SATURDAY (the Saturday after) ============
   One day a year, on html[data-season="smallbiz"]. A little main street
   along the foot of the page: shopfront, planter, a coffee cup and a
   shopping bag (the same bag drawing the Friday uses). Leaves continue
   underneath. Same two rules as the other scenes: clusters pinned to the
   page edges in PIXELS, and an opacity-only arrival so nothing fights a
   positioning transform. */

.sn-sb {
  position: absolute;
  opacity: 0;
  filter: drop-shadow(0 1px 2px rgba(60, 44, 30, 0.2));
  animation: sn-hvin 1.1s ease-out var(--d, 0s) both;
}
.sn-sb.shop    { left: 16px;   bottom: -4px; width: 150px; --d: 0.12s; --o: 0.96; }
.sn-sb.planter { left: 158px;  bottom: -2px; width: 58px;  --d: 0.30s; --o: 0.95; }
.sn-sb.tote    { right: 110px; bottom: -2px; width: 68px;  --d: 0.46s; --o: 0.94; }
.sn-sb.cup     { right: 24px;  bottom: -2px; width: 46px;  --d: 0.36s; --o: 0.95; }

@media (max-width: 760px) {
  .sn-sb.planter { display: none; }
  .sn-sb.shop { width: 122px; left: 10px; }
  .sn-sb.tote { right: 86px; width: 58px; }
  .sn-sb.cup  { right: 16px; width: 40px; }
}
@media (max-height: 700px) {
  .sn-sb.shop { width: 122px; }
  .sn-sb.planter { width: 48px; left: 132px; }
}

html[data-season="smallbiz"] .hero .container,
html[data-season="smallbiz"] .section .container,
html[data-season="smallbiz"] .notice-bar,
html[data-season="smallbiz"] .site-footer { position: relative; z-index: 4; }

@media (prefers-reduced-motion: reduce) {
  .sn-sb { animation: none; opacity: var(--o, 0.95); }
}
