/* ============================================================
   SkeiLand — standalone page styles
   Minimal blue / white theme. This page uses its own chrome
   (see views/frontend/skeiland/) and does NOT load
   bootstrap.min.css / style.css.

   FONT: Gotham is the brand font. It is licensed and is not
   bundled here. If you have the Gotham webfont files, drop them
   in assets/fonts/ and add @font-face rules, e.g.:

     @font-face{font-family:'Gotham';font-weight:700;font-display:swap;
       src:url('../fonts/Gotham-Bold.woff2') format('woff2');}

   Until then the stack falls back to Montserrat (loaded in the
   page header), the closest free geometric sans to Gotham.
   ============================================================ */

:root{
  --blue:#2a6cb9;        /* primary: headings, nav, pills */
  --blue-mid:#3179c9;    /* selected pill / accents */
  --blue-deep:#1d5a9e;   /* hover, deeper accents */
  --pin:#4a97d6;         /* map pins (lighter blue) */
  --pin-here:#e2483d;    /* "you are here" / chosen spot — the one non-blue pin */
  --water:#b7ddee;       /* map water tone */
  --sky:#eaf4fb;         /* soft blue tint */
  --line:#d9e8f4;        /* hairlines */
  --ink:#42618a;         /* body text */
  --muted:#8fa9c0;       /* card date */
  --white:#ffffff;
  --radius:15px;
  --shadow:0 8px 24px rgba(28,72,130,.13);
  --font:'Gotham','Gotham SSm','Montserrat','Helvetica Neue',Arial,sans-serif;

  /* The FAB's own geometry, shared so the Map/Satellite switch can park
     itself directly above it without hard-coding the same numbers twice.
     Both are right-edge controls inside .map-shell; the mobile breakpoint
     re-declares these once and everything that references them follows. */
  --fab-bottom:20px;
  --fab-height:54px;
  --fab-gap:10px;
}

*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}

/* Several components below set display:flex, which beats the browser's
   default rule for [hidden]. Without this, toggling .hidden in JS does
   nothing. Keep this ahead of every component. */
[hidden]{display:none !important}

html,body{height:100%}
/* dvh keeps the layout correct when mobile browser chrome shows/hides */
@supports (height:100dvh){ html,body{height:100dvh} }

body{
  font-family:var(--font);
  background:var(--white);
  color:var(--ink);
  display:flex;
  flex-direction:column;
  overflow:hidden;
}

/* ---------- Header (minimal, borderless) ---------- */
.hs-header{
  background:var(--white);
  padding:0 46px 10px;
  display:flex;
  align-items:center;
  gap:12px;
  z-index:1200;
  flex-shrink:0;
  position:relative;
}
.logo-wrap{display:flex;align-items:center;gap:8px;text-decoration:none;flex-shrink:0}
.logo-wrap img{height:72px;width:auto;display:block}
.logo-fallback{
  font-family:var(--font);font-weight:800;font-size:1.5rem;
  color:var(--blue);display:none;letter-spacing:.5px;
}

/* ---------- Site nav ---------- */
.hs-nav{display:flex;align-items:center;gap:12px;margin-left:52px;margin-right:auto}
.hs-nav a{
  font-family:var(--font);font-weight:500;font-size:1rem;
  color:var(--blue);text-decoration:none;
  padding:11px 22px;border-radius:999px;
  white-space:nowrap;
  transition:background .18s, color .18s;
}
.hs-nav a:hover{background:var(--sky)}
.hs-nav a.current{
  background:var(--blue-mid);
  color:var(--white);
  font-weight:600;
}
.hs-nav a:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

.hs-nav-toggle{
  display:none;
  border:none;background:var(--blue-mid);
  width:44px;height:44px;border-radius:50%;
  cursor:pointer;
  align-items:center;justify-content:center;
  flex-direction:column;gap:4px;
}
.hs-nav-toggle span{display:block;width:18px;height:2px;border-radius:2px;background:var(--white)}
.hs-nav-toggle:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* ---------- Search (top right) ----------
   One box that both geocodes an area and looks people up in our own data.
   position:relative anchors the results panel to it. */
.hs-search{position:relative;flex:0 1 320px;min-width:0}

.hs-search__box{
  display:flex;align-items:center;gap:9px;
  height:44px;padding:0 14px;
  background:var(--white);
  border:1.5px solid var(--line);border-radius:999px;
  transition:border-color .18s, box-shadow .18s;
}
.hs-search__box:focus-within{
  border-color:var(--blue);
  box-shadow:0 0 0 3px rgba(42,108,185,.12);
}
.hs-search__icon{
  width:17px;height:17px;flex-shrink:0;
  fill:none;stroke:var(--blue);stroke-width:2;stroke-linecap:round;
}
#hsSearchInput{
  flex:1 1 auto;min-width:0;
  border:none;outline:none;background:transparent;padding:0;
  font-family:var(--font);font-size:.88rem;font-weight:500;color:var(--ink);
}
#hsSearchInput::placeholder{color:var(--muted);font-weight:500}
/* we ship our own clear button; WebKit's would duplicate it */
#hsSearchInput::-webkit-search-cancel-button,
#hsSearchInput::-webkit-search-decoration{-webkit-appearance:none;display:none}

.hs-search__clear{
  flex-shrink:0;width:22px;height:22px;padding:0;
  border:none;border-radius:50%;cursor:pointer;
  background:var(--sky);color:var(--blue);
  display:flex;align-items:center;justify-content:center;
}
.hs-search__clear svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round}
.hs-search__clear:hover{background:var(--line)}

/* ---- results panel ---- */
.hs-search__panel{
  position:absolute;top:calc(100% + 8px);right:0;z-index:1400;
  width:min(400px, calc(100vw - 28px));
  max-height:min(60vh, 430px);overflow-y:auto;
  padding:6px;
  background:var(--white);
  border:1px solid var(--line);border-radius:16px;
  box-shadow:var(--shadow);
}
.hs-search__group + .hs-search__group{
  margin-top:5px;padding-top:6px;border-top:1px solid var(--line);
}
.hs-search__label{
  padding:6px 10px 4px;
  font-family:var(--font);font-size:.64rem;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;color:var(--muted);
}
.hs-search__row{
  display:flex;align-items:flex-start;gap:10px;
  width:100%;padding:9px 10px;
  background:none;border:none;border-radius:11px;
  font-family:var(--font);text-align:left;cursor:pointer;
}
.hs-search__row:hover,
.hs-search__row.on{background:var(--sky)}
.hs-search__row:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
.hs-search__rowicon{
  flex-shrink:0;width:26px;height:26px;margin-top:1px;
  border-radius:50%;background:var(--sky);
  display:flex;align-items:center;justify-content:center;
}
.hs-search__row.on .hs-search__rowicon{background:var(--white)}
.hs-search__rowicon svg{
  width:14px;height:14px;
  fill:none;stroke:var(--blue);stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
/* min-width:0 is what lets the ellipsis engage inside a flex child */
.hs-search__rowtext{display:flex;flex-direction:column;min-width:0;gap:1px}
.hs-search__rowtitle{
  font-size:.85rem;font-weight:600;color:var(--blue-deep);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.hs-search__rowsub{
  font-size:.71rem;font-weight:500;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.hs-search__empty{
  padding:15px 12px;text-align:center;
  font-family:var(--font);font-size:.8rem;font-weight:500;color:var(--muted);
}

/* ---------- Map + hero ---------- */
.map-shell{position:relative;flex:1;min-height:0}
#map{position:absolute;inset:0;z-index:1;background:var(--water)}
/* Basemap: MapLibre GL vector tiles, styled by assets/map/skei-basemap.json.

   There is no filter here any more, and that is the point. The palette used
   to be a CSS filter chain over raster tiles —
       grayscale(1) brightness(.85) sepia(.6) hue-rotate(192deg) …
   — which is a single transform applied to every pixel alike. It can tint a
   map one colour; it cannot give five features five different colours.

   Measured on the old tiles against the brand palette: water sat at hue 180
   and had to reach 213, while main roads were already at hue 48 and had to
   stay at 47. One hue-rotate cannot move the first without dragging the
   second into green. Brightness conflicted the same way — water had to drop
   to 56% lightness while roads stayed at 95%. And grayscale(1), which ran
   first to stop stray colour surviving, destroyed the hue information any
   later stage would have needed.

   Vector tiles carry each feature as its own layer, so the palette is set
   per feature in the style file (water #3586e7, main roads #fae493, parks
   #a7c188, buildings #ddd8cb, roads #fdf9ea) and every derived shade —
   casings, label halos, the land base — is computed from those five in
   tools/build-basemap-style.js. Edit the palette there, not here.

   Building outlines, impossible before, come free: the old raster tiles had
   no stroke to find (darkest pixel luminance 220, nothing below 170), while
   the vector building layer has a real edge. */
.leaflet-base-pane{filter:none}
.leaflet-tile-pane{background:var(--white)}

/* GL canvas fills its pane; without this it can overflow during a zoom. */
.leaflet-base-pane .maplibregl-map{width:100%;height:100%}
/* MapLibre draws its own attribution; Leaflet's control already carries it. */
.leaflet-base-pane .maplibregl-ctrl-attrib{display:none}

/* ---------- Satellite mode ----------
   Satellite is raster photography and is left exactly as delivered — the
   styled map's palette has nothing to say about it, and tinting it would
   flatten the roofs, trees and shoreline that are the reason to look. */
/* dark backdrop so loading tiles read as sky/ground, not a white flash */
#map.is-sat,
#map.is-sat .leaflet-tile-pane{background:#0d1b2e}

/* ---------- Map / Satellite switch ---------- */
.map-type{
  /* Keep the style switch in the same floating control stack as the add
    button and zoom buttons. */
  position:absolute;right:20px;bottom:86px;z-index:1150;
  display:flex;align-items:center;gap:4px;
  padding:4px;
  background:var(--white);
  /* It overlaps the white hero fade, so an unbordered white pill would
     vanish into it. The border is what makes it readable there — and it
     matches the header search box, so the two read as one family. */
  border:1.5px solid var(--line);
  border-radius:999px;
  box-shadow:0 4px 14px rgba(21,48,92,.16);
}
.map-type__btn{
  border:none;background:none;cursor:pointer;
  width:34px;height:34px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:.92rem;color:var(--blue);
  transition:background .18s,color .18s;
}
.map-type__btn i{pointer-events:none}
.map-type__btn:hover{background:var(--sky)}
.map-type__btn.on{background:var(--blue-mid);color:var(--white)}
.map-type__btn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* The header's white, carried down over the map and faded out.

   ONE gradient, not two stacked. Two translucent layers do not add up the
   way they read in the source: the combined alpha is 1-(1-a1)(1-a2), so two
   layers sitting at .4 still cover .64. Measured down the old version, the
   luminance fell only 1-3 per 10px the whole way to y=400 and then dropped 5
   in a single step onto the map colour — near-white for most of its height,
   then a hard line across the middle. A single layer cannot compound with
   itself, so the curve written here is the curve that renders.

   Nine stops rather than four for the same reason a photograph is dithered:
   the browser interpolates between what it is given, and four stops across
   300px band visibly.

   Solid white only at the very top, where it continues the header. It is
   already thinning above the heading, so the type sits IN the fade instead
   of on a slab that ends underneath it, and it reaches zero well before the
   bottom — which is why there is no longer an edge to find. */
.map-shell::before{
  content:'';position:absolute;left:0;right:0;top:0;height:300px;z-index:400;
  background:radial-gradient(58% 100% at 50% 0%,
    rgba(255,255,255,1)    0%,
    rgba(255,255,255,.96)  10%,
    rgba(255,255,255,.84)  22%,
    rgba(255,255,255,.64)  36%,
    rgba(255,255,255,.42)  50%,
    rgba(255,255,255,.24)  64%,
    rgba(255,255,255,.11)  78%,
    rgba(255,255,255,.03)  90%,
    rgba(255,255,255,0)   100%);
  pointer-events:none;
}

/* overlaid hero heading — centered */
.hero{
  position:absolute;left:0;right:0;top:0;z-index:500;
  padding:22px 16px 0;
  text-align:center;
  pointer-events:none;
}
.hero-eyebrow{
  font-family:var(--font);font-weight:700;
  font-size:clamp(1.05rem, 2.3vw, 2.3rem);
  letter-spacing:.06em;text-transform:uppercase;
  color:var(--blue);
  line-height:1.1;
}
.hero-title{
  font-family:var(--font);font-weight:800;
  font-size:clamp(2.5rem, 5.2vw, 5rem);
  line-height:1;letter-spacing:.01em;text-transform:uppercase;
  color:var(--blue);
  margin:0;
}
.hero-sub{
  font-family:var(--font);font-weight:700;
  font-size:clamp(.78rem, 1.2vw, 1.2rem);
  letter-spacing:.03em;text-transform:uppercase;
  color:var(--blue);
  margin-top:6px;
}
.count-pill{
  display:inline-block;
  background:var(--blue-mid);color:var(--white);
  border-radius:999px;
  font-family:var(--font);font-weight:600;
  font-size:clamp(.72rem, .95vw, .94rem);
  padding:8px 22px;margin-top:16px;
}

/* ---------- Map pins ----------
   One number sizes the pin: --pin-h. Everything else is derived from the
   SVG's own viewBox ("0 0 24 33"), so the avatar lands dead centre in the
   head at any size and a breakpoint only has to change the height.

   Width is held at the exact 24:33 viewBox ratio. That matters: the SVG
   scales with preserveAspectRatio, so any other ratio letterboxes the
   artwork inside the box and the head drifts off the centre the maths
   below assumes.

   Nothing here uses `transform`. .drop and .wave animate transform with
   fill-mode `both`, so a transform used for sizing or centring would be
   overwritten the moment a pin animates — and never restored. */
.scoop-pin{
  --pin-h:52px;
  --pin-w:calc(var(--pin-h) * 24 / 33);

  /* head circle from the viewBox: centre (12,12), radius 12 — both are
     12/33 of the height once scaled */
  --pin-head:calc(var(--pin-h) * 12 / 33);

  /* avatar diameter as a share of the head, leaving a ring of pin colour */
  --pin-face:.76;
  --pin-img:calc(var(--pin-head) * 2 * var(--pin-face));

  /* Pinned to the bottom-centre of Leaflet's icon box, which is exactly
     where iconAnchor puts the tip. Because the pin hangs off that point
     rather than filling the box, --pin-h can change freely without the
     tip sliding off the coordinate and without touching iconSize in JS. */
  position:absolute;
  left:calc(50% - var(--pin-w) / 2);
  bottom:0;
  display:block;
  width:var(--pin-w);
  height:var(--pin-h);
}
.scoop-pin svg{display:block;width:100%;height:100%;overflow:visible}
.scoop-pin .marker-body{
  fill:var(--pin);
  filter:drop-shadow(0 4px 5px rgba(28,72,130,.32));
  transition:fill .2s;
}
.scoop-pin .marker-glyph{fill:var(--white)}
.scoop-pin .marker-img{
  position:absolute;
  left:calc(50% - var(--pin-img) / 2);
  top:calc(var(--pin-head) - var(--pin-img) / 2);
  width:var(--pin-img);
  height:var(--pin-img);
  border-radius:50%;
  object-fit:cover;
  background:var(--sky);
  /* hairline so a photo reads as a face and not as part of the pin */
  box-shadow:0 0 0 1.5px var(--white);
  pointer-events:none;
  display:block;
}
/* Leaflet resets every image in the marker pane with
   `.leaflet-container .leaflet-marker-pane img{width:auto}`. That selector
   scores 0-2-1 and so outranks the 0-2-0 rule above, handing the width back
   to the file's own aspect ratio: a 1600x600 upload renders as an oval and a
   portrait one as a narrow ellipse, while the height stays square.

   Re-assert the square box from a selector that outranks Leaflet's. Only the
   two properties it clobbers are repeated; object-fit above then crops the
   photo into the circle exactly as the discovery cards do, so any upload
   shape lands the same way. */
.leaflet-marker-pane .scoop-pin .marker-img{
  width:var(--pin-img);
  height:var(--pin-img);
}

.scoop-pin.active .marker-body{fill:var(--blue)}

/* ---------- "You are here" / chosen spot ----------
   The same teardrop as a discovery pin, in the accent red. It marks the one
   thing on the map that is not a discovery — the visitor's own position, or
   the spot they are pinning — so it has to be the marker that is not blue.
   The target glyph carries the same meaning without relying on colour. */
.scoop-pin--here .marker-body{
  fill:var(--pin-here);
  filter:drop-shadow(0 4px 7px rgba(150,32,26,.4));
}
.scoop-pin--here .marker-glyph{fill:var(--white)}
/* the inner dot is punched back to the body colour, so the glyph reads as a
   ring rather than a filled blob at pin size */
.scoop-pin--here .marker-hole{fill:var(--pin-here)}
/* it is not one of the discoveries, so the active outline never applies */
.scoop-pin--here.active .marker-body{fill:var(--pin-here)}

/* ---------- Clustered pins ----------
   Where discoveries are denser than one per grid cell they collapse into a
   counted bubble. Same blue family as the pins so the map still reads as one
   thing, but a circle rather than a teardrop: a cluster marks an area, not a
   point, and should not look like it is pinning an exact spot. */
.scoop-cluster{
  display:flex;align-items:center;justify-content:center;
  border-radius:50%;
  background:var(--blue-mid);
  border:3px solid var(--white);
  box-shadow:0 4px 12px rgba(28,72,130,.36);
  color:var(--white);
  font-family:var(--font);font-weight:700;
  cursor:pointer;
  transition:transform .16s, background .16s;
}
.scoop-cluster span{font-size:.82rem;line-height:1;letter-spacing:-.01em}
.leaflet-marker-icon:hover .scoop-cluster{background:var(--blue-deep);transform:scale(1.07)}

/* deck note when the view holds more than the strip shows */
.cards-more{
  flex:0 0 auto;align-self:center;
  padding:10px 14px;margin:0;
  font-family:var(--font);font-size:.76rem;font-weight:600;
  color:var(--muted);white-space:nowrap;
}

/* ---------- Popups ---------- */
.leaflet-popup-content-wrapper{
  border-radius:var(--radius);
  background:var(--white);
  box-shadow:var(--shadow);
}
.leaflet-popup-content{margin:14px 16px;font-family:var(--font)}
.leaflet-popup-tip{background:var(--white)}
.pop-name{font-weight:700;color:var(--blue);font-size:1rem}
.pop-place{font-weight:600;font-size:.82rem;margin-top:3px;color:var(--blue)}
.pop-date{font-size:.72rem;font-weight:600;color:var(--muted);margin-top:4px}
.pop-note{font-size:.8rem;margin-top:8px;line-height:1.5;color:var(--ink)}
.leaflet-container a.leaflet-popup-close-button{color:var(--blue)}

/* attribution kept readable but subtle */
.leaflet-control-attribution{font-size:9px;background:rgba(255,255,255,.8)}

/* zoom controls — two separate white circles, bottom right */
.leaflet-control-zoom{border:none!important;box-shadow:none!important;background:transparent!important}
.leaflet-control-zoom a{
  color:var(--blue)!important;font-weight:600;font-size:1.18rem;
  width:34px!important;height:34px!important;line-height:32px!important;
  background:var(--white)!important;border:none!important;
  border-radius:50%!important;
  box-shadow:0 3px 10px rgba(28,72,130,.2);
  display:block;
}
.leaflet-control-zoom a:hover{background:var(--sky)!important}
.leaflet-control-zoom a+a{margin-top:6px}

/* ---------- Discovery cards ---------- */
.deck{
  position:absolute;left:0;right:0;bottom:0;z-index:1000;
  padding:10px 12px 14px;
  pointer-events:none;
}
.deck-label{
  pointer-events:auto;
  display:flex;align-items:center;gap:12px;
  font-family:var(--font);font-weight:600;font-size:.8rem;
  color:var(--blue);
  margin:0 6px 10px;
  white-space:nowrap;
}
.deck-label::before,.deck-label::after{
  content:'';height:1px;flex:1;background:var(--line);
}

/* The count sits on its own white pill.
   flex-shrink:0 so it keeps its shape on a narrow screen — the hairlines
   either side are flex:1 and will give up their width first, which is the
   right order: a rule can be short, the label should stay readable. */
.deck-count{
  flex-shrink:0;
  background:var(--white);
  border-radius:999px;
  padding:7px 16px;
  box-shadow:0 2px 10px rgba(28,72,130,.10);
  line-height:1;
}
.cards{
  pointer-events:auto;
  display:flex;gap:12px;
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  padding:4px 4px 8px;
  scrollbar-width:none;
}
.cards::-webkit-scrollbar{display:none}
.card{
  scroll-snap-align:start;
  flex:0 0 264px;
  background:var(--white);
  border:none;
  border-radius:var(--radius);
  box-shadow:var(--shadow);
  padding:12px 16px;
  display:flex;gap:13px;align-items:center;
  cursor:pointer;
  text-align:left;
  font-family:var(--font);
  color:var(--ink);
  transition:transform .18s, box-shadow .18s;
}
.card:hover{transform:translateY(-2px)}
.card.active{box-shadow:0 10px 26px rgba(42,108,185,.28)}
.card:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.card img{
  width:46px;height:46px;border-radius:50%;
  object-fit:cover;flex-shrink:0;
  background:var(--sky);
}
/* One flowing sentence. The connecting words ("found", "on") stay muted so
   the two things worth scanning — who, and where — still read first, which
   is what the old bold name and blue place line did with three rows. */
.card .c-line{
  font-size:.83rem;font-weight:600;line-height:1.45;color:var(--muted);
}
.card .c-line .c-who,
.card .c-line .c-where{color:var(--blue);font-weight:700}

/* ---------- Responsive ---------- */
@media (max-width: 819px){
  .hs-header{padding:0 16px 8px}
  .hs-nav{
    position:absolute;
    top:100%;left:0;right:0;
    margin-left:0;
    flex-direction:column;
    align-items:stretch;
    gap:2px;
    background:var(--white);
    padding:8px 16px 14px;
    box-shadow:var(--shadow);
    z-index:1300;
    display:none;
  }
  .hs-nav.open{display:flex}
  .hs-nav a{padding:12px 16px}
  .hs-nav-toggle{display:flex;flex-shrink:0}
  .logo-wrap img{height:48px}

  /* .hs-nav goes absolute here, so the row is logo | search | burger and
     search takes the slack. margin-left:auto keeps it off the logo. */
  .hs-search{flex:1 1 auto;margin-left:auto;max-width:none}
  .hs-search__box{height:40px;padding:0 12px;gap:7px}
  #hsSearchInput{font-size:.82rem}

  /* The heading takes proportionally more of a narrow screen, so the dome
     widens — narrowing it here would put type over map rather than save
     space. Same single-layer ramp as above, only wider and shorter. */
  .map-shell::before{
    height:230px;
    background:radial-gradient(96% 100% at 50% 0%,
      rgba(255,255,255,1)    0%,
      rgba(255,255,255,.96)  12%,
      rgba(255,255,255,.85)  26%,
      rgba(255,255,255,.66)  40%,
      rgba(255,255,255,.44)  54%,
      rgba(255,255,255,.25)  68%,
      rgba(255,255,255,.11)  81%,
      rgba(255,255,255,.03)  91%,
      rgba(255,255,255,0)   100%);
  }
  .hero{padding-top:14px}
  .card{flex:0 0 78vw;max-width:290px}

  /* A finger is a blunter pointer than a cursor, so the pin grows to a
     ~44px-wide head — the usual minimum tap target. Only the height is
     set; width, head centre and avatar all follow from it. */
  .scoop-pin{--pin-h:60px}

  /* ---------- Give a finger somewhere to land ----------
     On a phone the map ran edge to edge, and Leaflet claims every touch
     inside itself — so there was no part of the screen left that belonged
     to the page rather than to the map. Hence "you have to touch at the
     edge".

     The map is inset instead: a strip down each side and a band underneath
     that Leaflet does not own. The height still fills what is left, so
     nothing is wasted — shortening it only produced dead white space, since
     there is no content below the map to scroll to.

     Desktop is untouched: a cursor has no such problem and the full-bleed
     map is the better look there. */
  .map-shell{
    margin:0 12px 14px;
    border-radius:18px;
    overflow:hidden;                 /* clip the basemap to the rounded corner */
    box-shadow:0 10px 28px rgba(28,72,130,.12);
  }
}

@media (max-width: 380px){
  .hs-header{padding:0 12px 8px;gap:8px}
  .hs-search__box{height:38px;padding:0 10px}
  #hsSearchInput{font-size:.78rem}
  .logo-wrap img{height:42px}
}

/* Desktop: discovery deck docks to the LEFT of the map */
@media (min-width: 820px){
  .deck{
    left:20px;right:auto;bottom:18px;top:auto;
    width:292px;
    display:flex;flex-direction:column;
    max-height:58vh;
    padding:0;
  }
  .cards{
    flex-direction:column;
    overflow-y:auto;overflow-x:hidden;
    scroll-snap-type:y proximity;
    padding:2px 2px 4px;
  }
  .card{flex:0 0 auto}
}

@media (prefers-reduced-motion: reduce){
  *{transition:none!important;animation:none!important;scroll-behavior:auto!important}
}

/* ============================================================
   Floating "add a place" button
   ============================================================ */
.hs-fab{
  position:absolute;right:20px;bottom:var(--fab-bottom);z-index:1100;
  display:inline-flex;align-items:center;gap:0;
  height:var(--fab-height);padding:0 16px;
  border:none;border-radius:999px;
  background:var(--blue-mid);color:var(--white);
  font-family:var(--font);font-weight:600;font-size:.92rem;
  cursor:pointer;
  box-shadow:0 10px 24px rgba(42,108,185,.38);
  transition:gap .22s ease, padding .22s ease, background .18s;
}
.hs-fab svg{width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;flex-shrink:0}
.hs-fab__text{max-width:0;overflow:hidden;white-space:nowrap;opacity:0;transition:max-width .22s ease, opacity .18s ease}
.hs-fab:hover{background:var(--blue);gap:8px;padding:0 22px}
.hs-fab:hover .hs-fab__text{max-width:130px;opacity:1}
.hs-fab:focus-visible{outline:3px solid var(--blue-deep);outline-offset:3px}

/* keep leaflet's zoom buttons clear of the compact floating stack */
.leaflet-bottom.leaflet-right .leaflet-control-zoom{margin-bottom:136px}

/* ============================================================
   Shared modal shell
   ============================================================ */
.hs-modal{position:fixed;inset:0;z-index:4000;display:flex;align-items:center;justify-content:center;padding:24px}
.hs-modal[hidden]{display:none}
.hs-modal__backdrop{
  position:absolute;inset:0;
  background:rgba(21,48,92,.5);
  backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
  animation:hsFade .2s ease both;
}
.hs-modal__panel{
  position:relative;z-index:1;
  display:flex;
  width:100%;max-width:940px;max-height:88vh;
  background:var(--white);
  border-radius:22px;
  box-shadow:0 30px 70px rgba(16,40,80,.34);
  overflow:hidden;
  animation:hsPop .26s cubic-bezier(.2,.8,.3,1) both;
}
/* The form panel scrolls, and a default scrollbar paints an opaque track
   down the full right edge — including the two corners, which squares off
   the 22px radius so the panel reads as a rectangle on that side.

   The fix is to stop the scrollbar drawing a track at all. With a
   transparent track the panel's own rounded background shows through and
   the curve returns; the thumb is inset from the edge by a transparent
   border (background-clip keeps the paint inside the padding box), so it
   floats as a pill and never reaches a corner. No extra markup, and the
   scrollbar still behaves exactly like a scrollbar. */
.hs-modal__panel--form{
  max-width:720px;flex-direction:column;
  overflow-y:auto;overflow-x:hidden;
  /* Firefox */
  scrollbar-width:thin;
  scrollbar-color:rgba(42,108,185,.34) transparent;
}
.hs-modal__panel--form::-webkit-scrollbar{width:11px;background:transparent}
.hs-modal__panel--form::-webkit-scrollbar-track{background:transparent}
.hs-modal__panel--form::-webkit-scrollbar-thumb{
  background:rgba(42,108,185,.34);
  border-radius:999px;
  border:3px solid transparent;
  background-clip:padding-box;
}
.hs-modal__panel--form::-webkit-scrollbar-thumb:hover{
  background:rgba(42,108,185,.55);
  background-clip:padding-box;
}

/* Desktop: just a plain wrapper. .hs-modal__close stays position:absolute
   against .hs-modal__panel (the nearest positioned ancestor — position:
   static elements are not positioning contexts, so this wrapper does not
   get in the way) and overlays the gallery exactly as before. The mobile
   breakpoint below turns this same element into the sticky bar. */
.pm-topbar{position:static}

.hs-modal__close,
.hs-modal__share{
  position:absolute;top:12px;z-index:5;
  width:38px;height:38px;border:none;border-radius:50%;
  background:rgba(255,255,255,.92);color:var(--blue);
  cursor:pointer;display:flex;align-items:center;justify-content:center;
  box-shadow:0 3px 12px rgba(21,48,92,.22);
  transition:background .18s;
}
.hs-modal__close{right:12px}
/* parked just left of close: 12 + 38 (close) + 8 (gap) */
.hs-modal__share{right:58px}

.hs-modal__close svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round}
.hs-modal__share svg{
  width:16px;height:16px;
  fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
.hs-modal__close:hover,
.hs-modal__share:hover{background:var(--white)}
.hs-modal__close:focus-visible,
.hs-modal__share:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

@keyframes hsFade{from{opacity:0}to{opacity:1}}
@keyframes hsPop{from{opacity:0;transform:translateY(14px) scale(.985)}to{opacity:1;transform:none}}

/* ============================================================
   Place detail modal
   ============================================================ */
.pm-media{position:relative;flex:0 0 55%;background:var(--sky);min-width:0}
.pm-track{
  display:flex;height:100%;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  scrollbar-width:none;
}
.pm-track::-webkit-scrollbar{display:none}
.pm-track:focus-visible{outline:2px solid var(--blue);outline-offset:-3px}
.pm-track img{
  flex:0 0 100%;width:100%;height:100%;
  object-fit:cover;display:block;
  scroll-snap-align:center;
  background:var(--sky);
}
.pm-nav{
  position:absolute;top:50%;transform:translateY(-50%);z-index:3;
  width:36px;height:36px;border:none;border-radius:50%;
  background:rgba(255,255,255,.9);color:var(--blue);
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  box-shadow:0 3px 12px rgba(21,48,92,.22);
  opacity:0;transition:opacity .18s, background .18s;
}
.pm-nav svg{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:2.3;stroke-linecap:round;stroke-linejoin:round}
.pm-nav--prev{left:10px}
.pm-nav--next{right:10px}
.pm-media:hover .pm-nav{opacity:1}
.pm-nav:focus-visible{opacity:1;outline:2px solid var(--blue);outline-offset:2px}
.pm-nav[disabled]{opacity:0 !important;pointer-events:none}
.pm-dots{position:absolute;left:0;right:0;bottom:12px;z-index:3;display:flex;justify-content:center;gap:6px}
.pm-dots button{
  width:7px;height:7px;padding:0;border:none;border-radius:50%;cursor:pointer;
  background:rgba(255,255,255,.62);transition:width .2s, background .2s;
}
.pm-dots button.on{width:20px;border-radius:999px;background:var(--white)}

.pm-body{
  flex:1 1 auto;min-width:0;
  padding:30px 30px 28px;
  overflow-y:auto;
  display:flex;flex-direction:column;
}
.pm-chip{
  display:inline-flex;align-items:center;gap:6px;align-self:flex-start;
  background:var(--sky);color:var(--blue);
  font-size:.74rem;font-weight:700;letter-spacing:.02em;
  padding:6px 13px;border-radius:999px;text-transform:uppercase;
}
.pm-chip svg{width:10px;height:10px;fill:currentColor}
.pm-title{
  font-family:var(--font);font-weight:800;
  font-size:clamp(1.3rem,2.4vw,1.75rem);line-height:1.18;
  color:var(--blue-deep);margin:14px 0 0;
}
.pm-meta{
  display:flex;align-items:center;gap:12px;
  margin:20px 0;padding:14px 0;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
}
.pm-avatar{width:42px;height:42px;border-radius:50%;object-fit:cover;background:var(--sky);flex-shrink:0}
.pm-meta__text{display:flex;flex-direction:column;min-width:0}
.pm-meta__text--right{margin-left:auto;text-align:right}
.pm-meta__label{font-size:.66rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.pm-meta__text strong{font-size:.9rem;font-weight:700;color:var(--blue);margin-top:2px}
.pm-desc{font-size:.92rem;line-height:1.68;color:var(--ink);margin:0}
/* wraps on narrow screens rather than pushing the panel wider */
.pm-actions{
  margin-top:22px;
  display:flex;flex-wrap:wrap;gap:10px;align-items:center;
}
.pm-directions{
  display:inline-flex;align-items:center;gap:8px;
  font-size:.85rem;font-weight:700;color:var(--blue);text-decoration:none;
  padding:11px 20px;border-radius:999px;border:1.5px solid var(--blue);
  transition:background .18s,color .18s,border-color .18s;
}
.pm-directions svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.pm-directions:hover{background:var(--blue);color:var(--white)}

/* secondary action: Street View may have no imagery at a remote spot, so
   it reads as an option rather than competing with the primary button */
.pm-directions--ghost{
  color:var(--ink);border-color:var(--line);font-weight:600;
}
.pm-directions--ghost:hover{background:var(--sky);color:var(--blue-deep);border-color:var(--blue)}

/* ============================================================
   Submission form
   ============================================================ */
.sf-head{padding:30px 30px 0}
.sf-title{font-family:var(--font);font-weight:800;font-size:1.4rem;color:var(--blue-deep)}
.sf-sub{font-size:.86rem;line-height:1.6;color:var(--ink);margin-top:8px;max-width:52ch}
.sf-form{padding:22px 30px 30px;display:flex;flex-direction:column;gap:16px}
.sf-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.sf-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.sf-field{display:flex;flex-direction:column;min-width:0}
.sf-field>label{font-size:.78rem;font-weight:700;color:var(--blue-deep);margin-bottom:7px}
.sf-field>label span{color:#d05a5a}
.sf-field input[type=text],
.sf-field input[type=email],
.sf-field textarea{
  font-family:var(--font);font-size:.9rem;color:var(--ink);
  border:1.5px solid var(--line);border-radius:12px;
  padding:12px 14px;background:var(--white);
  transition:border-color .16s, box-shadow .16s;
  width:100%;
}
.sf-field textarea{resize:vertical;min-height:96px;line-height:1.55}
.sf-field input:focus,.sf-field textarea:focus{
  outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(49,121,201,.16);
}
.sf-field input.bad,.sf-field textarea.bad{border-color:#d98080}
.sf-err{color:#c95757;font-size:.72rem;font-weight:600;margin-top:5px;display:none}
.sf-err.on{display:block}
.sf-hint{color:var(--muted);font-size:.72rem;font-weight:600;margin-top:6px}

/* search bar for the mini map picker */
.sf-search{display:flex;gap:10px;align-items:stretch;margin:2px 0 10px}
.sf-search input[type=search]{
  flex:1;min-width:0;
  font-family:var(--font);font-size:.9rem;color:var(--ink);
  border:1.5px solid var(--line);border-radius:12px;
  padding:12px 14px;background:var(--white);
  transition:border-color .16s, box-shadow .16s;
  width:100%;
  appearance:none;-webkit-appearance:none;
}
.sf-search input[type=search]:focus{
  outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(49,121,201,.16);
}
.sf-search button{
  border:none;border-radius:12px;
  background:var(--blue-mid);color:var(--white);
  font-family:var(--font);font-size:.82rem;font-weight:700;
  padding:0 16px;cursor:pointer;white-space:nowrap;
  box-shadow:0 6px 16px rgba(42,108,185,.2);
  transition:background .18s, opacity .18s;
}
.sf-search button:hover{background:var(--blue)}
.sf-search button:focus-visible{outline:2px solid var(--blue-deep);outline-offset:2px}
.sf-search button[disabled]{opacity:.65;cursor:progress}

/* suggestions panel for the picker search — in normal flow so it pushes
   the map down instead of overlapping it */
.sf-search__panel{
  margin-top:6px;
  padding:6px;
  background:var(--white);
  border:1px solid var(--line);border-radius:16px;
  box-shadow:var(--shadow);
  max-height:min(40vh, 260px);
  overflow-y:auto;
  scrollbar-width:none;
}
.sf-search__panel::-webkit-scrollbar{display:none}
.sf-search__panel[hidden]{display:none}
.sf-search__group + .sf-search__group{
  margin-top:4px;padding-top:5px;border-top:1px solid var(--line);
}
.sf-search__label{
  padding:5px 10px 3px;
  font-family:var(--font);font-size:.64rem;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;color:var(--muted);
}
.sf-search__row{
  display:flex;align-items:flex-start;gap:10px;
  width:100%;padding:9px 10px;
  background:none;border:none;border-radius:11px;
  font-family:var(--font);text-align:left;cursor:pointer;
}
.sf-search__row:hover,
.sf-search__row.on{background:var(--sky)}
.sf-search__row:focus-visible{outline:2px solid var(--blue);outline-offset:-2px}
.sf-search__rowicon{
  flex-shrink:0;width:26px;height:26px;margin-top:1px;
  border-radius:50%;background:var(--sky);
  display:flex;align-items:center;justify-content:center;
}
.sf-search__row.on .sf-search__rowicon{background:var(--white)}
.sf-search__rowicon svg{
  width:14px;height:14px;
  fill:none;stroke:var(--blue);stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round;
}
.sf-search__rowtext{display:flex;flex-direction:column;min-width:0;gap:1px}
.sf-search__rowtitle{
  font-size:.85rem;font-weight:600;color:var(--blue-deep);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sf-search__rowsub{
  font-size:.71rem;font-weight:500;color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.sf-search__empty{
  padding:15px 12px;text-align:center;
  font-family:var(--font);font-size:.8rem;font-weight:500;color:var(--muted);
}

/* file inputs as tidy drop zones */
.sf-file{position:relative;display:block}
.sf-file input[type=file]{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}
.sf-file__label{
  display:flex;align-items:center;justify-content:center;
  border:1.5px dashed var(--line);border-radius:12px;
  padding:12px 14px;font-size:.82rem;font-weight:600;color:var(--muted);
  background:var(--white);text-align:center;
  transition:border-color .16s,color .16s,background .16s;
  min-height:46px;
}
.sf-file input[type=file]:focus-visible + .sf-file__label,
.sf-file:hover .sf-file__label{border-color:var(--blue);color:var(--blue);background:var(--sky)}
.sf-file.has .sf-file__label{border-style:solid;border-color:var(--blue);color:var(--blue)}

.sf-previews{display:flex;flex-wrap:wrap;gap:8px}
.sf-previews img{
  width:62px;height:62px;object-fit:cover;border-radius:10px;
  border:1.5px solid var(--line);background:var(--sky);
}

/* mini location picker */
.sf-map-wrap{position:relative}
.sf-map{
  height:285px;border-radius:12px;overflow:hidden;
  border:1.5px solid var(--line);background:var(--sky);
}
/* Same control as the main map, parked top-right of the picker because
   "Use my location" already holds the bottom-right corner. Sized down to suit
   the short picker map. It is a sibling of .sf-map, not a child, so the map's
   overflow:hidden cannot clip it. */
.map-type--picker{
  top:10px;right:10px;bottom:auto;z-index:500;
  padding:3px;gap:3px;
  box-shadow:0 3px 12px rgba(21,48,92,.2);
}
.map-type--picker .map-type__btn{width:30px;height:30px;font-size:.8rem}

.sf-locate{
  position:absolute;right:10px;bottom:10px;z-index:500;
  border:none;border-radius:999px;
  background:var(--white);color:var(--blue);
  font-family:var(--font);font-size:.72rem;font-weight:700;
  padding:8px 14px;cursor:pointer;
  box-shadow:0 3px 12px rgba(21,48,92,.2);
}
.sf-locate:hover{background:var(--sky)}
.sf-locate:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

.sf-actions{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:4px}
.sf-note{font-size:.78rem;font-weight:600;color:var(--muted);margin:0;flex:1;min-width:140px}
.sf-note.bad{color:#c95757}
.sf-submit{
  border:none;border-radius:999px;cursor:pointer;
  background:var(--blue-mid);color:var(--white);
  font-family:var(--font);font-weight:700;font-size:.9rem;
  padding:13px 30px;
  box-shadow:0 8px 20px rgba(42,108,185,.3);
  transition:background .18s,opacity .18s;
}
.sf-submit:hover{background:var(--blue)}
.sf-submit[disabled]{opacity:.6;cursor:progress}
.sf-submit:focus-visible{outline:2px solid var(--blue-deep);outline-offset:3px}

.sf-done{padding:46px 30px 40px;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}
.sf-done__mark{
  width:60px;height:60px;border-radius:50%;
  background:var(--sky);color:var(--blue);
  display:flex;align-items:center;justify-content:center;
}
.sf-done__mark svg{width:26px;height:26px;fill:none;stroke:currentColor;stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
.sf-done h3{font-family:var(--font);font-weight:800;font-size:1.25rem;color:var(--blue-deep)}
.sf-done p{font-size:.88rem;line-height:1.6;color:var(--ink);max-width:42ch}

/* ============================================================
   Modal + fab responsive
   ============================================================ */
@media (max-width: 819px){
  /* fab clears the discovery deck; pinch-zoom replaces the buttons */
  /* one place to move the FAB; the switch below follows automatically */
  :root{--fab-bottom:186px;--fab-height:50px}
  .hs-fab{right:14px;padding:0 15px}
  .leaflet-bottom.leaflet-right .leaflet-control-zoom{display:none}

  /* Top-right is where the hero headline lands on a narrow screen, so the
     switch would sit straight across "SKEILAND". It moves to the right edge
     just above the + button instead — the two then read as one stack of map
     controls rather than two things floating separately.

     :not(--picker) matters. The submission picker reuses .map-type for the
     same look, so an unscoped rule here also hits it: it would inherit this
     bottom offset while keeping its own top:10px, and an absolutely
     positioned box with BOTH set gets stretched between them. The picker
     keeps its own corner — it is inside a 190px map, not the page. */
  .map-type:not(.map-type--picker){
    right:14px;
    bottom:calc(var(--fab-bottom) + var(--fab-height) + var(--fab-gap));
    gap:2px;padding:3px;
    /* echo the FAB's lift so the pair feel like one group */
    box-shadow:0 8px 20px rgba(42,108,185,.26);
  }
  .map-type:not(.map-type--picker) .map-type__btn{width:32px;height:32px;font-size:.86rem}
  .leaflet-bottom.leaflet-right .leaflet-control-zoom{margin-bottom:132px}

  .hs-modal{
    padding:env(safe-area-inset-top) 0 0;
    align-items:flex-end;
  }
  .hs-modal__panel{
    flex-direction:column;
    max-width:none;
    /* dvh tracks the REAL visible area as iOS shows/hides its address bar;
       vh is fixed to the tallest possible viewport, so a plain 93vh sheet
       is taller than what is actually on screen whenever the address bar
       is showing (the common case) — see the close-button note below for
       why that alone still is not enough on iOS. */
    height:93vh;max-height:93vh;
  }
  @supports (height:93dvh){
    .hs-modal__panel{height:93dvh;max-height:93dvh}
  }
  .hs-modal__panel{
    border-radius:20px 20px 0 0;
    animation:hsSheet .28s cubic-bezier(.2,.8,.3,1) both;
    overflow-y:auto;
  }
  /* iOS close button: deliberately NOT position:fixed.
     A fixed element is placed against the browser's OWN idea of the
     viewport, which is exactly the thing iOS gets wrong here — Safari
     positions fixed elements against the largest possible viewport while
     the visible area is shorter (address bar showing, the common case),
     and iOS Chrome does not reliably support dvh at all. Either way the
     button ends up placed against a viewport height that is not what is
     actually on screen: it renders below the real fold ("half in Safari")
     or almost entirely off it ("a minute portion" in Chrome). No viewport
     unit reliably out-guesses both browsers at once.

     The fix sidesteps viewport math instead of chasing it. The button is
     pulled out of the gallery overlay and given its own full-width sticky
     bar as the FIRST child of the scrollable sheet (see the HTML wrapper
     in _place_modal.php). A sticky element is positioned relative to its
     own scroll container, which is real DOM the browser has actually laid
     out — there is no viewport arithmetic left to get wrong, and it works
     identically whether the address bar is showing, hidden, or animating
     between the two. */
  .pm-topbar{
    position:sticky;top:0;z-index:6;
    display:flex;justify-content:flex-end;gap:8px;
    padding:10px 10px 0;
    pointer-events:none;              /* only the buttons inside are clickable */
  }
  .pm-topbar .hs-modal__close,
  .pm-topbar .hs-modal__share{pointer-events:auto}
  .hs-modal__close,
  .hs-modal__share{
    position:static;                  /* undo the desktop absolute-overlay */
    width:38px;height:38px;
    flex-shrink:0;
  }

  /* Place modal only: pull the bar back over the gallery photo instead of
     pushing it down, so the mobile sheet keeps the same full-bleed hero
     image it always had. Safe here specifically because .pm-media is a
     fixed aspect-ratio box (4/3) directly below — nothing reflows under a
     negative margin whose size is known up front. The submit form has no
     such image to preserve, so its topbar (below) is left as plain, solid
     space instead of reaching for the same trick where it does not apply. */
  #placeModal .pm-topbar{margin-bottom:-48px}

  .pm-media{flex:0 0 auto;height:auto;aspect-ratio:4/3;width:100%}
  .pm-nav{display:none}
  .pm-body{padding:22px 20px 30px;overflow:visible}
  .pm-meta{margin:16px 0}

  .sf-head{padding:26px 20px 0}
  .sf-form{padding:18px 20px 30px}
  .sf-grid{grid-template-columns:1fr}
  .sf-search{flex-direction:column}
  .sf-search button{padding:12px 16px}
  .sf-submit{width:100%}
  .sf-actions{flex-direction:column-reverse;align-items:stretch}
  .sf-note{text-align:center}
}

@keyframes hsSheet{from{opacity:0;transform:translateY(40px)}to{opacity:1;transform:none}}

@media (prefers-reduced-motion: reduce){
  .hs-modal__panel,.hs-modal__backdrop{animation:none !important}
}

/* cards fade up in sequence on first paint */
.cards .card{animation:sklCardIn .38s cubic-bezier(.2,.8,.3,1) both}
@keyframes sklCardIn{
  from{opacity:0;transform:translateY(14px)}
  to{opacity:1;transform:none}
}

/* pins drop in one after another */
.scoop-pin.drop{animation:sklPinDrop .5s cubic-bezier(.2,.9,.3,1) both}
@keyframes sklPinDrop{
  from{opacity:0;transform:translateY(-22px) scale(.82)}
  60%{opacity:1}
  to{opacity:1;transform:none}
}

/* Wave bounce on first paint of a location: each pin hops twice, and the
   per-pin delay is set inline in JS so the crest travels across the map
   rather than every pin hopping at once. The stagger is scaled to the pin
   COUNT (see waveStep in skeiland.js) so 3 pins and 30 pins both finish in
   about the same beat instead of the wave dragging on for tens of seconds.

   transform-origin sits at the tip because that is where the pin meets the
   map — scaling from the centre makes it look like it detaches. */
.scoop-pin.wave{
  animation:sklPinWave 1.15s cubic-bezier(.28,.84,.42,1) both;
  transform-origin:50% 100%;
}
@keyframes sklPinWave{
  0%  {transform:translateY(0) scaleY(1)}
  16% {transform:translateY(-13px) scaleY(1.04)}
  33% {transform:translateY(0) scaleY(.93)}   /* squash on landing */
  46% {transform:translateY(-5px) scaleY(1.01)}
  60% {transform:translateY(0) scaleY(.975)}
  72% {transform:translateY(-1.5px) scaleY(1)}
  100%{transform:translateY(0) scaleY(1)}
}

/* empty state */
.cards-empty{
  font-family:var(--font);font-size:.85rem;font-weight:600;
  color:var(--muted);
  background:var(--white);
  border-radius:var(--radius);
  box-shadow:var(--shadow);
  padding:16px 18px;margin:0;
  line-height:1.5;
}

/* videos share the gallery slot with images */
.pm-track video{
  flex:0 0 100%;width:100%;height:100%;
  object-fit:cover;display:block;
  scroll-snap-align:center;
  background:#0d1b2e;
}

@media (prefers-reduced-motion: reduce){
  .cards .card,.scoop-pin.drop,.scoop-pin.wave{animation:none !important}
}

/* ============================================================
   Media picker — drop zone, stacked reorderable list
   ============================================================ */
.sf-drop{
  position:relative;
  border:1.5px dashed var(--line);
  border-radius:12px;
  background:var(--white);
  transition:border-color .16s, background .16s;
}
.sf-drop input[type=file]{
  position:absolute;inset:0;width:100%;height:100%;
  opacity:0;cursor:pointer;
}
.sf-drop__inner{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:4px;padding:20px 16px;text-align:center;pointer-events:none;
}
.sf-drop__inner svg{
  width:22px;height:22px;fill:none;stroke:var(--blue);
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;
  margin-bottom:2px;
}
.sf-drop__inner strong{font-size:.86rem;font-weight:700;color:var(--blue)}
.sf-drop__inner span{font-size:.72rem;font-weight:600;color:var(--muted)}
.sf-drop:hover,
.sf-drop.over,
.sf-drop input[type=file]:focus-visible + .sf-drop__inner{
  border-color:var(--blue);background:var(--sky);
}

/* stacked list of chosen files */
.sf-media{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}
.sf-media__row{
  display:flex;align-items:center;gap:12px;
  background:var(--white);
  border:1px solid var(--line);
  border-radius:12px;
  padding:8px 10px;
  cursor:grab;
  transition:border-color .16s, box-shadow .16s, opacity .16s, transform .16s;
}
.sf-media__row:active{cursor:grabbing}
.sf-media__row.dragging{opacity:.45}
.sf-media__row.over{border-color:var(--blue);box-shadow:0 0 0 3px rgba(49,121,201,.14)}

.sf-media__thumb{
  position:relative;flex-shrink:0;
  width:54px;height:54px;border-radius:9px;overflow:hidden;
  background:var(--sky);
}
.sf-media__thumb img,
.sf-media__thumb video{width:100%;height:100%;object-fit:cover;display:block}
.sf-media__badge{
  position:absolute;left:0;right:0;bottom:0;
  background:rgba(21,48,92,.72);color:#fff;
  font-size:.52rem;font-weight:800;letter-spacing:.08em;
  text-align:center;padding:2px 0;
}

.sf-media__meta{display:flex;flex-direction:column;min-width:0;flex:1}
.sf-media__name{
  font-size:.82rem;font-weight:600;color:var(--blue-deep);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.sf-media__size{font-size:.68rem;font-weight:600;color:var(--muted);margin-top:2px}

.sf-media__ctl{display:flex;align-items:center;gap:4px;flex-shrink:0}
.sf-media__btn{
  width:28px;height:28px;border:none;border-radius:8px;
  background:var(--sky);color:var(--blue);
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  transition:background .16s, color .16s, opacity .16s;
}
.sf-media__btn svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}
.sf-media__btn:hover{background:var(--blue);color:var(--white)}
.sf-media__btn[disabled]{opacity:.32;cursor:default}
.sf-media__btn[disabled]:hover{background:var(--sky);color:var(--blue)}
.sf-media__btn--del:hover{background:#d05a5a}
.sf-media__btn:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

/* ============================================================
   Toast
   ============================================================ */
.skei-toast{
  position:fixed;left:50%;bottom:26px;z-index:5000;
  transform:translate(-50%, 16px);
  display:flex;align-items:center;gap:10px;
  max-width:min(520px, calc(100vw - 32px));
  padding:13px 16px;
  border-radius:14px;
  background:var(--white);
  box-shadow:0 16px 40px rgba(16,40,80,.24);
  font-family:var(--font);font-size:.86rem;font-weight:600;
  color:var(--ink);
  opacity:0;pointer-events:none;
  transition:opacity .24s ease, transform .24s cubic-bezier(.2,.8,.3,1);
}
.skei-toast[hidden]{display:none}
.skei-toast.show{opacity:1;transform:translate(-50%, 0);pointer-events:auto}

.skei-toast__icon{
  flex-shrink:0;width:24px;height:24px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  font-size:.8rem;font-weight:800;color:var(--white);
}
.skei-toast.good .skei-toast__icon{background:#2f9e6b}
.skei-toast.bad  .skei-toast__icon{background:#d05a5a}
.skei-toast.good{border-left:4px solid #2f9e6b}
.skei-toast.bad {border-left:4px solid #d05a5a}

.skei-toast__msg{flex:1;line-height:1.45}
.skei-toast__close{
  flex-shrink:0;border:none;background:transparent;cursor:pointer;
  font-size:1.15rem;line-height:1;color:var(--muted);padding:0 2px;
}
.skei-toast__close:hover{color:var(--ink)}
.skei-toast__close:focus-visible{outline:2px solid var(--blue);outline-offset:2px}

@media (max-width: 819px){
  .skei-toast{bottom:16px;font-size:.8rem;padding:12px 14px}
  .sf-media__thumb{width:46px;height:46px}
  .sf-drop__inner{padding:16px 12px}
}

@media (prefers-reduced-motion: reduce){
  .skei-toast{transition:none}
}
