/* EkoVille — map markers: monsters, pickups, stops, player, zoom scale.
   Split of the old styles.css; index.html loads these in order (cascade order matters). */

/* ============================== Monsters & markers ============================== */
/* Zoom-aware marker scale: every marker's html sits in a .mw wrapper (the roots
   can't be scaled directly — monIn fills `both`, which pins their transform).
   GameMap.cycleZoom tags #map with zoom-mid/zoom-far and everything shrinks. */
#map.zoom-mid{--mkscale:.72}
#map.zoom-far{--mkscale:.5}
/* Rinki-ekopisteet shrink LESS: they are the delivery destinations you zoom
   out to find, so they must stay landmark-sized. (.truckm keeps the default —
   it announces itself with a toast + guide arrow.) */
#map.zoom-mid .stopm:not(.truckm) .mw{--mkscale:.88}
#map.zoom-far .stopm:not(.truckm) .mw{--mkscale:.72}
.mw{width:100%;height:100%;transform:scale(var(--mkscale,1));transform-origin:50% 50%;transition:transform .3s ease}

.mon{width:62px;height:74px;position:relative;animation:monIn .35s var(--ease-back) both}
@keyframes monIn{from{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}
.mon.gone{animation:none;opacity:0;transform:scale(.4);transition:opacity .35s,transform .35s}
.mon .crt{width:60px;height:60px;display:block;margin:0 auto;animation:bob 1.6s ease-in-out infinite;filter:drop-shadow(0 4px 5px rgba(0,0,0,.3))}
img.crt{object-fit:contain}
.cwrap{position:relative;display:inline-block}
.cwrap .evostar{position:absolute;top:-2px;right:-4px;width:26px;height:26px;border-radius:50%;background:linear-gradient(180deg,var(--gold-1),var(--gold-2));color:var(--gold-t);font-size:15px;font-style:normal;display:grid;place-items:center;border:2px solid #fff;box-shadow:0 3px 7px rgba(180,120,20,.45)}
.mon .bang{position:absolute;top:-8px;left:50%;transform:translateX(-50%);z-index:2;font-family:var(--display);font-weight:800;color:#fff;background:linear-gradient(180deg,var(--red-1),var(--red-2));width:22px;height:22px;border-radius:50%;display:none;place-items:center;font-size:13px;border:2px solid #fff;box-shadow:0 3px 6px rgba(0,0,0,.3)}
.mon.near .bang{display:grid;animation:pulse 1s infinite}
/* Countdown chip above the trash: how long until it despawns. Mirrors the truck
   timer. Hidden once in catch range — the "!" bang takes over there. */
.mon .montime{position:absolute;left:50%;bottom:100%;margin-bottom:5px;transform:translateX(-50%);z-index:6;
  font-family:var(--display);font-weight:800;font-size:11px;color:#fff;white-space:nowrap;font-variant-numeric:tabular-nums;
  padding:1px 7px;border-radius:99px;border:2px solid #fff;background:linear-gradient(180deg,var(--gold-2),var(--gold-d));
  box-shadow:0 2px 4px rgba(0,0,0,.3);text-shadow:0 1px 1px rgba(80,50,0,.5)}
.mon .montime.low{background:linear-gradient(180deg,var(--red-2),var(--red-d));animation:trucktimelow .8s ease-in-out infinite}
.mon.near .montime{display:none}
.mon.near .crt{animation:bob .9s ease-in-out infinite}
@keyframes bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
@keyframes pulse{0%,100%{transform:translateX(-50%) scale(1)}50%{transform:translateX(-50%) scale(1.25)}}
.mon.expiring{animation:expire .7s ease-in-out infinite}
/* ===== World pickups (power charges + XP lying on the ground) =====
   A disc on a pulsing halo, NOT a sticker: trash is a task you tap, a pickup is
   a reward you walk over, and the two shapes must not be confusable. */
.pick{position:relative;width:54px;height:54px;animation:monIn .35s var(--ease-back) both}
/* the base transform matters for reduced-motion, where the bob keyframes (which
   also carry the centring) never run */
.pick .pdisc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:40px;height:40px;border-radius:50%;
  display:grid;place-items:center;font-size:21px;line-height:1;z-index:2;
  background:linear-gradient(180deg,var(--k1),var(--k2));border:3px solid #fff;
  box-shadow:0 4px 0 var(--kd),0 7px 14px rgba(20,40,80,.4),inset 0 2px 0 rgba(255,255,255,.55);
  animation:pickbob 1.7s ease-in-out infinite}
.pick.xp{--k1:var(--gold-1);--k2:var(--gold-2);--kd:var(--gold-d);--kg:255,190,60}
.pick.magnet{--k1:var(--red-1);--k2:var(--red-2);--kd:var(--red-d);--kg:255,90,120}
.pick.freeze{--k1:var(--shiny-1);--k2:var(--shiny-2);--kd:var(--shiny-d);--kg:60,210,235}
.pick.refresh{--k1:var(--gold-1);--k2:var(--gold-2);--kd:var(--gold-d);--kg:255,190,60}
.pick.pat{--k1:var(--green-1);--k2:var(--green-2);--kd:var(--green-d);--kg:90,220,110}
/* Two offset halos so there is never a dead beat — same reasoning as the shiny
   ping: it is the motion that finds the eye across a busy map. */
.pick .phalo{position:absolute;left:27px;top:27px;width:52px;height:52px;margin:-26px 0 0 -26px;border-radius:50%;
  border:3px solid rgba(var(--kg),.85);animation:pickhalo 1.9s ease-out infinite}
.pick .phalo.p2{animation-delay:.95s}
.pick.near .pdisc{animation:pickbob .85s ease-in-out infinite}
.pick.gone{opacity:0;transform:scale(.4);transition:opacity .32s,transform .32s}
@keyframes pickbob{0%,100%{transform:translate(-50%,-50%) translateY(0)}50%{transform:translate(-50%,-50%) translateY(-6px)}}
@keyframes pickhalo{0%{transform:scale(.5);opacity:.9}100%{transform:scale(1.5);opacity:0}}
/* Label flying from the ground to whatever the pickup fed */
.flypick{position:absolute;z-index:660;font-family:var(--display);font-weight:800;font-size:20px;
  color:#fff;-webkit-text-stroke:2.5px var(--ink-line);paint-order:stroke fill;text-shadow:var(--drop);
  pointer-events:none;white-space:nowrap}
.flypick.xp,.flypick.refresh{color:#ffe066}
/* the km milestone is a sentence, not a number — it needs to stay readable */
.flypick.km{color:var(--blue-1);font-size:17px}
.flypick.freeze{color:var(--shiny-1)}
.flypick.magnet{color:var(--red-1)}
.flypick.pat,.flypick.petfood{color:var(--green-1)}
@media (prefers-reduced-motion:reduce){.pick .phalo{animation:none;opacity:.55;transform:scale(1.2)}.pick .pdisc{animation:none}}

/* Arrival burst: two rings + six sparks, one shot. `forwards` parks every piece
   at opacity 0 so nothing lingers behind the sticker for the rest of its life —
   this must NOT loop, or it competes with the shiny ping for attention. */
/* z-index 3 puts the burst OVER the sticker. Under it, the rings spent their
   whole life hidden behind a 60px sprite and the effect was invisible; the
   travel distances below are likewise sized to clear that sprite. */
.spawnfx{position:absolute;left:31px;top:30px;width:0;height:0;z-index:3;pointer-events:none}
.spawnfx .sring{position:absolute;left:0;top:0;width:112px;height:112px;margin:-56px 0 0 -56px;border-radius:50%;will-change:transform,opacity;
  border:3px solid var(--green-1);box-shadow:0 0 10px rgba(147,242,122,.95);animation:sringout .62s var(--ease-out) forwards}
.spawnfx .sring.r2{border-color:#fff;animation-delay:.13s}
.spawnfx .sspark{position:absolute;left:0;top:0;width:8px;height:8px;margin:-4px 0 0 -4px;border-radius:50%;
  background:linear-gradient(180deg,#fff,var(--gold-2));box-shadow:0 0 7px rgba(255,200,80,.95);
  transform:rotate(var(--a)) translateY(0);animation:ssparkout .6s var(--ease-out) forwards}
@keyframes sringout{from{transform:scale(.232);opacity:1}to{transform:scale(1);opacity:0}}
@keyframes ssparkout{0%{transform:rotate(var(--a)) translateY(-6px) scale(.4);opacity:0}
  22%{opacity:1}
  100%{transform:rotate(var(--a)) translateY(-50px) scale(1);opacity:0}}
@media (prefers-reduced-motion:reduce){.spawnfx{display:none}}
@keyframes expire{0%,100%{opacity:1}50%{opacity:.2}}

/* Rare shiny variant. The map marker must be spottable from a distance, so the
   glow sits on the sprite's own drop-shadow filter rather than on a background
   (the sticker is transparent — a box glow would frame empty space).
   `.mon` may carry position:relative: the divIcon className is '' and .mon lives
   INSIDE the marker html, so the Leaflet positioning invariant does not apply. */
.mon.shiny .crt{filter:drop-shadow(0 4px 5px rgba(0,0,0,.3)) drop-shadow(0 0 7px var(--shiny-1)) drop-shadow(0 0 14px var(--shiny-2));animation:bob 1.6s ease-in-out infinite,shimmer 1.9s ease-in-out infinite}
.mon.near.shiny .crt{animation:bob .9s ease-in-out infinite,shimmer 1.9s ease-in-out infinite}
.mon .shinystar{position:absolute;top:-6px;right:-2px;z-index:2;font-size:19px;font-style:normal;filter:drop-shadow(0 1px 3px rgba(0,0,0,.45));animation:twinkle 1.6s ease-in-out infinite}
@keyframes shimmer{0%,100%{filter:drop-shadow(0 4px 5px rgba(0,0,0,.3)) drop-shadow(0 0 6px var(--shiny-1)) drop-shadow(0 0 11px var(--shiny-2))}50%{filter:drop-shadow(0 4px 5px rgba(0,0,0,.3)) drop-shadow(0 0 13px var(--shiny-1)) drop-shadow(0 0 24px var(--shiny-2))}}
@keyframes twinkle{0%,100%{transform:scale(1) rotate(-8deg);opacity:.9}50%{transform:scale(1.3) rotate(8deg);opacity:1}}
/* Sonar ping: rings expanding from the SPRITE CENTRE (31,30 = the iconAnchor),
   centred with negative margins so the keyframe transform is free to scale.
   z-index 0 + earlier in the DOM keeps them behind the sticker; pointer-events
   are off so the rings never widen the marker's tap target over its neighbours. */
.mon .shinyping{position:absolute;left:31px;top:30px;width:56px;height:56px;margin:-28px 0 0 -28px;border-radius:50%;
  border:3px solid var(--shiny-2);box-shadow:0 0 0 2px rgba(255,255,255,.8),0 0 9px var(--shiny-2);
  pointer-events:none;z-index:0;opacity:0;animation:shinyping 1.9s ease-out infinite}
.mon .shinyping.p2{animation-delay:.95s}   /* half a cycle later — a lone ring leaves a dead beat between pulses */
/* Starts at sprite size, not smaller: a ring that peaks in opacity while still
   behind the 60px sticker is invisible, and what is left just blurs into the
   sprite's own glow. Growing outward from the edge is what reads as a ping. */
@keyframes shinyping{0%{transform:scale(1);opacity:0}15%{opacity:.95}100%{transform:scale(2.5);opacity:0}}
/* Same treatment wherever a sticker is shown (result panel, collection grid). */
/* The base filter carries the glow on its own, so reduced-motion (which kills
   the shimmer) still shows a shiny as cyan rather than plain. */
.cwrap.shiny .crt{filter:drop-shadow(0 0 7px var(--shiny-1)) drop-shadow(0 0 14px var(--shiny-2));animation:shimmer 1.9s ease-in-out infinite}
.cwrap.shiny::after{content:'✨';position:absolute;left:-6px;bottom:-2px;font-size:18px;animation:twinkle 1.6s ease-in-out infinite}
/* Reduced motion: the ping is pure animation, so freeze ONE ring as a static
   halo instead of letting the global rule leave it at its invisible end state. */
@media (prefers-reduced-motion:reduce){
  .mon .shinyping{animation:none;opacity:.8;transform:scale(1.3)}
  .mon .shinyping.p2{display:none}
}

.stopm{text-align:center}
.stopm .disc{width:44px;height:44px;border-radius:50%;border:4px solid rgba(255,255,255,.95);background:linear-gradient(180deg,var(--green-1),var(--green-2) 55%,var(--green-d));display:grid;place-items:center;box-shadow:0 5px 0 #1c5c1a,0 9px 18px rgba(30,80,20,.4),inset 0 -3px 8px rgba(0,0,0,.25);transition:transform .15s var(--ease-back);margin:0 auto}
.stopm.glow .disc{transform:scale(1.14);box-shadow:0 0 0 6px rgba(147,242,122,.55),0 5px 0 #1c5c1a}
.stopm .disc svg{width:21px;height:21px;color:#fff}
.stopm .imgdisc{width:50px;height:50px;background:none;border:0;box-shadow:none}
.stopm .imgdisc img{width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 3px 4px rgba(0,0,0,.4))}
/* Marker labels use the sticker theme: white fill, dark-green outline. */
.stopm .lab{margin-top:2px;font-size:11px;font-weight:800;color:#fff;-webkit-text-stroke:2px var(--ink-line);paint-order:stroke fill;text-shadow:var(--drop);background:none;padding:1px 4px;border-radius:99px;white-space:nowrap;display:inline-block}
/* image markers (Rinki-ekopiste): label sits ON TOP of the image.
   The relative context is .imgmark — NOT .stopm, whose position:absolute Leaflet needs. */
.stopm .imgmark{position:relative}
.stopm .imgmark .lab{position:absolute;left:50%;top:100%;margin-top:12px;transform:translateX(-50%);z-index:5}
/* Mobile recycling truck: a temporary delivery point drawn from its own artwork.
   A gold pulse ring marks it as a special one-off event, apart from the permanent
   green stops. The ring sits on the image disc; `position:relative` anchors it. */
.truckm .imgdisc{position:relative;width:64px;height:64px}
.truckm .imgdisc img{filter:drop-shadow(0 3px 5px rgba(0,0,0,.45))}
/* Artwork faces left; mirror it while the truck drives in heading east. */
.truckm .imgdisc img.flip{transform:scaleX(-1)}
.truckm .imgmark .lab{margin-top:2px}   /* pull the label up close under the truck */
/* Countdown chip above the truck: how long until it leaves. Turns red in the
   final minute so the player can judge whether the walk is still worth it. */
.trucktime{position:absolute;left:50%;bottom:100%;margin-bottom:4px;transform:translateX(-50%);z-index:6;
  font-family:var(--display);font-weight:800;font-size:12px;color:#fff;white-space:nowrap;font-variant-numeric:tabular-nums;
  padding:2px 8px;border-radius:99px;border:2px solid #fff;background:linear-gradient(180deg,var(--gold-2),var(--gold-d));
  box-shadow:0 2px 5px rgba(0,0,0,.3);text-shadow:0 1px 1px rgba(80,50,0,.5)}
.trucktime.low{background:linear-gradient(180deg,var(--red-2),var(--red-d));animation:trucktimelow .8s ease-in-out infinite}
@keyframes trucktimelow{0%,100%{transform:translateX(-50%) scale(1)}50%{transform:translateX(-50%) scale(1.12)}}
.truckm .imgdisc::after{content:'';position:absolute;inset:-3px;border-radius:50%;pointer-events:none;animation:truckpulse 1.7s ease-out infinite}
@keyframes truckpulse{0%{box-shadow:0 0 0 0 rgba(255,176,40,.6)}100%{box-shadow:0 0 0 15px rgba(255,176,40,0)}}

/* ============================== Player ============================== */
.playm{position:relative}
.playm .avwrap{position:absolute;left:50%;bottom:4px;transform:translateX(-50%)}
.playm .avwrap.flip{transform:translateX(-50%) scaleX(-1)}
.playm .av{display:block;height:52px;width:auto;filter:drop-shadow(0 5px 5px rgba(40,60,50,.32));animation:bob 1.9s ease-in-out infinite}
.playm .ring{display:none}

#guide{position:absolute;left:50%;top:50%;width:0;height:0;z-index:450;pointer-events:none}
/* Vivid orange + a dark contour and white halo, so the arrow stays legible on
   any map background (pale gold blended into roads). */
#guide .arrow{position:absolute;left:-10px;top:-58px;width:20px;height:20px;color:#ff5a1f;transform-origin:10px 58px;filter:drop-shadow(0 0 1.5px rgba(0,0,0,.7)) drop-shadow(0 0 2.5px rgba(255,255,255,.95))}
#guide.hide{display:none}
/* Pointing at the truck: keeps the contour, adds a pulsing warm glow so it reads
   apart from the everyday monster arrow. Only `filter` animates — the inline
   rotate that aims the arrow must stay untouched. */
#guide.truck .arrow{animation:guideglow 1.1s ease-in-out infinite}
@keyframes guideglow{
  0%,100%{filter:drop-shadow(0 0 1.5px rgba(0,0,0,.7)) drop-shadow(0 0 2px rgba(255,255,255,.95))}
  50%{filter:drop-shadow(0 0 1.5px rgba(0,0,0,.7)) drop-shadow(0 0 9px #ffcf3a)}}

