/* badbee.dev — alpine meadow scene
   vanilla CSS only, FOSS-only stack (system fonts + own SVG).

   Layer order (back→front):
     L1 sky / sun / clouds / birds
     L2 far snow-capped Swiss alps
     L3 mid forested mountains
     L4 rolling hills + chalet
     L5 far meadow + sparse flowers
     L6 title sign
     L7 mid meadow + flowers
     L8 foreground grass + flowers
   then: bees, particles, extras (overlays)
*/

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }

html {
  /* matches the scene roughly so any parallax sliver blends instead of contrasts */
  background: linear-gradient(180deg, #7ec8e3 0%, #bfe3f1 35%, #8fc35f 70%, #234d12 100%);
  color-scheme: light;
}

body {
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  opacity: 0;
  animation: fade-in 0.5s ease-out 0.05s forwards;
}
@keyframes fade-in {
  to { opacity: 1; }
}

.scene {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  cursor: crosshair;
  /* parallax base point — JS sets these to mouse offset */
  --px: 0;
  --py: 0;
}

.defs { position: absolute; width: 0; height: 0; pointer-events: none; }

/* every layer fills the viewport and stacks via z-index */
.layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  will-change: transform;
}
.layer .fill { width: 100%; height: 100%; display: block; overflow: visible; }

.layer-1     { z-index: 1;  --depth: 0.02; }
.layer-2     { z-index: 2;  --depth: 0.06; }
.layer-3     { z-index: 3;  --depth: 0.10; }
.layer-skies { z-index: 4;  --depth: 0.04; }   /* clouds + birds in front of mountains */
/* haze-far at z=5 */
.layer-4     { z-index: 6;  --depth: 0.16; }
.layer-5     { z-index: 7;  --depth: 0.24; }
/* haze-mid at z=8 */
.layer-6     { z-index: 9;  --depth: 0.32; }
.layer-7     { z-index: 10; --depth: 0.50; }
.layer-8     { z-index: 11; --depth: 0.85; }

/* parallax: each layer shifts proportionally to depth */
.layer {
  transform: translate3d(
    calc(var(--px, 0) * var(--depth) * -1px),
    calc(var(--py, 0) * var(--depth) * -1px),
    0
  );
}

/* ======= horizon haze (atmospheric perspective) ======= */
.haze {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;  /* between L3 mid-mountains and L4 hills */
}
.haze-far {
  z-index: 5;  /* between skies and L4 hills */
  background: linear-gradient(180deg,
    rgba(255,255,255,0) 50%,
    rgba(255,255,255,0.45) 65%,
    rgba(255,250,220,0.32) 78%,
    rgba(255,250,220,0) 85%);
  mix-blend-mode: screen;
}
.haze-mid {
  z-index: 8;  /* between L5 far meadow and L6 title */
  background: linear-gradient(180deg,
    rgba(255,255,200,0) 60%,
    rgba(255,235,180,0.18) 75%,
    rgba(255,235,180,0) 90%);
  mix-blend-mode: soft-light;
}

/* ======= L1: sky ======= */
.sun { transform-origin: 1440px 100px; animation: sun-pulse 7s ease-in-out infinite; cursor: pointer; }
.sun-face { opacity: 0; transition: opacity 0.18s ease; pointer-events: none; }
#sun.ouch .sun-face { opacity: 1; }
#sun.ouch #sun-disc { fill: #ffd95a; }
@keyframes sun-pulse {
  0%,100% { filter: brightness(1); transform: scale(1); }
  50%     { filter: brightness(1.06); transform: scale(1.03); }
}
/* sun rays rotate via inline <animateTransform>; CSS only handles the
   parent group's pulse via the .sun selector above. */

.cloud {
  opacity: 0.95;
  /* soft blue-gray underbelly so white clouds keep definition when they
     drift over the alps' white snow caps. */
  filter: drop-shadow(0 3px 4px rgba(40, 60, 90, 0.32));
}
.cloud--a { animation: drift-a 110s linear infinite; animation-delay: -38s; }
.cloud--b { animation: drift-b 160s linear infinite; animation-delay: -90s; }
.cloud--c { animation: drift-c 200s linear infinite; animation-delay: -150s; }
@keyframes drift-a {
  0%   { transform: translate(-200px, 110px); }
  100% { transform: translate(1900px, 110px); }
}
@keyframes drift-b {
  0%   { transform: translate(-300px, 200px); }
  100% { transform: translate(2000px, 200px); }
}
@keyframes drift-c {
  0%   { transform: translate(-260px, 60px); }
  100% { transform: translate(1900px, 60px); }
}

.bird {
  animation: bird-fly 80s linear infinite;
  transform-origin: 0 0;
  opacity: 0.85;
}
.bird.b1 { animation-duration: 70s; animation-delay: -20s; }
.bird.b2 { animation-duration: 95s; animation-delay: -45s; }
@keyframes bird-fly {
  0%   { transform: translate(-50px, 280px) scale(1); opacity: 0; }
  10%  { opacity: 0.85; }
  50%  { transform: translate(800px, 180px) scale(0.7); }
  90%  { opacity: 0.85; }
  100% { transform: translate(1700px, 240px) scale(0.4); opacity: 0; }
}

/* ======= L3: pines lean a touch in the wind ======= */
/* translate (not rotate) — rotate around fill-box on <use> swings wildly
   because Chromium computes the bbox from the symbol's local viewBox. */
.pines use {
  animation: breeze-tiny 9s ease-in-out infinite;
}
.pines use:nth-child(2n) { animation-duration: 11s; animation-delay: -2.5s; }
.pines use:nth-child(3n) { animation-duration: 12.5s; animation-delay: -5s; }
@keyframes breeze-tiny {
  0%,100% { translate: 0 0; }
  50%     { translate: 1px 0; }
}

/* ======= L4: chalet ======= */
.chalet { cursor: pointer; pointer-events: auto; }
.chalet .door {
  animation: window-glow 3.6s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: left center;
  transition: transform 0.35s ease, opacity 0.35s ease;
}
@keyframes window-glow {
  0%,100% { fill: #f7c948; }
  50%     { fill: #ffe27a; }
}
.chalet .old-lady {
  opacity: 0;
  transition: opacity 0.3s ease 0.15s;  /* fade in slightly after door opens */
}
.chalet.door-open .door {
  transform: scaleX(0.12);              /* swung-aside look */
  animation: none;
  fill: #d99a1f;
}
.chalet.door-open .old-lady {
  opacity: 1;
  transition-delay: 0.2s;
}
.chimney-smoke .puff {
  animation: puff-rise 5s ease-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}
.chimney-smoke .p1 { animation-delay: 0s;   }
.chimney-smoke .p2 { animation-delay: -1.7s; }
.chimney-smoke .p3 { animation-delay: -3.4s; }
@keyframes puff-rise {
  0%   { transform: translate(0, 0) scale(0.5); opacity: 0; }
  20%  { opacity: 0.85; }
  100% { transform: translate(-3px, -22px) scale(1.7); opacity: 0; }
}

/* ======= L5/7/8: flowers nudge in the breeze ======= */
/* translate-only; see pines comment above for why rotate misbehaves on <use>. */
.far-flowers use { animation: breeze-tiny 8s ease-in-out infinite; }

.mid-flowers, .near-flowers { cursor: pointer; }
.mid-flowers use  { animation: breeze-small 7s ease-in-out infinite; }
.mid-flowers use:nth-child(2n) { animation-duration: 8.4s; animation-delay: -1.6s; }
.mid-flowers use:nth-child(3n) { animation-duration: 9.2s; animation-delay: -3.1s; }

.near-flowers use { animation: breeze-small 6.5s ease-in-out infinite; }
.near-flowers use:nth-child(2n) { animation-duration: 7.8s; animation-delay: -1.4s; }
.near-flowers use:nth-child(3n) { animation-duration: 9s;   animation-delay: -3.3s; }
@keyframes breeze-small {
  0%,100% { translate: 0 0; }
  50%     { translate: 1.5px -0.5px; }
}

.grass use { animation: breeze-grass 5s ease-in-out infinite; }
.grass use:nth-child(2n) { animation-duration: 6.4s; animation-delay: -1.2s; }
.grass use:nth-child(3n) { animation-duration: 7.1s; animation-delay: -2.5s; }
@keyframes breeze-grass {
  0%,100% { translate: 0 0; }
  50%     { translate: 2px 0; }
}

/* ======= L6: title ======= */
.title {
  position: absolute;
  left: 50%;
  top: 46%;
  transform: translate(-50%, -50%);
  margin: 0;
  display: grid;                /* stack shadow + main in same grid cell */
  font-family: "Arial Black", "Helvetica Neue Black", Impact, "Segoe UI", system-ui, sans-serif;
  font-weight: 900;
  font-size: clamp(56px, 12vw, 200px);
  letter-spacing: -0.04em;
  line-height: 0.9;
  text-align: center;
  white-space: nowrap;
  user-select: none;
  pointer-events: auto;
  cursor: pointer;
  animation: title-bob 5.5s ease-in-out infinite;
  transition: filter 0.25s ease;
}
.title:hover .title-main {
  filter: drop-shadow(0 6px 0 rgba(0,0,0,0.18)) drop-shadow(0 0 18px rgba(255,230,120,0.7));
}
.title-shadow,
.title-main {
  grid-area: 1 / 1;
  display: block;
}
.title-shadow {
  color: transparent;
  -webkit-text-stroke: 14px #1a2a14;
  filter: blur(0.4px) drop-shadow(0 12px 0 rgba(0,0,0,0.22));
  transform: translate(6px, 6px);
}
.title-main {
  color: #fff7d6;
  -webkit-text-stroke: 6px #2b3d1a;
  background: linear-gradient(180deg, #fff5b0 0%, #f7c948 60%, #d99a1f 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
  paint-order: stroke fill;
  filter: drop-shadow(0 6px 0 rgba(0,0,0,0.18));
}
@keyframes title-bob {
  0%,100% { transform: translate(-50%, -50%) rotate(-0.4deg); }
  50%     { transform: translate(-50%, calc(-50% - 6px)) rotate(0.4deg); }
}

/* ======= bees ======= */
.bees, .particles, .extras, .bee-pollen {
  position: absolute;
  inset: 0;
  z-index: 12;
  pointer-events: none;
}
/* sits between foreground grass (layer-8 z=11) and the bees so pollen
   drips/puffs read as falling behind the bee that emitted them. */
.bee-pollen { z-index: 11; }
.particles  { z-index: 13; }
.extras     { z-index: 14; }

.bee {
  position: absolute;
  left: 0; top: 0;
  width: 60px; height: 40px;
  /* offset-path is set per-bee inline */
  offset-rotate: auto;
  animation-name: bee-fly, bee-bob;
  animation-iteration-count: infinite, infinite;
  animation-timing-function: linear, ease-in-out;
  pointer-events: auto;
  cursor: pointer;
}
.bee svg { width: 100%; height: 100%; display: block; overflow: visible; }
.bee .bee-wings {
  transform-origin: 0 -10px;
  animation: wingflap 0.07s ease-in-out infinite;
}
@keyframes wingflap {
  0%,100% { transform: scaleY(1); }
  50%     { transform: scaleY(0.35); }
}
@keyframes bee-fly {
  0%   { offset-distance: 0%; }
  100% { offset-distance: 100%; }
}
@keyframes bee-bob {
  0%,100% { translate: 0 0; }
  50%     { translate: 0 -6px; }
}

/* a bee flying right→left: kill the auto-rotate (which would put wings
   below the body) and mirror horizontally so the head leads the motion. */
.bee.bee--left {
  offset-rotate: 0deg;
  transform: scaleX(-1);
}

/* freeze every animation while the tab is hidden — prevents anything
   from queueing or accumulating in the background. */
body.paused *,
body.paused *::before,
body.paused *::after {
  animation-play-state: paused !important;
}

/* ======= particles ======= */
.pollen, .snowflake {
  position: absolute;
  width: 10px; height: 10px;
  pointer-events: none;
  will-change: transform, opacity;
}
.pollen {
  /* deeper amber edge + a faint dark halo so pollen pops against the
     white alpine peaks during the title-click burst. */
  background: radial-gradient(circle, #fff5a0 0%, #ffc940 50%, #d99a1f 76%, transparent 82%);
  border-radius: 50%;
  width: 6px; height: 6px;
  opacity: 0.95;
  filter: drop-shadow(0 0 1px rgba(80, 50, 0, 0.55));
  /* gravity-style ease-in: starts slow, accelerates downward */
  animation: pollen-fall 3s cubic-bezier(0.45, 0.05, 0.85, 0.5) forwards;
}
.pollen.up {
  /* ease-out: pollen lifts off and gradually slows as it rises */
  animation-timing-function: cubic-bezier(0.18, 0.7, 0.45, 1);
}
@keyframes pollen-fall {
  0%   { transform: translate(0, 0); opacity: 0; }
  10%  { opacity: 0.9; }
  100% { transform: translate(var(--dx, 0), var(--dy, 200px)); opacity: 0; }
}
.snowflake {
  background: radial-gradient(circle, #ffffff 0%, #ffffff 45%, transparent 75%);
  border-radius: 50%;
  width: 7px; height: 7px;
  animation: snow-fall linear forwards;
}
@keyframes snow-fall {
  0%   { transform: translate(0, 0) rotate(0); opacity: 0; }
  10%  { opacity: 0.95; }
  90%  { opacity: 0.95; }
  100% { transform: translate(var(--dx, 0), var(--dy, 320px)) rotate(360deg); opacity: 0; }
}

/* storm: darken the alps, the drift clouds, and the sky itself */
.alps-rock,
.layer-1 .fill,
.clouds-far {
  transition: filter 0.6s ease;
}
body.storming .alps-rock  { filter: brightness(0.55) saturate(0.75); }
body.storming .clouds-far { filter: brightness(0.78) saturate(0.85); }
body.storming .layer-1 .fill { filter: brightness(0.72) saturate(0.85); }

/* sun-click "ouch" tint: a subtle blood-red wash over the whole scene.
   Lands during the 380ms wince-shake then holds well past the sun's
   ouch-face for a slow burn before fading. Uses mix-blend-mode: multiply
   so the red darkens existing colours rather than overlaying flat — sky
   and snow turn ruddy, grass deepens, gold pollen warms. Pseudo-element
   on .scene so it sits above every layer/bee/particle but inside the
   scene's stacking context. */
.scene::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: rgb(170, 25, 25);
  mix-blend-mode: multiply;
  opacity: 0;
  z-index: 40;
}
body.sun-ouch .scene::after {
  animation: sun-ouch-tint 2.4s cubic-bezier(0.2, 0.65, 0.4, 1) forwards;
}
@keyframes sun-ouch-tint {
  0%   { opacity: 0; }
  9%   { opacity: 0.30; }   /* peak lands mid-wince (~215ms) */
  72%  { opacity: 0.22; }   /* hold past the ouch face */
  100% { opacity: 0; }      /* fade out */
}

/* lightning flash */
.lightning-flash {
  position: fixed;
  inset: 0;
  background: rgba(255,255,255,0.95);
  pointer-events: none;
  z-index: 100;
  animation: lightning-strobe 0.5s ease-out forwards;
}
@keyframes lightning-strobe {
  0%   { opacity: 0; }
  8%   { opacity: 1; }
  20%  { opacity: 0.2; }
  30%  { opacity: 0.95; }
  100% { opacity: 0; }
}

/* full-screen "boom" flash on title click: dark green vignette echoing the
   title's stroke (#1a2a14). Snaps on instantly (no fade-in), holds for ~40%
   of the duration so the moment is readable, then fades out. The radial
   gradient is centred on the title so the surrounding scene plunges into
   darkness while the title sits in a clearer pocket — combined with
   z-promotion below, the letters and gold pollen punch through. */
.boom-flash {
  position: fixed;
  inset: 0;
  /* gradient stops dropped by ~30% (0.5 → 0.35, 0.96 → 0.67) so the dark
     vignette reads as a translucent wash rather than a near-blackout. */
  background: radial-gradient(
    ellipse 48% 36% at var(--cx, 50%) var(--cy, 46%),
    rgba(26, 42, 20, 0) 0%,
    rgba(26, 42, 20, 0.5) 60%,
    rgba(15, 25, 12, 0.85) 100%
  );
  pointer-events: none;
  z-index: 50;
  opacity: 0;
  animation: boom-flash 1.65s cubic-bezier(0.16, 0.6, 0.4, 1) forwards;
}
@keyframes boom-flash {
  0%   { opacity: 1; }   /* snap on, no fade-in */
  51%  { opacity: 1; }   /* hold ~0.84s — dark lands first, ring/pollen punch in at 0.2s */
  100% { opacity: 0; }
}

/* expanding shockwave rings radiating outward from the title — gold leads,
   cream highlight trails. Visible motion is what sells the explosion;
   uniform dimming alone reads as a power blink. */
.boom-ring {
  position: fixed;
  /* width/height set inline to the title's bbox + pad; capsule radius hugs
     the title shape. Starts at scale 0 (a point at the title centre) and
     expands outward. z=51 sits under the title (z=60 during boom) so the
     letters always mask the ring wherever they exist. */
  border-radius: 9999px;
  border: 12px solid #f7c948;
  pointer-events: none;
  z-index: 51;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0);
  animation: boom-ring 1.0s cubic-bezier(0.42, 0, 1, 1) forwards;
}
@keyframes boom-ring {
  0%   { opacity: 1; transform: translate(-50%, -50%) scale(0);   border-width: 14px; }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(5.5); border-width: 2px; }
}

/* during the boom, lift the title + pollen above the dark overlay so the
   letters and gold ring pop through; everything else darkens. */
body.title-boom .layer-6  { z-index: 60; }
body.title-boom .particles { z-index: 61; }

/* SVG zigzag bolt */
.bolt {
  position: absolute;
  pointer-events: none;
  z-index: 99;
  animation: bolt-fade 0.35s ease-out forwards;
  filter: drop-shadow(0 0 8px #fff7a8);
}
@keyframes bolt-fade {
  0%   { opacity: 0; }
  15%  { opacity: 1; }
  100% { opacity: 0; }
}
/* ======= butterfly ======= */
.butterfly {
  position: absolute;
  width: 38px; height: 32px;
  offset-rotate: auto;
  animation: bee-fly 22s linear forwards;
  pointer-events: none;
  z-index: 11;
}
.butterfly svg { width: 100%; height: 100%; display: block; }
.butterfly .bf-wings {
  transform-origin: center;
  animation: bf-flap 0.18s ease-in-out infinite;
}
@keyframes bf-flap {
  0%,100% { transform: scaleX(1); }
  50%     { transform: scaleX(0.55); }
}

/* ======= rainbow easter egg ======= */
body.rainbow .scene { animation: hue-shift 6s linear infinite; }
@keyframes hue-shift {
  0%   { filter: hue-rotate(0deg); }
  100% { filter: hue-rotate(360deg); }
}

/* ======= a11y: reduced motion ======= */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001s !important;
  }
  body  { opacity: 1; }
  .layer { transform: none !important; }
  .bee   { display: none; }
  .particles, .extras, .bee-pollen { display: none; }
}

/* ======= small viewports ======= */
@media (max-width: 520px) {
  .title {
    font-size: clamp(34px, 13vw, 100px);
    letter-spacing: -0.05em;
  }
  .title-shadow { -webkit-text-stroke-width: 10px; }
  .title-main   { -webkit-text-stroke-width: 4px; }
  .layer-4 .chalet { display: none; } /* keep mid layer clean on phones */
}

/* ======= version pill ======= */
.version-pill {
  position: fixed;
  bottom: 8px;
  right: 8px;
  z-index: 50;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(0,0,0,0.25);
  color: #fff;
  font: 600 13px/22px ui-monospace, SFMono-Regular, Consolas, monospace;
  text-align: center;
  text-decoration: none;
  opacity: 0.45;
  transition: opacity 0.2s ease;
}
.version-pill:hover { opacity: 1; }

/* ======= noscript ======= */
.noscript-note {
  position: fixed; bottom: 8px; left: 50%; transform: translateX(-50%);
  background: rgba(255,255,255,0.85);
  color: #1a1a1a;
  padding: 4px 10px;
  border-radius: 8px;
  font-size: 13px;
  z-index: 50;
}
