/* ============================================================================
   America Éire — Story-page journey map
   The scroll-driven Ireland→US map treatment, lifted from the proven demo
   (/demo — see the `map` library book for the full geometry/why). Loaded ONLY
   on story pages that render the map (the route passes it in $styles when the
   story's destination is mappable — Alaska/Hawaii stories render map-less and
   never load this file).

   Consumes tokens.css (palette, type, space) and base.css (fonts, .kicker,
   .lead drop cap). What lives here is only the map treatment itself: the
   full-bleed sticky backdrop, the story column with its cream wash, the SVG
   styling, the decoration animations, and the mobile band.

   Class names are kept verbatim from the demo (.layout/.mapcol/.story/...)
   so the demo, this file, and the map book stay mutually legible. They are
   page-scoped by the stylesheet only ever loading on map story pages.
   ========================================================================== */

/* --- The two-layer layout: sticky map backdrop, story scrolls over it ----- */
.layout { position: relative; }

/* Map is a full-bleed sticky backdrop; the story (in normal flow) drives the
   page height and scrolls over it. */
.mapcol { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; }
.mapcol > .sticky { position: sticky; top: 0; height: 100vh; overflow: hidden; background: var(--sea); }

/* Story dominates; the map is decoration, most visible to the RIGHT of the
   text and never under it. The story spans the FULL viewport width so the
   cream wash gradient has the whole window to fade across (a narrower element
   edge clips the gradient into a visible seam). Text stays left via the
   paragraphs' max-width. Tune with --wash / --fade. */
:root { --wash: 50vw; --fade: 32vw; }
.story {
  position: relative; z-index: 2; width: 100%; min-height: 100vh;
  padding: 8vh 4vw 8vh 6vw;
  background: linear-gradient(to right,
    rgba(244, 237, 224, 0.70) 0,
    rgba(244, 237, 224, 0.70) var(--wash),
    rgba(244, 237, 224, 0) calc(var(--wash) + var(--fade)));
}

/* Story typography — the kicker (.kicker) and drop cap (.lead) come from
   base.css; only the map-page-specific pieces live here. */
.story h1 { margin-bottom: var(--space-3xs); }
.story .sub {
  font-family: var(--font-serif); font-style: italic;
  font-size: var(--step-0); color: var(--gold-deep);
  margin-bottom: var(--space-xl);
}
/* Fluid measure (Utopia-style): grows with the viewport so the text keeps
   pace and the open map margin stays proportionate instead of ballooning on
   wide screens (~26% map at the breakpoint, ~40% at 1600px where it caps at
   the 70ch ceiling). Floor 46ch keeps it readable near the breakpoint.
   Mobile drops the cap entirely (see media query). */
.story p {
  font-size: var(--step-0); line-height: 1.8;
  margin-bottom: var(--space-m);
  max-width: clamp(46ch, 16rem + 38vw, 70ch);
}
/* A kicker that happens to be a <p> (e.g. the initiative coda, mirroring the
   holding page's markup) must keep the kicker register — without this, the
   .story p rule above outranks base.css's .kicker (0-1-1 vs 0-1-0) and blows
   the line up to tracked, uppercase BODY size. */
.story p.kicker { font-size: var(--size-eyebrow); line-height: 1.5; margin-bottom: 0; }
.endcap { height: 32vh; display: flex; align-items: flex-end; padding-bottom: 5vh; }
.endcap p { font-family: var(--font-serif); font-style: italic; color: var(--color-subdued); font-size: var(--step-0); }
.endcap a { color: var(--color-accent); text-decoration: none; border-bottom: 1px solid var(--color-accent); }

/* --- The map SVG ----------------------------------------------------------- */
/* Endpoint place-labels (opt-in via data-ie-label / data-us-label on #mapcol).
   Stoker + Forest = the system's heading law, applied to the map. font-size is
   in COMPOSITE UNITS, so it scales with the map. Tuned June 11 across three
   live looks: 22 (too big) → 16 → 12 (too small) → 14, and the halo went
   4px (read as a white glow) → none → back at a 1.5px whisper in --sea at
   60% opacity: invisible on calm parchment, but it quietly carries the label
   across a graticule line or coast squiggle if one ever lands there (matters
   for the boilerplate-template version, where label positions vary per
   recipient). */
.pt-label {
  font-family: var(--font-serif);
  font-size: 14px;
  letter-spacing: 0.04em;
  fill: var(--green);
  paint-order: stroke;
  stroke: var(--sea);
  stroke-width: 1.5px;
  stroke-opacity: 0.6;
  stroke-linejoin: round;
  pointer-events: none;
}
/* .mapclip: the SVG's clip + containing block, created by story-map.js around
   the SVG it builds. position:relative (not the sticky itself) because Safari
   doesn't reliably make a sticky-inside-absolute the containing block for
   absolute descendants — the SVG escaped the band's overflow:hidden and
   painted full-page (June 11, 2026). Relative is honored everywhere; the clip
   moves here with it. The sticky's own overflow:hidden stays as a second
   fence and for the .loading note. */
.mapclip { position: relative; width: 100%; height: 100%; overflow: hidden; }
svg.map { position: absolute; top: 0; left: 0; height: 100%; will-change: transform; max-width: none; max-height: none; }
/* ^ max-width/max-height:none is LOAD-BEARING: base.css applies a responsive
   max-width:100% reset to svg, which silently capped this element's scripted
   width (e.g. 4664px → 1251px) while the inline height still applied — so the
   browser recomputed preserveAspectRatio against the capped box and shifted
   the whole canvas ~1700px off-target. The demo never hit this because it
   didn't load base.css. Symptom if it regresses: page fine, no errors, map
   content far off to the left / seemingly absent. (June 10, 2026) */
.coast path { fill: var(--land); stroke: var(--land-line); stroke-width: 1; stroke-linejoin: round; }
.route { fill: none; stroke: var(--orange); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 5 6; }
.dot { fill: var(--orange); stroke: var(--cream); stroke-width: 2; }
.pt-us { fill: var(--gold); stroke: var(--cream); stroke-width: 2; }
/* Ireland dot: explicit lighter green, NOT --green (#244838 reads near-black
   at a 6px dot — see the map book's recolor note). */
.pt-ie { fill: #3f7a52; stroke: var(--cream); stroke-width: 2; }
.grat line { stroke: var(--land-line); stroke-width: 0.5; opacity: 0.32; }
.loading {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-serif); font-style: italic; color: var(--color-subdued);
}

/* --- Decorative spot illustrations (engraved-chart warmth) ----------------- */
.deco .ink  { fill: none;        stroke: #7a5e2e; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
.deco .inkf { fill: var(--land); stroke: #7a5e2e; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
.deco .thin { fill: none;        stroke: #9a8050; stroke-width: 1;   stroke-linecap: round; }
.deco .wv   { fill: none;        stroke: #9a8050; stroke-width: 1.2; stroke-linecap: round; opacity: 0.7; }
@keyframes rock { 0%, 100% { transform: rotate(-2.5deg); } 50% { transform: rotate(2.5deg); } }
@keyframes bobv { 0%, 100% { transform: translateY(0); }   50% { transform: translateY(3px); } }
@keyframes drift { 0% { transform: translateX(0); } 100% { transform: translateX(-26px); } }
/* Sea texture drift — the water-lining pattern rect slides west exactly one
   tile (46px) then loops, so the motion is seamless. Slow on purpose: a
   shimmer, not traffic. Killed by the reduced-motion rule like everything. */
@keyframes seadrift { to { transform: translateX(-46px); } }
.seatex { animation: seadrift 18s linear infinite; }
/* transform-box:fill-box is load-bearing: without it the rotation origin
   resolves against the whole SVG and the ship flies off. */
.rock { animation: rock 5s ease-in-out infinite; transform-box: fill-box; transform-origin: center bottom; }
.bob { animation: bobv 4s ease-in-out infinite; }
.waveband { animation: drift 3.4s linear infinite; }

/* --- Torch glow (the landfall finale) ---------------------------------------
   Layered ignition inside #torchglow, whose group opacity frame() drives by
   proximity (eased — it blooms in the final approach): a breathing halo,
   slowly rotating light rays, a gold flame overlay that "catches fire" over
   the ink one, and three twinkling sparks. All killed by reduced-motion
   (the static glow remains). */
@keyframes torchpulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.08); opacity: 0.85; } }
.torchpulse { animation: torchpulse 2.8s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
@keyframes rayspin { to { transform: rotate(360deg); } }
.torchrays { animation: rayspin 26s linear infinite; transform-box: fill-box; transform-origin: center; }
@keyframes twinkle { 0%, 100% { opacity: 0.15; } 50% { opacity: 0.9; } }
.twinkle { animation: twinkle 1.9s ease-in-out infinite; }
.twinkle.t2 { animation-delay: 0.6s; }
.twinkle.t3 { animation-delay: 1.2s; }

/* --- Corner brand mark (mobile-only; revealed in the media query) ----------
   The full wordmark pinned to the band's upper-left, linking home — the ONLY
   brand/nav element on mobile (the site header is hidden there). z6 sits above
   the map (z4) and the hard-cut strip (z3). pointer-events:auto re-enables the
   link inside the pointer-events:none map column. Upper-LEFT is deliberate: on
   the right→left journey that's the Ireland/"behind" corner, never over the
   route or the moving dot. */
.bandmark { display: none; position: absolute; top: 0.7rem; left: 1rem; z-index: 6; pointer-events: auto; }
.bandmark img { width: 130px; height: auto; display: block; }

/* --- MOBILE — the desktop idea rotated 90° ---------------------------------
   Desktop: map is a full-bleed backdrop, story sits left with a left→right
   opaque→transparent wash. Mobile: map is a SHORT STICKY BAND across the top,
   the story scrolls beneath it, the same scroll engine runs. See the map
   book's "Mobile layout (the band)" for the full reasoning — including the
   z-index:4 fix (THE load-bearing line: below it the story's cream background
   paints over the map and the map "disappears"). */
@media (max-width: 820px) {
  /* The site header STAYS on mobile (changed June 10 — originally hidden per
     the June 7 demo design). The brand never doubles: story-map.js runs a
     shared-element glide that hides the header's logo the moment scrolling
     starts and flies the corner mark from its exact position into the band.
     Keeping the header also restores mobile nav, and navH > 0 means the map
     begins animating as the header scrolls off rather than on first touch. */

  /* --band: the single dial for how much map shows.
     Declared twice on purpose: Safari computes plain vh against the LARGEST
     viewport (URL bar retracted), so 33vh renders visibly taller there than
     in Chrome at the same size. svh — the small, toolbar-safe viewport unit —
     is what "a third of the screen" actually means. NOT dvh: that resizes as
     the toolbar collapses and the band would visibly jump mid-scroll.
     The @supports guard is load-bearing: an unsupported unit inside a custom
     property doesn't fall back per-declaration — it poisons every var(--band)
     use at computed-value time — so the svh value may only be declared where
     the unit is known-good. */
  :root { --band: 33vh; }
  @supports (height: 1svh) {
    :root { --band: 33svh; }
  }
  .mapcol { height: 100%; z-index: 4; }
  .mapcol > .sticky { height: var(--band); top: 0; border-bottom: 1px solid var(--gold); }

  /* Hard cut: a fixed strip welded to the band's BOTTOM edge, above the story
     (z3 > story z2), so text scrolling up vanishes cleanly at the boundary
     rather than floating into the map. Widen the transparent→cream span for a
     softer fade. */
  .layout::before {
    content: ""; position: fixed; left: 0; right: 0; top: 0; height: var(--band);
    z-index: 3; pointer-events: none;
    background: linear-gradient(to bottom,
      rgba(244, 237, 224, 0) 0,
      rgba(244, 237, 224, 0) calc(var(--band) - 3vh),
      rgba(244, 237, 224, 0.96) 100%);
  }

  /* Story starts below the band (padding-top = band + breathing room); solid
     cream from there down — no side wash on mobile. */
  .story {
    width: 100%; min-height: auto;
    padding: calc(var(--band) + 4vh) 6vw 8vh 6vw;
    background: var(--cream);
  }

  /* Drop the measure so prose fills the narrow column. */
  .story p { max-width: none; }

  /* Reveal the corner brand mark — FIXED on mobile, not absolute: its resting
     spot is identical to the band's corner once the band pins (i.e. the whole
     journey), but fixed positioning lets the glide travel ABOVE the band,
     which has overflow:hidden and would otherwise clip the mark mid-flight.
     Starts transparent; story-map.js drives the shared-element glide — the
     mark appears at the header logo's exact position/scale the moment
     scrolling starts (while the header's logo hides), then translates and
     shrinks into this corner as the header scrolls off. One logo on screen at
     all times. transform-origin top left is required by the glide math. */
  .bandmark { display: block; position: fixed; top: 0.7rem; left: 1rem; opacity: 0; transform-origin: top left; will-change: transform, opacity; }
}
