/* ==========================================================================
   CRAWLLOWEEN map
   The six-neighborhood route map. Load after components.css.

   WHY THIS EXISTS, and what changed from the source sketch:

   The sketch had seven stops including Old Town, on its own cool blue-black
   palette. Old Town is cut, so this is six. And the palette is retuned onto
   the site tokens, which is the more important change: every stop now carries
   ITS OWN neighborhood accent instead of one shared sodium orange.

   That turns the map into the colour index for the whole site. A buyer who
   learns "mine is the magenta one" on the map finds their card, their page and
   their wristband by the same cue. A single-accent map cannot do that.

   The lake stays cool. It is water, it is the one place on the page where a
   cold note is correct, and it stops the composition reading as all one temperature.
   ========================================================================== */

.map-section {
  position: relative;
  isolation: isolate;
}

/* ------------------------------------------------------------------- board */

.map-board {
  display: grid;
  gap: var(--sp-5);
  align-items: start;
}

/* One breakpoint. Below it the map sits above its own caption panel, which is
   the right reading order on a phone: see the shape, then read the stop. */
@media (min-width: 940px) {
  .map-board {
    grid-template-columns: 1.45fr 1fr;
    gap: var(--sp-7);
  }
}

.map-board > * { min-width: 0; }

.map-card {
  position: relative;
  background: var(--bg-elev);
  border: var(--border);
  border-radius: var(--r-lg);
  padding: clamp(var(--sp-3), 2vw, var(--sp-5));
}

.map-card svg.map {
  display: block;
  width: 100%;
  height: auto;
}

/* --------------------------------------------------------- map internals */

.map-grid line {
  stroke: var(--line-strong);
  stroke-width: 1;
}

/* The lake reads as water, not as a design element. At full opacity the flat
   slab dominated the right half of the composition and competed with the stops,
   so the fill is dropped well back and only the shoreline carries the colour. */
.map-shore {
  fill: var(--water-fill);
  fill-opacity: 0.45;
  stroke: var(--water-line);
  stroke-width: 1.5;
  stroke-opacity: 0.55;
}

.map-lake-label {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-widest);
  text-transform: uppercase;
  fill: var(--water-line);
  fill-opacity: 0.8;
}

/* The route is drawn in the brand ember rather than any one neighborhood's
   colour, because it belongs to all six. */
.map-route {
  fill: none;
  stroke: var(--ember);
  stroke-opacity: 0.75;
  stroke-width: 6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* -------------------------------------------------------------- the stops

   Each <a class="map-stop"> sets --stop to its neighborhood accent inline via
   the data-hood scope, so nothing here needs to know which is which.
   ---------------------------------------------------------------------- */

.map-stop {
  cursor: pointer;
  /* Fallback so a stop is never unstyled if a hood scope is missing. */
  --stop: var(--accent, var(--ember));

  /* ------------------------------------------------------------------
     THESE TWO EXIST BECAUSE OF THE <use> SHADOW BOUNDARY. READ BEFORE EDITING.

     Each glyph lives in a <symbol> and is instanced with <use>, which builds a
     shadow tree. A descendant selector written here, like `.map-stop .glyph`,
     does NOT match shapes inside that tree. Only INHERITED properties cross the
     boundary, and custom properties inherit.

     So the shapes inside each <symbol> carry `style="fill:var(--glyph-fill)"`
     or `style="fill:var(--cut-fill)"`, and the values are set here and
     inherited in. Writing `.map-stop .glyph { fill: ... }` looks correct,
     changes nothing, and ships six solid blobs with no faces.

     --cut-fill must always equal the disc fill, because the cuts are holes: eyes,
     teeth, a mouth. They read as the disc showing through the glyph.
     ------------------------------------------------------------------ */
  --glyph-fill: var(--bg-sunk);
  --cut-fill: var(--bone);
}

.map-stop:hover,
.map-stop:focus-visible,
.map-stop.is-on { --cut-fill: var(--stop); }

.map-stop .hit { fill: transparent; }

.map-stop .disc {
  fill: var(--bone);
  stroke: var(--bg-sunk);
  stroke-width: 2;
  transition: fill var(--dur-base) var(--ease-standard);
}

.map-stop .name {
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  fill: var(--text-dim);
  transition: fill var(--dur-base) var(--ease-standard);
  /* Halo the label so it stays legible where it crosses the grid or the lake. */
  paint-order: stroke;
  stroke: var(--bg-elev);
  stroke-width: 5px;
  stroke-linejoin: round;
}

.map-stop .lift {
  transition: transform var(--dur-base) var(--ease-release);
  transform-origin: center;
}

.map-stop .ring {
  fill: none;
  stroke: var(--stop);
  stroke-width: 2;
  stroke-opacity: 0;
  transition: stroke-opacity var(--dur-base) var(--ease-standard);
}

.map-stop .halo {
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease-standard);
}

/* Hover and keyboard focus read identically. */
.map-stop:hover .disc,
.map-stop:focus-visible .disc { fill: var(--stop); }

.map-stop:hover .cut,
.map-stop:focus-visible .cut { fill: var(--stop); }

.map-stop:hover .name,
.map-stop:focus-visible .name { fill: var(--text); }

.map-stop:hover .lift,
.map-stop:focus-visible .lift { transform: translateY(-3px); }

.map-stop:focus { outline: none; }
.map-stop:focus-visible .ring { stroke-opacity: 1; stroke-width: 2.5; }

/* Selected. Set by map.js on the group matching the panel. */
.map-stop.is-on .disc { fill: var(--stop); }
.map-stop.is-on .cut  { fill: var(--stop); }
.map-stop.is-on .name { fill: var(--stop); }
.map-stop.is-on .ring { stroke-opacity: 0.55; }
.map-stop.is-on .halo { opacity: 1; }

/* --------------------------------------------------------------- panel */

.map-panel {
  position: relative;
  overflow: hidden;
  background: var(--bg-elev);
  border: var(--border);
  border-radius: var(--r-lg);
  padding: clamp(var(--sp-5), 2.6vw, var(--sp-6));
}

/* The rule at the top takes the selected neighborhood's colour, so the panel
   itself confirms the choice. */
.map-panel::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--panel-accent, var(--ember));
  transition: background var(--dur-base) var(--ease-standard);
}

.map-panel__idx {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-widest);
  text-transform: uppercase;
  color: var(--text-faint);
}

.map-panel__idx .n { color: var(--panel-accent, var(--ember)); }

.map-panel__name {
  font-family: var(--font-display);
  font-weight: var(--fw-black);
  text-transform: uppercase;
  font-size: clamp(2rem, 5vw, 3.2rem);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-tight);
  margin: var(--sp-3) 0 0;
}

.map-panel__char {
  margin-top: var(--sp-3);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--track-widest);
  text-transform: uppercase;
  color: var(--panel-accent, var(--ember));
}

.map-panel__note {
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-sm);
  color: var(--text-dim);
}

.map-panel__meta {
  margin-top: var(--sp-5);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
}

/* CTA line chips. Real transit information, and a small trust signal: it says
   somebody checked which train actually gets you there. */
.map-line {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  padding: var(--sp-1) var(--sp-3);
}

.map-line__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.map-panel__cta {
  margin-top: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.map-hint {
  margin: var(--sp-3) var(--sp-1) 0;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--text-faint);
}

/* ------------------------------------------------------------- running order

   Doubles as the legend and as a no-JS fallback: it is a plain list of links
   to all six neighborhood pages, so the map is never the only way through.
   ---------------------------------------------------------------------- */

.map-order {
  margin-top: var(--sp-7);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--line);
  display: grid;
  gap: 0 var(--sp-7);
  grid-template-columns: repeat(auto-fit, minmax(min(380px, 100%), 1fr));
}

.map-order__row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  transition: border-color var(--dur-fast) var(--ease-standard);
}

.map-order__row:hover { border-bottom-color: var(--row-accent, var(--ember)); }

.map-order__k {
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  color: var(--row-accent, var(--ember));
  flex: 0 0 auto;
}

.map-order__h {
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  font-size: var(--fs-h4);
  letter-spacing: var(--track-normal);
  line-height: var(--lh-snug);
  color: var(--text);
}

.map-order__c {
  margin-left: auto;
  font-size: var(--fs-xs);
  color: var(--text-dim);
  text-align: right;
}

/* The footnote under the running order. Exists as a class because the preview
   harness carried it as an inline style, and spacing belongs in a stylesheet. */
.map-note {
  margin-top: var(--sp-6);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}

/* --------------------------------------------------------- load sequence

   The route draws, then the stops arrive along it. One composed moment,
   not six independent animations.

   Delays come from --i on each stop rather than nth-of-type, so adding or
   removing a neighborhood does not require editing the CSS. The sketch
   hardcoded seven nth-of-type rules and would have silently stopped animating
   the sixth stop when Old Town was removed.
   ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .js-motion .map-route {
    stroke-dasharray: 1200;
    stroke-dashoffset: 1200;
    animation: map-draw 1.5s var(--ease-standard) 0.15s forwards;
  }

  .js-motion .map-stop {
    opacity: 0;
    animation: map-pop var(--dur-slow) var(--ease-release) forwards;
    animation-delay: calc(0.55s + (var(--i, 0) * 0.11s));
  }

  @keyframes map-draw { to { stroke-dashoffset: 0; } }
  @keyframes map-pop  { from { opacity: 0; } to { opacity: 1; } }
}
