// peper-climber.jsx, Doodle-Jump-variant. Peper springt automatisch op
// platforms; sommige bewegen, sommige breken. Verzamel power-pepers voor
// een jetpack-boost. Ontwijk wasknijpers. Onbegrensde hoogte, score = m.

function PeperClimber({ onClose }) {
  const FIELD_W = 480;
  const FIELD_H = 720;
  const PLAYER_W = 64;
  const PLAYER_H = 76;
  const GRAVITY = 1300;
  const JUMP_VEL = -780;
  const JETPACK_VEL = -1500;
  const MOVE_SPEED = 360;
  const PLATFORM_W = 92;
  const PLATFORM_H = 18;
  const SPAWN_GAP = 92; // verticale afstand tussen platforms

  const STORAGE_KEY = "peper-climber-best";

  const [phase, setPhase] = React.useState("intro");
  const [score, setScore] = React.useState(0);
  const [best, setBest] = React.useState(() => {
    try { return parseInt(localStorage.getItem(STORAGE_KEY) || "0", 10) || 0; } catch { return 0; }
  });
  const [scale, setScale] = React.useState(1);
  const [narrow, setNarrow] = React.useState(typeof window !== "undefined" && window.innerWidth <= 600);
  const [, forceRender] = React.useReducer(x => x + 1, 0);

  const wrapRef = React.useRef(null);
  const playerRef = React.useRef({ x: FIELD_W / 2 - PLAYER_W / 2, y: FIELD_H - 200, vx: 0, vy: 0, jetpack: 0, face: 1 });
  const platformsRef = React.useRef([]);     // {x,y,kind,w,vx?,broken?}
  const enemiesRef = React.useRef([]);       // wasknijpers
  const powerupsRef = React.useRef([]);      // jetpack-pepers
  const particlesRef = React.useRef([]);
  const cloudsRef = React.useRef([]);
  const starsRef = React.useRef([]);
  const auroraRef = React.useRef([]);
  const animTimeRef = React.useRef(0);
  const cameraYRef = React.useRef(0);        // hoogste y die als 0 telt
  const heightRef = React.useRef(0);         // gestegen pixels
  const inputRef = React.useRef({ left: 0, right: 0, tilt: 0 });
  const lastFrameRef = React.useRef(0);
  const idRef = React.useRef(0);

  // schaling
  React.useEffect(() => {
    function measure() {
      setNarrow(window.innerWidth <= 600);
      if (!wrapRef.current) return;
      const r = wrapRef.current.getBoundingClientRect();
      if (r.width > 0 && r.height > 0) {
        setScale(Math.max(0.3, Math.min(r.width / FIELD_W, r.height / FIELD_H)));
      }
    }
    measure();
    let ro;
    if (typeof ResizeObserver !== "undefined" && wrapRef.current) {
      ro = new ResizeObserver(measure);
      ro.observe(wrapRef.current);
    }
    window.addEventListener("resize", measure);
    window.addEventListener("orientationchange", measure);
    return () => {
      if (ro) ro.disconnect();
      window.removeEventListener("resize", measure);
      window.removeEventListener("orientationchange", measure);
    };
  }, []);

  // body-scroll lock
  React.useEffect(() => {
    const prev = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => { document.body.style.overflow = prev; };
  }, []);

  // toetsen
  React.useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape") { onClose && onClose(); return; }
      if (e.key === "ArrowLeft" || e.key === "a" || e.key === "A") { inputRef.current.left = 1; }
      if (e.key === "ArrowRight" || e.key === "d" || e.key === "D") { inputRef.current.right = 1; }
      if (e.key === " " || e.key === "Enter") {
        if (phase === "intro") start();
        else if (phase === "dead") restart();
      }
    }
    function onUp(e) {
      if (e.key === "ArrowLeft" || e.key === "a" || e.key === "A") { inputRef.current.left = 0; }
      if (e.key === "ArrowRight" || e.key === "d" || e.key === "D") { inputRef.current.right = 0; }
    }
    window.addEventListener("keydown", onKey);
    window.addEventListener("keyup", onUp);
    return () => {
      window.removeEventListener("keydown", onKey);
      window.removeEventListener("keyup", onUp);
    };
  }, [phase]);

  React.useEffect(() => {
    cloudsRef.current = Array.from({ length: 5 }, () => ({
      id: ++idRef.current,
      x: Math.random() * FIELD_W,
      y: Math.random() * FIELD_H * 2,
      s: 0.7 + Math.random() * 0.5,
      vx: 6 + Math.random() * 8,
    }));
    starsRef.current = Array.from({ length: 28 }, () => ({
      id: ++idRef.current,
      x: Math.random() * FIELD_W,
      y: Math.random() * FIELD_H,
      r: 0.7 + Math.random() * 1.6,
      ph: Math.random() * Math.PI * 2,
      tw: 1.5 + Math.random() * 2,
    }));
    auroraRef.current = Array.from({ length: 3 }, (_, i) => ({
      id: ++idRef.current,
      y: 60 + i * 90,
      ph: i * 1.2,
    }));
  }, []);

  function spawnInitial() {
    platformsRef.current = [];
    enemiesRef.current = [];
    powerupsRef.current = [];
    particlesRef.current = [];
    // grond-platform vlak onder speler
    platformsRef.current.push({
      id: ++idRef.current,
      x: FIELD_W / 2 - PLATFORM_W / 2,
      y: FIELD_H - 90,
      w: PLATFORM_W * 1.6,
      kind: "static",
    });
    // initiële stack
    for (let i = 1; i < 12; i++) {
      addPlatformAt(FIELD_H - 90 - i * SPAWN_GAP, i);
    }
  }

  function pickKind(level) {
    // moeilijker met hoogte: meer bewegende, meer breekbare
    const r = Math.random();
    if (level < 4) return "static";
    if (r < 0.55) return "static";
    if (r < 0.78) return "moving";
    if (r < 0.92) return "breakable";
    return "static";
  }

  function addPlatformAt(y, level) {
    const kind = pickKind(level);
    const w = PLATFORM_W;
    const x = 20 + Math.random() * (FIELD_W - w - 40);
    const vx = kind === "moving" ? (Math.random() < 0.5 ? -1 : 1) * (60 + Math.random() * 70) : 0;
    platformsRef.current.push({ id: ++idRef.current, x, y, w, kind, vx, broken: false });

    // soms een wasknijper-vijand op level >= 8
    if (level >= 8 && Math.random() < 0.10) {
      enemiesRef.current.push({
        id: ++idRef.current,
        x: 30 + Math.random() * (FIELD_W - 90),
        y: y - 38,
        w: 50, h: 38,
        vx: (Math.random() < 0.5 ? -1 : 1) * (40 + Math.random() * 30),
      });
    }

    // soms een jetpack-peper op level >= 5
    if (level >= 5 && Math.random() < 0.06) {
      powerupsRef.current.push({
        id: ++idRef.current,
        x: x + w / 2 - 18,
        y: y - 44,
        w: 36, h: 36,
      });
    }
  }

  function reset() {
    playerRef.current = { x: FIELD_W / 2 - PLAYER_W / 2, y: FIELD_H - 200, vx: 0, vy: -200, jetpack: 0, face: 1 };
    cameraYRef.current = 0;
    heightRef.current = 0;
    inputRef.current = { left: 0, right: 0, tilt: 0 };
    spawnInitial();
    setScore(0);
  }

  function start() { reset(); setPhase("playing"); }
  function restart() { reset(); setPhase("playing"); }

  function jump(vel = JUMP_VEL) {
    playerRef.current.vy = vel;
    // puff
    for (let i = 0; i < 5; i++) {
      const ang = -Math.PI / 2 + (Math.random() - 0.5) * 1.2;
      const v = 60 + Math.random() * 60;
      particlesRef.current.push({
        id: ++idRef.current,
        x: playerRef.current.x + PLAYER_W / 2,
        y: playerRef.current.y + PLAYER_H,
        vx: Math.cos(ang) * v,
        vy: Math.sin(ang) * v + 60,
        life: 0.4, r: 3 + Math.random() * 2,
        c: ["#FFD23F", "#FF8C1A"][Math.floor(Math.random() * 2)],
      });
    }
  }

  // game loop
  React.useEffect(() => {
    if (phase !== "playing") return;
    let raf = 0;
    lastFrameRef.current = performance.now();

    function frame(ts) {
      const dt = Math.min(0.04, (ts - lastFrameRef.current) / 1000);
      lastFrameRef.current = ts;
      const p = playerRef.current;

      // input
      const ax = (inputRef.current.right - inputRef.current.left) + inputRef.current.tilt;
      if (ax !== 0) p.face = ax > 0 ? 1 : -1;
      p.vx = ax * MOVE_SPEED;
      p.x += p.vx * dt;
      // wrap horizontaal
      if (p.x + PLAYER_W < 0) p.x = FIELD_W;
      if (p.x > FIELD_W) p.x = -PLAYER_W;

      // gravity / jetpack
      if (p.jetpack > 0) {
        p.jetpack -= dt;
        p.vy = JETPACK_VEL;
      } else {
        p.vy = Math.min(900, p.vy + GRAVITY * dt);
      }
      const prevY = p.y;
      p.y += p.vy * dt;

      // camera schuift wanneer speler boven helft komt
      const middle = FIELD_H * 0.42;
      if (p.y < middle) {
        const shift = middle - p.y;
        p.y = middle;
        cameraYRef.current += shift;
        heightRef.current += shift;
        // platforms en items mee verschuiven? Nee: we tekenen via cameraYRef.
        // Vervang: ze blijven in wereld-coords; we tekenen y - cameraY.
        // Maar onze data heeft absolute y vast, simpeler: we verschuiven alle items.
        for (const pl of platformsRef.current) pl.y += shift;
        for (const en of enemiesRef.current) en.y += shift;
        for (const pu of powerupsRef.current) pu.y += shift;
        for (const cl of cloudsRef.current) cl.y += shift * 0.4;
        for (const pa of particlesRef.current) pa.y += shift;
      }

      // platforms beweging
      for (const pl of platformsRef.current) {
        if (pl.kind === "moving" && pl.vx) {
          pl.x += pl.vx * dt;
          if (pl.x < 10) { pl.x = 10; pl.vx = -pl.vx; }
          if (pl.x + pl.w > FIELD_W - 10) { pl.x = FIELD_W - 10 - pl.w; pl.vx = -pl.vx; }
        }
      }

      // collision met platforms (alleen bij vallen)
      if (p.vy > 0 && p.jetpack <= 0) {
        for (const pl of platformsRef.current) {
          if (pl.broken) continue;
          const px1 = p.x + 8, px2 = p.x + PLAYER_W - 8;
          const py2 = p.y + PLAYER_H;
          const prevPy2 = prevY + PLAYER_H;
          if (px2 < pl.x || px1 > pl.x + pl.w) continue;
          if (prevPy2 <= pl.y && py2 >= pl.y) {
            p.y = pl.y - PLAYER_H;
            jump();
            if (pl.kind === "breakable") {
              pl.broken = true;
              // brokjes
              for (let i = 0; i < 8; i++) {
                particlesRef.current.push({
                  id: ++idRef.current,
                  x: pl.x + Math.random() * pl.w,
                  y: pl.y,
                  vx: (Math.random() - 0.5) * 200,
                  vy: 50 + Math.random() * 80,
                  life: 0.7, r: 3 + Math.random() * 3,
                  c: "#A86C3A",
                });
              }
            }
            break;
          }
        }
      }

      // power-ups
      for (let i = powerupsRef.current.length - 1; i >= 0; i--) {
        const pu = powerupsRef.current[i];
        if (p.x + PLAYER_W - 4 < pu.x || p.x + 4 > pu.x + pu.w) continue;
        if (p.y + PLAYER_H - 4 < pu.y || p.y + 4 > pu.y + pu.h) continue;
        powerupsRef.current.splice(i, 1);
        p.jetpack = 1.6;
        for (let k = 0; k < 12; k++) {
          const ang = Math.random() * Math.PI * 2;
          particlesRef.current.push({
            id: ++idRef.current,
            x: p.x + PLAYER_W / 2, y: p.y + PLAYER_H / 2,
            vx: Math.cos(ang) * 150, vy: Math.sin(ang) * 150,
            life: 0.7, r: 4, c: "#FFD23F",
          });
        }
      }

      // enemies bewegen + collision
      for (const en of enemiesRef.current) {
        en.x += en.vx * dt;
        if (en.x < 10) { en.x = 10; en.vx = -en.vx; }
        if (en.x + en.w > FIELD_W - 10) { en.x = FIELD_W - 10 - en.w; en.vx = -en.vx; }

        // hit?
        const overlap =
          p.x + PLAYER_W - 6 > en.x && p.x + 6 < en.x + en.w &&
          p.y + PLAYER_H - 6 > en.y && p.y + 6 < en.y + en.h;
        if (overlap) {
          if (p.jetpack > 0) {
            // wasknijper smelt
            en.dead = true;
          } else if (p.vy > 0 && p.y + PLAYER_H - 8 < en.y + 6) {
            // bovenop springen, stomp
            en.dead = true;
            jump(JUMP_VEL * 0.85);
          } else {
            die();
            return;
          }
        }
      }
      enemiesRef.current = enemiesRef.current.filter(e => !e.dead && e.y < FIELD_H + 60);

      // platforms recyclen wanneer onderkant van scherm
      platformsRef.current = platformsRef.current.filter(pl => pl.y < FIELD_H + 40);
      powerupsRef.current = powerupsRef.current.filter(pu => pu.y < FIELD_H + 40);

      // nieuwe platforms aan top toevoegen tot we vol zitten
      const topY = platformsRef.current.length
        ? Math.min(...platformsRef.current.map(pl => pl.y))
        : 0;
      let nextY = topY - SPAWN_GAP;
      const level = Math.floor(heightRef.current / 200);
      while (nextY > -20) {
        addPlatformAt(nextY, level + Math.floor((-nextY) / 100));
        nextY -= SPAWN_GAP;
      }

      // valt buiten beeld?
      if (p.y > FIELD_H + 20) {
        die();
        return;
      }

      // score = hoogte in meters (1m = 30px)
      setScore(Math.floor(heightRef.current / 30));

      // wolken trage drift
      for (const cl of cloudsRef.current) {
        cl.x -= cl.vx * dt * 0.4;
        if (cl.x < -120) { cl.x = FIELD_W + 60; cl.y = Math.random() * FIELD_H; }
      }
      // sterren twinkelen
      for (const st of starsRef.current) { st.ph += dt * st.tw; }
      // aurora-fase
      animTimeRef.current += dt;

      // particles
      particlesRef.current = particlesRef.current
        .map(d => ({ ...d, x: d.x + d.vx * dt, y: d.y + d.vy * dt, vy: d.vy + 600 * dt, life: d.life - dt }))
        .filter(d => d.life > 0);

      forceRender();
      raf = requestAnimationFrame(frame);
    }
    raf = requestAnimationFrame(frame);
    return () => cancelAnimationFrame(raf);
  }, [phase]);

  function die() {
    setBest(prev => {
      const nv = scoreRefVal.current;
      if (nv > prev) {
        try { localStorage.setItem(STORAGE_KEY, String(nv)); } catch {}
        return nv;
      }
      return prev;
    });
    setPhase("dead");
  }
  const scoreRefVal = React.useRef(0);
  React.useEffect(() => { scoreRefVal.current = score; }, [score]);

  // touch-controls: linker helft = links, rechter helft = rechts
  const activeSideRef = React.useRef(null);
  function onPointer(e) {
    if (phase !== "playing") {
      if (phase === "intro") start();
      else if (phase === "dead") restart();
      return;
    }
    const r = e.currentTarget.getBoundingClientRect();
    const xRel = (e.clientX - r.left) / r.width;
    if (xRel < 0.5) { inputRef.current.left = 1; inputRef.current.right = 0; activeSideRef.current = "L"; }
    else { inputRef.current.right = 1; inputRef.current.left = 0; activeSideRef.current = "R"; }
  }
  function onPointerEnd() {
    inputRef.current.left = 0;
    inputRef.current.right = 0;
    activeSideRef.current = null;
  }
  function onPointerMove(e) {
    if (activeSideRef.current == null) return;
    const r = e.currentTarget.getBoundingClientRect();
    const xRel = (e.clientX - r.left) / r.width;
    if (xRel < 0.5) { inputRef.current.left = 1; inputRef.current.right = 0; activeSideRef.current = "L"; }
    else { inputRef.current.right = 1; inputRef.current.left = 0; activeSideRef.current = "R"; }
  }

  const p = playerRef.current;

  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 200,
      background: "#1A2330",
      fontFamily: "'Patrick Hand', cursive",
      color: "#1A1A1A",
      display: "flex", flexDirection: "column",
      overscrollBehavior: "contain",
      touchAction: "none",
    }}>
      <div style={{
        flexShrink: 0,
        display: "flex", alignItems: "center", justifyContent: "space-between",
        padding: narrow ? "8px 10px" : "10px 16px",
        gap: 8,
        background: "rgba(255,245,220,0.96)",
        borderBottom: "3px solid #1A1A1A",
      }}>
        <div style={{
          fontFamily: "'Bangers', sans-serif",
          fontSize: narrow ? 22 : 28, letterSpacing: "0.04em",
          color: "#FF8C1A",
          WebkitTextStroke: "1.2px #1A1A1A",
          textShadow: "2px 2px 0 #1A1A1A",
          display: "flex", alignItems: "center", gap: 6, whiteSpace: "nowrap",
        }}>
          <span style={{ fontSize: narrow ? 20 : 24, WebkitTextStroke: 0, textShadow: "none" }}>⬆</span>
          {narrow ? "CLIMBER" : "PEPER CLIMBER"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: narrow ? 6 : 10 }}>
          <Pill bg="#FFD23F" color="#1A1A1A" narrow={narrow}>📏 {score}m</Pill>
          <Pill bg="#FF8C1A" color="#FFF" narrow={narrow}>🏆 {best}m</Pill>
          <button onClick={onClose} aria-label="Sluiten" style={{
            width: 44, height: 44, borderRadius: "50%",
            background: "#1A1A1A", color: "#F0FAE6",
            border: "3px solid #F0FAE6", boxShadow: "2px 2px 0 #1A1A1A",
            fontFamily: "'Bangers', sans-serif", fontSize: 22, cursor: "pointer", flexShrink: 0,
          }}>✕</button>
        </div>
      </div>

      <div ref={wrapRef} style={{
        flex: 1, position: "relative",
        display: "flex", alignItems: "center", justifyContent: "center",
        padding: 6, overflow: "hidden",
      }}>
        <div
          style={{ width: FIELD_W * scale, height: FIELD_H * scale, position: "relative", cursor: "pointer" }}
          onPointerDown={onPointer}
          onPointerUp={onPointerEnd}
          onPointerCancel={onPointerEnd}
          onPointerLeave={onPointerEnd}
          onPointerMove={onPointerMove}
        >
          <svg
            viewBox={`0 0 ${FIELD_W} ${FIELD_H}`}
            width={FIELD_W * scale}
            height={FIELD_H * scale}
            style={{
              display: "block",
              border: "4px solid #1A1A1A",
              boxShadow: "5px 5px 0 #1A1A1A",
              touchAction: "none", userSelect: "none",
            }}>
            <defs>
              <linearGradient id="pc-sky" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#0B0B2E" />
                <stop offset="35%" stopColor="#2A1A56" />
                <stop offset="70%" stopColor="#7E2D7E" />
                <stop offset="100%" stopColor="#FF6B5A" />
              </linearGradient>
              <linearGradient id="pc-plat" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#7BD86C" />
                <stop offset="100%" stopColor="#1F6826" />
              </linearGradient>
              <linearGradient id="pc-plat-move" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#FFE56F" />
                <stop offset="100%" stopColor="#E36210" />
              </linearGradient>
              <linearGradient id="pc-plat-break" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#D4A476" />
                <stop offset="100%" stopColor="#5C3A1A" />
              </linearGradient>
              <radialGradient id="pc-power" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#FFFAE0" />
                <stop offset="50%" stopColor="#FFD23F" />
                <stop offset="100%" stopColor="#FF8C1A" />
              </radialGradient>
              <radialGradient id="pc-power-halo" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="rgba(255, 210, 63, 0.6)" />
                <stop offset="100%" stopColor="rgba(255, 210, 63, 0)" />
              </radialGradient>
              <linearGradient id="pc-aurora1" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="rgba(63, 230, 200, 0)" />
                <stop offset="50%" stopColor="rgba(63, 230, 200, 0.55)" />
                <stop offset="100%" stopColor="rgba(63, 230, 200, 0)" />
              </linearGradient>
              <linearGradient id="pc-aurora2" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="rgba(155, 93, 229, 0)" />
                <stop offset="50%" stopColor="rgba(155, 93, 229, 0.45)" />
                <stop offset="100%" stopColor="rgba(155, 93, 229, 0)" />
              </linearGradient>
              <linearGradient id="pc-clip" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#E0E5EA" />
                <stop offset="100%" stopColor="#7C828A" />
              </linearGradient>
              <linearGradient id="pc-jet" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#FFFAE0" />
                <stop offset="50%" stopColor="#FFD23F" />
                <stop offset="100%" stopColor="#E63946" />
              </linearGradient>
              <radialGradient id="pc-vignette" cx="0.5" cy="0.5" r="0.7">
                <stop offset="55%" stopColor="rgba(0,0,0,0)" />
                <stop offset="100%" stopColor="rgba(0,0,0,0.55)" />
              </radialGradient>
              <filter id="pc-glow" x="-50%" y="-50%" width="200%" height="200%">
                <feGaussianBlur stdDeviation="3" result="b" />
                <feMerge><feMergeNode in="b" /><feMergeNode in="SourceGraphic" /></feMerge>
              </filter>
            </defs>
            <rect x="0" y="0" width={FIELD_W} height={FIELD_H} fill="url(#pc-sky)" />

            {/* aurora-banden */}
            {auroraRef.current.map((a, i) => (
              <path key={a.id}
                d={`M -20 ${a.y + Math.sin(animTimeRef.current * 0.6 + a.ph) * 12}
                    Q ${FIELD_W * 0.25} ${a.y - 30 + Math.cos(animTimeRef.current + a.ph) * 18}
                      ${FIELD_W * 0.5} ${a.y + Math.sin(animTimeRef.current * 0.4 + a.ph) * 12}
                    T ${FIELD_W + 20} ${a.y + 8}
                    L ${FIELD_W + 20} ${a.y + 30}
                    Q ${FIELD_W * 0.5} ${a.y + 50} 0 ${a.y + 30} Z`}
                fill={i % 2 === 0 ? "url(#pc-aurora1)" : "url(#pc-aurora2)"}
                opacity="0.6" />
            ))}

            {/* sterren */}
            {starsRef.current.map(st => (
              <circle key={st.id} cx={st.x} cy={st.y} r={st.r}
                fill="#FFF8EC" opacity={0.4 + 0.5 * Math.abs(Math.sin(st.ph))} />
            ))}

            {/* maan */}
            <g>
              <circle cx={FIELD_W - 80} cy={90} r={40}
                fill="rgba(255, 250, 220, 0.18)" />
              <circle cx={FIELD_W - 80} cy={90} r={28}
                fill="#FFF8EC" stroke="#1A1A1A" strokeWidth="2" />
              <circle cx={FIELD_W - 86} cy={84} r="4" fill="#D8CFB6" opacity="0.7" />
              <circle cx={FIELD_W - 75} cy={96} r="3" fill="#D8CFB6" opacity="0.6" />
            </g>

            {/* wolken met depth */}
            {cloudsRef.current.map(c => (
              <g key={c.id} transform={`translate(${c.x} ${c.y}) scale(${c.s})`} opacity="0.4">
                <ellipse cx="3" cy="3" rx="42" ry="14" fill="rgba(0,0,0,0.3)" />
                <ellipse cx="0" cy="0" rx="42" ry="14" fill="#FFF8EC" />
                <ellipse cx="-22" cy="6" rx="18" ry="10" fill="#FFF8EC" />
                <ellipse cx="24" cy="6" rx="20" ry="11" fill="#FFF8EC" />
                <ellipse cx="-8" cy="-5" rx="14" ry="6" fill="#FFFFFF" opacity="0.6" />
              </g>
            ))}

            {/* platforms met depth en glow */}
            {platformsRef.current.map(pl => {
              if (pl.broken) return null;
              const grad = pl.kind === "moving" ? "url(#pc-plat-move)" :
                pl.kind === "breakable" ? "url(#pc-plat-break)" : "url(#pc-plat)";
              const glowColor = pl.kind === "moving" ? "rgba(255,210,63,0.4)" :
                pl.kind === "breakable" ? "rgba(212, 164, 118, 0.3)" : "rgba(123, 216, 108, 0.4)";
              return (
                <g key={pl.id}>
                  {/* glow */}
                  <ellipse cx={pl.x + pl.w / 2} cy={pl.y + PLATFORM_H + 4}
                    rx={pl.w * 0.55} ry="6"
                    fill={glowColor} />
                  {/* schaduw */}
                  <rect x={pl.x + 3} y={pl.y + 4} width={pl.w} height={PLATFORM_H}
                    fill="rgba(0,0,0,0.35)" rx="6" />
                  {/* hoofd-platform */}
                  <rect x={pl.x} y={pl.y} width={pl.w} height={PLATFORM_H}
                    fill={grad} stroke="#1A1A1A" strokeWidth="2.5" rx="6" />
                  {/* highlight bovenkant */}
                  <rect x={pl.x + 3} y={pl.y + 2} width={pl.w - 6} height="3"
                    fill="#FFF" opacity="0.5" rx="2" />
                  {pl.kind === "moving" && (
                    <>
                      <text x={pl.x + 10} y={pl.y + PLATFORM_H - 5} fontSize="11" fill="#1A1A1A" fontWeight="bold">◀</text>
                      <text x={pl.x + pl.w - 18} y={pl.y + PLATFORM_H - 5} fontSize="11" fill="#1A1A1A" fontWeight="bold">▶</text>
                    </>
                  )}
                  {pl.kind === "breakable" && (
                    <>
                      <line x1={pl.x + 6} y1={pl.y + 7} x2={pl.x + pl.w - 6} y2={pl.y + 7}
                        stroke="#3F2510" strokeWidth="1.2" strokeDasharray="2 2" opacity="0.7" />
                      <line x1={pl.x + 6} y1={pl.y + 12} x2={pl.x + pl.w - 6} y2={pl.y + 12}
                        stroke="#3F2510" strokeWidth="1.2" strokeDasharray="3 1" opacity="0.5" />
                    </>
                  )}
                  {pl.kind === "static" && (
                    <ellipse cx={pl.x + pl.w * 0.25} cy={pl.y + PLATFORM_H - 3}
                      rx="3" ry="1.5" fill="#FFF" opacity="0.4" />
                  )}
                </g>
              );
            })}

            {/* powerups, jetpack-peper */}
            {powerupsRef.current.map(pu => {
              const cx = pu.x + pu.w / 2;
              const cy = pu.y + pu.h / 2;
              const t = animTimeRef.current;
              const pulse = 1 + 0.12 * Math.sin(t * 4);
              return (
                <g key={pu.id}>
                  <circle cx={cx} cy={cy} r={28 * pulse} fill="url(#pc-power-halo)" />
                  <circle cx={cx} cy={cy} r="20"
                    fill="none" stroke="#FFE56F" strokeWidth="2"
                    strokeDasharray="6 4"
                    transform={`rotate(${(t * 100) % 360} ${cx} ${cy})`} />
                  <circle cx={cx} cy={cy} r="16" fill="url(#pc-power)" stroke="#1A1A1A" strokeWidth="2.5" />
                  <text x={cx} y={cy + 1} textAnchor="middle" dominantBaseline="middle"
                    fontSize="18" fontWeight="bold">🚀</text>
                </g>
              );
            })}

            {/* vijanden, wasknijper met depth */}
            {enemiesRef.current.map(en => (
              <g key={en.id} transform={`translate(${en.x + en.w / 2} ${en.y + en.h / 2})`}>
                <ellipse cx="3" cy={en.h / 2 + 3} rx={en.w * 0.45} ry="4" fill="rgba(0,0,0,0.35)" />
                <rect x={-en.w / 2} y={-en.h / 2} width={en.w} height={en.h * 0.55}
                  fill="url(#pc-clip)" stroke="#1A1A1A" strokeWidth="2.5" rx="4" />
                <rect x={-en.w / 2} y="0" width={en.w / 2 - 2} height={en.h * 0.5}
                  fill="#9098A0" stroke="#1A1A1A" strokeWidth="2.5" rx="3" />
                <rect x="2" y="0" width={en.w / 2 - 2} height={en.h * 0.5}
                  fill="#9098A0" stroke="#1A1A1A" strokeWidth="2.5" rx="3" />
                <line x1="0" y1={-en.h / 2 + 4} x2="0" y2={en.h * 0.45}
                  stroke="#1A1A1A" strokeWidth="1.5" opacity="0.6" />
                <circle cx={-7} cy={-en.h * 0.18} r="4.5" fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
                <circle cx={7} cy={-en.h * 0.18} r="4.5" fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
                <circle cx={-6} cy={-en.h * 0.18} r="2" fill="#1A1A1A" />
                <circle cx={8} cy={-en.h * 0.18} r="2" fill="#1A1A1A" />
                <path d="M -7 5 q 7 6 14 0" stroke="#1A1A1A" strokeWidth="2" fill="none" strokeLinecap="round" />
              </g>
            ))}

            {/* particles */}
            {particlesRef.current.map(d => (
              <g key={d.id}>
                <circle cx={d.x} cy={d.y} r={d.r * 1.6}
                  fill={d.c} opacity={Math.max(0, d.life * 0.4)} />
                <circle cx={d.x} cy={d.y} r={d.r}
                  fill={d.c} opacity={Math.max(0, d.life * 1.5)} />
              </g>
            ))}

            {/* speler met jetpack-trail */}
            <g transform={`translate(${p.x + PLAYER_W / 2} ${p.y + PLAYER_H / 2})`}>
              {p.jetpack > 0 && (
                <g transform={`scale(${p.face} 1) translate(-12 22)`}>
                  <ellipse cx="0" cy="14" rx="14" ry="22" fill="rgba(255,210,63,0.4)" />
                  <ellipse cx="0" cy="0"
                    rx={11 + Math.sin(animTimeRef.current * 24) * 3}
                    ry="18" fill="url(#pc-jet)" opacity="0.95" />
                  <ellipse cx="0" cy="3" rx="6" ry="11" fill="#FFFAE0" opacity="0.85" />
                </g>
              )}
              <ellipse cx="0" cy={PLAYER_H * 0.4} rx={PLAYER_W * 0.32} ry="3.5" fill="rgba(0,0,0,0.4)" />
              <g transform={`scale(${p.face} 1)`}>
                <image href="/assets/peper-raket.png"
                  x={-PLAYER_W / 2} y={-PLAYER_H / 2}
                  width={PLAYER_W} height={PLAYER_H}
                  preserveAspectRatio="xMidYMid meet"
                  style={{ filter: p.jetpack > 0
                    ? "drop-shadow(0 0 8px #FFD23F) drop-shadow(2px 4px 0 rgba(0,0,0,0.4))"
                    : "drop-shadow(2px 4px 0 rgba(0,0,0,0.45))" }} />
              </g>
            </g>

            {/* fog/atmosfeer aan top */}
            <rect x="0" y="0" width={FIELD_W} height="80"
              fill="rgba(11, 11, 46, 0.5)" pointerEvents="none" />

            {/* vignette */}
            <rect x="0" y="0" width={FIELD_W} height={FIELD_H}
              fill="url(#pc-vignette)" pointerEvents="none" />

            {/* hoogte-indicator */}
            <g>
              <rect x={FIELD_W - 26} y={20} width={14} height={FIELD_H - 80}
                fill="rgba(0,0,0,0.45)" stroke="#FFF" strokeWidth="1.5" rx="6" />
              <rect x={FIELD_W - 26}
                y={20 + (FIELD_H - 80) * (1 - Math.min(1, score / Math.max(50, best * 1.2 || 100)))}
                width={14} height={4}
                fill="#FFD23F" stroke="#1A1A1A" strokeWidth="1.5" />
              <rect x={FIELD_W - 26}
                y={20 + (FIELD_H - 80) * (1 - Math.min(1, score / Math.max(50, best * 1.2 || 100))) - 1}
                width={14} height={2}
                fill="#FFFAE0" />
            </g>
          </svg>

          {phase === "playing" && (
            <div style={{
              position: "absolute", top: 12, left: 0, right: 0, textAlign: "center",
              fontFamily: "'Bangers', sans-serif", fontSize: 50 * scale,
              color: "#FFF", WebkitTextStroke: `${1.8 * scale}px #1A1A1A`,
              textShadow: `${3 * scale}px ${3 * scale}px 0 #1A1A1A`,
              pointerEvents: "none", letterSpacing: "0.05em",
            }}>{score}m</div>
          )}

          {phase === "intro" && (
            <Overlay>
              <Title color="#FF8C1A">PEPER CLIMBER</Title>
              <p style={overlayText}>
                Houd <strong>links</strong>/<strong>rechts</strong> ingedrukt (of pijltjes/A-D).
                Hete Peper springt automatisch op platforms. Pak <span style={{ color: "#FFD23F" }}>🚀</span>
                voor een jetpack-boost en stomp wasknijpers van bovenaf!
              </p>
              <BigBtn onClick={start} color="#5BB85B">▶ START</BigBtn>
            </Overlay>
          )}

          {phase === "dead" && (
            <Overlay>
              <Title color="#E63946">VAL!</Title>
              <p style={overlayText}>
                Je klom <strong>{score}</strong>m hoog.
                {score >= best && score > 0 && <><br /><span style={{ color: "#FFD23F", fontWeight: "bold" }}>🏆 NIEUW RECORD!</span></>}
                {score < best && <><br />Beste: <strong>{best}</strong>m</>}
              </p>
              <BigBtn onClick={restart} color="#5BB85B">↻ NOG EENS</BigBtn>
            </Overlay>
          )}
        </div>
      </div>
    </div>
  );

  function Pill({ bg, color, narrow, children }) {
    return (
      <span style={{
        background: bg, color, border: "3px solid #1A1A1A",
        boxShadow: "2px 2px 0 #1A1A1A",
        padding: narrow ? "4px 8px" : "6px 12px",
        fontFamily: "'Bangers', sans-serif",
        fontSize: narrow ? 16 : 20, letterSpacing: "0.04em",
      }}>{children}</span>
    );
  }
  function Title({ color, children }) {
    return (
      <div style={{
        fontFamily: "'Bangers', sans-serif", fontSize: 44,
        color, WebkitTextStroke: "1.5px #1A1A1A",
        textShadow: "3px 3px 0 #1A1A1A", letterSpacing: "0.05em",
        textAlign: "center", margin: 0,
      }}>{children}</div>
    );
  }
  function BigBtn({ onClick, color, children }) {
    return (
      <button onPointerDown={e => { e.stopPropagation(); }} onClick={onClick} style={{
        background: color, color: "#FFF",
        border: "4px solid #1A1A1A", boxShadow: "4px 4px 0 #1A1A1A",
        fontFamily: "'Bangers', sans-serif", fontSize: 28,
        padding: "10px 28px", cursor: "pointer", letterSpacing: "0.04em",
        marginTop: 8,
      }}>{children}</button>
    );
  }
  function Overlay({ children }) {
    return (
      <div style={{
        position: "absolute", inset: 0,
        background: "rgba(15,20,40,0.78)",
        display: "flex", flexDirection: "column",
        alignItems: "center", justifyContent: "center",
        padding: 20, gap: 12, color: "#FFF8EC",
      }} onPointerDown={e => e.stopPropagation()}>{children}</div>
    );
  }
}

const overlayText = {
  fontSize: 19, lineHeight: 1.5, maxWidth: 460, textAlign: "center",
  color: "#FFF8EC", margin: 0,
};

Object.assign(window, { PeperClimber });
