/* =============================================================
   FUSION — loads AFTER storybook.css and only adds/overrides.
   Everything paper (hero, post-it, footer, tokens) comes from
   storybook.css untouched.

   style.css is deliberately NOT loaded here: its global
   `html { scroll-behavior: smooth }` fights ScrollTrigger's scrub,
   and its glass cards lost to the post-it.
   map-real.css is NOT loaded either — it's the sticky-map layout
   for index-map.html. The handful of MapLibre surface rules that
   ARE needed are re-stated below against storybook tokens.
   ============================================================= */

/* --- the cover dissolves into the map -------------------------
   Fixed and out of the flow, so the trip stage sits at scroll 0 and is already
   pinned and showing the peninsula behind it — the hero fades off a map that is
   already there, instead of a section boundary sliding up the screen.
   The class is added by fusion.js, never here: without GSAP there is no fade,
   and a permanently fixed hero would bury the fallback page. */
body.is-cinema .sb-hero {
  position: fixed;
  inset: 0;
  z-index: 3;
  will-change: opacity;
}
body.is-cinema .trip { position: relative; z-index: 1; }
body.is-cinema .sb-hero__scene img { will-change: transform; }

/* --- the map, underneath the paper ---------------------------- */
.trip__map {
  position: absolute;
  inset: 0;
  z-index: 0;
}
#leaf { width: 100%; height: 100%; }
.maplibregl-map { font-family: var(--sb-body); background: var(--sb-sky); }
.maplibregl-canvas { outline: none; }

/* Warms the basemap toward paper and softens its edges into the page. */
.rmap__tint {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    radial-gradient(80% 60% at 50% 40%, rgba(253, 246, 227, 0.35), transparent 70%),
    /* open ocean deepens toward the west edge */
    linear-gradient(90deg, rgba(30, 76, 143, 0.20), transparent 46%),
    linear-gradient(180deg, rgba(30, 76, 143, 0.16), transparent 32%, rgba(242, 189, 58, 0.16));
  mix-blend-mode: multiply;
}

.rmap__vehicle {
  font-size: 22px;
  line-height: 1;
  filter: drop-shadow(0 2px 4px rgba(12, 38, 72, 0.55));
  transition: opacity 0.4s var(--sb-ease);
  will-change: transform;
  pointer-events: none;
}
/* The glyph is a child because MapLibre owns the marker root's transform; this
   is the only place a heading can be written without being erased. `display:
   block` is load-bearing — transform is ignored on an inline box. */
.rmap__glyph {
  display: block;
  transition: transform 0.5s var(--sb-ease);
}

/* Themed emoji pin sitting above a stop's dot. */
.rmap__pin {
  font-size: 16px;
  line-height: 1;
  filter: drop-shadow(0 2px 3px rgba(12, 38, 72, 0.4));
  transition: opacity 0.4s var(--sb-ease);
  pointer-events: none;
  will-change: opacity;
}
.rmap__pin--tentative { opacity: 0.72; }

/* Non-stop landmark — faint flavour over the interior. */
.rmap__landmark {
  font-size: 15px;
  line-height: 1;
  opacity: 0.5;
  filter: saturate(0.8) drop-shadow(0 1px 2px rgba(12, 38, 72, 0.3));
  pointer-events: none;
}

/* Per-leg travel-time chip, pinned to a route segment's midpoint. */
.rmap__leg {
  font: 600 11px/1 system-ui, -apple-system, sans-serif;
  color: #2f2a24;
  background: rgba(253, 246, 227, 0.82);
  border: 1px solid rgba(30, 76, 143, 0.18);
  border-radius: 999px;
  padding: 2px 7px;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(12, 38, 72, 0.18);
  pointer-events: none;
}

/* Journey badge — distance travelled, top-left over the ocean. */
.rmap__badge {
  position: absolute; left: clamp(0.8rem, 3vw, 1.4rem); top: clamp(0.8rem, 3vh, 1.4rem);
  z-index: 5; pointer-events: none;
  font: 500 12px/1.25 var(--sb-body, system-ui), sans-serif; color: #2f2a24;
  background: rgba(253, 246, 227, 0.86); border: 1px solid rgba(30, 76, 143, 0.18);
  border-radius: 12px; padding: 7px 11px; box-shadow: 0 2px 8px rgba(12, 38, 72, 0.14);
}
.rmap__badge b { font-size: 15px; font-weight: 700; }
.rmap__badge span { display: block; font-size: 9.5px; letter-spacing: 0.09em; text-transform: uppercase; opacity: 0.6; margin-top: 3px; }

/* Photo card — the active stop, bottom-left over the ocean. */
.rmap__photo {
  position: absolute; left: clamp(0.8rem, 3vw, 1.4rem); bottom: clamp(3.2rem, 9vh, 4.8rem);
  z-index: 5; width: clamp(138px, 22vw, 196px); pointer-events: none;
  background: #fdf6e3; border-radius: 12px; padding: 6px; transform-origin: bottom left;
  box-shadow: 0 6px 20px rgba(12, 38, 72, 0.28);
  opacity: 0; transform: translateY(8px) scale(0.97);
  transition: opacity 0.5s var(--sb-ease), transform 0.5s var(--sb-ease);
}
.rmap__photo.is-on { opacity: 1; transform: translateY(0) scale(1); }
.rmap__photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; display: block; }
.rmap__photo-cap { padding: 6px 4px 2px; }
.rmap__photo-cap b { display: block; font: 700 13px/1.2 var(--sb-body, sans-serif); color: #2f2a24; }
.rmap__photo-cap span { display: block; font-size: 10.5px; color: #6b5d4a; margin-top: 2px; }
@media (max-width: 859px) { .rmap__photo { display: none; } }   /* phone: the note owns the screen */

/* attribution — required by OpenFreeMap / OSM */
.maplibregl-ctrl-attrib { background: rgba(253, 246, 227, 0.72) !important; font-size: 10px; }
.maplibregl-ctrl-attrib,
.maplibregl-ctrl-attrib a { color: var(--ink-soft) !important; }
/* On a phone the dots span nearly the full width and sit right on top of it.
   The attribution is a licence condition, not decoration — it gets out of the
   way rather than being covered. (On desktop the dots are a narrow island in
   the middle and the bottom-right corner is already clear.)
   Cleared by the dots' own geometry: their offset from the bottom, plus their
   height, plus a gap — so it keeps clearing them if the dots are restyled. */
@media (max-width: 859px) {
  .maplibregl-ctrl-bottom-right {
    bottom: calc(clamp(0.8rem, 3vh, 1.5rem) + var(--dots-h) + 0.4rem);
  }
}

/* --- the post-it -----------------------------------------------
   storybook.css centres the note with `transform: translate(-50%,-50%)`, but
   fusion.js animates x/y on that same element — and GSAP owns the whole
   transform property, so its tweens wiped the horizontal half of the centring
   and the note hung 86px off the right edge of a phone. Hand the centring to
   GSAP instead (xPercent/yPercent in fusion.js), and keep CSS out of it.
   Scoped here so index-storybook.html, whose JS never sets x/y at rest, is
   left exactly as lane-b built it. */
.postit { transform: none; }

/* .trip__notes covers the whole stage to position the note, so it was also
   swallowing clicks on the map's attribution link underneath — required by the
   OSM licence and, until now, dead. Only the note's own CTA needs to be
   clickable; the paper itself doesn't. */
.trip__notes { pointer-events: none; }
.postit__cta { pointer-events: auto; }

/* --- the illustration layer sits between map and scrim --------- */
/* pointer-events:none because an illustration at opacity 0 still swallows
   clicks — with the art transparent over Incheon, the invisible plate was what
   sat between the reader and the map's attribution link. It's decoration
   (aria-hidden); nothing here is meant to be clicked. */
.trip__bg { z-index: 1; pointer-events: none; }
/* fusion.js drives opacity AND scale per frame — the art rushes in from bigger
   and settles rather than fading up — so it needs transform hinted too. The
   scale(1.14) in storybook.css stays as the base value; the inline transform
   fusion.js writes overrides it every frame. */
.trip__bg img { will-change: opacity, transform; }

/* The rail is gone — the real map replaced it — so the scrim no longer needs
   to darken the left. It now backs the note instead: dark on the right (desktop,
   where the post-it lives) and along the bottom (phone, where it's centred). */
.trip__scrim {
  z-index: 2;
  background:
    linear-gradient(0deg, rgba(12, 38, 72, 0.34) 0%, transparent 42%),
    radial-gradient(80% 55% at 50% 55%, rgba(12, 38, 72, 0.22), transparent 70%);
}
@media (min-width: 860px) {
  .trip__scrim {
    background:
      linear-gradient(270deg, rgba(12, 38, 72, 0.44) 0%, rgba(12, 38, 72, 0.14) 34%, transparent 58%),
      linear-gradient(0deg, rgba(12, 38, 72, 0.24) 0%, transparent 34%);
  }
}

/* Phone: the note is the page, so give it the width it needs and pull it up off
   the dots. storybook.css's 74vw was fine when it was decoration over art; now
   it carries the whole stop. */
@media (max-width: 859px) {
  .postit {
    width: min(86vw, 23rem);
    padding: 1.35rem 1.25rem 1.2rem;
    top: 46%;
  }
  .postit__note { font-size: clamp(1rem, 4vw, 1.2rem); }
}

/* =============================================================
   DOTS — jump straight to any stop
   ============================================================= */
:root {
  /* the dots' rendered height: tap target + the pill's padding. Named because
     the map attribution has to clear it — see the attribution rule above. */
  --dots-h: calc(30px + 0.6rem);
}
.trip__dots {
  position: absolute;
  left: 50%;
  bottom: clamp(0.8rem, 3vh, 1.5rem);
  transform: translateX(-50%);
  z-index: 6;
  display: flex;
  align-items: center;
  gap: clamp(2px, 1vw, 5px);
  padding: 0.3rem 0.5rem;
  border-radius: 999px;
  background: rgba(253, 246, 227, 0.78);
  box-shadow: 0 2px 10px rgba(12, 38, 72, 0.24);
  max-width: calc(100vw - 1.5rem);
}
.trip__dot {
  appearance: none;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  /* the dot is 7px but the tap target must not be */
  width: 26px;
  height: 30px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}
.trip__dot span {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(47, 42, 36, 0.3);
  transition: transform 0.25s var(--sb-ease), background 0.25s var(--sb-ease);
}
/* the two headline nights read as different stops even before you get there */
.trip__dot[data-highlight="jazz"] span { background: rgba(232, 176, 75, 0.95); }
.trip__dot[data-highlight="pkm"]  span { background: rgba(167, 139, 250, 0.9); }
.trip__dot.is-on span { background: var(--sb-red); transform: scale(1.9); }
.trip__dot:focus-visible { outline: 2px solid var(--sb-cobalt); outline-offset: 2px; border-radius: 50%; }

/* no-GSAP / reduced-motion: the map can't be scroll-driven, so it goes away
   with the rest of the stage furniture and the notes just stack. */
.trip__stage.no-anim .trip__map,
.trip__stage.no-anim .trip__dots { display: none; }

/* =============================================================
   MAP-PAGE COVER — the route panorama, panning north → south.
   The art is 2.34:1, so a plain object-fit cover on a 16:10 screen
   crops away both ends: the snow on the left and the palms on the
   right, which are the only two things that say "this is a coast
   with a top and a bottom". Sized to the viewport's HEIGHT instead
   and slid sideways, the whole painting gets seen and the slide
   itself previews the direction of travel.
   ============================================================= */
.sb-hero--map .sb-hero__scene { display: block; }
.sb-hero--map .sb-hero__scene img {
  position: absolute;
  inset: 0 auto 0 0;
  width: auto;
  height: 100%;
  /* on a wide, short viewport the height-sized art would be narrower than
     the screen and leave a gap; then there is simply nothing to pan */
  min-width: 100%;
  max-width: none;
  object-fit: cover;
  /* -100% is the image's own width, so this lands exactly on its right
     edge however wide the art turns out to be */
  animation: coast-pan 40s ease-in-out infinite alternate;
}
@keyframes coast-pan {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-100% + 100vw)); }
}

/* The way back. They arrived by tapping a button on the home page, so
   there has to be a door out that isn't the browser's back arrow. */
.sb-back {
  position: absolute;
  top: clamp(0.8rem, 3vh, 1.5rem);
  left: clamp(0.8rem, 3vw, 1.5rem);
  z-index: 5;
  padding: 0.35em 0.9em;
  border-radius: 999px;
  font-family: var(--sb-hand);
  font-size: clamp(0.9rem, 3.4vw, 1.05rem);
  text-decoration: none;
  color: var(--sb-cobalt);
  background: rgba(255, 253, 247, 0.9);
  box-shadow: 0 3px 12px rgba(12, 38, 72, 0.26);
  transition: transform 0.18s var(--sb-ease);
}
.sb-back:hover { transform: translateX(-2px); }

.sb-credit {
  margin-top: 1.4rem;
  font-size: 0.8rem;
  opacity: 0.75;
}
.sb-credit a { color: inherit; }

@media (prefers-reduced-motion: reduce) {
  .sb-hero--map .sb-hero__scene img { animation: none; }
  .sb-back { transition: none; }
}

/* =============================================================
   BGM toggle — sits above everything, outside the pinned stage,
   so it stays put while the trip scrolls. Sound can never start
   on its own (browsers block audible autoplay), so this button
   IS the gesture, not a convenience.
   ============================================================= */
.bgm {
  position: fixed;
  right: clamp(0.8rem, 3vw, 1.5rem);
  bottom: clamp(0.8rem, 3vh, 1.5rem);
  z-index: 20;
  appearance: none;
  border: 0;
  cursor: pointer;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  font-size: 1.05rem;
  line-height: 1;
  color: var(--sb-cobalt);
  background: rgba(253, 246, 227, 0.78);
  box-shadow: 0 2px 10px rgba(12, 38, 72, 0.24);
  transition: transform 0.18s var(--sb-ease), background 0.18s;
}
.bgm:hover { transform: scale(1.06); }
.bgm[aria-pressed="true"] { background: var(--sb-wheat, #f2c94c); }
@media (prefers-reduced-motion: reduce) { .bgm { transition: none; } }

/* =============================================================
   POSTERS — the two headline nights get a page of their own.
   Rendered from data.js HIGHLIGHTS by fusion.js.
   ============================================================= */
.posters { position: relative; }

.poster {
  position: relative;
  min-height: 78svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding: clamp(3rem, 10vh, 6rem) var(--sb-edge);
}
.poster--jazz { background: linear-gradient(180deg, #1b2545, #3a2b56); }
.poster--pkm  { background: linear-gradient(180deg, #3a2b56, var(--sb-cobalt)); }

.poster__art { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.poster__art img {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.62;
}
/* the art is a backdrop, not the subject — sink it so the card reads */
.poster::after {
  content: "";
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(70% 60% at 50% 50%, rgba(12, 20, 45, 0.35), rgba(12, 20, 45, 0.72));
}

/* a pinned paper card, same stock as the post-it */
.poster__card {
  position: relative;
  z-index: 2;
  width: min(90vw, 30rem);
  padding: clamp(1.6rem, 5vw, 2.4rem);
  text-align: center;
  filter:
    drop-shadow(0 1px 1px rgba(60, 45, 20, 0.22))
    drop-shadow(0 18px 34px rgba(6, 14, 34, 0.45));
}
.poster__card::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background-color: var(--paper);
  background-image:
    radial-gradient(72% 52% at 18% 14%, rgba(255, 255, 255, 0.75), transparent 62%),
    radial-gradient(58% 46% at 88% 88%, rgba(203, 182, 140, 0.42), transparent 68%);
  filter: url(#paper-edge);
}
.poster__kicker {
  margin: 0;
  font-family: var(--sb-hand);
  font-size: 1.1rem;
  color: var(--ink-red);
}
.poster__title {
  margin: 0.1em 0 0;
  font-family: var(--sb-display);
  font-size: clamp(1.8rem, 6vw, 2.8rem);
  line-height: 1.05;
  color: var(--sb-cobalt);
}
.poster__note {
  margin: 0.8rem 0 0;
  font-family: var(--sb-hand);
  font-size: clamp(1.1rem, 3.6vw, 1.3rem);
  line-height: 1.45;
  color: var(--ink);
}
.poster__cta {
  display: inline-flex; align-items: center; gap: 0.4em;
  margin-top: 1.2rem;
  padding: 0.5em 1.2em;
  border-radius: 999px;
  font-family: var(--sb-body);
  font-weight: 700;
  font-size: 0.9rem;
  text-decoration: none;
  color: #fffdf7;
  background: var(--sb-red);
  box-shadow: 0 3px 0 #a32a23;
  transition: transform 0.2s var(--sb-ease);
}
.poster__cta:hover { transform: translateY(-2px); }

/* the tape on each poster echoes its post-it's tape, so the trip and the
   headline pages are visibly the same two nights */
.poster__card::after {
  content: "";
  position: absolute; top: -12px; left: 50%;
  width: 104px; height: 28px;
  transform: translateX(-50%) rotate(-2deg);
  border-left: 1px dashed rgba(255, 255, 255, 0.55);
  border-right: 1px dashed rgba(255, 255, 255, 0.55);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16);
}
.poster--jazz .poster__card::after { background: rgba(232, 176, 75, 0.75); }
.poster--pkm  .poster__card::after { background: rgba(167, 139, 250, 0.7); }
