/* ==========================================================================
   norway-map — iteration block
   --------------------------------------------------------------------------
   Cinematic LIGHT-themed MapLibre globe of Norway. flyTo()s between 24
   mineral prospects on a continuous shuffled loop. DHQ choreography +
   chrome stack, but every overlay inverted for a light basemap:
     - Carto light_nolabels (white ocean / pale tan land)
     - MapLibre 4.7 globe projection
     - dark ink overlays on light surface
     - Milano Red (#C42800) accent stays — pulse dot, scan-line tint,
       prospect marker.

   Scoped to .nm so its variables don't leak.
   ========================================================================== */

.nm {
  /* Dark plate (2026-07): matches the Project Hub map terminal. */
  --nm-bg:         #0B0F16;
  --nm-bleed:      #0B0F16;
  --nm-border:     rgba(244, 245, 247, 0.12);
  --nm-text:       #F4F5F7;
  --nm-text-dim:   rgba(244, 245, 247, 0.62);
  --nm-text-faint: rgba(244, 245, 247, 0.40);
  --nm-accent:       #E23100;
  --nm-accent-soft:  rgba(226, 49, 0, 0.55);
  --nm-accent-glow:  rgba(226, 49, 0, 0.30);
  --nm-font-sans: 'IBM Plex Sans', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --nm-font-mono: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  background: var(--nm-bg);
  color: var(--nm-text);
  font-family: var(--nm-font-sans);
}

/* 300vh outer + sticky 100vh stage so the globe stays on screen long
   enough for the user to see the flyTo loop reach several prospects
   before the next block takes over. */
.nm-outer {
  position: relative;
  height: 300vh;
}
.nm-stage {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
  background: var(--nm-bg);
}

.nm-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Light canvas filter — just a touch of contrast + slight desaturation
   so the basemap reads as a quiet textured surface, not a flat page. */
.nm-canvas .maplibregl-canvas {
  filter: contrast(1.06) saturate(0.7) brightness(0.92);
}

/* Subtle inset vignette — light edges fading toward off-white so the
   globe reads as a centred frame rather than a flat document. */
.nm-vignette {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at center, transparent 0%, rgba(11, 15, 22, 0.25) 65%, rgba(11, 15, 22, 0.8) 100%);
  pointer-events: none;
  z-index: 2;
}

/* Dark hairline grid instead of DHQ's white grid — works on light surface. */
.nm-grid-overlay {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(244, 245, 247, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(244, 245, 247, 0.045) 1px, transparent 1px);
  background-size: 72px 72px;
  pointer-events: none;
  z-index: 3;
}

.nm-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 4;
  opacity: 0.035; /* light specks on the dark surface */
  background-image: url("data:image/svg+xml;utf8,<svg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* Scan-line keeps the accent tint but at lower opacity on light bg. */
.nm-scan-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 140px;
  background: linear-gradient(180deg, transparent 0%, rgba(226, 49, 0, 0.10) 50%, transparent 100%);
  opacity: 0.6;
  z-index: 3;
  pointer-events: none;
  animation: nm-scan 14s linear infinite;
}
@keyframes nm-scan { 0% { top: -140px; } 100% { top: 100%; } }

/* Desktop legibility scrim (client, 1 Sep 2026): a slight white gradient from
   the left edge fading out by 50% of the stage, above the map texture but
   under the content, so the intro column ("Discover / Partner / Redeploy")
   stays legible when zoomed-in terrain passes behind it. Desktop only. */
.nm-scrim {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  display: none;
  background: linear-gradient(
    90deg,
    rgba(240, 241, 238, 0.85) 0%,
    rgba(240, 241, 238, 0.5) 28%,
    rgba(240, 241, 238, 0) 50%
  );
}
@media (min-width: 761px) {
  .nm-scrim { display: block; }
}

.nm-corner {
  position: absolute;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(244, 245, 247, 0.28);
  z-index: 5;
  pointer-events: none;
}
.nm-corner-tl { top: 24px; left: 24px;  border-right: none; border-bottom: none; }
.nm-corner-tr { top: 24px; right: 24px; border-left: none;  border-bottom: none; }
.nm-corner-bl { bottom: 24px; left: 24px; border-right: none; border-top: none; }
.nm-corner-br { bottom: 24px; right: 24px; border-left: none; border-top: none; }

.nm-content {
  position: relative;
  z-index: 10;
  height: 100%;
  display: flex;
  flex-direction: column;
  /* Panel anchored at the TOP — eyebrow → flipped ruler → headline + figure.
     The map fills the lower two-thirds of the stage. */
  justify-content: flex-start;
  gap: 28px;
  /* Same left axis as every containered section (css/layout.css --teako-page-inset). */
  padding: 44px var(--teako-page-inset, 56px);
  pointer-events: none;
}
.nm-content > * { pointer-events: auto; }

/* ---------- Feature layout (eyebrow / headline+body+figure / ruler) ----------
   Replaces the previous top-bar / headline-block / bottom-bar trio.
   .nm-content's existing flex column with space-between handles the
   vertical distribution: eyebrow up top, feature-body centred in the
   remaining height (auto via space-between), ruler hugging the bottom. */

.nm-feature-top { /* lives at the top of .nm-content via space-between */ }

.nm-feature-eyebrow {
  display: inline-block;
  /* Clear the fixed site-nav wordmark, which overlays the section's top-left. */
  margin-left: 160px;
  font-family: var(--nm-font-mono);
  font-size: 11px;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--nm-text-dim);
}

.nm-feature-body {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 80px;
  width: 100%;
}

/* Once the count-up has made its point, the big km² figure fades away
   (nm-quiet, set from JS) and the card-placement pass reclaims the right
   side of the stage. The title and paragraph stay — the left side keeps
   telling the story. */
.nm-feature-figure {
  transition: opacity 1.4s ease;
}
.nm.nm-quiet .nm-feature-figure {
  opacity: 0;
  pointer-events: none;
}

.nm-feature-text {
  max-width: 680px;
  flex: 1 1 auto;
}

.nm-feature-headline {
  margin: 0;
  font-family: var(--nm-font-sans);
  font-size: clamp(40px, 5.2vw, 68px);
  font-weight: 600;
  line-height: 1.0;
  letter-spacing: -0.035em;
  color: var(--nm-text);
}

.nm-feature-sub {
  margin: 20px 0 0;
  font-family: var(--nm-font-sans);
  font-size: 15px;
  line-height: 1.5;
  color: var(--nm-text-dim);
  max-width: 480px;
}

.nm-feature-figure {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-shrink: 0;
}

.nm-feature-unit {
  font-family: var(--nm-font-mono);
  font-size: clamp(13px, 1.1vw, 17px);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--nm-text-dim);
}
.nm-feature-unit sup {
  font-size: 0.7em;
  vertical-align: super;
}

.nm-feature-value {
  font-family: var(--nm-font-sans);
  font-size: clamp(72px, 10vw, 160px);
  font-weight: 700;
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--nm-text);
  font-variant-numeric: tabular-nums;
}

/* Tick ruler — flipped from the bottom-anchored original. The 1 px solid
   baseline now sits at the TOP and the ticks drop DOWN from it: tall
   ticks every 30 px, short hairlines every 6 px, both hanging beneath
   the line. */
.nm-feature-ruler {
  position: relative;
  height: 16px;
  flex-shrink: 0;
}
.nm-feature-ruler::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 1px;
  height: 13px;
  background-image:
    /* Tall ticks: 1px every 30px, 13px tall */
    repeating-linear-gradient(
      to right,
      rgba(244, 245, 247, 0.8) 0,
      rgba(244, 245, 247, 0.8) 1px,
      transparent 1px,
      transparent 30px
    ),
    /* Short ticks: 1px every 6px, 6px tall (clipped via background-size) */
    repeating-linear-gradient(
      to right,
      rgba(244, 245, 247, 0.45) 0,
      rgba(244, 245, 247, 0.45) 1px,
      transparent 1px,
      transparent 6px
    );
  background-size: 100% 13px, 100% 6px;
  /* Anchor both tick layers to the TOP so they hang below the baseline. */
  background-position: 0 0, 0 0;
  background-repeat: no-repeat, no-repeat;
}
.nm-feature-ruler::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  background: rgba(244, 245, 247, 0.8);
}

/* Milano-Red indicator that travels along the ruler in lockstep with the
   7,000 KM² count-up. JS sets `left` (0 → 100 %) and `opacity` each frame;
   the indicator fades out across the last 15 % so the final number lands
   on its own. */
.nm-feature-ruler-indicator {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 2px;
  background: #C42800;
  opacity: 0;
  pointer-events: none;
  box-shadow: 0 0 12px rgba(196, 40, 0, 0.55);
  transform: translateX(-1px); /* visually centre the 2 px bar on its left edge */
}

.nm-top-bar { display: flex; justify-content: space-between; align-items: center; }

.nm-logo {
  font-family: var(--nm-font-sans);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.022em;
  line-height: 1;
  color: var(--nm-text);
}

.nm-status-badge {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid var(--nm-border);
  border-radius: 6px;
  font-family: var(--nm-font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.05em;
  color: var(--nm-text-dim);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  text-transform: uppercase;
}

.nm-pulse-dot {
  width: 7px;
  height: 7px;
  background: var(--nm-accent);
  border-radius: 50%;
  animation: nm-pulse 1.8s ease-out infinite;
}
@keyframes nm-pulse {
  0%   { box-shadow: 0 0 0 0   var(--nm-accent-glow); }
  70%  { box-shadow: 0 0 0 12px rgba(196, 40, 0, 0); }
  100% { box-shadow: 0 0 0 0   rgba(196, 40, 0, 0); }
}

.nm-headline-block { max-width: 660px; }

.nm-headline {
  margin: 0;
  font-family: var(--nm-font-sans);
  font-size: clamp(40px, 5.2vw, 68px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.035em;
  color: var(--nm-text);
}

.nm-sub {
  margin: 22px 0 0;
  font-family: var(--nm-font-sans);
  font-size: 16px;
  line-height: 1.5;
  color: var(--nm-text-dim);
  max-width: 520px;
  font-weight: 400;
  letter-spacing: -0.01em;
}

.nm-bottom-bar { display: flex; justify-content: space-between; align-items: flex-end; gap: 40px; }
.nm-meta {
  font-family: var(--nm-font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--nm-text-faint);
  line-height: 1.9;
}
.nm-meta-row   { display: flex; gap: 14px; align-items: baseline; }
.nm-meta-label { min-width: 130px; text-transform: uppercase; letter-spacing: 0.08em; font-size: 9.5px; }
.nm-meta-value { color: var(--nm-text); font-weight: 500; font-variant-numeric: tabular-nums; }
.nm-meta-value.ok { color: #1f7a3c; }
.nm-meta-right { text-align: right; }
.nm-meta-right .nm-meta-row { justify-content: flex-end; }

/* ---------- Prospect marker (dot + card popup, MapLibre Marker target) ---------- */

.nm-marker { position: relative; width: 0; height: 0; pointer-events: none; }

.nm-marker-dot {
  position: absolute;
  left: -7px;
  top: -7px;
  width: 14px;
  height: 14px;
  background: var(--nm-accent);
  border-radius: 50%;
  border: 2px solid #ffffff;
  box-shadow: 0 0 0 0 var(--nm-accent-glow), 0 2px 8px rgba(0, 0, 0, 0.4);
  opacity: 0;
  transform: scale(0.3);
  animation:
    nm-dotIn 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) forwards,
    nm-markerPulse 1.8s ease-out 0.5s infinite;
}
@keyframes nm-dotIn { to { opacity: 1; transform: scale(1); } }
@keyframes nm-markerPulse {
  0%   { box-shadow: 0 0 0 0   rgba(226, 49, 0, 0.55), 0 2px 8px rgba(0, 0, 0, 0.4); }
  70%  { box-shadow: 0 0 0 22px rgba(226, 49, 0, 0),    0 2px 8px rgba(0, 0, 0, 0.4); }
  100% { box-shadow: 0 0 0 0   rgba(226, 49, 0, 0),    0 2px 8px rgba(0, 0, 0, 0.4); }
}
.nm-marker.leaving .nm-marker-dot { animation: nm-dotOut 0.5s ease-in forwards; }
@keyframes nm-dotOut { to { opacity: 0; transform: scale(0.5); } }

/* ---------- Cluster dots (plain pointers, no name card) ---------- */
/* Calmer than the single-prospect dot: a touch smaller, staggered in via a
   per-dot --nm-delay, and NO infinite pulse — 8–12 pulsing dots at once would
   read as noise. `both` keeps each dot hidden through its stagger delay. */
.nm-cluster .nm-marker-dot {
  width: 12px;
  height: 12px;
  left: -6px;
  top: -6px;
  animation: nm-dotIn 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) var(--nm-delay, 0ms) both;
}
.nm-cluster.leaving .nm-marker-dot {
  animation: nm-dotOut 0.5s ease-in forwards;
}

/* Light glass card — inverted from DHQ's dark glass. */
.nm-marker-card {
  position: absolute;
  left: 16px;
  top: -32px;
  min-width: 240px;
  max-width: 270px;
  padding: 12px 14px 13px;
  background: rgba(255, 255, 255, 0.78);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  backdrop-filter: blur(20px) saturate(1.4);
  border: 1px solid rgba(244, 245, 247, 0.12);
  border-radius: 0;
  box-shadow:
    0 14px 40px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(196, 40, 0, 0.04),
    inset 0 1px 0 rgba(255, 255, 255, 0.6);
  opacity: 0;
  transform: translate(-8px, 0) scale(0.96);
  animation: nm-cardIn 0.55s cubic-bezier(0.2, 0.8, 0.2, 1) 0.25s forwards;
}
.nm-marker-card::before {
  content: '';
  position: absolute;
  left: -7px;
  top: 34px;
  width: 7px;
  height: 1px;
  background: rgba(20, 26, 38, 0.18);
}
@keyframes nm-cardIn { to { opacity: 1; transform: translate(0, 0) scale(1); } }
.nm-marker.leaving .nm-marker-card { animation: nm-cardOut 0.45s cubic-bezier(0.4, 0, 1, 1) forwards; }
@keyframes nm-cardOut { to { opacity: 0; transform: translate(8px, -2px) scale(0.98); } }

/* Mineral kicker — small mono caps line above the title. A coloured dot
   leads it so the four mineral types read at a glance: copper (brand red),
   gold (warm), silver (cool grey), uranium (acid green). */
.nm-card-mineral {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
  font-family: var(--nm-font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--nm-text-dim);
}
.nm-card-mineral-swatch {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
}
.nm-card-mineral[data-mineral="copper"]   .nm-card-mineral-swatch { background: #C42800; }
.nm-card-mineral[data-mineral="gold"]     .nm-card-mineral-swatch { background: #C8A24A; }
.nm-card-mineral[data-mineral="silver"]   .nm-card-mineral-swatch { background: #9aa1ad; }
.nm-card-mineral[data-mineral="uranium"]  .nm-card-mineral-swatch { background: #7DBE3A; }

.nm-card-title {
  font-family: var(--nm-font-sans);
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.015em;
  margin-bottom: 3px;
  color: var(--nm-text);
}
.nm-card-location {
  font-family: var(--nm-font-sans);
  font-size: 12.5px;
  color: var(--nm-text-dim);
  font-weight: 400;
  letter-spacing: -0.005em;
}

/* MapLibre default chrome — gone. */
.nm .maplibregl-ctrl-attrib,
.nm .maplibregl-ctrl-logo { display: none !important; }

@media (max-width: 720px) {
  .nm-content { padding: 28px 24px; }
  .nm-headline { font-size: 38px; }
  .nm-bottom-bar { flex-direction: column; align-items: flex-start; gap: 16px; }
  .nm-meta-right { text-align: left; }
  .nm-meta-right .nm-meta-row { justify-content: flex-start; }
  .nm-corner { display: none; }
}

/* ---------- Static portfolio dots (persistent — replaces the fly-through) ---------- */
/* All 78 licence points sit at once. Plain dots are small and calm (no pulse —
   78 pulsing dots would be noise); the curated key areas are larger, ringed
   and gently pulsing to carry the eye, with a labelled name. */
.nm-dot .nm-marker-dot {
  width: 9px; height: 9px; left: -4.5px; top: -4.5px;
  border-width: 1.5px;
  box-shadow: 0 1px 4px rgba(20, 26, 38, 0.22);
  animation: nm-dotIn 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) var(--nm-delay, 0ms) both;
}
.nm-dot-key .nm-marker-dot {
  width: 13px; height: 13px; left: -6.5px; top: -6.5px;
  border-width: 2px;
  animation:
    nm-dotIn 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) var(--nm-delay, 0ms) both,
    nm-markerPulse 2.6s ease-out 0.7s infinite;
}

/* ---------- Curated area labels ---------- */
.nm-marker-label {
  position: absolute; top: 0; transform: translateY(-50%);
  white-space: nowrap; pointer-events: none;
  font-family: 'Space Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 0.13em; text-transform: uppercase;
  font-weight: 500; color: #141A26;
  text-shadow: 0 0 10px rgba(244, 245, 247, 0.95), 0 1px 0 rgba(244, 245, 247, 0.95);
  opacity: 0; animation: nm-labelIn 0.6s ease 0.55s forwards;
}
.nm-marker-label::before {
  content: ""; position: absolute; top: 50%; width: 13px; height: 1px;
  background: var(--nm-accent);
}
.nm-label-right { left: 17px; }
.nm-label-right::before { left: -17px; }
.nm-label-left  { right: 17px; text-align: right; }
.nm-label-left::before { right: -17px; }
@keyframes nm-labelIn { to { opacity: 1; } }

/* Labels fade out with their cluster on the tour. */
.nm-marker.leaving .nm-marker-label { animation: nm-labelOut 0.42s ease forwards; }
@keyframes nm-labelOut { to { opacity: 0; } }

/* ---------- Glow-field tour: named-stop readout ---------- */
/* No ring — on each stop the named licence lights up (active dot) and a leader
   line carries a readout: project name + its real area + primary commodities. */
.nm-named { position: relative; width: 0; height: 0; pointer-events: none; }

.nm-active-dot {
  position: absolute; left: -6px; top: -6px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--nm-cat, var(--nm-accent)); border: 2px solid rgba(11, 15, 22, 0.9);
  box-shadow: 0 0 0 5px rgba(244, 245, 247, 0.10), 0 2px 10px rgba(0, 0, 0, 0.5);
  opacity: 0; transform: scale(0.4);
  animation: nm-actIn 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
@keyframes nm-actIn { to { opacity: 1; transform: scale(1); } }

/* Infrastructure readout (the stop's closing beat): a square steel marker —
   plant, port or railhead — visually outside the commodity palette. */
.nm-infra .nm-active-dot { border-radius: 2px; }
.nm-infra .nm-tag-meta { letter-spacing: 0.11em; }

/* When an infra point lands inside a project readout's zone on BOTH sides
   (Tunnsjødal vs Mykkelvika, Rørosbanen vs Tynset), the tag drops BELOW
   the square, centred, and the side lead disappears. */
.nm-infra.nm-tag-below .nm-lead { display: none; }
.nm-infra.nm-tag-below .nm-tag {
  left: auto;
  right: auto;
  top: 22px;
  transform: translateX(-50%);
  align-items: center;
  text-align: center;
}

/* Main-city anchors — surface with the road network on the infrastructure
   beat (toggled via .is-on from setRoads), gone the rest of the time. */
/* Opacity lives on the CHILDREN: MapLibre manages an inline opacity on the
   marker root element itself (terrain occlusion), which overrides any class
   rule put there — the labels would show permanently. */
.nm-city {
  font-family: 'Space Mono', ui-monospace, monospace; /* MapLibre's stylesheet defaults markers to Helvetica */
  display: flex;
  align-items: center;
  gap: 7px;
  pointer-events: none;
}
.nm-city .nm-city-dot,
.nm-city .nm-city-name {
  opacity: 0;
  transition: opacity 1.1s ease;
}
.nm-city.is-on .nm-city-dot,
.nm-city.is-on .nm-city-name { opacity: 1; }
.nm-city-dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: rgba(244, 245, 247, 0.9);
  box-shadow: 0 0 0 3px rgba(244, 245, 247, 0.12);
  flex-shrink: 0;
}
.nm-city-name {
  font-family: var(--nm-font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(244, 245, 247, 0.72);
  text-shadow: 0 1px 6px rgba(11, 15, 22, 0.9);
  white-space: nowrap;
}

.nm-lead {
  position: absolute; top: 0; height: 1px; width: 40px; background: var(--nm-cat, var(--nm-accent));
  transform: scaleX(0);
  animation: nm-leadIn 0.45s cubic-bezier(0.3, 0.9, 0.3, 1) 0.12s forwards;
}
.nm-side-right .nm-lead { left: 7px;  transform-origin: left center; }
.nm-side-left  .nm-lead { right: 7px; transform-origin: right center; }
@keyframes nm-leadIn { to { transform: scaleX(1); } }

.nm-tag {
  position: absolute; top: 0; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 3px; white-space: nowrap;
  opacity: 0; animation: nm-tagIn 0.5s ease 0.24s forwards;
}
.nm-side-right .nm-tag { left: 55px;  align-items: flex-start; text-align: left; }
.nm-side-left  .nm-tag { right: 55px; align-items: flex-end;   text-align: right; }
@keyframes nm-tagIn { to { opacity: 1; } }

.nm-tag-name {
  font-family: var(--nm-font-sans); font-weight: 500; font-size: 18px;
  letter-spacing: -0.01em; color: var(--nm-text);
  text-shadow: 0 1px 0 rgba(11, 15, 22, 0.9), 0 0 12px rgba(11, 15, 22, 0.95);
}
.nm-tag-meta {
  font-family: var(--nm-font-mono); font-size: 10.5px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--nm-cat, var(--nm-accent));
  text-shadow: 0 0 12px rgba(11, 15, 22, 0.95);
}

.nm-named.leaving .nm-active-dot,
.nm-named.leaving .nm-lead,
.nm-named.leaving .nm-tag { animation: nm-fadeOut 0.4s ease forwards; }
@keyframes nm-fadeOut { to { opacity: 0; } }

/* Stagger multiple readouts within one stop (set via --nm-pop in JS). */
.nm-active-dot { animation-delay: var(--nm-pop, 0ms); }
.nm-lead { animation-delay: calc(var(--nm-pop, 0ms) + 120ms); }
.nm-tag  { animation-delay: calc(var(--nm-pop, 0ms) + 240ms); }

/* ---------- Category legend (bottom-right, above the corner tick) ---------- */
/* Populated by JS from the licence register; the tour lights up the rows it
   is currently naming, so the legend reads as a live caption. */
.nm-legend {
  position: absolute;
  right: 40px;
  bottom: 56px;
  z-index: 6;
  display: flex;
  flex-direction: column;
  gap: 9px;
  pointer-events: none;
}
.nm-legend-row {
  display: flex;
  align-items: center;
  gap: 9px;
  justify-content: flex-end;
  opacity: 0.55;
  transition: opacity 0.35s ease;
}
.nm-legend-row.is-active { opacity: 1; }
.nm-legend-dot {
  order: 3;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--nm-cat, var(--nm-accent));
  box-shadow: 0 0 0 3px rgba(244, 245, 247, 0.07);
}
.nm-legend-row.is-active .nm-legend-dot { box-shadow: 0 0 0 3px rgba(244, 245, 247, 0.14); }
/* Silver-under-LOI reads as an OPEN ring in the legend, matching its map marker. */
.nm-legend-row[data-cat="ag"] .nm-legend-dot {
  background: transparent;
  border: 1.5px solid var(--nm-cat, var(--nm-accent));
}
.nm-legend-label {
  order: 1;
  font-family: var(--nm-font-mono); font-size: 10.5px;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--nm-text-dim);
}
.nm-legend-row.is-active .nm-legend-label { color: var(--nm-text); }
.nm-legend-count {
  order: 2;
  font-family: var(--nm-font-mono); font-size: 10.5px;
  letter-spacing: 0.08em; color: var(--nm-text-faint);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 760px) {
  .nm-legend { right: 20px; bottom: 48px; gap: 7px; }
  .nm-legend-label { font-size: 9.5px; }
  /* Feature layout at phone width: tighter type, eyebrow clears the
     smaller mobile wordmark, readouts drop their meta line (JS already
     limits each stop to a single name). */
  .nm-content { padding: 24px 20px; }
  .nm-feature-eyebrow { margin-left: 76px; font-size: 10px; }
  .nm-feature-body { flex-direction: column; align-items: flex-start; gap: 20px; }
  .nm-feature-headline { font-size: 34px; }
  .nm-feature-sub { font-size: 13.5px; max-width: none; }
  .nm-feature-figure { align-self: flex-end; text-align: right; }
  .nm-feature-value { font-size: 56px; }
  .nm-tag-name { font-size: 15px; }
  .nm-tag-meta { display: none; }
}

/* ---------- Aerial snapshot on showcase readouts (2026-07) ---------- */
/* Pure bird's-eye Esri satellite close-up of the licence ground (no boundary
   overlay — client call). Framed with the survey corner ticks used across
   the site plus the theme's 45° hatch motif on a footer band. The crop is
   assembled at the next integer zoom and scaled down (--nm-s) for exact
   framing, with a slow drift over the hold for a quietly cinematic feel. */
/* Stage-level row: cards evenly spaced in clear map space, leaders tying
   each one back to its licence dot. */
.nm-aerial-row {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
}
.nm-aerial-row svg { position: absolute; inset: 0; }
.nm-aerial-row line {
  stroke-width: 1;
  opacity: 0.8;
  /* pathLength="1" on the element — the leader DRAWS from the dot out to
     the card, then the card rises at its far end. */
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: nm-lineDraw 0.4s ease-out calc(var(--nm-pop, 0ms) + 450ms) forwards;
}
@keyframes nm-lineDraw { to { stroke-dashoffset: 0; } }
.nm-aerial-slot { position: absolute; }
.nm-tag-aerial {
  position: relative;
  display: block;
  overflow: hidden;
  border: 1px solid rgba(244, 245, 247, 0.22);
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.6);
  background: #0B0F16;
}
/* Static crop — no drift/zoom; the shot is ready the moment it appears. */
.nm-tag-aerial .nm-aerial-crop {
  position: absolute;
  display: block;
  transform: scale(var(--nm-s, 1));
}
.nm-tag-aerial img {
  position: absolute;
  width: 256px;
  height: 256px;
  max-width: none;
  filter: saturate(0.8) contrast(1.05) brightness(0.92);
}
/* Thin inner frame line between the ticks — quiet instrument feel. */
.nm-tag-aerial::after {
  content: "";
  position: absolute;
  inset: 4px;
  border: 1px solid rgba(244, 245, 247, 0.12);
  pointer-events: none;
}
.nm-aerial-tick {
  position: absolute;
  width: 11px; height: 11px;
  pointer-events: none;
  z-index: 2;
}
.nm-aerial-tick--tl { top: 5px; left: 5px; border-top: 1.5px solid rgba(244, 245, 247, 0.8); border-left: 1.5px solid rgba(244, 245, 247, 0.8); }
.nm-aerial-tick--br { bottom: 24px; right: 5px; border-bottom: 1.5px solid rgba(244, 245, 247, 0.8); border-right: 1.5px solid rgba(244, 245, 247, 0.8); }
/* Footer band: the theme's 45° hatch swatch + a mono coordinate readout. */
.nm-aerial-band {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 19px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 7px;
  background: rgba(11, 15, 22, 0.82);
  border-top: 1px solid rgba(244, 245, 247, 0.16);
}
.nm-aerial-hatch {
  width: 42px;
  height: 9px;
  background-image: repeating-linear-gradient(
    45deg, rgba(244, 245, 247, 0.55) 0, rgba(244, 245, 247, 0.55) 1px, transparent 1px, transparent 5px
  );
}
.nm-tag-aerial b {
  font-family: var(--nm-font-mono);
  font-weight: 400;
  font-size: 8.5px;
  letter-spacing: 0.09em;
  color: rgba(244, 245, 247, 0.6);
  white-space: nowrap;
}
/* Choreography: name pops on its dot, a readable beat, the leader draws,
   then the close-up is simply THERE — a fast clean fade, fully composed,
   no zoom-in theatrics (client call). Everything leaves together. */
.nm-tag-aerial {
  opacity: 0;
  animation: nm-aerialIn 0.3s ease-out calc(var(--nm-pop, 0ms) + 650ms) forwards;
}
@keyframes nm-aerialIn { to { opacity: 1; } }
.nm-aerial-row.leaving line { stroke-dashoffset: 0; animation: nm-fadeOut 0.4s ease forwards; }
.nm-aerial-row.leaving .nm-tag-aerial { animation: nm-fadeOut 0.4s ease forwards; }

/* Hatch weave behind the tiles: a tile that fails to load (its img hides
   itself via onerror) reveals the brand motif instead of a hole. Later in
   the file than the `background: #0B0F16` shorthand above, so the image
   layer wins. */
.nm-tag-aerial {
  background-image: repeating-linear-gradient(
    45deg, rgba(244, 245, 247, 0.07) 0, rgba(244, 245, 247, 0.07) 1px, transparent 1px, transparent 6px
  );
}

/* Cards and readouts hold the tour while the cursor rests on them — they
   need real hit areas (their containers are pointer-events: none). */
.nm-aerial-slot { pointer-events: auto; }
.nm-named .nm-tag,
.nm-named .nm-active-dot { pointer-events: auto; }

/* ---------- Tour HUD: stop counter + scale bar (bottom-left) ---------- */
/* Mirrors the legend's bottom-right anchor. The counter crossfades between
   stops (is-in toggled from JS around the text swap); the scale bar tracks
   the camera continuously. */
.nm-hud {
  position: absolute;
  left: 40px;
  bottom: 56px;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  pointer-events: none;
}
.nm-stop {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--nm-font-mono);
  font-size: 10.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.35s ease;
}
.nm-stop.is-in { opacity: 1; }
.nm-stop-idx {
  color: var(--nm-text);
  font-variant-numeric: tabular-nums;
}
.nm-stop-sep { color: var(--nm-text-faint); }
.nm-stop-idx:empty,
.nm-stop-idx:empty + .nm-stop-sep { display: none; }
.nm-stop-region { color: var(--nm-text-dim); }
.nm-scale {
  display: flex;
  align-items: center;
  gap: 8px;
}
.nm-scale-bar {
  position: relative;
  height: 5px;
  width: 80px;
  border-left: 1px solid rgba(244, 245, 247, 0.7);
  border-right: 1px solid rgba(244, 245, 247, 0.7);
  transition: width 0.2s linear;
}
.nm-scale-bar::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: rgba(244, 245, 247, 0.7);
}
.nm-scale-label {
  font-family: var(--nm-font-mono);
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nm-text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------- Closing-beat CTA ---------- */
/* Same underline-link language as the investor-sections CTA: mono caps,
   hairline underline, red ↗. Fade only — no rise, no scale (client killed
   entrance theatrics on this map). */
.nm-cta {
  position: absolute;
  left: 50%;
  bottom: 96px;
  transform: translateX(-50%);
  z-index: 7;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--nm-text);
  font-family: var(--nm-font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nm-text);
  text-decoration: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease, gap 240ms cubic-bezier(0.33, 1, 0.68, 1), border-color 240ms ease;
}
.nm-cta::after {
  content: '\2197';
  color: var(--nm-accent);
  transition: transform 240ms cubic-bezier(0.33, 1, 0.68, 1);
}
.nm-cta.is-on {
  opacity: 1;
  pointer-events: auto;
}
.nm-cta:hover { gap: 14px; border-color: var(--nm-accent); }
.nm-cta:hover::after { transform: translate(2px, -2px); }

@media (max-width: 760px) {
  .nm-hud { left: 20px; bottom: 48px; gap: 8px; }
  .nm-stop { font-size: 9.5px; }
  .nm-cta { bottom: 72px; font-size: 11px; }
}

/* ---------- The model strip (2026-08 · client call 30 Jul) ----------
   Three numbered legs under the subhead: discover / divest & retain / earn.
   Quiet mono index, short bold title, one-line description. Lives in the
   left feature column so it stays when the km² figure fades (nm-quiet). */
.nm-model {
  margin-top: 28px;
  max-width: 520px;
}
.nm-model-kicker {
  display: block;
  margin-bottom: 10px;
  font-family: var(--nm-font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--nm-text-faint);
}
.nm-model-row {
  display: grid;
  grid-template-columns: 28px 118px 1fr;
  gap: 12px;
  align-items: baseline;
  padding: 10px 0;
  border-top: 1px solid var(--nm-border);
}
.nm-model-num {
  font-family: var(--nm-font-mono);
  font-size: 11px;
  color: var(--nm-accent);
}
.nm-model-t {
  font-family: var(--nm-font-sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--nm-text);
}
.nm-model-d {
  font-family: var(--nm-font-sans);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--nm-text-dim);
}
@media (max-width: 720px) {
  .nm-model { max-width: none; }
  .nm-model-row { grid-template-columns: 24px 1fr; }
  .nm-model-d { grid-column: 2; }
}

/* ---------- Chapter tour additions (2026-08) ----------
   Sonar ping on each named project as its reveal lands — an expanding ring
   in the project's category colour, repeating quietly while the chapter
   holds. Delayed by the same --nm-pop stagger as the tag itself. */
.nm-ping {
  position: absolute;
  left: 50%; top: 50%;
  width: 14px; height: 14px;
  margin: -7px 0 0 -7px;
  border: 1.5px solid var(--nm-cat, var(--nm-accent));
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  animation: nm-ping 2.4s ease-out infinite;
  animation-delay: var(--nm-pop, 0ms);
}
@keyframes nm-ping {
  0%   { transform: scale(0.5); opacity: 0; }
  12%  { opacity: 0.85; }
  60%  { transform: scale(3.4); opacity: 0; }
  100% { transform: scale(3.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .nm-ping { animation: none; opacity: 0; }
}

/* Model strip ↔ chapter sync: the live leg(s) hold full presence with an
   accent hairline; the others recede while a chapter is on stage. */
.nm-model-row { transition: opacity 0.6s ease, border-top-color 0.6s ease; }
.nm-model-row.is-dim { opacity: 0.35; }
.nm-model-row.is-live { border-top-color: var(--nm-accent-soft); }
.nm-model-row.is-live .nm-model-t { color: var(--nm-text); }

/* ---------- Interactive strip (2026-08-02) ----------
   Rows are chapter controls; the active chapter lists its projects under
   its own row; a reader pause sits in the kicker line. */
.nm-model-kicker {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}
.nm-model-pause {
  appearance: none;
  background: none;
  border: 1px solid var(--nm-border);
  border-radius: 2px;
  padding: 3px 10px;
  font-family: var(--nm-font-mono);
  font-size: 9px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nm-text-dim);
  cursor: pointer;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.nm-model-pause:hover {
  color: var(--nm-text);
  border-color: var(--nm-text-faint);
}
.nm-model-row[data-nm-chapter] { cursor: pointer; }
.nm-model-row[data-nm-chapter]:hover .nm-model-t { color: var(--nm-text); }
.nm-model-row[data-nm-chapter]:hover .nm-model-num { color: var(--nm-accent); }
.nm-model-row[data-nm-chapter]:focus-visible {
  outline: 1px solid var(--nm-accent-soft);
  outline-offset: 2px;
}
/* Softer recede — 0.35 read as broken in review; 0.55 reads as "not now". */
.nm-model-row.is-dim { opacity: 0.55; }

.nm-model-detail {
  grid-column: 2 / -1;
  display: grid;
  grid-template-columns: 1fr 1fr; /* two columns — half the height, so the
                                     list can never push the CTA into the HUD */
  gap: 3px 16px;
  padding-top: 0;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 0.45s ease, opacity 0.35s ease, padding-top 0.45s ease;
}
.nm-model-row.has-detail .nm-model-detail {
  max-height: 150px;
  opacity: 1;
  padding-top: 8px;
}
.nm-model-detail-item {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nm-model-detail-item {
  font-family: var(--nm-font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--nm-text-dim);
}
.nm-model-detail-item::before {
  content: '';
  display: inline-block;
  width: 5px; height: 5px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--nm-accent-soft);
  vertical-align: 1px;
}
@media (max-width: 720px) {
  .nm-model-detail { grid-column: 1 / -1; }
}

/* ---------- Flagship info cards (2026-08-02) ----------
   The three main-project aerials carry a fact block below the picture:
   name / ownership · commodity · area / one disclosed status line. */
.nm-aerial-info {
  display: flex;
  flex-direction: column;
  gap: 3px;
  box-sizing: border-box;
  margin-top: 6px;
  padding: 9px 11px 10px;
  background: rgba(11, 15, 22, 0.86);
  border: 1px solid var(--nm-border);
  border-radius: 2px;
}
.nm-aerial-info b {
  font-family: var(--nm-font-sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--nm-text);
}
.nm-aerial-info i {
  font-style: normal;
  font-family: var(--nm-font-mono);
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--nm-accent);
}
.nm-aerial-info em {
  font-style: normal;
  font-family: var(--nm-font-sans);
  font-size: 11px;
  line-height: 1.4;
  color: var(--nm-text-dim);
}

/* ---------- Paper-map preview (?nmlight=1 · 2026-08-02) ----------
   A/B variant: off-white terrain plate on the dark site. The section's
   entire palette flips via the scoped variables; a paper scrim keeps the
   left text column readable over terrain. Remove the URL flag to compare. */
.nm.nm--light {
  --nm-bg:         #E9E6DE;
  --nm-bleed:      #E9E6DE;
  --nm-border:     rgba(11, 15, 22, 0.16);
  --nm-text:       #171C24;
  --nm-text-dim:   rgba(23, 28, 36, 0.66);
  --nm-text-faint: rgba(23, 28, 36, 0.42);
  --nm-accent:     #C42800; /* Milano red reads richer on paper than #E23100 */
  --nm-accent-soft: rgba(196, 40, 0, 0.55);
  --nm-accent-glow: rgba(196, 40, 0, 0.25);
}
/* The dark vignette becomes a paper scrim anchoring the text column. */
.nm.nm--light .nm-vignette {
  background: linear-gradient(90deg,
    rgba(233, 230, 222, 0.94) 0%,
    rgba(233, 230, 222, 0.66) 30%,
    rgba(233, 230, 222, 0) 56%);
}
.nm.nm--light .nm-grain { opacity: 0.06; }
.nm.nm--light .nm-grid-overlay { opacity: 0.14; filter: invert(1); }
.nm.nm--light .nm-aerial-info { background: rgba(249, 248, 244, 0.92); }
.nm.nm--light .nm-model-pause { background: rgba(249, 248, 244, 0.6); }

/* ---------- Partner group leader lines (2026-08-02) ----------
   Each partner readout draws a thin line to every one of its projects —
   the label owns the whole group, not the nearest dot. */
.nm-group-leads {
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  transition: opacity 0.5s ease;
}
.nm-group-leads.leaving { opacity: 0; }
.nm-group-leads line {
  stroke-width: 1.2;
  opacity: 0.7;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: nm-group-lead-draw 0.7s ease forwards;
  animation-delay: var(--nm-pop, 0ms);
}
@keyframes nm-group-lead-draw {
  to { stroke-dashoffset: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .nm-group-leads line {
 animation: none; stroke-dashoffset: 0; }
}

/* ---------- Overview roll-call pings (2026-08-02) ---------- */
.nm-oping {
  position: relative;
  width: 0; height: 0;
  pointer-events: none;
}
.nm-oping .nm-ping {
  animation-duration: 1.6s;
  animation-delay: 0ms;
}

/* ---------- Figure-as-caption (2026-08-02) ----------
   Once the tour takes the figure over (nm-callout), it PINS to the top
   right of the stage — out of the text flow entirely, so content swaps
   can never shift the layout — and crossfades between beats. */
.nm.nm-quiet.nm-callout .nm-feature-figure {
  opacity: 1;
  pointer-events: none;
}
/* The figure is PINNED top-right from first paint (2026-08-02) — the km²
   count-up and the roll-call caption share one fixed home, so the takeover
   never repositions anything. */
.nm .nm-feature-figure {
  position: absolute;
  top: 118px;
  right: 56px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  width: 300px;
  text-align: right;
  transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1),
              transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.nm .nm-feature-figure.is-swap {
  opacity: 0; /* crossfade only — vertical motion read as a bounce (client) */
}
.nm .nm-feature-value {
  order: 1;
  font-variant-numeric: tabular-nums;
  line-height: 0.9;
}
.nm .nm-feature-unit {
  order: 2;
  max-width: 100%;
  text-align: right;
  line-height: 1.5;
  white-space: normal;
  letter-spacing: 0.16em;
}
@media (max-width: 760px) {
  .nm .nm-feature-figure { top: 96px; right: 20px; width: 200px; }
}

/* Text-only flagship cards (2026-08-02) — no imagery on this slide.
   min-height, NOT a fixed height (client, 1 Sep 2026: the Løkken body runs
   four lines and was clipped mid-sentence) — the card grows to its content
   and the placement budget (CH in the placement pass) covers the tallest
   card, so collision maths stay safe and no text is ever cut. */
.nm-aerial-info--solo {
  box-sizing: border-box;
  min-height: 104px;
  margin-top: 0;
  border-left: 2px solid var(--nm-accent);
  box-shadow: 0 4px 24px rgba(11, 15, 22, 0.10);
}

/* Cluster fan-out (2026-08-02): tags in tight dot clusters offset
   vertically via margin so nothing prints over a neighbour. */
.nm-marker.nm-named .nm-tag { margin-top: var(--nm-tagdy, 0px); }

/* ---------- Teako-branded info cards (2026-08-02) ----------
   The 45° language from the brand kit: a slit-cut corner, a diagonal
   hatch band along the top, and the // mark after the project name. */
.nm-aerial-info {
  position: relative;
  clip-path: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 0 100%);
  border-left: 2px solid var(--nm-accent);
  border-radius: 0;
  padding-top: 14px;
}
.nm-aerial-info::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 5px;
  background: repeating-linear-gradient(-45deg,
    var(--nm-accent) 0 3px, transparent 3px 8px);
  opacity: 0.85;
}
.nm-aerial-info::after {
  content: '';
  position: absolute;
  top: 0; right: 0;
  width: 16px; height: 16px;
  background: linear-gradient(135deg, transparent calc(50% - 0.5px),
    var(--nm-accent) calc(50% - 0.5px), var(--nm-accent) calc(50% + 1px),
    transparent calc(50% + 1px));
}
.nm-aerial-info b {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.nm-aerial-info b::after {
  content: '//';
  font-family: var(--nm-font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: -0.08em;
  color: var(--nm-accent);
  transform: skewX(-8deg);
}

/* Chapter steppers (2026-08-02) — ‹ pause › cluster in the strip kicker. */
.nm-model-ctl { display: inline-flex; gap: 6px; align-items: center; }
.nm-model-step {
  min-width: 26px;
  padding: 3px 8px;
  font-size: 12px;
  line-height: 1;
}

/* Card-bearing projects: dot + ping only, no duplicate name tag. */
.nm-marker.nm-notag .nm-tag,
.nm-marker.nm-notag .nm-lead { display: none; }

/* Standing portfolio CTA under the strip (2026-08-02). */
.nm-model-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  padding-bottom: 3px;
  font-family: var(--nm-font-mono);
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--nm-text);
  border-bottom: 1px solid var(--nm-border);
  transition: color 0.25s ease, border-color 0.25s ease;
}
.nm-model-cta svg { width: 13px; height: 13px; color: var(--nm-accent); }
.nm-model-cta:hover { color: var(--nm-accent); border-color: var(--nm-accent-soft); }


/* Display headings in Geologica (2026-08-02) — one voice site-wide. */
.nm-feature-headline { font-family: 'Geologica', var(--nm-font-sans); }

/* MapLibre injects Helvetica on its containers — keep the map's DOM layer on brand. */
.nm .maplibregl-map { font-family: 'IBM Plex Sans', system-ui, sans-serif; }

/* Country initials — cartographic furniture on the map slide (2026-08-18). */
.nm-country {
  font-family: 'Space Mono', ui-monospace, monospace;
  font-size: 10.5px;
  letter-spacing: 0.22em;
  color: rgba(11, 15, 22, 0.38);
  text-shadow: 0 0 6px rgba(244, 245, 247, 0.8);
  pointer-events: none;
  user-select: none;
}
.nm-country--dark { color: rgba(244, 245, 247, 0.35); text-shadow: none; }

/* Sign-off audit fixes (2026-08-18). */
/* Clicked model row shows its selected state immediately. */
.nm-model-row.is-on { border-top-color: var(--nm-accent-soft); }
.nm-model-row.is-on .nm-model-t { color: var(--nm-text); }

/* Mobile map slide: text panels must never sit raw on the live map. */
@media (max-width: 760px) {
  .nm-model-row {
    background: rgba(244, 245, 247, 0.93);
    padding-left: 12px;
    padding-right: 12px;
    backdrop-filter: blur(2px);
  }
  .nm--light .nm-model-row { background: rgba(244, 245, 247, 0.93); }
  .nm:not(.nm--light) .nm-model-row { background: rgba(11, 15, 22, 0.88); }
  .nm-scale { display: none; }         /* collided with the legend at 390px */
  .nm-legend { bottom: 72px; }         /* clears the portfolio CTA */
}

/* ---------- Mid-width map room (2026-08-20) ----------
   Between phone and full desktop the 680px story column plus the paper
   scrim were burying Norway. The column yields progressively so the map
   always keeps at least half the stage. */
@media (max-width: 1360px) {
  .nm-feature-text { max-width: 540px; }
  .nm-feature-headline { font-size: clamp(34px, 4.3vw, 54px); }
  .nm-feature-sub { max-width: 430px; font-size: 14px; }
  .nm-model { max-width: 460px; margin-top: 22px; }
  .nm.nm--light .nm-vignette {
    background: linear-gradient(90deg,
      rgba(233, 230, 222, 0.94) 0%,
      rgba(233, 230, 222, 0.68) 26%,
      rgba(233, 230, 222, 0) 46%);
  }
}
@media (max-width: 1080px) {
  .nm-content { padding: 36px 40px; }
  .nm-feature-text { max-width: 360px; }
  .nm-feature-headline { font-size: clamp(30px, 4.4vw, 42px); }
  .nm-feature-sub { max-width: 360px; }
  /* Stack the description under the title so the column stays clear of
     Norway's west coast instead of running text over the dots. */
  .nm-model { max-width: 340px; }
  .nm-model-row { grid-template-columns: 24px 1fr; gap: 6px 10px; }
  .nm-model-d { grid-column: 2; font-size: 12px; }
  .nm-model-pause { white-space: nowrap; }
  .nm.nm--light .nm-vignette {
    background: linear-gradient(90deg,
      rgba(233, 230, 222, 0.94) 0%,
      rgba(233, 230, 222, 0.66) 24%,
      rgba(233, 230, 222, 0) 45%);
  }
}

/* ---------- Detail line: info affordance + tooltip (2026-08-28) ----------
   The chapter detail lines used to read "Name · 126 km² · Copper, …" and get
   cut mid-word by an ellipsis — and they silently dropped every mineral past
   the second. Name + area now hold the line; the rest sits behind this "i".

   Constraint from the brief: do NOT buy the space with height. The line stays
   one row in the same two-column grid, and the tooltip is rendered to <body>
   as position:fixed, so it costs the section nothing. (It has to escape: its
   own container is overflow:hidden with an animated max-height, so a tooltip
   drawn in place would simply be clipped.) */
.nm-model-detail-info {
  -webkit-appearance: none;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 12px;
  height: 12px;
  margin-left: 6px;
  padding: 0;
  flex: 0 0 auto;
  border: 1px solid var(--nm-accent-soft);
  border-radius: 50%;
  background: transparent;
  color: var(--nm-accent);
  font-family: var(--nm-font-mono);
  font-size: 8px;
  line-height: 1;
  cursor: help;
  vertical-align: 1px;
  transition: background 0.18s ease, color 0.18s ease, border-color 0.18s ease;
}
.nm-model-detail-info:hover,
.nm-model-detail-info:focus-visible {
  background: var(--nm-accent);
  border-color: var(--nm-accent);
  color: #FAFAF7;
  outline: none;
}
.nm-model-detail-info:focus-visible {
  box-shadow: 0 0 0 2px var(--nm-accent-glow);
}

/* Lives on <body>, so it cannot use the section-scoped --nm-* variables.
   Deliberately dark in both themes: it reads as an overlay either way. */
.nm-tip {
  position: fixed;
  z-index: 9999;
  max-width: 260px;
  padding: 7px 10px;
  border-radius: 3px;
  background: #171C24;
  color: rgba(250, 250, 247, 0.92);
  font-family: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px;
  line-height: 1.45;
  letter-spacing: 0.04em;
  white-space: pre-line; /* info bits are newline-joined, one fact per line */
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
  pointer-events: none;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 0.16s ease, transform 0.16s ease;
}
.nm-tip.is-on { opacity: 1; transform: translateY(0); }
/* Little pointer, flipped when the tooltip has to sit below the icon. */
.nm-tip::after {
  content: '';
  position: absolute;
  left: 50%;
  margin-left: -4px;
  border: 4px solid transparent;
  border-top-color: #171C24;
  top: 100%;
}
.nm-tip.is-below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: #171C24;
}
@media (prefers-reduced-motion: reduce) {
  .nm-tip { transition: none; }
  .nm-model-detail-info { transition: none; }
}

/* Lay the detail line out as a row so the "i" is never the thing that gets
   clipped — if anything has to give, it is the name text, not the affordance.
   (Overrides the plain nowrap/ellipsis rule set on the item further up.) */
.nm-model-detail-item {
  display: flex;
  align-items: center;
  min-width: 0;
  overflow: visible;
}
.nm-model-detail-item::before {
  flex: 0 0 auto;
  vertical-align: 0;
}
.nm-model-detail-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   PHONES — "How Teako works" mobile layout (client pick, 29 Aug 2026: V2)
   Map top half with the eyebrow + headline + live caption top-left; legend
   behind a "Key" button (closable pop-up); bottom half = the model as an
   accordion — The portfolio (paragraph) · Discover · Partner · Redeploy —
   the live chapter open, the rest collapsed; tour controls across the top
   of the panel; the portfolio CTA pinned. Desktop untouched.
   Sits at the end of the file so it wins at equal specificity.
   ========================================================================== */
@media (max-width: 760px) {
  .nm { --nm-map-share: 52%; }
  /* No pinning on phones (client, 29 Aug: "it gets stuck"): the section is one
     screen tall and scrolls away like any other. The tour keeps running while
     it is on screen. */
  .nm-outer { height: auto; }
  .nm-stage { position: relative; top: auto; }
  /* The map canvas ignores touches so a swipe always scrolls the page; the
     tour flies the map, and the Key / controls / accordion stay tappable. */
  .nm-canvas { pointer-events: none; }
  /* Vignette/grid/grain centre on the visible map band, not the whole stage
     (the ellipse's left edge was reading as a grey "C" on phones). */
  .nm-vignette, .nm-grid-overlay, .nm-grain { bottom: 48%; }
  .nm-corner, .nm-hud, .nm-cta, .nm-scale, .nm-legend { display: none !important; }
  .nm-key .nm-legend { display: flex !important; }
  .nm-content { padding: 0; display: block; }
  .nm-feature-top { position: absolute; left: 20px; right: 20px; top: 18px; z-index: 12; }
  .nm-feature-eyebrow { margin-left: 0; display: block; font-size: 10px; letter-spacing: 0.18em; }
  .nm-feature-ruler { display: none; }
  .nm-feature-body { position: absolute; left: 20px; right: 20px; top: 38px; display: block; z-index: 12; pointer-events: none; }
  .nm-feature-text { max-width: none; }
  .nm-feature-headline { font-size: 24px; line-height: 1.05; letter-spacing: -0.03em; }
  .nm-feature-sub { display: none; }
  /* The live caption (km² count-up, then "3 Main projects" etc.) sits under
     the headline instead of pinned top-right. */
  .nm .nm-feature-figure,
  .nm.nm-quiet .nm-feature-figure,
  .nm.nm-quiet.nm-callout .nm-feature-figure {
    position: static; top: auto; right: auto; width: auto;
    display: flex; flex-direction: row; align-items: baseline; gap: 8px;
    margin-top: 8px; opacity: 1; pointer-events: none; text-align: left;
    transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1);
  }
  .nm .nm-feature-figure.is-swap { opacity: 0; }
  .nm .nm-feature-value { font-size: 22px; line-height: 1; order: 0; }
  .nm .nm-feature-unit { font-size: 10px; letter-spacing: 0.12em; order: 1; }
  /* Key button + pop-up. */
  .nm-key-btn {
    position: absolute; right: 20px; top: calc(var(--nm-map-share) - 44px); z-index: 13;
    appearance: none; display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 10px; border: 1px solid rgba(11, 15, 22, 0.18); border-radius: 999px;
    background: rgba(244, 245, 247, 0.92); color: #0B0F16; cursor: pointer;
    font-family: var(--nm-font-mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  }
  .nm-key-btn i { width: 7px; height: 7px; border-radius: 50%; background: var(--nm-accent); }
  .nm-key {
    position: absolute; left: 20px; right: 20px; top: calc(var(--nm-map-share) - 52px); transform: translateY(-100%);
    z-index: 15; display: none; padding: 14px 14px 12px; border-radius: 8px;
    background: rgba(244, 245, 247, 0.97); border: 1px solid rgba(11, 15, 22, 0.12);
    box-shadow: 0 12px 32px rgba(11, 15, 22, 0.16);
  }
  .nm-key.is-open { display: block; }
  .nm-key-title { display: block; margin-bottom: 8px; font-family: var(--nm-font-mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--nm-text-faint); }
  .nm-key .nm-legend { position: static; transform: none; flex-direction: column; gap: 7px; pointer-events: auto; }
  .nm-key .nm-legend-row { justify-content: flex-start; gap: 8px; opacity: 1; }
  .nm-key .nm-legend-dot { order: 0; }
  .nm-key .nm-legend-label { order: 1; font-size: 10px; letter-spacing: 0.1em; color: var(--nm-text); }
  .nm-key .nm-legend-count { order: 2; margin-left: auto; font-size: 10px; color: var(--nm-text); }
  .nm-key-close {
    position: absolute; top: 6px; right: 6px; width: 30px; height: 30px; appearance: none; border: 0;
    background: transparent; color: var(--nm-text); font-size: 20px; line-height: 1; cursor: pointer;
  }
  /* The model panel: bottom half. */
  .nm-model {
    position: absolute; left: 0; right: 0; top: var(--nm-map-share); bottom: 0; margin: 0; max-width: none;
    padding: 12px 20px 16px; background: #F4F5F7; border-top: 1px solid rgba(11, 15, 22, 0.12);
    z-index: 14; display: flex; flex-direction: column; min-height: 0; pointer-events: auto;
  }
  .nm:not(.nm--light) .nm-model { background: #0B0F16; }
  /* Controls own the whole top bar; the kicker text goes. */
  .nm-model-kicker { display: flex; margin: 0 0 8px; }
  .nm-model-kicker > span:first-child { display: none; }
  .nm-model-ctl { display: flex; width: 100%; gap: 8px; }
  .nm-model-ctl [data-nm-pause] { flex: 1 1 auto; }
  /* Accordion. */
  .nm-acc { position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: none; margin: 0 -20px; padding: 0 20px; }
  .nm-acc::-webkit-scrollbar { display: none; }
  .nm-acc .nm-model-row, .nm-acc .nm-acc-item {
    display: grid; grid-template-columns: 1fr auto; grid-template-areas: "t chev" "d d" "det det";
    gap: 4px 10px; align-items: baseline; padding: 10px 0; border-top: 1px solid rgba(11, 15, 22, 0.12);
    background: none !important; backdrop-filter: none; opacity: 1 !important; cursor: pointer;
  }
  .nm-acc .nm-model-num { display: none; }
  .nm-acc .nm-model-t, .nm-acc .nm-acc-t { grid-area: t; font-size: 12.5px; color: var(--nm-text-dim); }
  .nm-acc .is-open .nm-model-t, .nm-acc .is-open .nm-acc-t { color: var(--nm-text); }
  .nm-acc .nm-model-d { grid-area: d; display: none; margin-top: 2px; }
  .nm-acc .is-open .nm-model-d { display: block; }
  .nm-acc .nm-model-detail { grid-area: det; grid-template-columns: 1fr; gap: 2px 0; display: none; max-height: none; opacity: 1; padding-top: 4px; }
  .nm-acc .is-open.has-detail .nm-model-detail { display: grid; }
  .nm-acc .nm-model-detail-item { font-size: 11.5px; }
  .nm-acc .nm-model-detail-name { overflow: visible; text-overflow: clip; }
  .nm-acc-chev { grid-area: chev; width: 14px; height: 14px; color: var(--nm-text-faint); transition: transform 0.3s; }
  .nm-acc .is-open .nm-acc-chev { transform: rotate(180deg); color: var(--nm-accent); }
  .nm-acc-item--intro .nm-acc-t { font-family: var(--nm-font-sans); font-weight: 600; letter-spacing: 0.02em; text-transform: uppercase; }
  .nm-acc-item--intro .nm-feature-sub { grid-area: d; display: none; margin: 2px 0 0; font-size: 12.5px; }
  .nm-acc-item--intro.is-open .nm-feature-sub { display: block; }
  .nm-model-cta { margin-top: 10px; align-self: flex-start; }
}


/* Compose-then-reveal (2026-08-31): the canvas stays invisible until the
   country mask and borders have landed and the first frame settles, so the
   section arrives as one composed piece instead of glow dots on a void.
   norway-map.js adds is-composed on map idle (4s fallback in the load
   handler). */
[data-nm-map] .maplibregl-canvas { opacity: 0; transition: opacity 700ms ease; }
[data-nm-map].is-composed .maplibregl-canvas { opacity: 1; }

/* ---------- Model strip accordion (client 2026-09-01) ----------
   The 1-2-3 skeleton always shows so the order reads, but while a chapter
   holds only ITS row is expanded (description + project chips); the other
   legs collapse to their title lines. The full-paragraph 0.35-opacity rows
   were unreadable whenever zoomed-in terrain passed behind them. Collapsed
   rows stay click targets for jumping the tour. */
.nm-model.is-solo .nm-model-row:not(.is-live) .nm-model-d,
.nm-model.is-solo .nm-model-row:not(.is-live) .nm-model-detail { display: none; }
.nm-model.is-solo .nm-model-row:not(.is-live) { padding: 8px 0; }
/* Collapsed titles read at dim ink but full opacity — the old 0.35 fade is
   what washed out over terrain. */
.nm-model.is-focused .nm-model-row.is-dim { opacity: 1; }
.nm-model.is-focused .nm-model-row.is-dim .nm-model-t { color: var(--nm-text-dim); }
.nm-model.is-solo .nm-model-row.is-live .nm-model-d,
.nm-model.is-solo .nm-model-row.is-live .nm-model-detail {
  animation: nmRowIn 480ms cubic-bezier(0.33, 1, 0.68, 1);
}
@keyframes nmRowIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* Legibility of the focused leg (client 2026-09-01 "check the legibility"):
   the lone visible row can afford full ink for its description — the grey
   dim made sense when three rows competed, not for a solo leg over terrain.
   A quiet paper halo on the strip's type keeps every glyph readable when
   zoomed-in relief passes underneath; the scrim underneath is unchanged. */
.nm-model.is-focused .nm-model-row.is-live .nm-model-d {
  color: var(--nm-text);
}
.nm-feature-sub,
.nm-model-kicker,
.nm-model-num,
.nm-model-t,
.nm-model-d,
.nm-model-detail,
.nm-model-cta {
  text-shadow:
    0 1px 2px rgba(250, 250, 247, 0.9),
    0 0 8px rgba(250, 250, 247, 0.8),
    0 0 20px rgba(250, 250, 247, 0.6);
}

/* ---------- Always-visible copy (client 2026-09-01) ----------
   "No fade on the text or lighter colours": every piece of copy in this
   section reads at full ink in every tour state — the intro under the
   headline included. Expansion, not tone, marks the active leg. Map
   furniture (legend, HUD, readouts) keeps its own styling. */
.nm-feature-sub { color: var(--nm-text); }
.nm-model-kicker { color: var(--nm-text); }
.nm-model-d { color: var(--nm-text); }
.nm-model-row.is-dim { opacity: 1; }
.nm-model.is-focused .nm-model-row.is-dim .nm-model-t { color: var(--nm-text); }
.nm-model-detail { color: var(--nm-text); }

/* Play glyph in the pause/resume toggle (SVG, sized to the mono label). */
.nm-model-pause svg { width: 9px; height: 9px; vertical-align: -0.5px; margin-right: 2px; }

/* Wide-chapter highlight (client 2026-09-01): all three legs stay expanded;
   the live leg reads in the accent — red title over the accent top rule —
   instead of the others receding. */
.nm-model.is-focused .nm-model-row.is-live .nm-model-t { color: var(--nm-accent); }
.nm-model.is-focused .nm-model-row.is-live { border-top-color: var(--nm-accent); }

/* Chip legibility (client 2026-09-01): the project lists under the active
   leg read at full ink, a step larger, with full-accent dots and info rings
   — the dim 10px mono washed out over terrain. */
.nm-model-detail-item { color: var(--nm-text); font-size: 11px; }
.nm-model-detail-item::before { background: var(--nm-accent); }
.nm-model-detail-info { border-color: var(--nm-accent); }
