// how-it-works.jsx — Sticky scroll-driven 3-step map journey
//
// Section is 3 viewport-heights tall. Inside: a single sticky map + compass
// HUD that stay in view while step overlays scroll across them.
//
// Steps (driven by scroll progress 0..1):
//   0.00 - 0.33  STEP 1 · MARK YOUR TARGET   (zoom in on Yosemite hex)
//   0.33 - 0.66  STEP 2 · WATCH              (pull back, ping waves)
//   0.66 - 1.00  STEP 3 · ALERT              (zoom to NYC, iOS push)

const HIW_KEY_MAP = {
  bg: 'bg', bgDeep: 'bg',
  ink: 'text', inkMute: 'textMute', inkDim: 'textDim',
  amber: 'amber', amberDim: 'amberDim',
  pine: 'pine2', pineDim: 'pineDim',
  divider: 'border', panel: 'bg3', panelHi: 'bg4',
  red: 'red',
};
const HIW_C = new Proxy({}, {
  get(_t, k) { return window.CS_TOKENS[HIW_KEY_MAP[k] || k]; },
});

const HIW_MONO = '"SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace';

// ── Section progress hook ─────────────────────────────────
function useSectionProgress(ref) {
  const [p, setP] = React.useState(0);
  React.useEffect(() => {
    const onScroll = () => {
      if (!ref.current) return;
      const rect = ref.current.getBoundingClientRect();
      const total = rect.height - window.innerHeight;
      const scrolled = -rect.top;
      const prog = Math.max(0, Math.min(1, scrolled / total));
      setP(prog);
    };
    onScroll();
    window.addEventListener('scroll', onScroll, { passive: true });
    return () => window.removeEventListener('scroll', onScroll);
  }, []);
  return p;
}

// Tween between values across a [start,end] window of progress
const tween = (p, start, end, from, to) => {
  if (p <= start) return from;
  if (p >= end) return to;
  const local = (p - start) / (end - start);
  return from + (to - from) * local;
};
const stepP = (p, start, end) => Math.max(0, Math.min(1, (p - start) / (end - start)));
const ease3 = (t) => 1 - Math.pow(1 - t, 3);

// ── Topo background that pans + zooms with scroll ────────
function HiwMap({ progress }) {
  // Map pan/zoom across the 3 steps:
  //   step 1 (0.0-0.33): zoom in on Yosemite hex (focus left-center)
  //   step 2 (0.33-0.66): zoom out, show probes spreading
  //   step 3 (0.66-1.0): pan to NYC, zoom in
  const zoom = (() => {
    if (progress < 0.33) return tween(progress, 0, 0.33, 1.4, 1.0);
    if (progress < 0.66) return tween(progress, 0.33, 0.66, 1.0, 0.7);
    return tween(progress, 0.66, 1.0, 0.7, 1.5);
  })();
  const panX = (() => {
    // Yosemite is left-center, NYC is right-edge. Negative = look left.
    if (progress < 0.33) return tween(progress, 0, 0.33, -180, 0);
    if (progress < 0.66) return tween(progress, 0.33, 0.66, 0, 80);
    return tween(progress, 0.66, 1.0, 80, 380);
  })();
  const panY = tween(progress, 0, 1, 0, -40);

  return (
    <svg viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid slice"
      style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
      <defs>
        <radialGradient id="hiw-fade" cx="50%" cy="50%" r="60%">
          <stop offset="0%" stopColor="white" stopOpacity="0.7"/>
          <stop offset="100%" stopColor="white" stopOpacity="0.1"/>
        </radialGradient>
        <mask id="hiw-mask">
          <rect width="1600" height="900" fill="url(#hiw-fade)"/>
        </mask>
        {/* Hex pattern overlay */}
        <pattern id="hiw-hex" x="0" y="0" width="48" height="55.4" patternUnits="userSpaceOnUse">
          <path d="M24 0 L48 13.85 L48 41.55 L24 55.4 L0 41.55 L0 13.85 Z"
            fill="none" stroke={HIW_C.ink} strokeWidth="0.5" opacity="0.3"/>
        </pattern>
      </defs>

      <g transform={`translate(${panX} ${panY}) scale(${zoom}) translate(${(1 - zoom) * 800 / zoom} ${(1 - zoom) * 450 / zoom})`}>
        {/* Topo contours: yosemite-ish on left, NYC-ish on right */}
        <g stroke={HIW_C.ink} fill="none" strokeWidth="0.6" mask="url(#hiw-mask)">
          {/* Yosemite peak field (left) */}
          {topoBlob(380, 460, 60, 0.0)}
          {topoBlob(380, 460, 95, 0.05)}
          {topoBlob(380, 460, 140, 0.08)}
          {topoBlob(380, 460, 195, 0.12)}
          {topoBlob(380, 460, 260, 0.18)}
          {topoBlob(380, 460, 340, 0.25)}

          {/* Sierra ridges */}
          {topoBlob(580, 380, 50, 0.04)}
          {topoBlob(580, 380, 95, 0.08)}
          {topoBlob(580, 380, 145, 0.12)}

          {/* East — central plains, lighter */}
          {topoBlob(900, 500, 70, 0.06)}
          {topoBlob(900, 500, 120, 0.1)}

          {/* NYC — denser, more compact */}
          {topoBlob(1380, 380, 40, 0.0)}
          {topoBlob(1380, 380, 70, 0.02)}
          {topoBlob(1380, 380, 105, 0.04)}
          {topoBlob(1380, 380, 145, 0.06)}
        </g>

        {/* Hex grid overlay (only visible in step 1) */}
        <rect width="1600" height="900" fill="url(#hiw-hex)"
          opacity={Math.max(0, 1 - Math.abs(progress - 0.15) * 6)}/>

        {/* Faint river / coast lines */}
        <g stroke={HIW_C.ink} fill="none" opacity="0.2">
          <path d="M 0 600 Q 300 540, 520 580 T 980 540 Q 1200 510, 1600 580" strokeWidth="0.6"/>
          <path d="M 1450 200 Q 1480 400, 1430 600 Q 1400 750, 1380 900" strokeWidth="0.7"/>
        </g>

        {/* STEP 1: Yosemite hex highlight */}
        {progress < 0.4 && (
          <g opacity={tween(progress, 0.05, 0.15, 0, 1) * (1 - tween(progress, 0.30, 0.40, 0, 1))}>
            {/* Pulsing hex at Upper Pines (~ x:380 y:460) */}
            <g transform="translate(380 460)">
              <path d="M 0 -40 L 35 -20 L 35 20 L 0 40 L -35 20 L -35 -20 Z"
                fill={`${HIW_C.amber}25`} stroke={HIW_C.amber} strokeWidth="1.5"/>
              <path d="M 0 -40 L 35 -20 L 35 20 L 0 40 L -35 20 L -35 -20 Z"
                fill="none" stroke={HIW_C.amber} strokeWidth="0.8" opacity="0.5"
                style={{ animation: 'hiw-hex-pulse 2s ease-in-out infinite' }}
                transform="scale(1.4)"/>
              <circle r="3" fill={HIW_C.amber}/>
              <text y="-50" fill={HIW_C.amber} fontFamily={HIW_MONO} fontSize="10"
                textAnchor="middle" letterSpacing="1">
                UPPER PINES · 14
              </text>
            </g>
            {/* Crosshair lines */}
            <g stroke={HIW_C.amber} strokeWidth="0.4" opacity="0.4" strokeDasharray="3 3">
              <line x1="0" y1="460" x2="345" y2="460"/>
              <line x1="415" y1="460" x2="1600" y2="460"/>
              <line x1="380" y1="0" x2="380" y2="420"/>
              <line x1="380" y1="500" x2="380" y2="900"/>
            </g>
          </g>
        )}

        {/* STEP 2: probe waves emanating from Yosemite */}
        {progress >= 0.30 && progress < 0.72 && (
          <g opacity={tween(progress, 0.32, 0.42, 0, 1) * (1 - tween(progress, 0.62, 0.70, 0, 1))}>
            {/* Server marker at Yosemite */}
            <g transform="translate(380 460)">
              <rect x="-18" y="-10" width="36" height="20" fill={HIW_C.panel}
                stroke={HIW_C.pine} strokeWidth="1"/>
              <line x1="-12" y1="-4" x2="12" y2="-4" stroke={HIW_C.pine} strokeWidth="0.8"/>
              <line x1="-12" y1="0" x2="12" y2="0" stroke={HIW_C.pine} strokeWidth="0.8"/>
              <line x1="-12" y1="4" x2="12" y2="4" stroke={HIW_C.pine} strokeWidth="0.8"/>
              <circle cx="14" cy="-7" r="1.2" fill={HIW_C.pine}>
                <animate attributeName="opacity" values="0.3;1;0.3" dur="1.4s" repeatCount="indefinite"/>
              </circle>
              <text y="-22" fill={HIW_C.pine} fontFamily={HIW_MONO} fontSize="8"
                textAnchor="middle" letterSpacing="1">PROBE · 90s</text>
            </g>
            {/* Concentric pulse rings */}
            {[0, 1, 2].map(i => (
              <circle key={i} cx="380" cy="460" r="40" fill="none"
                stroke={HIW_C.pine} strokeWidth="1" opacity="0.5"
                style={{
                  animation: `hiw-ping 2.4s ease-out infinite`,
                  animationDelay: `${i * 0.8}s`,
                  transformOrigin: '380px 460px',
                }}/>
            ))}
          </g>
        )}

        {/* STEP 3: NYC user pin + alert beam */}
        {progress >= 0.55 && (
          <g opacity={tween(progress, 0.55, 0.70, 0, 1)}>
            {/* Beam from Yosemite to NYC */}
            <line x1="380" y1="460" x2="1380" y2="380"
              stroke={HIW_C.amber} strokeWidth="1.2" opacity="0.6"
              strokeDasharray="6 4"
              style={{ animation: 'hiw-beam-flow 1.2s linear infinite' }}/>
            {/* User pin at NYC */}
            <g transform="translate(1380 380)">
              <circle r="14" fill={`${HIW_C.amber}30`}/>
              <circle r="6" fill={HIW_C.amber}>
                <animate attributeName="r" values="6;9;6" dur="1.2s" repeatCount="indefinite"/>
              </circle>
              <text y="-22" fill={HIW_C.amber} fontFamily={HIW_MONO} fontSize="9"
                textAnchor="middle" letterSpacing="1">YOU · NYC</text>
            </g>
          </g>
        )}
      </g>
    </svg>
  );
}

function topoBlob(cx, cy, r, distort) {
  const points = 24;
  let d = '';
  for (let i = 0; i <= points; i++) {
    const a = (i / points) * Math.PI * 2;
    const wobble = Math.sin(a * 3 + cx * 0.01) * distort + Math.cos(a * 5 + cy * 0.01) * distort * 0.6;
    const rr = r * (1 + wobble);
    const x = cx + Math.cos(a) * rr;
    const y = cy + Math.sin(a) * rr * 0.85;
    d += (i === 0 ? 'M' : 'L') + x.toFixed(1) + ',' + y.toFixed(1) + ' ';
  }
  return <path key={`${cx}-${cy}-${r}`} d={d + 'Z'}/>;
}

// ── Compass HUD (top-right, mini, spins with scroll) ─────
function CompassHud({ scrollAngle }) {
  const { mobile } = window.useViewport();
  return (
    <div style={{
      position: 'absolute',
      top: mobile ? 70 : 80,
      right: mobile ? 12 : 32,
      zIndex: 8,
      display: 'flex', alignItems: 'center', gap: mobile ? 8 : 12,
      padding: mobile ? '6px 10px' : '8px 14px',
      background: window.CS_TOKENS.chipBg,
      backdropFilter: 'blur(8px)',
      border: `1px solid ${HIW_C.divider}`,
      borderRadius: 4,
    }}>
      <svg width={mobile ? 22 : 28} height={mobile ? 22 : 28} viewBox="0 0 100 100">
        <path d="M50 4 L88 26 L88 74 L50 96 L12 74 L12 26 Z"
          fill="none" stroke={HIW_C.ink} strokeWidth="3" strokeLinejoin="round"/>
        <g transform={`rotate(${28 + scrollAngle} 50 50)`}>
          <path d="M50 26 L52.4 50 L50 53 L47.6 50 Z" fill={HIW_C.amber}/>
          <path d="M50 74 L47.6 50 L50 47 L52.4 50 Z" fill={HIW_C.ink} opacity="0.7"/>
        </g>
        <circle cx="50" cy="50" r="2.5" fill={HIW_C.ink}/>
      </svg>
      <div style={{
        fontFamily: HIW_MONO, fontSize: mobile ? 8.5 : 9.5, letterSpacing: 1.4,
        color: HIW_C.inkMute, lineHeight: 1.4,
      }}>
        <div style={{ color: HIW_C.amber }}>{(28 + scrollAngle).toFixed(0)}°</div>
        <div>HEADING</div>
      </div>
    </div>
  );
}

// ── Step number indicator (right edge) ───────────────────
function StepIndicator({ progress }) {
  const { mobile } = window.useViewport();
  if (mobile) return null; // Step number indicator hidden on mobile (cramped)
  const step = progress < 0.33 ? 0 : progress < 0.66 ? 1 : 2;
  return (
    <div style={{
      position: 'absolute', right: 32, top: '50%', transform: 'translateY(-50%)',
      display: 'flex', flexDirection: 'column', gap: 18, zIndex: 8,
    }}>
      {[0, 1, 2].map(i => (
        <div key={i} style={{
          display: 'flex', alignItems: 'center', gap: 12,
          opacity: i === step ? 1 : 0.35,
          transition: 'opacity 0.3s',
        }}>
          <div style={{
            fontFamily: HIW_MONO, fontSize: 10, letterSpacing: 1.5,
            color: i === step ? HIW_C.amber : HIW_C.inkMute, fontWeight: 600,
          }}>
            {String(i + 1).padStart(2, '0')}
          </div>
          <div style={{
            width: i === step ? 28 : 14, height: 1,
            background: i === step ? HIW_C.amber : HIW_C.inkMute,
            transition: 'all 0.3s',
          }}/>
        </div>
      ))}
    </div>
  );
}

// On mobile, all step overlays use the same centered position to avoid horizontal overflow.
const stepOverlayBase = (mobile, side) => mobile
  ? { left: 16, right: 16, bottom: 80, maxWidth: 'none' }
  : (side === 'left'
    ? { top: '50%', left: '8%', transform: 'translateY(-50%)', maxWidth: 460 }
    : { top: '50%', right: '8%', transform: 'translateY(-50%)', maxWidth: 460 });

// ── Step 1 overlay: site card ────────────────────────────
function Step1Overlay({ progress }) {
  const { mobile } = window.useViewport();
  const p = stepP(progress, 0.0, 0.33);
  const fade = Math.min(1, p * 4) * (1 - Math.max(0, (p - 0.85) / 0.15));
  if (fade <= 0) return null;
  return (
    <div style={{
      position: 'absolute', ...stepOverlayBase(mobile, 'left'),
      opacity: fade, zIndex: 6,
    }}>
      <StepHeader number="01" label="DEFINE YOUR HUNT"/>
      <h2 style={hiwH2(mobile)}>One specific site, or every site that matches.</h2>
      <p style={hiwBody(mobile)}>
        Pin a single campground and lock on. Or draw a region across multiple
        parks and stack filters — lakefront, RV length, hookups, weekend
        nights — and we monitor every site in the resolved set as one watch.
      </p>

      {/* Two scene cards: precision watch + area watch */}
      <div style={{ display: 'flex', flexDirection: 'column', gap: mobile ? 8 : 10,
        marginTop: mobile ? 14 : 20 }}>
        {/* Single-site card */}
        <div style={{
          padding: mobile ? 10 : 14, background: HIW_C.panel,
          border: `1px solid ${HIW_C.divider}`, borderRadius: 4,
          fontFamily: HIW_MONO, fontSize: mobile ? 10 : 11,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6, gap: 8 }}>
            <span style={{ color: HIW_C.amber, letterSpacing: 1.4 }}>● UPPER PINES · #14</span>
            <span style={{ color: HIW_C.inkDim, fontSize: mobile ? 9 : 10 }}>YOSEMITE NP</span>
          </div>
          <div style={{ display: 'flex', gap: mobile ? 8 : 14, color: HIW_C.inkMute, flexWrap: 'wrap' }}>
            <span>JUL 12 — JUL 14</span>
            <span style={{ color: HIW_C.divider }}>│</span>
            <span>$36/NT</span>
            <span style={{ color: HIW_C.divider }}>│</span>
            <span style={{ color: HIW_C.amber }}>SINGLE-SITE LOCK</span>
          </div>
        </div>

        {/* Area-watch card — the killer use case */}
        <div style={{
          padding: mobile ? 10 : 14, background: HIW_C.panel,
          border: `1px solid ${HIW_C.amber}`, borderRadius: 4,
          fontFamily: HIW_MONO, fontSize: mobile ? 10 : 11,
          boxShadow: `inset 0 0 28px rgba(232,163,61,0.05)`,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6, gap: 8 }}>
            <span style={{ color: HIW_C.amber, letterSpacing: 1.4 }}>◇ CENTRAL OREGON</span>
            <span style={{ color: HIW_C.inkDim, fontSize: mobile ? 9 : 10 }}>AREA WATCH</span>
          </div>
          <div style={{ display: 'flex', gap: mobile ? 6 : 8, color: HIW_C.inkMute,
            flexWrap: 'wrap', marginBottom: 8 }}>
            {['LAKEFRONT', '35FT+ DRIVEWAY', 'WATER + ELECTRIC', 'FRI–SUN'].map(chip => (
              <span key={chip} style={{
                fontSize: mobile ? 9 : 9.5, letterSpacing: 1.1,
                padding: '3px 7px', border: `1px solid ${HIW_C.divider}`,
                color: HIW_C.inkMute,
              }}>
                {chip}
              </span>
            ))}
          </div>
          <div style={{ display: 'flex', gap: mobile ? 8 : 14, color: HIW_C.inkMute,
            paddingTop: 6, borderTop: `1px solid ${HIW_C.divider}`, flexWrap: 'wrap' }}>
            <span><span style={{ color: HIW_C.amber, fontWeight: 600 }}>47</span> SITES MATCHED</span>
            <span style={{ color: HIW_C.divider }}>│</span>
            <span>14 CAMPGROUNDS</span>
            <span style={{ color: HIW_C.divider }}>│</span>
            <span style={{ color: HIW_C.amber }}>REGIONAL SWEEP</span>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Step 2 overlay: probe metrics ────────────────────────
function Step2Overlay({ progress }) {
  const { mobile } = window.useViewport();
  const p = stepP(progress, 0.33, 0.66);
  const fade = Math.min(1, p * 4) * (1 - Math.max(0, (p - 0.85) / 0.15));
  if (fade <= 0) return null;
  return (
    <div style={{
      position: 'absolute', ...stepOverlayBase(mobile, 'right'),
      opacity: fade, zIndex: 6,
    }}>
      <StepHeader number="02" label="WATCH"/>
      <h2 style={hiwH2(mobile)}>We watch while you live your life.</h2>
      <p style={hiwBody(mobile)}>
        Distributed watchers monitor Recreation.gov on your behalf —
        respectfully rate-limited, redundantly routed, never asleep at the desk.
        Pro inventory gets accelerated check intervals; hot inventory gets the
        fastest cadence we run.
      </p>

      {/* Posture readout — design commitments, not fabricated production metrics */}
      <div style={{
        marginTop: mobile ? 16 : 24, padding: mobile ? 12 : 16, background: HIW_C.panel,
        border: `1px solid ${HIW_C.divider}`, borderRadius: 4,
        fontFamily: HIW_MONO, fontSize: mobile ? 10 : 11,
        display: 'grid', gridTemplateColumns: '1fr 1fr', gap: mobile ? 12 : 16,
      }}>
        <Stat label="SCAN" value="CONTINUOUS" tint={HIW_C.pine}/>
        <Stat label="ROUTING" value="REDUNDANT" tint={HIW_C.amber}/>
        <Stat label="LIMITS" value="RESPECTED" tint={HIW_C.pine}/>
        <Stat label="DELIVERY" value="MULTI-CHANNEL" tint={HIW_C.amber}/>
      </div>
    </div>
  );
}

function Stat({ label, value, tint }) {
  return (
    <div>
      <div style={{ color: HIW_C.inkDim, letterSpacing: 1, fontSize: 9, marginBottom: 4 }}>
        {label}
      </div>
      <div style={{ color: tint, fontSize: 22, fontWeight: 600, letterSpacing: '-0.01em' }}>
        {value}
      </div>
    </div>
  );
}

// ── Step 3 overlay: iOS push notification ───────────────
function Step3Overlay({ progress }) {
  const { mobile } = window.useViewport();
  const p = stepP(progress, 0.66, 1.0);
  const fade = Math.min(1, p * 4);
  const pushSlide = Math.min(1, Math.max(0, (p - 0.15) * 3));
  if (fade <= 0) return null;
  return (
    <div style={{
      position: 'absolute', ...stepOverlayBase(mobile, 'left'),
      opacity: fade, zIndex: 6,
    }}>
      <StepHeader number="03" label="ALERT"/>
      <h2 style={hiwH2(mobile)}>The instant a site opens, you know.</h2>
      <p style={hiwBody(mobile)}>
        Push notification on Pro and Basic. Email if you want it. A deeplink that
        hands you off to Recreation.gov to complete the booking — no scalper
        behavior, no payment data leaves your hands.
      </p>

      {/* iOS push notification */}
      <div style={{
        marginTop: mobile ? 18 : 28,
        opacity: pushSlide,
        transform: `translateY(${(1 - pushSlide) * -16}px)`,
        transition: 'transform 0.4s ease-out',
      }}>
        <IosPush/>
      </div>
    </div>
  );
}

function IosPush() {
  const { mobile } = window.useViewport();
  // Generic iOS dark push card — exactly the chrome users see at the top of
  // their phone. Then a deeper Campsite Sniper "card" expands below.
  return (
    <div style={{ width: '100%', maxWidth: mobile ? '100%' : 380, fontFamily: '-apple-system, system-ui, sans-serif' }}>
      <div style={{
        background: 'rgba(40, 42, 47, 0.92)',
        backdropFilter: 'blur(24px)',
        borderRadius: 18,
        padding: '12px 14px',
        boxShadow: '0 8px 24px rgba(0,0,0,0.5)',
        display: 'flex', gap: 12, alignItems: 'flex-start',
      }}>
        {/* App icon */}
        <div style={{
          width: 38, height: 38, borderRadius: 9,
          background: HIW_C.bg,
          border: `1px solid ${HIW_C.amber}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <svg width="22" height="22" viewBox="0 0 100 100">
            <path d="M50 4 L88 26 L88 74 L50 96 L12 74 L12 26 Z"
              fill="none" stroke={HIW_C.ink} strokeWidth="4" strokeLinejoin="round"/>
            <g transform="rotate(28 50 50)">
              <path d="M50 26 L52.4 50 L50 53 L47.6 50 Z" fill={HIW_C.amber}/>
              <path d="M50 74 L47.6 50 L50 47 L52.4 50 Z" fill={HIW_C.ink} opacity="0.7"/>
            </g>
            <circle cx="50" cy="50" r="3" fill={HIW_C.ink}/>
          </svg>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
            marginBottom: 2,
          }}>
            <span style={{ fontSize: 13, fontWeight: 600, color: '#fff', letterSpacing: 0.2 }}>
              CAMPSITE SNIPER
            </span>
            <span style={{ fontSize: 11, color: 'rgba(255,255,255,0.55)' }}>now</span>
          </div>
          <div style={{ fontSize: 14, fontWeight: 600, color: '#fff', marginBottom: 2, lineHeight: 1.3 }}>
            Upper Pines #14 just opened
          </div>
          <div style={{ fontSize: 13, color: 'rgba(255,255,255,0.7)', lineHeight: 1.35 }}>
            Jul 12 – Jul 14 · $36/nt · Tap to book
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Step header ──────────────────────────────────────────
function StepHeader({ number, label }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 14, marginBottom: 18,
    }}>
      <span style={{
        fontFamily: HIW_MONO, fontSize: 11, letterSpacing: 2,
        color: HIW_C.amber, fontWeight: 600,
      }}>
        {number}
      </span>
      <span style={{
        height: 1, width: 32, background: HIW_C.amber, opacity: 0.6,
      }}/>
      <span style={{
        fontFamily: HIW_MONO, fontSize: 11, letterSpacing: 2,
        color: HIW_C.inkMute, fontWeight: 600,
      }}>
        {label}
      </span>
    </div>
  );
}

const hiwH2 = (mobile) => ({
  fontFamily: HIW_MONO,
  fontSize: mobile ? 'clamp(24px, 7vw, 32px)' : 'clamp(28px, 3.4vw, 44px)',
  fontWeight: 600,
  letterSpacing: '-0.01em',
  lineHeight: 1.1,
  color: HIW_C.ink,
  textTransform: 'uppercase',
  marginBottom: mobile ? 12 : 16,
  marginTop: 0,
});
const hiwBody = (mobile) => ({
  fontFamily: HIW_MONO,
  fontSize: mobile ? 12.5 : 14,
  lineHeight: 1.6,
  color: HIW_C.inkMute,
  margin: 0,
  maxWidth: mobile ? '100%' : 420,
});

// ── Section heading (entry) ──────────────────────────────
function HiwHeading({ progress }) {
  const { mobile } = window.useViewport();
  // Visible only at the very top, fades out before step 1's content arrives
  const fade = 1 - Math.min(1, progress * 8);
  if (fade <= 0) return null;
  return (
    <div style={{
      position: 'absolute',
      top: mobile ? 84 : 100,
      left: '50%', transform: 'translateX(-50%)',
      textAlign: 'center', opacity: fade, zIndex: 6, width: '100%',
      padding: mobile ? '0 16px' : '0 32px',
    }}>
      <div style={{
        fontFamily: HIW_MONO, fontSize: mobile ? 10 : 11, letterSpacing: 2,
        color: HIW_C.amber, marginBottom: mobile ? 12 : 16,
      }}>
        {mobile ? 'HOW IT WORKS' : '─── HOW IT WORKS ───'}
      </div>
      <h1 style={{
        fontFamily: HIW_MONO,
        fontSize: mobile ? 'clamp(26px, 8.5vw, 36px)' : 'clamp(36px, 4.6vw, 64px)',
        fontWeight: 600,
        letterSpacing: '-0.01em', lineHeight: 1.05, margin: 0, color: HIW_C.ink,
        textTransform: 'uppercase',
      }}>
        Three steps. One missed weekend never again.
      </h1>
      <div style={{
        fontFamily: HIW_MONO, fontSize: 11, letterSpacing: 1.5,
        color: HIW_C.inkDim, marginTop: mobile ? 16 : 24,
      }}>
        ↓ SCROLL
      </div>
    </div>
  );
}

// ── Main section ─────────────────────────────────────────
function HowItWorks() {
  if (window.useTokens) window.useTokens();
  const ref = React.useRef(null);
  const progress = useSectionProgress(ref);

  // Compass spins with section progress: 1.5 rotations across the section
  const scrollAngle = progress * 540;

  return (
    <section id="how-it-works" ref={ref} style={{
      position: 'relative', height: '400vh',
      background: HIW_C.bgDeep, color: HIW_C.ink,
      marginTop: -1, // kiss the previous section's bottom edge
    }}>
      {/* Top fade-in from previous section so the seam is invisible */}
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0, height: 120,
        background: `linear-gradient(to bottom, ${HIW_C.bgDeep}, transparent)`,
        pointerEvents: 'none', zIndex: 7,
      }}/>
      {/* Sticky stage */}
      <div style={{
        position: 'sticky', top: 0, height: '100vh', overflow: 'hidden',
      }}>
        {/* Map (animates with progress) */}
        <HiwMap progress={progress}/>

        {/* Ambient overlays */}
        <div style={{
          position: 'absolute', inset: 0,
          background: `radial-gradient(ellipse at center, transparent 30%, ${HIW_C.bgDeep} 90%)`,
          pointerEvents: 'none',
        }}/>

        {/* Compass HUD */}
        <CompassHud scrollAngle={scrollAngle}/>

        {/* Step indicator */}
        <StepIndicator progress={progress}/>

        {/* Heading + step overlays */}
        <HiwHeading progress={progress}/>
        <Step1Overlay progress={progress}/>
        <Step2Overlay progress={progress}/>
        <Step3Overlay progress={progress}/>

        {/* Bottom-left readout */}
        <div style={{
          position: 'absolute', bottom: 28, left: 32,
          fontFamily: HIW_MONO, fontSize: 9.5, letterSpacing: 1.2,
          color: HIW_C.inkDim, display: 'flex', gap: 18,
        }}>
          <span>SECTION 02</span>
          <span style={{ opacity: 0.4 }}>│</span>
          <span style={{ color: HIW_C.amber }}>{Math.round(progress * 100)}%</span>
        </div>
      </div>

      <style>{`
        @keyframes hiw-hex-pulse {
          0%, 100% { opacity: 0.5; }
          50% { opacity: 0.15; }
        }
        @keyframes hiw-ping {
          0% { r: 40; opacity: 0.6; }
          100% { r: 240; opacity: 0; }
        }
        @keyframes hiw-beam-flow {
          0% { stroke-dashoffset: 0; }
          100% { stroke-dashoffset: -20; }
        }
      `}</style>
    </section>
  );
}

window.HowItWorks = HowItWorks;
