// ============================================================
// HUNGRY HOLE 3D — core screens: Splash, Onboarding, WorldMap, LevelIntro, Home
// Polished casual-.io shell: bright sky, candy 3D buttons, isometric city island,
// winding level-node trail, persistent BottomNav + top resource bar. ORIGINAL art.
// ============================================================
const { useState: useStateCo, useEffect: useEffectCo, useRef: useRefCo } = React;

// ----- 0 · Loading screen -----
// First thing the player sees: the splash art + an animated progress bar, then auto-advance
// straight to Home (the old "Tap to Play" splash is bypassed). Drops the user's hero art in if
// present at www/assets/loading-splash.webp; otherwise a built-in animated sky/hole/title scene.
function Loading({ go }) {
  const [p, setP] = useStateCo(0);
  const [imgOk, setImgOk] = useStateCo(false);
  useEffectCo(() => {
    let raf, t0 = performance.now(); const dur = 2400;
    const tick = (now) => { const f = Math.min(1, (now - t0) / dur); setP(f); if (f < 1) raf = requestAnimationFrame(tick); else setTimeout(() => go('home'), 420); };
    raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf);
  }, []);
  const pct = Math.round(p * 100);
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden',
      background: 'linear-gradient(180deg,#7FC4FF 0%,#A9DBFF 46%,#CDEFD2 55%,#8FD86A 70%,#79C657 100%)' }}>
      {/* the user's hero art, if dropped at assets/loading-splash.webp — covers the fallback scene */}
      <img src="assets/loading-splash.webp" alt="" onLoad={() => setImgOk(true)} onError={(e) => { e.target.style.display = 'none'; }}
        style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
      {!imgOk && (
        <>
          {[[8, 13, 64], [70, 8, 86], [24, 28, 48], [82, 32, 56], [46, 18, 42]].map((c, i) => (
            <div key={i} style={{ position: 'absolute', left: c[0] + '%', top: c[1] + '%', width: c[2], height: c[2] * 0.46, borderRadius: 100,
              background: 'rgba(255,255,255,0.88)', boxShadow: '20px 7px 0 -7px rgba(255,255,255,0.82), -17px 6px 0 -8px rgba(255,255,255,0.78)',
              animation: `hh-bob ${3 + i * 0.4}s ease-in-out infinite` }} />
          ))}
          <div style={{ position: 'absolute', top: '11%', left: 0, right: 0, textAlign: 'center' }}>
            <div className="disp" style={{ fontSize: 54, lineHeight: 0.9, color: '#fff', WebkitTextStroke: '3px #16223C', paintOrder: 'stroke fill', textShadow: '0 6px 0 rgba(16,34,68,0.22)' }}>HUNGRY<br />HOLE</div>
            <div className="disp" style={{ fontSize: 36, marginTop: 2, color: 'var(--sun)', WebkitTextStroke: '3px #16223C', paintOrder: 'stroke fill' }}>3D</div>
          </div>
          <div style={{ position: 'absolute', top: '44%', left: '50%', transform: 'translate(-50%,-50%)', width: 168, height: 168, borderRadius: '50%',
            background: 'radial-gradient(circle at 50% 42%, #070b16 0%, #070b16 52%, rgba(70,160,255,0.95) 59%, rgba(70,160,255,0.0) 74%)',
            color: '#46A0FF', boxShadow: '0 0 60px 8px rgba(70,160,255,0.45)', animation: 'hh-glowpulse 2s ease-in-out infinite' }} />
        </>
      )}
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: '12%', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10, padding: '0 24px' }}>
        <div style={{ width: '66%', maxWidth: 300, height: 13, borderRadius: 100, background: 'rgba(255,255,255,0.5)', overflow: 'hidden', boxShadow: 'inset 0 2px 4px rgba(0,0,0,0.18), 0 2px 6px rgba(0,0,0,0.12)' }}>
          <div style={{ width: pct + '%', height: '100%', borderRadius: 100, background: 'linear-gradient(90deg,#5BE06B,#7CFC4A 55%,#FFD24A)', boxShadow: '0 0 10px rgba(124,252,74,0.6), inset 0 1px 0 rgba(255,255,255,0.5)', transition: 'width .12s linear' }} />
        </div>
        <div className="disp" style={{ fontSize: 14, color: '#fff', letterSpacing: 0.4, textShadow: '0 2px 4px rgba(0,0,0,0.35)' }}>Loading… {pct}%</div>
      </div>
    </div>
  );
}

// ----- shared helpers -----
// progress = furthest playable level (one past the furthest played)
function nextPlayable() {
  const HH = window.HH; const stars = HH.STARS; let nextN = 1;
  for (const lv of HH.LEVELS.flat()) { if ((stars[lv[0]] || 0) > 0) nextN = Math.min(160, lv[0] + 1); }
  return nextN;
}

// Top resource bar (hub screens): avatar chip + coin + gem chips + gear.
// `go` routes; coin/gem tap → shop; avatar tap → profile; gear → settings.
// Uses the index.html .hh-topbar / .hh-topbar-* CSS family for the candy chips.
function HHTopBar({ go, wallet, dark, onAvatar }) {
  const gems = (wallet && wallet.gems != null) ? wallet.gems : 60;
  const coins = (wallet && wallet.coins != null) ? wallet.coins : 0;
  const lvl = Math.max(1, Math.ceil(nextPlayable() / 10));
  // reflect the player's chosen avatar (set in Profile) so the home bar updates after save
  const HH = window.HH;
  const prof = (HH && HH.profile) || (window.loadProfile ? window.loadProfile() : { avatar: 'hole' });
  return (
    <div className="hh-topbar" style={{ position: 'absolute', top: 0, left: 0, right: 0, zIndex: 40, paddingLeft: 12, paddingRight: 12 }}>
      {/* avatar chip — chosen AvatarDisc (hole or emoji) + tiny level badge */}
      <button onClick={onAvatar || (() => go('profile'))} aria-label="Profile"
        style={{ position: 'relative', flex: 'none', width: 58, height: 58, cursor: 'pointer', padding: 0, border: 0, borderRadius: 18,
          background: 'transparent', boxShadow: 'none' }}>
        <img src="assets/ui-ai/icon-profile.webp" alt="" style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block',
          filter: 'drop-shadow(0 6px 0 #061B36) drop-shadow(0 12px 18px rgba(0,0,0,0.34))' }} />
        <span style={{ position: 'absolute', bottom: -5, right: -5, minWidth: 22, height: 22, padding: '0 5px', borderRadius: 100, background: 'linear-gradient(180deg,#FFE76A,#E69B12)', border: '2px solid #fff', display: 'grid', placeItems: 'center', fontFamily: 'var(--num)', fontWeight: 900, fontSize: 12, color: '#5a3c06', boxShadow: '0 3px 0 #8D5100, 0 7px 10px rgba(0,0,0,0.26)' }}>{lvl}</span>
      </button>
      <div className="hh-topbar-spacer" />
      {/* coin chip */}
      <button onClick={() => go('shop')} className="hh-topbar-chip" style={{ cursor: 'pointer', border: 'none' }}>
        <Coin size={20} /><span className="num">{coins.toLocaleString()}</span>
      </button>
      {/* gem chip */}
      <button onClick={() => go('shop')} className="hh-topbar-chip gem" style={{ cursor: 'pointer', border: 'none' }}>
        <Gem size={20} /><span className="num">{gems.toLocaleString()}</span>
      </button>
      {/* spacer pushes the gear to the far top-right corner (away from the gem) */}
      <div className="hh-topbar-spacer" />
      {/* gear → settings */}
      <button onClick={() => go('settings')} className="hh-topbar-gear" aria-label="Settings" style={{ marginLeft: 2 }}>
        <img src="assets/ui-ai/icon-settings-3d.webp" alt="" style={{ width: 44, height: 44, objectFit: 'contain', display: 'block' }} />
      </button>
    </div>
  );
}

// ---------- 1 · Splash ----------
// Bright premium title screen: sunny sky, sun bloom, drifting clouds, a layered
// candy wordmark, a big HoleVisual hero devouring orbiting props, "▶ Tap to Play".
function Splash({ go }) {
  const [p, setP] = useStateCo(0);
  useEffectCo(() => { let v = 0; const iv = setInterval(() => { v = Math.min(1, v + 0.02 + Math.random() * 0.024); setP(v); if (v >= 1) clearInterval(iv); }, 36); return () => clearInterval(iv); }, []);
  const ready = p >= 1;
  const orbit = ['car', 'house', 'tree', 'donut', 'bench', 'hydrant', 'cone', 'bin'];
  return (
    <div onClick={() => ready && go('home')} style={{ position: 'absolute', inset: 0, overflow: 'hidden', cursor: ready ? 'pointer' : 'default',
      background: 'linear-gradient(180deg, #2FA4FF 0%, #6FCBFF 42%, #BFE6FF 74%, #E2F2FF 100%)' }}>
      <StatusBar />
      {/* warm sun bloom top-right + soft rotating rays */}
      <div style={{ position: 'absolute', top: '-12%', right: '-14%', width: 320, height: 320, borderRadius: '50%', pointerEvents: 'none', zIndex: 1,
        background: 'radial-gradient(circle, rgba(255,246,205,0.95) 0%, rgba(255,243,200,0.4) 38%, transparent 70%)', filter: 'blur(4px)' }} />
      <div style={{ position: 'absolute', top: '-18%', right: '-20%', width: 360, height: 360, pointerEvents: 'none', zIndex: 1, opacity: 0.45,
        background: 'conic-gradient(from 0deg, transparent 0 8deg, rgba(255,240,180,0.5) 8deg 16deg, transparent 16deg 30deg)',
        borderRadius: '50%', maskImage: 'radial-gradient(circle, #000 40%, transparent 72%)', WebkitMaskImage: 'radial-gradient(circle, #000 40%, transparent 72%)',
        animation: 'hh-spin 60s linear infinite' }} />
      {/* faint city skyline silhouette along the horizon for depth */}
      <svg viewBox="0 0 100 26" preserveAspectRatio="none" style={{ position: 'absolute', left: 0, right: 0, bottom: 0, width: '100%', height: 150, zIndex: 1, opacity: 0.35, pointerEvents: 'none' }}>
        <path d="M0 26 V14 h6 V8 h5 V16 h7 V6 h6 V16 h8 V11 h5 V4 h5 V16 h7 V9 h6 V16 h8 V7 h5 V16 h7 V12 h6 V16 h8 V26 Z" fill="#A8D6F8" />
      </svg>
      {/* drifting soft clouds (parallax layers) */}
      {[0, 1, 2, 3, 4].map(i => (
        <div key={'cl' + i} className="hh-anim" style={{ position: 'absolute', top: `${8 + i * 11}%`, left: `${-28 + i * 26}%`, pointerEvents: 'none', zIndex: 2,
          animation: `hh-cloud ${24 + i * 7}s linear ${-i * 6}s infinite` }}>
          <div style={{ width: 120 - i * 8, height: 30 + (i % 2) * 8, borderRadius: 100, background: 'rgba(255,255,255,0.78)', filter: 'blur(3px)',
            boxShadow: '26px -10px 0 -3px rgba(255,255,255,0.78), 54px -2px 0 -6px rgba(255,255,255,0.78)' }} />
        </div>
      ))}

      {/* hero hole devouring orbiting props */}
      <div style={{ position: 'absolute', top: '32%', left: '50%', transform: 'translate(-50%,-50%)', width: 300, height: 300, zIndex: 6 }}>
        {/* soft ground shadow disc under the hero */}
        <div style={{ position: 'absolute', left: '50%', top: '54%', transform: 'translate(-50%,-50%)', width: 200, height: 70, borderRadius: '50%',
          background: 'radial-gradient(ellipse, rgba(16,34,58,0.22), transparent 70%)', filter: 'blur(4px)', pointerEvents: 'none' }} />
        {orbit.map((t, i) => { const dur = 8 + (i % 4) * 2.6; const orb = 104 + (i % 3) * 22; return (
          <div key={i} style={{ position: 'absolute', left: '50%', top: '50%', '--orb': `${orb}px`,
            animation: `hh-orbit ${dur}s linear infinite`, animationDelay: `${-i * 1.2}s`, opacity: 0.96 }}>
            <Prop type={t} size={28 - (i % 3) * 4} /></div>); })}
        <div style={{ position: 'absolute', left: '50%', top: '50%', transform: 'translate(-50%,-50%)', animation: 'hh-bob 3.4s ease-in-out infinite' }}>
          <HoleVisual r={70} skin="classic" /></div>
        {/* floating player name tag — .io signature */}
      </div>

      {/* wordmark — original stacked candy treatment */}
      <div style={{ position: 'absolute', left: 0, right: 0, top: '56%', textAlign: 'center', padding: '0 24px', zIndex: 8 }}>
        <div className="eyebrow fadeup" style={{ color: 'rgba(16,34,58,0.55)', marginBottom: 8 }}>Hungry Hole Studio</div>
        <h1 className="disp fadeup" style={{ animationDelay: '.05s', margin: 0, fontSize: 56, lineHeight: 0.86, color: 'var(--ink)',
          textShadow: '0 3px 0 #fff, 0 5px 0 rgba(255,255,255,0.7), 0 10px 22px rgba(16,34,58,0.22)' }}>HUNGRY<br/>HOLE <span style={{ color: 'var(--sun)', WebkitTextStroke: '0px', textShadow: '0 3px 0 #C97F0E, 0 6px 16px rgba(201,127,14,0.4)' }}>3D</span></h1>
        <div className="fadeup" style={{ animationDelay: '.12s', marginTop: 12, fontWeight: 800, fontSize: 15, color: 'rgba(16,34,58,0.62)', letterSpacing: 0.4 }}>City run</div>
      </div>

      {/* loader / start */}
      <div style={{ position: 'absolute', bottom: 54, left: 34, right: 34, zIndex: 10 }}>
        {!ready
          ? <><Bar v={p} color="linear-gradient(90deg,#7CFC4A,#A7F23C,#FFD24A)" track="rgba(255,255,255,0.55)" h={11} />
              <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 10, fontWeight: 800, fontSize: 12.5, color: 'rgba(16,34,58,0.55)' }}>
                <span>Loading</span><span className="num">{Math.round(p * 100)}%</span></div></>
          : <button className="btn sun block shimmer" onClick={() => go('home')} style={{ fontSize: 22, padding: '18px', animation: 'hh-bob 2.2s ease-in-out infinite' }}>
              <I.play width={20} height={20} /> Play</button>}
      </div>
    </div>
  );
}

// ---------- 2 · Onboarding ×3 ----------
// Clean friendly intro: drag to move · eat & grow · beat the goal.
function Onboarding({ go }) {
  const O = window.HH.ONBOARD;
  const [i, setI] = useStateCo(0);
  const W = window.HH.WORLDS[0];
  const card = O[i];
  const next = () => i < 2 ? setI(i + 1) : go('home');
  const accent = card.k === 'drag' ? 'var(--sky)' : card.k === 'eat' ? 'var(--mint)' : 'var(--sun)';
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden',
      background: 'linear-gradient(180deg, #33A9FF 0%, #9FDCFF 50%, #DCEFFE 100%)' }}>
      <StatusBar dark />
      {/* soft clouds */}
      {[0, 1, 2].map(n => <div key={n} className="hh-anim" style={{ position: 'absolute', top: `${8 + n * 11}%`, left: `${-20 + n * 34}%`, pointerEvents: 'none',
        width: 110 - n * 8, height: 32, borderRadius: 60, background: 'rgba(255,255,255,0.6)', filter: 'blur(5px)', animation: `hh-cloud ${24 + n * 6}s linear ${-n * 5}s infinite` }} />)}

      <button className="btn ghost sm" onClick={() => go('home')} style={{ position: 'absolute', top: 48, right: 16, zIndex: 10, padding: '9px 18px' }}>Skip</button>

      {/* demo stage — a faux board with the hole and props */}
      <div style={{ position: 'absolute', top: 92, left: 22, right: 22, height: 320, zIndex: 5 }}>
        <div className="panel" style={{ width: '100%', height: '100%', borderRadius: 30, position: 'relative', overflow: 'hidden',
          background: `linear-gradient(180deg, ${W.sky[0]}, ${W.sky[1]})` }}>
          {/* ground plane */}
          <div style={{ position: 'absolute', inset: 0, transform: 'perspective(720px) rotateX(50deg) scale(0.92)', transformOrigin: 'center 62%' }}>
            <div style={{ position: 'absolute', left: '8%', right: '8%', top: '34%', bottom: '-20%', borderRadius: 28,
              background: 'linear-gradient(180deg,#CDC8D8,#B9B3C8)', boxShadow: 'inset 0 0 0 3px rgba(255,255,255,0.35)' }} />
            {card.k === 'drag' && <div style={{ position: 'absolute', left: '50%', top: '54%', transform: 'translate(-50%,-50%)', animation: 'hh-drag-demo 1.7s ease-in-out infinite' }}><HoleVisual r={34} skin="classic" /></div>}
            {card.k === 'eat' && <>
              <div style={{ position: 'absolute', left: '50%', top: '56%', transform: 'translate(-50%,-50%)' }}><HoleVisual r={36} skin="classic" /></div>
              {[0, 1, 2].map(n => <div key={n} style={{ position: 'absolute', left: `${40 + n * 12}%`, top: '30%', transform: 'rotateX(-50deg)', animation: `hh-fall 1.9s ${n * 0.45}s ease-in infinite` }}><Prop type={['cube', 'cone', 'bench'][n]} size={30} /></div>)}
            </>}
            {card.k === 'grow' && <div style={{ position: 'absolute', left: '50%', top: '54%', transform: 'translate(-50%,-50%)', animation: 'hh-grow-demo 1.5s ease-in-out infinite alternate' }}><HoleVisual r={32} skin="classic" /></div>}
          </div>
          {/* drag knob hint */}
          {card.k === 'drag' && <div style={{ position: 'absolute', bottom: 26, left: '50%', transform: 'translateX(-50%)', width: 40, height: 40, borderRadius: '50%', background: 'rgba(255,255,255,0.95)', border: '3px solid #fff', boxShadow: '0 4px 12px rgba(16,34,58,0.35)', animation: 'hh-drag-demo 1.7s ease-in-out infinite' }} />}
          {/* mini goal bar to teach the win condition */}
          {card.k === 'grow' && <div style={{ position: 'absolute', bottom: 22, left: 26, right: 26 }}><ProgressBar value={720} target={900} h={14} /></div>}
          {/* growing +N float on eat */}
          {card.k === 'eat' && <div className="hh-outline-sm" style={{ position: 'absolute', left: '50%', top: '40%', transform: 'translateX(-50%)', fontSize: 18, color: '#9DFF7A', animation: 'hh-bob 1.6s ease-in-out infinite' }}>+1</div>}
        </div>
      </div>

      {/* copy */}
      <div style={{ position: 'absolute', bottom: 38, left: 24, right: 24, textAlign: 'center', zIndex: 6 }}>
        <div className="eyebrow" style={{ color: accent }}>Step {i + 1} of 3</div>
        <h2 className="disp" style={{ fontSize: 40, margin: '6px 0 8px', color: 'var(--ink)' }}>{card.title}</h2>
        <p style={{ fontSize: 16, fontWeight: 700, color: 'var(--slate)', margin: '0 auto 22px', maxWidth: 300, lineHeight: 1.45 }}>{card.line}</p>
        <div style={{ display: 'flex', justifyContent: 'center', gap: 8, marginBottom: 20 }}>
          {[0, 1, 2].map(n => <span key={n} style={{ width: n === i ? 26 : 8, height: 8, borderRadius: 100, background: n === i ? accent : 'rgba(16,34,58,0.18)', transition: 'width .22s, background .22s' }} />)}
        </div>
        <button className="btn block shimmer" onClick={next} style={{ fontSize: 19 }}>{i < 2 ? 'Next ›' : "Let's eat!"}</button>
      </div>
    </div>
  );
}

// ---------- 3 · World Map (the flagship level select) ----------
// Winding path of level nodes (locked / unlocked / star-rated), current level
// glowing, themed parallax props beside the trail, a .hh-topbar + persistent BottomNav.
function WorldMap({ go, openLevel, world, setWorld, wallet, planet = 0 }) {
  const HH = window.HH;
  const W = (HH.worldView ? HH.worldView(world, planet) : HH.WORLDS[world]);   // planet re-tint
  const PL = HH.planetForIndex ? HH.planetForIndex(planet) : null;
  const levels = HH.LEVELS[world];
  const stars = HH.STARS;
  const scrollRef = useRefCo(null);
  const dark = window.__hhTheme === 'dark';
  const night = !!W.night || dark;
  const nextN = nextPlayable();
  const totalStars = Object.values(stars).reduce((a, b) => a + b, 0);
  const worldStars = levels.reduce((a, lv) => a + (stars[lv[0]] || 0), 0);
  const worldDone = levels.filter(lv => (stars[lv[0]] || 0) > 0).length;

  // winding node positions (S-curve down the trail)
  const nodeX = (i) => 50 + Math.sin(i * 1.1) * 28;
  const ROW = 100;

  // scroll the current node into view on open
  useEffectCo(() => {
    const el = scrollRef.current; if (!el) return;
    const idx = levels.findIndex(lv => lv[0] === nextN);
    if (idx >= 0) { const y = (levels.length - 1 - idx) * ROW; el.scrollTop = Math.max(0, y - 240); }
  }, [world]);

  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden',
      background: '#071B34' }}>
      <StatusBar dark={!night} />
      <img src="assets/ui-ai/map-bg.webp" alt="" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 0 }} />
      <div style={{ position: 'absolute', inset: 0, zIndex: 1, pointerEvents: 'none',
        background: 'linear-gradient(180deg,rgba(2,12,28,0.18) 0%,rgba(2,12,28,0.02) 42%,rgba(2,8,20,0.44) 100%)' }} />

      {/* ambient bloom (sun by day, neon by night) for atmosphere */}
      <div style={{ position: 'absolute', top: '4%', left: '64%', width: 180, height: 180, borderRadius: '50%', zIndex: 1, pointerEvents: 'none',
        background: night ? `radial-gradient(circle, ${W.ring || '#21E6FF'}44, transparent 70%)` : 'radial-gradient(circle, rgba(255,246,205,0.9), transparent 70%)', filter: 'blur(8px)' }} />

      {/* parallax far hills/skyline silhouette behind the trail — adds depth (two layers) */}
      <svg viewBox="0 0 100 40" preserveAspectRatio="none" style={{ display: 'none', position: 'absolute', left: 0, right: 0, bottom: 0, top: '46%', width: '100%', zIndex: 1, opacity: night ? 0.4 : 0.55, pointerEvents: 'none' }}>
        <path d="M0 40 L0 24 Q12 14 24 22 Q38 8 52 20 Q66 6 80 18 Q90 12 100 20 L100 40 Z" fill={shade(W.ground || W.sky[1], night ? 0.1 : -0.12)} opacity="0.7" />
        <path d="M0 40 L0 30 Q16 22 32 28 Q48 18 64 28 Q80 20 100 28 L100 40 Z" fill={shade(W.groundDark || W.ground || W.sky[1], -0.18)} opacity="0.8" />
      </svg>

      {/* drifting clouds far behind the trail */}
      {[0, 1, 2, 3].map(i => (
        <div key={'cl' + i} className="hh-anim" style={{ display: 'none', position: 'absolute', top: 150 + i * 165, left: -60, zIndex: 2, opacity: night ? 0.12 : 0.6, pointerEvents: 'none',
          animation: `hh-cloud ${26 + i * 8}s linear ${-i * 8}s infinite` }}>
          <div style={{ width: 96 + i * 24, height: 26 + i * 6, borderRadius: 100, background: '#fff', filter: 'blur(2px)', boxShadow: '20px -8px 0 -2px #fff, 44px 0 0 -5px #fff' }} />
        </div>
      ))}

      {/* node path (scrolls) */}
      <div ref={scrollRef} className="pf-scroll" style={{ position: 'absolute', top: 188, bottom: 0, left: 0, right: 0, paddingBottom: 130, zIndex: 6 }}>
        <div style={{ position: 'relative', height: levels.length * ROW + 90, margin: '24px 0 40px' }}>
          {/* (removed floating prop sprites beside the trail — the 3D map art already carries the scene) */}

          {/* connecting path — soft white casing + dashed accent core + tiny milestone flags */}
          <svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }} preserveAspectRatio="none" viewBox={`0 0 100 ${levels.length * ROW + 40}`}>
            <path d={levels.map((lv, i) => { const y = (levels.length - 1 - i) * ROW + 30; const x = nodeX(i); return `${i === 0 ? 'M' : 'L'} ${x} ${y}`; }).join(' ')}
              fill="none" stroke={night ? 'rgba(255,255,255,0.30)' : 'rgba(255,255,255,0.9)'} strokeWidth="7" strokeLinecap="round" strokeLinejoin="round" />
            <path d={levels.map((lv, i) => { const y = (levels.length - 1 - i) * ROW + 30; const x = nodeX(i); return `${i === 0 ? 'M' : 'L'} ${x} ${y}`; }).join(' ')}
              fill="none" stroke={W.accent || 'var(--sky)'} strokeWidth="3" strokeDasharray="1 5" strokeLinecap="round" opacity="0.9" />
            {/* faded "done" overlay along the played section, mint-tinted */}
            <path d={levels.filter(lv => (stars[lv[0]] || 0) > 0).map((lv, k, arr) => { const i = levels.indexOf(lv); const y = (levels.length - 1 - i) * ROW + 30; const x = nodeX(i); return `${k === 0 ? 'M' : 'L'} ${x} ${y}`; }).join(' ')}
              fill="none" stroke="#22C9A0" strokeWidth="3" strokeLinecap="round" opacity="0.55" />
          </svg>

          {levels.map((lv, i) => {
            const n = lv[0]; const st = stars[n] || 0;
            const unlocked = n <= nextN; const isNext = n === nextN; const done = st > 0;
            const goal = HH.GOALS[lv[2]];
            const y = (levels.length - 1 - i) * ROW + 30; const x = nodeX(i);
            const size = isNext ? 64 : 56;
            const isBoss = n % 10 === 0; // every 10th level = mini boss / world finale
            return (
              <div key={n} style={{ position: 'absolute', left: `${x}%`, top: y, transform: 'translate(-50%,-50%)', display: 'flex', flexDirection: 'column', alignItems: 'center', zIndex: isNext ? 12 : 8 }}>
                {isNext && <div style={{ position: 'absolute', top: -36, whiteSpace: 'nowrap', animation: 'hh-bob 1.8s ease-in-out infinite' }}>
                  <div className="hh-level" style={{ fontSize: 12, background: goal.color, color: '#fff' }}>PLAY ▾</div></div>}
                {/* calm static glow behind the current node (no spinning conic — it flickered on Android) */}
                {isNext && <div style={{ position: 'absolute', width: 100, height: 100, borderRadius: '50%', pointerEvents: 'none',
                  background: `radial-gradient(circle, ${goal.color}55, ${goal.color}22 52%, transparent 72%)` }} />}
                <button onClick={() => unlocked && openLevel(n)} disabled={!unlocked} style={{ cursor: unlocked ? 'pointer' : 'default', border: 'none', background: 'none', padding: 0, position: 'relative' }}>
                  <div style={{ width: size, height: size, borderRadius: isBoss ? '30% 70% 70% 30% / 30% 30% 70% 70%' : '50%', display: 'grid', placeItems: 'center', position: 'relative',
                    background: !unlocked ? 'linear-gradient(180deg,#fff,#EBEFF7)'
                      : done ? `linear-gradient(180deg,#fff,${W.card || '#EEF3FB'})`
                      : `linear-gradient(180deg,${goal.color},${shade(goal.color, -0.16)})`,
                    border: isNext ? `4px solid ${goal.color}` : isBoss ? '4px solid var(--sun)' : '4px solid #fff',
                    boxShadow: isNext ? `0 0 0 5px rgba(255,255,255,0.9), 0 8px 18px rgba(16,34,58,0.34)` : '0 5px 12px rgba(16,34,58,0.24)',
                    opacity: unlocked ? 1 : 0.78, animation: isNext ? 'hh-bob 2s ease-in-out infinite' : 'none' }}>
                    {!unlocked ? <span style={{ color: 'var(--slate)' }}><I.lock width={22} height={22} /></span>
                      : done ? <span className="disp num" style={{ fontSize: 26, color: '#16223C' }}>{n}</span>
                      : <GoalGlyph id={lv[2]} size={28} color="#fff" />}
                    {/* boss crown */}
                    {isBoss && unlocked && <span style={{ position: 'absolute', top: -16, left: '50%', transform: 'translateX(-50%)', color: 'var(--sun)', filter: 'drop-shadow(0 2px 3px rgba(180,120,0,0.45))' }}><I.crown width={22} height={22} /></span>}
                    {/* small goal-type dot for unlocked, un-played nodes */}
                    {unlocked && !done && !isNext && <span style={{ position: 'absolute', bottom: -2, right: -2, width: 18, height: 18, borderRadius: '50%', background: '#fff', display: 'grid', placeItems: 'center', boxShadow: '0 2px 4px rgba(16,34,58,0.25)' }}>
                      <span className="num" style={{ fontSize: 10, fontWeight: 800, color: '#16223C' }}>{n}</span></span>}
                  </div>
                  {unlocked && <div style={{ position: 'absolute', bottom: -14, left: '50%', transform: 'translateX(-50%)' }}><Stars n={st} size={14} gap={1} /></div>}
                </button>
              </div>
            );
          })}
        </div>
      </div>

      {/* ===== sticky header (above the scroll) ===== */}
      {/* top scrim for legibility */}
      <div style={{ position: 'absolute', left: 0, right: 0, top: 0, height: 188, zIndex: 18, pointerEvents: 'none',
        background: 'linear-gradient(180deg, rgba(6,22,45,0.82) 0%, rgba(6,22,45,0.44) 55%, transparent 100%)' }} />

      {/* top resource bar */}
      <HHTopBar go={go} wallet={wallet} dark={!night} />

      {/* world switcher */}
      <div style={{ position: 'absolute', top: 100, left: 16, right: 16, zIndex: 28, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
        <button onClick={() => setWorld(Math.max(0, world - 1))} disabled={world === 0}
          style={{ opacity: world === 0 ? 0.3 : 1, background: 'rgba(255,255,255,0.95)', border: '1px solid var(--line)', borderRadius: '50%', width: 40, height: 40, cursor: world === 0 ? 'default' : 'pointer', display: 'grid', placeItems: 'center', color: '#16223C', boxShadow: 'var(--shadow)', flexShrink: 0 }}><I.back width={22} /></button>
        <div className="panel" style={{ flex: 1, maxWidth: 234, padding: '9px 16px 11px', textAlign: 'center', borderRadius: 18, position: 'relative' }}>
          <div className="eyebrow" style={{ fontSize: 8.5, color: W.accent || 'var(--sky)' }}>{PL && PL.isNew ? PL.icon + ' ' + PL.name + ' · ' : ''}World {W.id}</div>
          <div className="disp" style={{ fontSize: 21, color: 'var(--ink)', lineHeight: 1 }}>{W.name}</div>
          <div style={{ fontWeight: 800, fontSize: 11, color: 'var(--slate)', marginTop: 3 }}>{W.sub}</div>
          {/* world completion mini-bar */}
          <div style={{ margin: '6px auto 4px', maxWidth: 150 }}>
            <div style={{ height: 6, borderRadius: 100, background: 'rgba(16,34,58,0.12)', overflow: 'hidden' }}>
              <div style={{ height: '100%', width: `${Math.round((worldDone / levels.length) * 100)}%`, borderRadius: 100, background: 'linear-gradient(90deg,#7CFC4A,#FFD24A)', transition: 'width .3s' }} />
            </div>
          </div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>
            <I.star width={13} style={{ color: 'var(--sun)' }} />
            <span className="num" style={{ fontSize: 12, color: 'var(--ink)' }}>{worldStars}</span>
            <span style={{ color: 'var(--slate)', fontSize: 11 }}>/ {levels.length * 3}</span>
            <span style={{ color: 'var(--line)', margin: '0 4px' }}>·</span>
            <span style={{ color: 'var(--slate)', fontSize: 11 }}>★ {totalStars} total</span>
          </div>
        </div>
        <button onClick={() => setWorld(Math.min(15, world + 1))} disabled={world === 15}
          style={{ opacity: world === 15 ? 0.3 : 1, background: 'rgba(255,255,255,0.95)', border: '1px solid var(--line)', borderRadius: '50%', width: 40, height: 40, cursor: world === 15 ? 'default' : 'pointer', display: 'grid', placeItems: 'center', color: '#16223C', boxShadow: 'var(--shadow)', flexShrink: 0 }}><I.back width={22} style={{ transform: 'rotate(180deg)' }} /></button>
      </div>

      <BottomNav active="map" go={go} />
    </div>
  );
}

// ---------- 4 · Level Intro ----------
// Polished pre-level card over a live board preview: level name, goal glyph +
// label + target, reward, loadout, 3-star bar, big PLAY button.
function LevelIntro({ go, startLevel, world, level, planet = 0 }) {
  const HH = window.HH;
  const W = (HH.worldView ? HH.worldView(world, planet) : HH.WORLDS[world]);
  const PL = HH.planetForIndex ? HH.planetForIndex(planet) : null;
  const gLevel = HH.globalLevel ? HH.globalLevel(planet, level) : level;
  const lv = HH.LEVELS.flat().find(l => l[0] === level) || HH.LEVELS[0][0];
  const goal = HH.GOALS[lv[2]];
  const st = HH.STARS[level] || 0;
  const diff = HH.DIFFICULTY(level, planet);
  const mm = String(Math.floor(diff.time / 60)).padStart(1, '0');
  const ss = String(diff.time % 60).padStart(2, '0');
  const reward = 60 + level * 20;
  const CH = (HH.challengeFor ? HH.challengeFor(level) : { name: 'Classic', color: 'var(--sky)', desc: '' });
  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden' }}>
      {/* board preview */}
      <Board world={W} level={level} interactive={false} small onUpdate={() => {}} />
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, rgba(27,39,64,0.18), rgba(27,39,64,0.46))', backdropFilter: 'blur(2px)', WebkitBackdropFilter: 'blur(2px)' }} />
      <StatusBar />
      <IconBtn light onClick={() => go('map')} style={{ position: 'absolute', top: 48, left: 18, zIndex: 20 }}><I.close /></IconBtn>

      <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 22, zIndex: 15 }}>
        <div className="panel pop" style={{ width: '100%', maxWidth: 332, padding: '24px 22px 22px', textAlign: 'center', position: 'relative' }}>
          {/* goal-tinted top glow */}
          <div style={{ position: 'absolute', top: -1, left: '18%', right: '18%', height: 4, borderRadius: 100, background: goal.color, opacity: 0.9 }} />
          {/* header: world + goal verb */}
          <div className="eyebrow" style={{ color: goal.color }}>{PL && PL.isNew ? PL.icon + ' ' + PL.name + ' · ' : ''}World {W.id} · {goal.verb}</div>
          <h2 className="disp" style={{ fontSize: 30, margin: '4px 0 2px', lineHeight: 1.02 }}>{lv[1]}</h2>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, marginTop: 4, marginBottom: 12 }}>
            <span className="hh-level" style={{ fontSize: 12 }}>LEVEL {gLevel}</span>
            <Stars n={st} size={18} />
          </div>
          {/* CHALLENGE badge — glossy chip with a colored name-tag + description */}
          <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 14 }}>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '6px 13px 6px 6px', borderRadius: 100,
              background: 'linear-gradient(180deg,#FFFFFF,#EDF3FC)', border: `2px solid ${CH.color}`, maxWidth: 300,
              boxShadow: `0 4px 0 ${CH.color}3a, 0 8px 16px rgba(16,34,68,0.16)` }}>
              <span className="disp" style={{ fontSize: 11.5, color: '#fff', whiteSpace: 'nowrap', padding: '4px 11px', borderRadius: 100,
                background: `linear-gradient(180deg,${CH.color},${shade(CH.color, -0.22)})`, boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.45)', letterSpacing: 0.3 }}>{CH.name}</span>
              <span style={{ fontSize: 11.5, fontWeight: 700, color: 'var(--slate)', textAlign: 'left', lineHeight: 1.18 }}>{CH.desc}</span>
            </div>
          </div>

          {/* goal callout — glyph + premium TARGET/TIME objective bar */}
          <div className="card" style={{ padding: '18px 16px', marginBottom: 12, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 13, background: '#fff', position: 'relative', overflow: 'hidden' }}>
            {/* soft radial halo behind the glyph for depth */}
            <div style={{ position: 'absolute', top: -20, left: '50%', transform: 'translateX(-50%)', width: 150, height: 150, borderRadius: '50%', background: `radial-gradient(circle, ${goal.color}1f, transparent 70%)`, pointerEvents: 'none' }} />
            <span style={{ width: 64, height: 64, borderRadius: '50%', background: `linear-gradient(180deg,${goal.color},${shade(goal.color, -0.16)})`, color: '#fff', display: 'grid', placeItems: 'center', boxShadow: `0 7px 0 ${shade(goal.color, -0.28)}, 0 12px 20px ${goal.color}55, inset 0 3px 0 rgba(255,255,255,0.5)`, animation: 'hh-bob 2.6s ease-in-out infinite', position: 'relative' }}><GoalGlyph id={goal.id} size={34} color="#fff" /></span>
            <div className="disp" style={{ fontSize: 21, position: 'relative', lineHeight: 1.05 }}>{goal.label}</div>
            {/* premium objective bar — two solid stat chips (not flat pills) */}
            <div style={{ width: '100%', display: 'flex', gap: 9, position: 'relative' }}>
              {[{ ic: <I.target width={19} style={{ color: goal.color }} />, lab: 'TARGET', val: diff.target.toLocaleString(), f: 1.35 },
                { ic: <I.flag width={17} style={{ color: 'var(--mint)' }} />, lab: 'TIME', val: mm + ':' + ss, f: 1 }].map((c, i) => (
                <div key={i} style={{ flex: c.f, display: 'flex', alignItems: 'center', gap: 9, padding: '10px 13px', borderRadius: 15,
                  background: 'linear-gradient(180deg,#26354F,#141E34)',
                  boxShadow: '0 4px 0 rgba(5,12,26,0.55), 0 8px 14px rgba(0,0,0,0.26), inset 0 1px 0 rgba(255,255,255,0.14)' }}>
                  <span style={{ flexShrink: 0, display: 'grid', placeItems: 'center', filter: 'drop-shadow(0 1px 2px rgba(0,0,0,0.4))' }}>{c.ic}</span>
                  <div style={{ textAlign: 'left', lineHeight: 1 }}>
                    <div style={{ fontSize: 8.5, fontWeight: 800, letterSpacing: 1.2, color: 'rgba(255,255,255,0.55)' }}>{c.lab}</div>
                    <div className="num" style={{ fontSize: 18, fontWeight: 800, color: '#fff', marginTop: 2 }}>{c.val}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* reward + loadout row */}
          <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
            <div className="card" style={{ flex: 1, padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 8, background: '#fff' }}>
              <Coin size={24} />
              <div style={{ textAlign: 'left', lineHeight: 1.1 }}>
                <div className="eyebrow" style={{ fontSize: 8.5 }}>Reward</div>
                <div className="num" style={{ fontWeight: 800, fontSize: 16, color: 'var(--ink)' }}>+{reward}</div>
              </div>
            </div>
            <button onClick={() => go('powerups')} className="card" style={{ flex: 1, padding: '8px 12px', display: 'flex', alignItems: 'center', gap: 8, background: '#fff', cursor: 'pointer' }}>
              <div style={{ flex: 1, display: 'flex', gap: 5, justifyContent: 'center' }}>
                {(HH.equipped || ['magnet']).slice(0, 3).map(id => { const pu = HH.POWERUPS.find(p => p.id === id); return pu ? <span key={id} style={{ width: 30, height: 30, borderRadius: 9, background: pu.color, display: 'grid', placeItems: 'center', color: '#fff' }}><PowerIcon id={pu.icon} size={17} color="#fff" /></span> : null; })}
              </div>
              <span style={{ fontWeight: 800, fontSize: 11, color: 'var(--grape)', whiteSpace: 'nowrap' }}>Edit ›</span>
            </button>
          </div>

          {/* 3-star hint */}
          <div style={{ fontSize: 12, fontWeight: 800, color: 'var(--slate)', marginBottom: 16 }}>★★★ = hit the score target with time to spare</div>

          <button className="btn sun block shimmer" onClick={() => startLevel(level)} style={{ fontSize: 21, padding: '16px' }}>
            <I.play width={20} height={20} />  PLAY</button>
        </div>
      </div>
    </div>
  );
}

// ---------- 4b · Isometric "city island" hero (original CSS/SVG art) ----------
// A floating low-poly diamond island with candy buildings, trees, a road, a pond,
// drifting clouds, a little helicopter doing a circuit, a roaming delivery car, and a
// hungry hole — all bobbing gently. Themed to the active world's palette.
function CityIslandHero({ W, accent }) {
  const ground = W.ground || '#7FD06A';
  const groundDark = W.groundDark || '#5FB94E';
  const palette = [
    { top: '#FF6B6B', body: '#E8557A' },
    { top: '#7C5CFC', body: '#5B43C2' },
    { top: '#2D6CDF', body: '#2455B0' },
    { top: '#FFC23D', body: '#E2A020' },
    { top: '#22C9A0', body: '#159C7C' },
  ];
  const buildings = [
    { x: 26, y: 34, w: 44, h: 72, ...palette[0] },
    { x: 78, y: 20, w: 38, h: 100, ...palette[1] },
    { x: 122, y: 38, w: 48, h: 66, ...palette[2] },
    { x: 178, y: 26, w: 34, h: 86, ...palette[3] },
    { x: 218, y: 46, w: 30, h: 56, ...palette[4] },
  ];
  return (
    <div style={{ position: 'relative', width: 280, height: 264, margin: '0 auto' }}>
      {/* drifting helicopter doing a wide circuit, blades spinning */}
      <div style={{ position: 'absolute', left: '50%', top: '50%', width: 0, height: 0, animation: 'hh-spin 14s linear infinite', zIndex: 8 }}>
        <div style={{ position: 'absolute', left: 120, top: -96, animation: 'hh-bob 2.4s ease-in-out infinite' }}>
          <svg width="48" height="34" viewBox="0 0 48 34">
            <g style={{ transformOrigin: '3px 6px', animation: 'hh-spin 0.5s linear infinite' }}>
              <ellipse cx="2" cy="6" rx="22" ry="3" fill="rgba(120,140,170,0.55)" />
            </g>
            <path d="M3 6v6" stroke="#5A6B86" strokeWidth="2" strokeLinecap="round" />
            <path d="M2 12h18a8 7 0 018 7v3a4 4 0 01-4 4H10a8 8 0 01-8-8z" fill={accent || '#2D6CDF'} />
            <path d="M28 19h12l4 4-4 2h-12z" fill={shade(accent || '#2D6CDF', -0.18)} />
            <circle cx="11" cy="19" r="3.4" fill="#DCEFFE" />
            <path d="M6 26h16" stroke="#3A4A66" strokeWidth="2.4" strokeLinecap="round" />
            <path d="M7 26v3M21 26v3" stroke="#3A4A66" strokeWidth="2" strokeLinecap="round" />
          </svg>
        </div>
      </div>

      {/* the island bobs as one piece */}
      <div style={{ position: 'absolute', inset: 0, animation: 'hh-bob 4.5s ease-in-out infinite' }}>
        <svg width="280" height="264" viewBox="0 0 280 264" style={{ overflow: 'visible' }}>
          <defs>
            <linearGradient id="hh-isle-top" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stopColor={shade(ground, 0.12)} />
              <stop offset="1" stopColor={ground} />
            </linearGradient>
            <linearGradient id="hh-isle-dirt" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stopColor={shade(groundDark, -0.05)} />
              <stop offset="1" stopColor={shade(groundDark, -0.4)} />
            </linearGradient>
          </defs>
          {/* soft cast shadow under the island */}
          <ellipse cx="140" cy="236" rx="98" ry="20" fill="rgba(16,34,58,0.18)" />
          {/* dirt underside of the floating diamond */}
          <path d="M30 150 L140 210 L250 150 L140 248 Z" fill="url(#hh-isle-dirt)" />
          <path d="M30 150 L140 210 L140 248 Z" fill={shade(groundDark, -0.5)} opacity="0.5" />
          {/* a couple of dangling roots / rocks under the isle for charm */}
          <path d="M96 200 q-3 14 1 22 q4 -8 3 -22 Z" fill={shade(groundDark, -0.45)} opacity="0.8" />
          <path d="M178 196 q4 12 -1 20 q-5 -7 -2 -20 Z" fill={shade(groundDark, -0.45)} opacity="0.8" />
          {/* grassy top diamond */}
          <path d="M30 150 L140 90 L250 150 L140 210 Z" fill="url(#hh-isle-top)" />
          {/* grass rim highlight */}
          <path d="M30 150 L140 90 L250 150" fill="none" stroke="rgba(255,255,255,0.4)" strokeWidth="2" />
          {/* a curved road across the isometric top */}
          <path d="M64 162 Q140 128 214 158" fill="none" stroke="rgba(120,116,135,0.85)" strokeWidth="13" strokeLinecap="round" />
          <path d="M64 162 Q140 128 214 158" fill="none" stroke="rgba(244,246,250,0.9)" strokeWidth="1.6" strokeDasharray="2 7" strokeLinecap="round" />
          {/* a little park pond with a glint */}
          <ellipse cx="92" cy="174" rx="16" ry="7.5" fill="#5BC7FF" opacity="0.92" />
          <ellipse cx="92" cy="172" rx="16" ry="7.5" fill="none" stroke="rgba(255,255,255,0.5)" strokeWidth="1" />
          <ellipse cx="86" cy="171" rx="4" ry="1.6" fill="rgba(255,255,255,0.7)" />
          {/* a tiny boat in the pond, gently bobbing */}
          <g style={{ animation: 'hh-bob 3.6s ease-in-out infinite', transformOrigin: '98px 173px' }}>
            <path d="M94 175 h10 l-2 3 h-6 z" fill="#E8557A" />
            <path d="M99 175 v-6 l5 4 z" fill="#fff" />
          </g>
        </svg>

        {/* candy buildings (HTML, positioned on the iso top) */}
        {buildings.map((b, i) => (
          <div key={i} style={{ position: 'absolute', left: b.x, top: b.y, width: b.w, transformOrigin: 'bottom' }}>
            {/* roof */}
            <div style={{ height: 10, borderRadius: '6px 6px 0 0', background: b.top, boxShadow: 'inset 0 2px 0 rgba(255,255,255,0.4)' }} />
            {/* body with window grid */}
            <div style={{ height: b.h, background: `linear-gradient(180deg, ${b.body}, ${shade(b.body, -0.18)})`, borderRadius: '0 0 6px 6px',
              boxShadow: '0 8px 14px rgba(16,34,58,0.28), inset -6px 0 0 rgba(0,0,0,0.12)', position: 'relative', overflow: 'hidden' }}>
              <div style={{ position: 'absolute', inset: '8px 7px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 5, alignContent: 'start' }}>
                {Array.from({ length: Math.min(8, Math.floor(b.h / 14) * 2) }).map((_, k) => (
                  <span key={k} style={{ height: 7, borderRadius: 2, background: (i + k) % 3 === 0 ? '#FFE7A0' : 'rgba(255,255,255,0.78)', opacity: 0.9 }} />
                ))}
              </div>
            </div>
          </div>
        ))}

        {/* two chunky trees on the island */}
        <div style={{ position: 'absolute', left: 234, top: 120 }}>
          <div style={{ width: 30, height: 30, borderRadius: '50%', background: `radial-gradient(circle at 34% 30%, ${shade(ground, 0.2)}, ${shade(ground, -0.12)})`, boxShadow: '0 4px 8px rgba(16,34,58,0.22)' }} />
          <div style={{ width: 7, height: 14, margin: '0 auto', background: '#6B4A2F', borderRadius: '0 0 3px 3px' }} />
        </div>
        <div style={{ position: 'absolute', left: 50, top: 148 }}>
          <div style={{ width: 22, height: 22, borderRadius: '50%', background: `radial-gradient(circle at 34% 30%, ${shade(ground, 0.18)}, ${shade(ground, -0.14)})`, boxShadow: '0 3px 6px rgba(16,34,58,0.2)' }} />
          <div style={{ width: 6, height: 10, margin: '0 auto', background: '#6B4A2F', borderRadius: '0 0 3px 3px' }} />
        </div>

        {/* a little delivery car rolling along the road */}
        <div style={{ position: 'absolute', left: 70, top: 154, animation: 'hh-drag-demo 5s ease-in-out infinite' }}>
          <svg width="34" height="20" viewBox="0 0 34 20">
            <path d="M2 13 q1 -6 8 -6 h10 q5 0 7 5 h4 a2 2 0 012 2 v2 h-31 z" fill="#FF8FB0" />
            <path d="M11 8 h7 v4 h-9 q0 -3 2 -4z" fill="#DCEFFE" />
            <circle cx="9" cy="17" r="3" fill="#2A2A33" /><circle cx="25" cy="17" r="3" fill="#2A2A33" />
            <circle cx="9" cy="17" r="1.2" fill="#9AA3AD" /><circle cx="25" cy="17" r="1.2" fill="#9AA3AD" />
          </svg>
        </div>

        {/* the hungry hole sitting on the road, with a name tag */}
        <div style={{ position: 'absolute', left: 116, top: 152, animation: 'hh-bob 3s ease-in-out infinite' }}>
          <HoleVisual r={26} skin="classic" />
        </div>
      </div>
    </div>
  );
}

function ArcadeCityBackdrop() {
  const b = [
    { l: -26, t: 130, w: 88, h: 250, c: '#1E78A9' },
    { l: 328, t: 138, w: 92, h: 238, c: '#9A5B50' },
    { l: 48, t: 178, w: 70, h: 156, c: '#2B84B8' },
    { l: 280, t: 188, w: 70, h: 152, c: '#466B8F' },
  ];
  return <div aria-hidden style={{ position: 'absolute', inset: 0, overflow: 'hidden', background: 'linear-gradient(180deg,#0B3B66 0%,#1C6EA7 28%,#7FC5E9 50%,#334761 100%)' }}>
    <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(120% 70% at 50% 28%,rgba(255,255,255,0.16),transparent 58%), linear-gradient(180deg,rgba(1,14,30,0.52),transparent 36%,rgba(0,0,0,0.25) 100%)' }} />
    {b.map((x, i) => <div key={i} style={{ position: 'absolute', left: x.l, top: x.t, width: x.w, height: x.h, borderRadius: 10, transform: i % 2 ? 'skewY(-6deg)' : 'skewY(6deg)', transformOrigin: 'bottom',
      background: `linear-gradient(180deg,${shade(x.c, 0.18)},${shade(x.c, -0.25)})`, boxShadow: '0 18px 34px rgba(0,0,0,0.28), inset 8px 0 0 rgba(255,255,255,0.08), inset -8px 0 0 rgba(0,0,0,0.12)' }}>
      <div style={{ position: 'absolute', inset: '18px 12px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 7, alignContent: 'start' }}>
        {Array.from({ length: 16 }).map((_, k) => <span key={k} style={{ height: 12, borderRadius: 2, background: k % 4 === 0 ? '#FFE08A' : 'rgba(210,238,255,0.65)' }} />)}
      </div>
    </div>)}
    <div style={{ position: 'absolute', left: -50, right: -50, top: 382, height: 360, transform: 'perspective(360px) rotateX(55deg)', transformOrigin: 'top',
      background: 'linear-gradient(90deg,#667489 0 9%,#ECE8D8 9% 38%,#76839A 38% 47%,#ECE8D8 47% 80%,#667489 80% 100%)',
      boxShadow: 'inset 0 24px 0 rgba(255,255,255,0.22), inset 0 -40px 80px rgba(0,0,0,0.28)' }}>
      <div style={{ position: 'absolute', inset: 0, opacity: 0.38, backgroundImage: 'linear-gradient(#A7B0B8 1px,transparent 1px),linear-gradient(90deg,#A7B0B8 1px,transparent 1px)', backgroundSize: '34px 34px' }} />
      <div style={{ position: 'absolute', left: 0, right: 0, top: 118, height: 58, background: '#596273' }}>
        {Array.from({ length: 8 }).map((_, i) => <span key={i} style={{ position: 'absolute', left: `${i * 14 + 2}%`, top: 25, width: 46, height: 6, borderRadius: 4, background: '#EEF3F7' }} />)}
      </div>
    </div>
    <div style={{ position: 'absolute', inset: 0, backdropFilter: 'blur(1.2px)', WebkitBackdropFilter: 'blur(1.2px)' }} />
  </div>;
}

function ArcadeLogo() {
  return <div aria-label="Hungry Hole 3D" style={{ position: 'absolute', top: 112, left: 0, right: 0, zIndex: 34, textAlign: 'center', pointerEvents: 'none', transform: 'rotate(-3deg)' }}>
    <div className="disp" style={{ fontSize: 54, lineHeight: 0.84, color: '#fff', letterSpacing: 0,
      WebkitTextStroke: '2.5px #07305F', paintOrder: 'stroke fill',
      textShadow: '0 5px 0 #0B376A, 0 10px 0 #051A33, 0 16px 24px rgba(0,0,0,0.46)' }}>HUNGRY</div>
    <div className="disp" style={{ marginTop: 0, fontSize: 74, lineHeight: 0.82, color: '#FFC816', letterSpacing: 0,
      WebkitTextStroke: '2.8px #07305F', paintOrder: 'stroke fill',
      textShadow: '0 7px 0 #C35A05, 0 13px 0 #061D38, 0 18px 28px rgba(0,0,0,0.5)' }}>
      H<span style={{ color: '#FFD845' }}>O</span>LE</div>
    <div className="disp" style={{ display: 'inline-block', marginLeft: 154, marginTop: -8, fontSize: 46, lineHeight: 0.86, color: '#21BFFF',
      WebkitTextStroke: '2.2px #07305F', paintOrder: 'stroke fill',
      textShadow: '0 5px 0 #07639C, 0 9px 0 #061D38, 0 13px 20px rgba(0,0,0,0.5)' }}>3D</div>
  </div>;
}

function ArcadeHoleScene() {
  return <div aria-hidden style={{ position: 'absolute', left: 0, right: 0, top: 282, height: 260, zIndex: 26, pointerEvents: 'none' }}>
    <div style={{ position: 'absolute', left: '50%', top: 132, width: 236, height: 144, transform: 'translate(-50%,-50%) rotateX(58deg)', borderRadius: '50%',
      background: 'radial-gradient(circle at 50% 48%,#000 0 46%,#07111F 47% 54%,#12B9FF 56%,#2878FF 62%,rgba(33,210,255,0.18) 72%,transparent 75%)',
      boxShadow: '0 0 20px #33D8FF, 0 0 48px rgba(38,133,255,0.9), inset 0 0 28px #000', animation: 'hh-glowpulse 2.2s ease-in-out infinite' }} />
    <div style={{ position: 'absolute', left: 86, top: 120, width: 50, height: 30, borderRadius: 8, background: 'linear-gradient(180deg,#FFE04A,#DBA000)', transform: 'rotate(-22deg)', boxShadow: '0 7px 10px rgba(0,0,0,0.32), inset 0 2px 0 rgba(255,255,255,0.55)' }} />
    <div style={{ position: 'absolute', right: 90, top: 106, width: 16, height: 96, borderRadius: 8, background: 'linear-gradient(90deg,#8899A8,#E6EEF5,#5D6A78)', transform: 'rotate(42deg)', boxShadow: '0 8px 14px rgba(0,0,0,0.38)' }} />
    <div style={{ position: 'absolute', right: 82, top: 170, width: 42, height: 34, borderRadius: 5, background: 'linear-gradient(180deg,#DCE7EF,#7B8B9B)', transform: 'rotate(-10deg)', boxShadow: '0 8px 12px rgba(0,0,0,0.28), inset 0 2px 0 #fff' }} />
    <div style={{ position: 'absolute', left: 132, top: 184, width: 24, height: 24, borderRadius: 4, background: 'linear-gradient(180deg,#FF7A2D,#D34212)', transform: 'rotate(24deg)', clipPath: 'polygon(50% 0,100% 100%,0 100%)', boxShadow: '0 6px 10px rgba(0,0,0,0.22)' }} />
    <div style={{ position: 'absolute', left: 42, top: 188, width: 62, height: 62, borderRadius: '50%', border: '7px solid #8FE3FF', background: 'radial-gradient(circle,#2B99D6 0 45%,#0F5E9B 46% 100%)', boxShadow: '0 8px 15px rgba(0,0,0,0.25), inset 0 0 0 5px rgba(255,255,255,0.45)' }} />
  </div>;
}

// ---------- 5 · Home / main hub ----------
// Rich hub: top resource bar, an isometric city-island hero (animated), the current
// world's level chips with the active one highlighted, a big green PLAY → current
// level, quick-access tiles, and the persistent BottomNav.
function Home({ go, openLevel, world, setWorld, wallet, nextLevel }) {
  const HH = window.HH;
  const nextN = nextPlayable();
  const curWorld = Math.floor((nextN - 1) / 10);
  const W = HH.WORLDS[curWorld] || HH.WORLDS[0];
  const levels = HH.LEVELS[curWorld] || HH.LEVELS[0];
  const stars = HH.STARS;
  const totalStars = Object.values(stars).reduce((a, b) => a + b, 0);
  const nlv = HH.LEVELS.flat().find(l => l[0] === nextN);
  const dark = window.__hhTheme === 'dark';
  const night = !!W.night || dark;
  const accent = W.accent || 'var(--sky)';

  return (
    <div style={{ position: 'absolute', inset: 0, overflow: 'hidden', background: '#071B34' }}>
      <StatusBar dark={!night} />
      <img src="assets/ui-ai/home-bg.webp" alt="" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 0 }} />
      <div style={{ position: 'absolute', inset: 0, zIndex: 1, pointerEvents: 'none',
        background: 'linear-gradient(180deg,rgba(2,12,28,0.28) 0%,rgba(2,12,28,0.03) 28%,rgba(2,12,28,0.02) 58%,rgba(2,8,20,0.50) 100%)' }} />

      {/* top resource bar (avatar + coin + gem + gear) */}
      <HHTopBar go={go} wallet={wallet} dark={!night} />
      <img src="assets/ui-ai/logo-hungry-hole-3d.webp" alt="Hungry Hole 3D" style={{ position: 'absolute', top: 90, left: '50%', width: 'min(86vw, 350px)', height: 'auto', transform: 'translateX(-50%) rotate(-2deg)', zIndex: 34, pointerEvents: 'none',
        filter: 'drop-shadow(0 10px 0 rgba(3,18,38,0.58)) drop-shadow(0 18px 24px rgba(0,0,0,0.32))' }} />

      {/* ===== bottom command deck ===== */}
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 30,
        padding: '16px 24px calc(196px + env(safe-area-inset-bottom, 0px))' }}>
        {nlv && <button onClick={() => openLevel(nextN)} className="btn block shimmer hh-ai-play" style={{ marginBottom: 40, letterSpacing: 0 }}>
          <GameIcon id="play" size={34} tone="mint" /> PLAY</button>}

        {/* compact action tiles */}
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 14 }}>
          <HomeNav tone="grape" iconId="power" label="Power" onClick={() => go('powerups')} />
          <HomeNav tone="sun" iconId="daily" label="Daily" onClick={() => go('daily')} badge />
          <HomeNav tone="sky" iconId="missions" label="Missions" onClick={() => go('missions')} />
          <HomeNav tone="coral" iconId="rank" label="Rank" onClick={() => go('leaderboard')} />
        </div>
      </div>

      {/* persistent bottom nav */}
      <BottomNav active="home" go={go} />
    </div>
  );
}

// Cartoon candy quick-access tile: white extruded card + a glossy colored icon disc.
// `tone` selects the disc palette (grape / sun / mint / coral).
function HomeNav({ icon, iconId, label, onClick, badge, tone }) {
  const tones = {
    grape: ['#9C82FF', '#6A48E8'],
    sky: ['#35A8FF', '#116FD8'],
    sun: ['#FFD061', '#EBA014'],
    mint: ['#46E6BF', '#13A883'],
    coral: ['#FF8B8B', '#ED4F52'],
  };
  const [c1, c2] = tones[tone] || tones.grape;
  return <button onClick={onClick} aria-label={label} className={'hh-ai-tile ' + (tone === 'grape' || tone === 'coral' ? 'purple' : 'blue')} style={{ borderRadius: 20, padding: '8px 4px', minHeight: 88, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', position: 'relative',
    border: '2px solid rgba(202,232,255,0.82)',
    background: tone === 'coral' ? 'linear-gradient(180deg,#9B4BFF,#5E1AB4)' : `linear-gradient(180deg,${c1},${c2} 58%,#06305F)`,
    color: '#fff',
    boxShadow: '0 7px 0 #041B36, 0 14px 24px rgba(0,0,0,0.36), inset 0 3px 0 rgba(255,255,255,0.42), inset 0 -5px 8px rgba(0,0,0,0.28)' }}>
    {badge && <span style={{ position: 'absolute', top: 7, right: 9, width: 10, height: 10, borderRadius: 10, background: '#FF4E5F', border: '2px solid #fff', boxShadow: '0 2px 6px rgba(255,78,95,0.45)' }} />}
    {iconId ? <GameIcon id={iconId} size={44} tone={tone === 'sky' ? 'sky' : tone} /> : <span style={{ width: 44, height: 44, borderRadius: 14, display: 'grid', placeItems: 'center', color: '#fff',
      background: `linear-gradient(180deg,${c1},${c2})`,
      boxShadow: `0 4px 0 ${shade(c2, -0.24)}, 0 8px 14px ${c2}66, inset 0 2px 0 rgba(255,255,255,0.5)` }}>{icon}</span>}
  </button>;
}

// ---------- Dynamic new-user Walkthrough (animated, illustrated with AI art) ----------
// A 4-step overlay that teaches the loop with live CSS-animated AI images:
// drag the hole · swallow props · grow huge · beat the score goal.
function Walkthrough({ onDone }) {
  const [i, setI] = useStateCo(0);
  const A = 'assets/ui-ai/';
  const steps = [
    { key: 'drag', title: 'Drag to move',      desc: 'Slide your finger anywhere to steer the hole around the city.', accent: '#35A8FF' },
    { key: 'eat',  title: 'Swallow everything', desc: 'Roll over cars, benches and people — gulp them straight down.', accent: '#22C9A0' },
    { key: 'grow', title: 'Grow bigger',        desc: 'The more you eat, the bigger you grow — soon whole buildings fit!', accent: '#9B6BFF' },
    { key: 'goal', title: 'Reach the goal',     desc: 'Hit the score target before the timer runs out to clear the level.', accent: '#F4A906' },
  ];
  const s = steps[i];
  const last = i === steps.length - 1;
  const done = () => { try { localStorage.setItem('hh_tut_done', '1'); } catch (e) {} onDone && onDone(); };
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 200, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 22,
      background: 'linear-gradient(180deg,rgba(8,18,38,0.62),rgba(8,18,38,0.80))', backdropFilter: 'blur(3px)', WebkitBackdropFilter: 'blur(3px)' }}>
      <div className="panel pop" key={s.key} style={{ width: '100%', maxWidth: 342, padding: '18px 18px 20px', textAlign: 'center', position: 'relative' }}>
        <button onClick={done} style={{ position: 'absolute', top: 13, right: 15, border: 0, background: 'none', cursor: 'pointer', fontWeight: 800, fontSize: 13, color: 'var(--slate)', zIndex: 3 }}>Skip</button>
        <div className="eyebrow" style={{ color: s.accent, marginBottom: 10 }}>How to play · {i + 1}/4</div>

        {/* animated stage — sky over road, the hole, and per-step AI props in motion */}
        <div style={{ position: 'relative', width: '100%', height: 248, borderRadius: 22, overflow: 'hidden',
          background: 'linear-gradient(180deg,#8FCAFF 0%,#BFE6FF 44%,#9FD98A 44%,#7CC06A 100%)',
          boxShadow: 'inset 0 2px 0 rgba(255,255,255,0.55), inset 0 -12px 26px rgba(0,0,0,0.18)' }}>
          <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, height: '54%', background: 'linear-gradient(180deg,#8A93A6,#6E7689)' }} />
          <div style={{ position: 'absolute', left: '50%', bottom: 0, top: '50%', width: 8, transform: 'translateX(-50%)', background: 'repeating-linear-gradient(180deg,#fff 0 15px,transparent 15px 31px)', opacity: 0.85 }} />
          {/* the hole */}
          <img src={A + 'wt-hole.png'} alt="" style={{ position: 'absolute', left: '50%', bottom: s.key === 'grow' ? 14 : 26, width: s.key === 'grow' ? 152 : 122,
            transform: 'translateX(-50%)', transformOrigin: '50% 62%', filter: 'drop-shadow(0 8px 10px rgba(0,0,0,0.34))',
            animation: s.key === 'grow' ? 'hh-wt-grow 2.4s ease-in-out infinite' : 'hh-bob 2.8s ease-in-out infinite' }} />
          {s.key === 'drag' && <>
            <span style={{ position: 'absolute', left: '50%', bottom: 60, width: 66, height: 66, borderRadius: '50%', transform: 'translateX(-50%)', border: '3px solid rgba(255,255,255,0.85)', animation: 'hh-wt-trail 1.6s ease-out infinite' }} />
            <img src={A + 'wt-finger.png'} alt="" style={{ position: 'absolute', left: '50%', bottom: 34, width: 66, transformOrigin: '50% 0%', filter: 'drop-shadow(0 6px 8px rgba(0,0,0,0.3))', animation: 'hh-wt-drag 3s ease-in-out infinite' }} />
          </>}
          {s.key === 'eat' && [0, 1].map(n => (
            <img key={n} src={A + 'wt-car.png'} alt="" style={{ position: 'absolute', left: '50%', bottom: 26, width: 60, transform: 'translateX(-50%)',
              '--fx': n ? '-32px' : '28px', animation: `hh-wt-suck 1.9s ${n * 0.95}s ease-in infinite` }} />
          ))}
          {s.key === 'grow' && <img src={A + 'wt-building.png'} alt="" style={{ position: 'absolute', left: '50%', bottom: 22, width: 82, transform: 'translateX(-50%)', '--fx': '8px', animation: 'hh-wt-suck 2.4s ease-in infinite' }} />}
          {s.key === 'goal' && <>
            <img src={A + 'wt-burst.png'} alt="" style={{ position: 'absolute', left: '50%', top: 14, width: 108, transform: 'translateX(-50%)', filter: 'drop-shadow(0 8px 10px rgba(0,0,0,0.3))', animation: 'hh-bob 2.2s ease-in-out infinite' }} />
            {[...Array(7)].map((_, n) => <span key={n} style={{ position: 'absolute', left: `${20 + n * 9}%`, top: 6, width: 9, height: 9, borderRadius: 2, background: ['#FF5A5A', '#FFC21F', '#35A8FF', '#22C9A0', '#9B6BFF'][n % 5], animation: `hh-wt-confetti ${1.6 + (n % 3) * 0.4}s ${n * 0.2}s linear infinite` }} />)}
            <div style={{ position: 'absolute', left: 24, right: 24, bottom: 24, height: 16, borderRadius: 100, background: 'rgba(8,20,40,0.5)', overflow: 'hidden', boxShadow: 'inset 0 1px 3px rgba(0,0,0,0.4)' }}>
              <div style={{ height: '100%', borderRadius: 100, background: 'linear-gradient(90deg,#7CFC4A,#FFC21F)', animation: 'hh-wt-fill 2.6s ease-out infinite' }} />
            </div>
          </>}
        </div>

        <h2 className="disp" style={{ fontSize: 24, margin: '16px 0 6px', lineHeight: 1.05 }}>{s.title}</h2>
        <p style={{ fontWeight: 700, fontSize: 13.5, color: 'var(--slate)', margin: '0 auto 15px', maxWidth: 282, lineHeight: 1.36 }}>{s.desc}</p>
        <div style={{ display: 'flex', justifyContent: 'center', gap: 7, marginBottom: 15 }}>
          {steps.map((_, n) => <span key={n} style={{ width: n === i ? 22 : 8, height: 8, borderRadius: 100, background: n === i ? s.accent : 'rgba(120,140,170,0.4)', transition: 'all .25s' }} />)}
        </div>
        <button className={'btn block shimmer ' + (last ? 'mint' : 'sun')} onClick={() => last ? done() : setI(i + 1)} style={{ fontSize: 18 }}>
          {last ? <><I.play width={18} /> Let’s Play</> : 'Next ›'}</button>
      </div>
    </div>
  );
}

Object.assign(window, { Loading, Splash, Onboarding, WorldMap, LevelIntro, Home, Walkthrough });
