/* ============================================================
   Eco Bizzy Grove, ambient motion + atmosphere layer.
   Purely decorative: no text, no meaning, no functionality here.
   - Every non-essential animation is gated behind
     (prefers-reduced-motion: no-preference); with reduced motion
     the page renders fully visible and static, exactly as before.
   - Overlays are pointer-events:none (and aria-hidden in the HTML)
     so they can never block clicks, focus, or reading order.
   - All colors derive from the site tokens in site.css, so light
     and dark themes both work with no hardcoded palette.
   ============================================================ */

/* ---------------- 1. Hero atmosphere ---------------- */
/* .fx-sky sits under .wrap (z 2) and .buzz-wrap (z 1) */
.fx-sky{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }

/* Aurora: three big soft radial glows drifting slowly behind the headline.
   Parallax: grove-fx.js sets --mx / --my (mouse, -1..1) and --sy (scroll)
   on the hero; the translate property composes with the keyframe transform,
   so drift + parallax never fight each other. */
.fx-blob{
  position:absolute; border-radius:50%;
  translate:
    calc(var(--mx,0) * var(--px,12px))
    calc(var(--my,0) * var(--py,10px) + var(--sy,0) * var(--sp,0px));
  transition:translate 1.1s cubic-bezier(.22,.8,.26,1);
}
.fx-b1{ width:580px; height:580px; top:-230px; left:-150px; --px:20px; --py:12px; --sp:70px;
  background:radial-gradient(circle at 42% 42%, color-mix(in srgb, var(--gold) 30%, transparent), transparent 68%); }
.fx-b2{ width:660px; height:660px; top:-160px; right:-210px; --px:-26px; --py:-16px; --sp:110px;
  background:radial-gradient(circle at 55% 45%, color-mix(in srgb, var(--ink-dim) 26%, transparent), transparent 70%); }
.fx-b3{ width:480px; height:480px; bottom:-270px; left:30%; --px:14px; --py:18px; --sp:-50px;
  background:radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--gold) 22%, transparent), transparent 70%); }
/* light theme: quieter, warmer wash on the white background */
:root[data-theme="light"] .fx-b1{ background:radial-gradient(circle at 42% 42%, color-mix(in srgb, var(--gold) 17%, transparent), transparent 68%); }
:root[data-theme="light"] .fx-b2{ background:radial-gradient(circle at 55% 45%, color-mix(in srgb, var(--ink-dim) 16%, transparent), transparent 70%); }
:root[data-theme="light"] .fx-b3{ background:radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--gold) 12%, transparent), transparent 70%); }
@media (prefers-reduced-motion: no-preference){
  .fx-blob{ will-change:transform; }
  .fx-b1{ animation:fxDriftA 26s ease-in-out infinite alternate; }
  .fx-b2{ animation:fxDriftB 32s ease-in-out infinite alternate; }
  .fx-b3{ animation:fxDriftC 24s ease-in-out infinite alternate; }
}
@keyframes fxDriftA{ from{ transform:translate3d(0,0,0) scale(1) }    to{ transform:translate3d(60px,36px,0) scale(1.12) } }
@keyframes fxDriftB{ from{ transform:translate3d(0,0,0) scale(1.08) } to{ transform:translate3d(-70px,28px,0) scale(.96) } }
@keyframes fxDriftC{ from{ transform:translate3d(0,0,0) scale(.94) }  to{ transform:translate3d(46px,-30px,0) scale(1.1) } }

/* Honeycomb: a faint hex lattice (Buzz's home turf) that drifts very slowly.
   The lattice is a tiny inline-SVG mask over a token-gold fill, so it
   re-tints itself automatically in each theme. */
.fx-comb{
  position:absolute; inset:-60px; opacity:.05; background:var(--gold);
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='28'%20height='48'%20viewBox='0%200%2028%2048'%3E%3Cg%20fill='none'%20stroke='%23fff'%20stroke-width='1.2'%3E%3Cpath%20d='M14,-16L27.9,-8L27.9,8L14,16L0.1,8L0.1,-8Z'/%3E%3Cpath%20d='M14,32L27.9,40L27.9,56L14,64L0.1,56L0.1,40Z'/%3E%3Cpath%20d='M0,8L13.9,16L13.9,32L0,40L-13.9,32L-13.9,16Z'/%3E%3Cpath%20d='M28,8L41.9,16L41.9,32L28,40L14.1,32L14.1,16Z'/%3E%3C/g%3E%3C/svg%3E");
  mask-image:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='28'%20height='48'%20viewBox='0%200%2028%2048'%3E%3Cg%20fill='none'%20stroke='%23fff'%20stroke-width='1.2'%3E%3Cpath%20d='M14,-16L27.9,-8L27.9,8L14,16L0.1,8L0.1,-8Z'/%3E%3Cpath%20d='M14,32L27.9,40L27.9,56L14,64L0.1,56L0.1,40Z'/%3E%3Cpath%20d='M0,8L13.9,16L13.9,32L0,40L-13.9,32L-13.9,16Z'/%3E%3Cpath%20d='M28,8L41.9,16L41.9,32L28,40L14.1,32L14.1,16Z'/%3E%3C/g%3E%3C/svg%3E");
  -webkit-mask-size:28px 48px; mask-size:28px 48px;
  -webkit-mask-repeat:repeat; mask-repeat:repeat;
}
:root[data-theme="light"] .fx-comb{ opacity:.06; }
@media (prefers-reduced-motion: no-preference){
  .fx-comb{ animation:fxCombDrift 90s linear infinite; }
}
/* one full tile period, so the loop is seamless */
@keyframes fxCombDrift{ to{ transform:translate3d(28px,48px,0) } }

/* Pollen: little gold motes rising through the hero (grove-fx.js seeds them,
   and only when motion is allowed, so reduced motion gets none at all). */
.fx-pollen{ position:absolute; inset:0; }
.fx-mote{
  position:absolute; bottom:-18px; border-radius:50%; opacity:0;
  background:color-mix(in srgb, var(--gold) 85%, #fff);
}
:root:not([data-theme="light"]) .fx-mote{
  box-shadow:0 0 10px 1px color-mix(in srgb, var(--gold) 50%, transparent);  /* firefly glow at night */
}
:root[data-theme="light"] .fx-mote{ background:color-mix(in srgb, var(--gold) 80%, transparent); }
.fx-mote-big{ filter:blur(2px); }
@media (prefers-reduced-motion: no-preference){
  .fx-mote{ animation:fxRiseMote linear infinite; }
}
@media (prefers-reduced-motion: reduce){
  .fx-pollen{ display:none; }
}
@keyframes fxRiseMote{
  0%  { transform:translate3d(0,0,0); opacity:0 }
  8%  { opacity:var(--op,.4) }
  85% { opacity:var(--op,.4) }
  100%{ transform:translate3d(var(--drift,40px),-560px,0); opacity:0 }
}

/* ---------------- 2. Buzz, alive ---------------- */
/* Warm halo behind the mascot (kept as a static soft glow under reduced motion) */
.fx-buzz-halo{
  position:absolute; z-index:-1; left:50%; top:50%; width:124%; aspect-ratio:1;
  translate:-50% -50%; border-radius:50%;
  background:radial-gradient(circle, color-mix(in srgb, var(--gold) 28%, transparent) 0%, transparent 62%);
}
:root[data-theme="light"] .fx-buzz-halo{
  background:radial-gradient(circle, color-mix(in srgb, var(--gold) 18%, transparent) 0%, transparent 62%);
}
@media (prefers-reduced-motion: no-preference){
  .fx-buzz-halo{ animation:fxHaloPulse 5.5s ease-in-out infinite alternate; }
  /* entrance, then hand off to the existing buzzFloat idle bob (grove.html) */
  .buzz-wrap{
    animation:fxBuzzIn .9s cubic-bezier(.22,1,.36,1) both,
              buzzFloat 6s ease-in-out .9s infinite;
  }
  /* the PNG itself: a slow sway plus a quick wing-buzz jiggle every few seconds */
  .buzz-wrap .buzz{
    transform-origin:50% 62%;
    animation:fxBuzzSway 7s ease-in-out infinite, fxBuzzJig 9s linear infinite;
  }
}
@keyframes fxHaloPulse{ from{ transform:scale(.94); opacity:.75 } to{ transform:scale(1.06); opacity:1 } }
@keyframes fxBuzzIn{
  from{ opacity:0; transform:translateY(-44%) scale(.9) }
  to  { opacity:1; transform:translateY(-50%) scale(1) }
}
@keyframes fxBuzzSway{ 0%,100%{ transform:rotate(-1.5deg) } 50%{ transform:rotate(1.8deg) } }
@keyframes fxBuzzJig{
  0%,86%,100%{ translate:0 0 }
  88%{ translate:-2px 0 } 90%{ translate:2.5px -1px }
  92%{ translate:-2.5px 1px } 94%{ translate:2px 0 } 96%{ translate:0 0 }
}

/* ---------------- 3. Hero content entrance ---------------- */
/* Keyframe-only (no base opacity:0), so if anything fails the text just shows. */
@media (prefers-reduced-motion: no-preference){
  .grove-hero .eyebrow          { animation:fxHeroUp .7s cubic-bezier(.22,1,.36,1) both; }
  .grove-hero h1                { animation:fxHeroUp .8s cubic-bezier(.22,1,.36,1) .1s both; }
  .grove-hero .lead             { animation:fxHeroUp .8s cubic-bezier(.22,1,.36,1) .2s both; }
  .grove-hero .hero-cta         { animation:fxHeroUp .8s cubic-bezier(.22,1,.36,1) .3s both; }
  .grove-hero .wrap > p:not(.lead){ animation:fxHeroUp .8s cubic-bezier(.22,1,.36,1) .42s both; }
}
@keyframes fxHeroUp{ from{ opacity:0; transform:translate3d(0,18px,0) } }

/* ---------------- 4. Scroll reveal ---------------- */
/* grove-fx.js adds .fx-reveal (candidate) then .fx-in (visible) via one
   IntersectionObserver. The hidden state only exists when motion is allowed
   AND the class was added by JS, so there is no way to strand content. */
@media (prefers-reduced-motion: no-preference){
  .fx-reveal:not(.fx-in){ opacity:0; }
  .fx-in{ animation:fxRiseIn .75s cubic-bezier(.22,1,.36,1) var(--fxd,0ms) backwards; }
  /* a small gold underline grows in under revealed section titles */
  .sec-head.fx-reveal h2::after{
    content:""; display:block; width:0; height:3px; margin-top:14px;
    border-radius:2px; background:var(--gold);
    transition:width .8s cubic-bezier(.22,1,.36,1) .35s;
  }
  .sec-head.fx-in h2::after{ width:56px; }
}
@keyframes fxRiseIn{
  from{ opacity:0; transform:translate3d(0,24px,0) }
  to  { opacity:1; transform:none }
}

/* ---------------- 5. Vine dividers ---------------- */
.fx-divider{ max-width:560px; margin:30px auto 0; padding:0 26px; pointer-events:none; }
.fx-divider svg{ display:block; width:100%; height:auto; color:var(--gold); opacity:.8; }
.fx-stem{ fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; }
.fx-leaf{ fill:color-mix(in srgb, currentColor 26%, transparent); stroke:currentColor; stroke-width:1.2; stroke-linejoin:round; }
.fx-hex{ fill:none; stroke:currentColor; stroke-width:1.4; stroke-linejoin:round; }
@media (prefers-reduced-motion: no-preference){
  .fx-divider .fx-leaf, .fx-divider .fx-hex{ transform-box:fill-box; transform-origin:center; }
  /* stems draw outward from the center hex; leaves pop in after (per-leaf --fxld) */
  .fx-divider.fx-reveal:not(.fx-in) .fx-stem{ stroke-dasharray:300; stroke-dashoffset:300; }
  .fx-divider.fx-in .fx-stem{
    stroke-dasharray:300; stroke-dashoffset:0;
    transition:stroke-dashoffset 1.5s cubic-bezier(.4,0,.2,1) .15s;
  }
  .fx-divider.fx-reveal:not(.fx-in) .fx-leaf,
  .fx-divider.fx-reveal:not(.fx-in) .fx-hex{ opacity:0; transform:scale(.4); }
  .fx-divider.fx-in .fx-leaf,
  .fx-divider.fx-in .fx-hex{
    opacity:1; transform:scale(1);
    transition:opacity .5s ease var(--fxld,.5s),
               transform .6s cubic-bezier(.34,1.56,.64,1) var(--fxld,.5s);
  }
}

/* ---------------- 6. Listing cards ---------------- */
.gcard{ position:relative; }
/* cursor-following gold glare (grove-fx.js sets --gx / --gy); a tint only,
   pointer-events:none, clipped by the card's own overflow:hidden */
@media (hover:hover) and (pointer:fine){
  .gcard::after{
    content:""; position:absolute; inset:0; z-index:1; pointer-events:none; opacity:0;
    background:radial-gradient(420px circle at var(--gx,50%) var(--gy,35%),
      color-mix(in srgb, var(--gold) 15%, transparent), transparent 62%);
    transition:opacity .35s ease;
  }
  .gcard:hover::after{ opacity:1; }
  .gcard:hover{
    box-shadow:0 22px 48px -24px color-mix(in srgb, var(--emerald) 60%, transparent),
               0 0 0 1px color-mix(in srgb, var(--gold) 35%, transparent);
  }
}
@media (prefers-reduced-motion: no-preference) and (hover:hover) and (pointer:fine){
  /* smooth the JS tilt (inline transform) in and out */
  .gcard{ transition:transform .25s cubic-bezier(.22,1,.36,1), border-color .18s, box-shadow .35s ease; }
}

/* ---------------- 7. Micro-interactions ---------------- */
/* primary button: a soft shine sweeps across on hover */
.btn-gold{ position:relative; overflow:hidden; }
@media (prefers-reduced-motion: no-preference){
  .btn-gold::after{
    content:""; position:absolute; inset:0; pointer-events:none;
    background:linear-gradient(115deg, transparent 32%, rgba(255,255,255,.22) 46%,
      rgba(255,255,255,.4) 50%, rgba(255,255,255,.22) 54%, transparent 68%);
    transform:translateX(-130%);
  }
  .btn-gold:hover::after{ transform:translateX(130%); transition:transform .7s ease; }
  .btn-ghost:hover{ transform:translateY(-1px); }
  .linklike{ transition:color .18s, translate .25s cubic-bezier(.22,1,.36,1); }
  .linklike:hover{ translate:3px 0; }
  .filter-chip.active{ animation:fxChipPop .3s cubic-bezier(.34,1.56,.64,1); }
  .filter-chip:hover{ transform:translateY(-1px); }
  .filter-chip{ transition:transform .18s, color .18s, background .18s, border-color .18s; }
}
@keyframes fxChipPop{ 50%{ transform:scale(1.08) } }
/* focus glow on the search + city filter (visibility aid, not motion) */
.grove-search:focus, .grove-city:focus{
  box-shadow:0 0 0 3px color-mix(in srgb, var(--gold) 22%, transparent);
}
/* footprint teaser: a warm static glow in the corner, pulsing when allowed */
.fp-teaser{ position:relative; overflow:hidden; }
.fp-teaser::before{
  content:""; position:absolute; top:-130px; right:-90px; width:360px; height:360px;
  border-radius:50%; pointer-events:none;
  background:radial-gradient(circle, color-mix(in srgb, var(--gold) 16%, transparent), transparent 65%);
}
@media (prefers-reduced-motion: no-preference){
  .fp-teaser::before{ animation:fxHaloPulse 6s ease-in-out infinite alternate; }
}

/* ---------------- 8. Modal + form success ---------------- */
@media (prefers-reduced-motion: no-preference){
  .modal-overlay.show{ animation:fxFadeIn .22s ease both; }
  .modal-overlay.show .modal{ animation:fxModalIn .34s cubic-bezier(.22,1,.36,1) both; }
  .success.show .badge{ animation:fxBadgePop .55s cubic-bezier(.34,1.56,.64,1); }
}
.modal{ box-shadow:0 40px 90px -40px rgba(0,0,0,.6); }
@keyframes fxFadeIn{ from{ opacity:0 } }
@keyframes fxModalIn{ from{ opacity:0; transform:translateY(14px) scale(.97) } }
@keyframes fxBadgePop{ 0%{ transform:scale(.4) } 60%{ transform:scale(1.15) } 100%{ transform:scale(1) } }
