// super-peper.jsx, Mario-achtige platformer met Super Peper. Spring over
// wasknijpers, verzamel pepers en bereik de vlag aan het einde.

const LEVEL_COUNT = 20;

function makeRng(seed) {
  let s = (seed | 0) || 1;
  return () => {
    s = (s * 1664525 + 1013904223) | 0;
    return ((s >>> 0) % 100000) / 100000;
  };
}

// procedurele level-generator. Idx 0..LEVEL_COUNT-1, langer en pittiger
// naarmate idx stijgt. Houdt rekening met de spring-fysica: gat <= 220px
// blijft haalbaar bij volle aanloop.
function buildLevel(idx, FIELD_H, GROUND_H, ENEMY_W, ENEMY_H) {
  const rng = makeRng((idx + 1) * 9871);
  const LEVEL_W = Math.round(2200 + idx * 220);

  const platforms = [];
  let cursor = 0;
  const startW = 480 + Math.round(rng() * 120);
  platforms.push({ x: 0, y: FIELD_H - GROUND_H, w: startW, h: GROUND_H, kind: "ground" });
  cursor = startW;

  const numGaps = 1 + Math.floor(idx * 0.55);
  for (let g = 0; g < numGaps; g++) {
    if (cursor >= LEVEL_W - 600) break;
    const gapMax = 130 + Math.min(80, idx * 4);
    const gap = 90 + Math.round(rng() * (gapMax - 90));
    cursor += gap;
    if (cursor >= LEVEL_W - 600) break;
    const seg = 280 + Math.round(rng() * 380);
    platforms.push({ x: cursor, y: FIELD_H - GROUND_H, w: seg, h: GROUND_H, kind: "ground" });
    cursor += seg;
  }
  if (cursor < LEVEL_W) {
    platforms.push({ x: cursor, y: FIELD_H - GROUND_H, w: LEVEL_W - cursor, h: GROUND_H, kind: "ground" });
  }

  function onGround(x, w) {
    return platforms.some(p =>
      p.kind === "ground" && x >= p.x + 4 && x + w <= p.x + p.w - 4
    );
  }
  function brickOverlaps(x, y, w) {
    return platforms.some(p =>
      p.kind === "brick" &&
      p.x < x + w + 30 && p.x + p.w + 30 > x &&
      Math.abs(p.y - y) < 50
    );
  }

  // bakstenen-platformen, op haalbare hoogtes
  const numBricks = 3 + Math.round(idx * 0.6);
  for (let i = 0; i < numBricks; i++) {
    for (let attempt = 0; attempt < 8; attempt++) {
      const x = Math.round(280 + rng() * Math.max(200, LEVEL_W - 580));
      const w = Math.round(80 + rng() * 90);
      const yOff = Math.round(110 + rng() * 120);
      const y = FIELD_H - GROUND_H - yOff;
      if (!brickOverlaps(x, y, w)) {
        platforms.push({ x, y, w, h: 24, kind: "brick" });
        break;
      }
    }
  }

  // pijpen, alleen op grond, niet boven gaten en niet vlakbij vlag
  const numPipes = Math.floor(idx * 0.3);
  for (let i = 0; i < numPipes; i++) {
    for (let attempt = 0; attempt < 6; attempt++) {
      const x = Math.round(640 + rng() * Math.max(200, LEVEL_W - 1500));
      const ph = Math.round(60 + rng() * 50);
      if (!onGround(x, 60)) continue;
      if (platforms.some(p => p.kind === "pipe" && Math.abs(p.x - x) < 250)) continue;
      platforms.push({ x, y: FIELD_H - GROUND_H - ph, w: 60, h: ph, kind: "pipe" });
      break;
    }
  }

  // vijanden op brede grond-stukken, niet in spawn-zone
  const enemies = [];
  const numEnemies = 2 + Math.round(idx * 0.6);
  const groundPlats = platforms.filter(p =>
    p.kind === "ground" && p.w > 240 && p.x + p.w > 420
  );
  for (let i = 0; i < numEnemies && groundPlats.length; i++) {
    const pf = groundPlats[Math.floor(rng() * groundPlats.length)];
    const minX = Math.max(pf.x + 60, 420);
    const maxX = pf.x + pf.w - 60;
    if (maxX <= minX) continue;
    const x = Math.round(minX + rng() * (maxX - minX));
    const speed = 45 + Math.round(rng() * 30) + idx * 2;
    enemies.push({ x, y: FIELD_H - GROUND_H - ENEMY_H, vx: rng() < 0.5 ? -speed : speed });
  }

  // pepertjes verspreid over het level, niet boven gaten
  const coins = [];
  const numCoins = 8 + idx;
  for (let i = 0; i < numCoins; i++) {
    let placed = false;
    for (let attempt = 0; attempt < 5; attempt++) {
      const x = Math.round(180 + rng() * (LEVEL_W - 400));
      const y = Math.round(FIELD_H - GROUND_H - 90 - rng() * 200);
      // ofwel boven grond, ofwel in een hoogte waar speler kan komen
      if (onGround(x, 1) || y < FIELD_H - GROUND_H - 140) {
        coins.push({ x, y });
        placed = true;
        break;
      }
    }
  }

  const goalX = LEVEL_W - 140;
  return { LEVEL_W, PLATFORMS: platforms, ENEMIES_INIT: enemies, COINS_INIT: coins, GOAL_X: goalX };
}

function SuperPeper({ onClose }) {
  const FIELD_W = 880;
  const FIELD_H = 500;
  const GROUND_H = 60;
  const PLAYER_W = 80;
  const PLAYER_H = 108;
  const GRAVITY = 2000;
  const MOVE_SPEED = 320;
  const JUMP_VEL = 960;
  const ENEMY_W = 56;
  const ENEMY_H = 72;
  const COIN_R = 18;

  const [scale, setScale] = React.useState(1);
  const [narrow, setNarrow] = React.useState(typeof window !== "undefined" && window.innerWidth <= 600);
  const [phase, setPhase] = React.useState("intro");
  const [levelIdx, setLevelIdx] = React.useState(0);
  const [pendingStart, setPendingStart] = React.useState(false);
  const [keepProgress, setKeepProgress] = React.useState(false);
  const [score, setScore] = React.useState(0);
  const [coinsCol, setCoinsCol] = React.useState(0);
  const [lives, setLives] = React.useState(3);

  const LEVEL = React.useMemo(
    () => buildLevel(levelIdx, FIELD_H, GROUND_H, ENEMY_W, ENEMY_H),
    [levelIdx]
  );
  const { LEVEL_W, PLATFORMS, ENEMIES_INIT, COINS_INIT, GOAL_X } = LEVEL;
  const [best, setBest] = React.useState(() => {
    try { return parseInt(localStorage.getItem("super-peper-best") || "0", 10) || 0; }
    catch { return 0; }
  });
  const [, forceRender] = React.useReducer(x => x + 1, 0);

  const wrapRef = React.useRef(null);
  const fieldRef = React.useRef(null);
  const playerRef = React.useRef({ x: 80, y: 100, vx: 0, vy: 0, grounded: false, facing: 1, run: 0 });
  const cameraRef = React.useRef(0);
  const enemiesRef = React.useRef([]);
  const coinsRef = React.useRef([]);
  const particlesRef = React.useRef([]);
  const cloudsRef = React.useRef([]);
  const animRef = React.useRef(0);
  const idRef = React.useRef(0);
  const keysRef = React.useRef({ left: false, right: false, jump: false, jumpEdge: false });
  const lastFrameRef = 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);
    };
  }, []);

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

  React.useEffect(() => {
    function onKey(e) { if (e.key === "Escape") onClose && onClose(); }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  // Buiten de "playing"-fase fungeert Enter of Space als "klik op de
  // grote actieknop". Zo kunnen gamepad- en QR-controller-gebruikers
  // zonder muis door intro-, won- en lost-schermen heen.
  React.useEffect(() => {
    if (phase === "playing") return;
    function onKey(e) {
      if (e.key !== "Enter" && e.key !== " ") return;
      e.preventDefault();
      if (phase === "intro" || phase === "complete") startGame();
      else if (phase === "won") gotoNextLevel();
      else if (phase === "lost") retry();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [phase]);

  // wolken, vogels en bergen voor diepte
  const mountainsRef = React.useRef([]);
  const treesRef = React.useRef([]);
  const flowersRef = React.useRef([]);
  const birdsRef = React.useRef([]);
  const sunRaysRef = React.useRef(0);

  React.useEffect(() => {
    cloudsRef.current = Array.from({ length: 10 }, (_, i) => ({
      id: ++idRef.current,
      x: (i * 380) + Math.random() * 200,
      y: 40 + Math.random() * 130,
      s: 0.6 + Math.random() * 0.7,
      vx: 4 + Math.random() * 7,
    }));
    // bergen, in twee rijen voor parallax-diepte
    mountainsRef.current = Array.from({ length: 12 }, (_, i) => ({
      id: ++idRef.current,
      x: i * 280 + Math.random() * 80,
      h: 110 + Math.random() * 90,
      w: 240 + Math.random() * 100,
      far: i % 2 === 0,
    }));
    // bomen, dichterbij
    treesRef.current = Array.from({ length: 18 }, (_, i) => ({
      id: ++idRef.current,
      x: i * 220 + Math.random() * 80,
      h: 90 + Math.random() * 50,
      kind: Math.random() > 0.5 ? "pine" : "round",
    }));
    // bloemetjes op de grond (foreground)
    flowersRef.current = Array.from({ length: 24 }, (_, i) => ({
      id: ++idRef.current,
      x: 40 + i * 130 + Math.random() * 60,
      c: ["#E63946", "#FFD23F", "#FF8C1A", "#FFFFFF"][Math.floor(Math.random() * 4)],
    }));
    // vogels
    birdsRef.current = Array.from({ length: 4 }, (_, i) => ({
      id: ++idRef.current,
      x: i * 800 + Math.random() * 300,
      y: 70 + Math.random() * 120,
      vx: 22 + Math.random() * 12,
      flapT: Math.random() * Math.PI * 2,
    }));
  }, []);

  function loadLevelInto(level, keep) {
    playerRef.current = { x: 80, y: FIELD_H - GROUND_H - PLAYER_H, vx: 0, vy: 0, grounded: false, facing: 1, run: 0 };
    cameraRef.current = 0;
    enemiesRef.current = level.ENEMIES_INIT.map((e, i) => ({
      ...e, id: 'e' + i, alive: true, w: ENEMY_W, h: ENEMY_H, sq: 0,
    }));
    coinsRef.current = level.COINS_INIT.map((c, i) => ({
      ...c, id: 'c' + i, taken: false,
    }));
    particlesRef.current = [];
    if (!keep) {
      setScore(0);
      setCoinsCol(0);
      setLives(3);
    }
    keysRef.current = { left: false, right: false, jump: false, jumpEdge: false };
  }

  // start het level zodra de useMemo voor LEVEL met de juiste idx is bijgewerkt
  React.useEffect(() => {
    if (!pendingStart) return;
    loadLevelInto(LEVEL, keepProgress);
    setPhase("playing");
    setPendingStart(false);
  }, [pendingStart, LEVEL, keepProgress]);

  function startGame() {
    if (levelIdx !== 0) setLevelIdx(0);
    setKeepProgress(false);
    setPendingStart(true);
  }

  function retry() {
    if (levelIdx !== 0) setLevelIdx(0);
    setKeepProgress(false);
    setPendingStart(true);
  }

  function gotoNextLevel() {
    const nextIdx = levelIdx + 1;
    if (nextIdx >= LEVEL_COUNT) {
      setPhase("complete");
      return;
    }
    setLevelIdx(nextIdx);
    setKeepProgress(true);
    setPendingStart(true);
  }

  function spawnPuff(x, y, color = "#FFD23F", count = 10) {
    for (let i = 0; i < count; i++) {
      const a = Math.random() * Math.PI * 2;
      const v = 100 + Math.random() * 200;
      particlesRef.current.push({
        id: ++idRef.current,
        x, y,
        vx: Math.cos(a) * v,
        vy: Math.sin(a) * v - 100,
        life: 0.5 + Math.random() * 0.4,
        color, r: 3 + Math.random() * 4,
      });
    }
  }

  // toetsenbord
  React.useEffect(() => {
    function isJump(k) { return k === " " || k === "ArrowUp" || k === "w" || k === "W"; }
    function isLeft(k) { return k === "ArrowLeft" || k === "a" || k === "A"; }
    function isRight(k) { return k === "ArrowRight" || k === "d" || k === "D"; }
    function down(e) {
      if (isLeft(e.key)) { keysRef.current.left = true; e.preventDefault(); }
      else if (isRight(e.key)) { keysRef.current.right = true; e.preventDefault(); }
      else if (isJump(e.key)) {
        if (!keysRef.current.jump) keysRef.current.jumpEdge = true;
        keysRef.current.jump = true;
        e.preventDefault();
      }
    }
    function up(e) {
      if (isLeft(e.key)) keysRef.current.left = false;
      else if (isRight(e.key)) keysRef.current.right = false;
      else if (isJump(e.key)) keysRef.current.jump = false;
    }
    window.addEventListener("keydown", down);
    window.addEventListener("keyup", up);
    return () => {
      window.removeEventListener("keydown", down);
      window.removeEventListener("keyup", up);
    };
  }, []);

  // 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;
      animRef.current += dt;

      const p = playerRef.current;
      const k = keysRef.current;
      const prevY = p.y; // bewaar voor stomp-check (was speler boven of in vijand?)

      // horizontale beweging
      const targetVx = (k.left ? -MOVE_SPEED : 0) + (k.right ? MOVE_SPEED : 0);
      const accel = p.grounded ? 14 : 7;
      p.vx += (targetVx - p.vx) * Math.min(1, dt * accel);
      if (Math.abs(p.vx) < 6) p.vx = 0;
      if (targetVx > 0) p.facing = 1;
      else if (targetVx < 0) p.facing = -1;

      // jump
      if (k.jumpEdge && p.grounded) {
        p.vy = -JUMP_VEL;
        p.grounded = false;
        spawnPuff(p.x + PLAYER_W / 2, p.y + PLAYER_H, "#C8B07A", 6);
      }
      k.jumpEdge = false;
      // korte hop als knop losgelaten wordt
      if (!k.jump && p.vy < -200) p.vy = -200;

      p.vy += GRAVITY * dt;

      // beweeg x, los botsingen op
      p.x += p.vx * dt;
      for (const pf of PLATFORMS) {
        if (overlap(p.x, p.y, PLAYER_W, PLAYER_H, pf.x, pf.y, pf.w, pf.h)) {
          if (p.vx > 0) p.x = pf.x - PLAYER_W;
          else if (p.vx < 0) p.x = pf.x + pf.w;
          p.vx = 0;
        }
      }
      if (p.x < 0) { p.x = 0; p.vx = 0; }
      if (p.x + PLAYER_W > LEVEL_W) p.x = LEVEL_W - PLAYER_W;

      // beweeg y
      p.y += p.vy * dt;
      p.grounded = false;
      for (const pf of PLATFORMS) {
        if (overlap(p.x, p.y, PLAYER_W, PLAYER_H, pf.x, pf.y, pf.w, pf.h)) {
          if (p.vy > 0) {
            p.y = pf.y - PLAYER_H;
            p.vy = 0;
            p.grounded = true;
          } else if (p.vy < 0) {
            p.y = pf.y + pf.h;
            p.vy = 0;
            // bonk effect
            spawnPuff(p.x + PLAYER_W / 2, p.y, "#A06B3F", 4);
          }
        }
      }

      // run animation cycle
      if (p.grounded && Math.abs(p.vx) > 20) p.run += dt * 12;
      else p.run = 0;

      // val van level af -> levenkwijt
      if (p.y > FIELD_H + 100) {
        loseLife(p);
      }

      // vijanden
      for (const e of enemiesRef.current) {
        if (!e.alive) {
          e.sq += dt;
          continue;
        }
        e.x += e.vx * dt;
        // botsing met platforms zijwaarts: omdraaien
        for (const pf of PLATFORMS) {
          if (overlap(e.x, e.y, e.w, e.h, pf.x, pf.y, pf.w, pf.h)) {
            if (e.vx > 0) e.x = pf.x - e.w;
            else if (e.vx < 0) e.x = pf.x + pf.w;
            e.vx = -e.vx;
          }
        }
        // val-detectie: als geen platform onder, omdraaien
        const foot = { x: e.vx > 0 ? e.x + e.w + 2 : e.x - 2, y: e.y + e.h + 4 };
        let onGround = false;
        for (const pf of PLATFORMS) {
          if (foot.x >= pf.x && foot.x <= pf.x + pf.w &&
              foot.y >= pf.y && foot.y <= pf.y + pf.h + 8) {
            onGround = true; break;
          }
        }
        if (!onGround) e.vx = -e.vx;
      }

      // botsing met vijand
      for (const e of enemiesRef.current) {
        if (!e.alive) continue;
        if (overlap(p.x, p.y, PLAYER_W, PLAYER_H, e.x, e.y, e.w, e.h)) {
          // stomp-check: speler is aan het vallen én was vorig frame nog boven (of vlak boven)
          // de vijand. Tolerantie groot genoeg voor hoge val-snelheden bij grote sprongen.
          const prevBottom = prevY + PLAYER_H;
          const enemyTop = e.y;
          const descending = p.vy >= 0;
          const wasAbove = prevBottom <= enemyTop + 12;
          if (descending && wasAbove) {
            e.alive = false;
            e.sq = 0;
            p.y = enemyTop - PLAYER_H;
            p.vy = -520; // stevige bounce omhoog
            setScore(s => s + 100);
            spawnPuff(e.x + e.w / 2, e.y, "#C8C2B4", 14);
          } else {
            loseLife(p);
            return forceRender();
          }
        }
      }

      // pepers verzamelen
      const cx = p.x + PLAYER_W / 2;
      const cy = p.y + PLAYER_H / 2;
      for (const c of coinsRef.current) {
        if (c.taken) continue;
        if (Math.hypot(c.x - cx, c.y - cy) < COIN_R + 22) {
          c.taken = true;
          setCoinsCol(n => n + 1);
          setScore(s => s + 50);
          spawnPuff(c.x, c.y, "#FFD23F", 10);
        }
      }

      // einddoel: speler raakt vlag-zone (rechterrand voorbij vlag)
      if (p.x + PLAYER_W >= GOAL_X) {
        // bonus voor het halen van een level: meer punten naarmate je hoger komt
        const levelBonus = 250 + levelIdx * 75;
        setScore(s => s + levelBonus);
        const lastLevel = levelIdx + 1 >= LEVEL_COUNT;
        const total = score + levelBonus + (lastLevel ? lives * 200 : 0);
        setBest(prev => {
          if (total > prev) {
            try { localStorage.setItem("super-peper-best", String(total)); } catch {}
            return total;
          }
          return prev;
        });
        setPhase("won");
        return;
      }

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

      // wolken-drift
      cloudsRef.current.forEach(c => {
        c.x += c.vx * dt;
        if (c.x > LEVEL_W + 80) c.x = -80;
      });
      // vogels vliegen door
      birdsRef.current.forEach(b => {
        b.x += b.vx * dt;
        b.flapT += dt * 8;
        if (b.x > LEVEL_W + 60) {
          b.x = -60;
          b.y = 70 + Math.random() * 120;
        }
      });
      sunRaysRef.current += dt * 0.4;

      // camera volgt speler
      const targetCam = Math.max(0, Math.min(LEVEL_W - FIELD_W, p.x - FIELD_W * 0.4));
      cameraRef.current += (targetCam - cameraRef.current) * Math.min(1, dt * 8);

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

  function loseLife(p) {
    spawnPuff(p.x + PLAYER_W / 2, p.y + PLAYER_H / 2, "#E63946", 20);
    setLives(n => {
      const nv = n - 1;
      if (nv <= 0) {
        setPhase("lost");
        return 0;
      }
      // herspawnen vlakbij waar je viel
      const spawnX = Math.max(80, p.x - 200);
      playerRef.current = {
        x: spawnX, y: 100, vx: 0, vy: 0,
        grounded: false, facing: 1, run: 0,
      };
      return nv;
    });
  }

  // mobiele-besturing knop helpers
  function btnDown(key) {
    return (e) => {
      e.preventDefault(); e.stopPropagation();
      if (key === "left") keysRef.current.left = true;
      else if (key === "right") keysRef.current.right = true;
      else if (key === "jump") {
        if (!keysRef.current.jump) keysRef.current.jumpEdge = true;
        keysRef.current.jump = true;
      }
    };
  }
  function btnUp(key) {
    return (e) => {
      e.preventDefault(); e.stopPropagation();
      if (key === "left") keysRef.current.left = false;
      else if (key === "right") keysRef.current.right = false;
      else if (key === "jump") keysRef.current.jump = false;
    };
  }

  const cam = cameraRef.current;
  const p = playerRef.current;
  // run-animation: kleine y-offset
  const runBob = phase === "playing" && p.grounded && Math.abs(p.vx) > 20
    ? Math.sin(p.run) * 3
    : (!p.grounded ? -2 : 0);

  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 200,
      background: "#1A1A4E",
      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",
        color: "#1A1A1A",
      }}>
        <div style={{
          fontFamily: "'Bangers', sans-serif",
          fontSize: narrow ? 22 : 28, letterSpacing: "0.04em",
          color: "#3FA34D",
          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 ? "SUPER" : "SUPER PEPER"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: narrow ? 6 : 10 }}>
          <Pill bg="#2D9CDB" color="#FFF" narrow={narrow}>LV {levelIdx + 1}/{LEVEL_COUNT}</Pill>
          <Pill bg="#E63946" color="#FFF" narrow={narrow}>❤ {lives}</Pill>
          <Pill bg="#FF8C1A" color="#FFF" narrow={narrow}>🌶️ {coinsCol}</Pill>
          <Pill bg="#FFD23F" color="#1A1A1A" narrow={narrow}>⚡ {score}</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",
        }}>
          <svg
            ref={fieldRef}
            viewBox={`0 0 ${FIELD_W} ${FIELD_H}`}
            preserveAspectRatio="none"
            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="sp-sky" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#FFC885" />
                <stop offset="25%" stopColor="#FF9A55" />
                <stop offset="55%" stopColor="#FFB59A" />
                <stop offset="80%" stopColor="#A8DCF6" />
                <stop offset="100%" stopColor="#E2F2DA" />
              </linearGradient>
              <linearGradient id="sp-ground" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#C18E59" />
                <stop offset="40%" stopColor="#8E5E2A" />
                <stop offset="100%" stopColor="#5A3A18" />
              </linearGradient>
              <linearGradient id="sp-grass-top" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#82D982" />
                <stop offset="50%" stopColor="#5BB85B" />
                <stop offset="100%" stopColor="#2E7B2E" />
              </linearGradient>
              <linearGradient id="sp-pipe" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="#2A6E2A" />
                <stop offset="20%" stopColor="#3FA34D" />
                <stop offset="50%" stopColor="#9AD89A" />
                <stop offset="80%" stopColor="#3FA34D" />
                <stop offset="100%" stopColor="#1F5520" />
              </linearGradient>
              <linearGradient id="sp-pipe-cap" x1="0" y1="0" x2="1" y2="0">
                <stop offset="0%" stopColor="#1F5520" />
                <stop offset="50%" stopColor="#5BB85B" />
                <stop offset="100%" stopColor="#1F5520" />
              </linearGradient>
              <linearGradient id="sp-brick" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#F4A574" />
                <stop offset="50%" stopColor="#C97B45" />
                <stop offset="100%" stopColor="#7A3F1A" />
              </linearGradient>
              <linearGradient id="sp-brick-light" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#FFCFA8" />
                <stop offset="100%" stopColor="#E68A53" />
              </linearGradient>
              <linearGradient id="sp-mountain-far" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#B89AC4" />
                <stop offset="100%" stopColor="#7E5F92" />
              </linearGradient>
              <linearGradient id="sp-mountain-near" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#8AB890" />
                <stop offset="100%" stopColor="#4D7A52" />
              </linearGradient>
              <linearGradient id="sp-tree-pine" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#3D7A3D" />
                <stop offset="100%" stopColor="#1F4A1F" />
              </linearGradient>
              <linearGradient id="sp-tree-round" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#5BB85B" />
                <stop offset="100%" stopColor="#2E7B2E" />
              </linearGradient>
              <radialGradient id="sp-sun-glow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#FFE56F" stopOpacity="0.9" />
                <stop offset="50%" stopColor="#FFB347" stopOpacity="0.4" />
                <stop offset="100%" stopColor="#FFB347" stopOpacity="0" />
              </radialGradient>
              <radialGradient id="sp-coin-glow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#FFE56F" stopOpacity="0.7" />
                <stop offset="100%" stopColor="#FFE56F" stopOpacity="0" />
              </radialGradient>
            </defs>

            {/* lucht */}
            <rect x="0" y="0" width={FIELD_W} height={FIELD_H} fill="url(#sp-sky)" />

            {/* zon met aura en stralen */}
            <g transform={`translate(${FIELD_W - 100} 90)`}>
              <circle cx="0" cy="0" r="120" fill="url(#sp-sun-glow)" />
              {/* zonnestralen die langzaam draaien */}
              <g transform={`rotate(${(sunRaysRef.current * 12).toFixed(1)})`} opacity="0.3">
                {[0, 30, 60, 90, 120, 150].map(a => (
                  <rect key={a} x="-2" y="-90" width="4" height="40"
                    fill="#FFE56F" transform={`rotate(${a})`} />
                ))}
              </g>
              <circle cx="0" cy="0" r="38" fill="#FFE56F" stroke="#1A1A1A" strokeWidth="3" />
              <circle cx="-10" cy="-10" r="11" fill="rgba(255,255,255,0.7)" />
              {/* gezichtje */}
              <circle cx="-10" cy="-2" r="2.5" fill="#1A1A1A" />
              <circle cx="10" cy="-2" r="2.5" fill="#1A1A1A" />
              <path d="M -8 10 Q 0 16 8 10" stroke="#1A1A1A" strokeWidth="2" fill="none" strokeLinecap="round" />
            </g>

            {/* verre bergen, parallax 0.15 */}
            <g transform={`translate(${(-cam * 0.15).toFixed(1)} 0)`}>
              {mountainsRef.current.filter(m => m.far).map(m => (
                <g key={m.id}>
                  <path d={`M ${m.x} ${FIELD_H - GROUND_H - 10}
                    L ${m.x + m.w * 0.3} ${FIELD_H - GROUND_H - m.h}
                    L ${m.x + m.w * 0.55} ${FIELD_H - GROUND_H - m.h * 0.7}
                    L ${m.x + m.w * 0.8} ${FIELD_H - GROUND_H - m.h * 0.95}
                    L ${m.x + m.w} ${FIELD_H - GROUND_H - 10} Z`}
                    fill="url(#sp-mountain-far)" stroke="#1A1A1A" strokeWidth="2" opacity="0.85" />
                  {/* sneeuwtop */}
                  <path d={`M ${m.x + m.w * 0.22} ${FIELD_H - GROUND_H - m.h * 0.78}
                    L ${m.x + m.w * 0.3} ${FIELD_H - GROUND_H - m.h}
                    L ${m.x + m.w * 0.38} ${FIELD_H - GROUND_H - m.h * 0.78} Z`}
                    fill="#FFFFFF" stroke="#1A1A1A" strokeWidth="1.5" opacity="0.95" />
                </g>
              ))}
            </g>

            {/* dichtere bergen, parallax 0.28 */}
            <g transform={`translate(${(-cam * 0.28).toFixed(1)} 0)`}>
              {mountainsRef.current.filter(m => !m.far).map(m => (
                <path key={m.id}
                  d={`M ${m.x} ${FIELD_H - GROUND_H - 10}
                    L ${m.x + m.w * 0.4} ${FIELD_H - GROUND_H - m.h * 0.85}
                    L ${m.x + m.w * 0.65} ${FIELD_H - GROUND_H - m.h * 0.55}
                    L ${m.x + m.w} ${FIELD_H - GROUND_H - 10} Z`}
                  fill="url(#sp-mountain-near)" stroke="#1A1A1A" strokeWidth="2" opacity="0.92" />
              ))}
            </g>

            {/* heuvels achtergrond, parallax 0.4 */}
            <g transform={`translate(${(-cam * 0.4).toFixed(1)} 0)`}>
              {[0, 1, 2].map(i => {
                const baseX = i * 1100;
                return (
                  <g key={i}>
                    <ellipse cx={baseX + 200} cy={FIELD_H - GROUND_H + 20} rx={220} ry={120}
                      fill="#7BC57B" stroke="#1A1A1A" strokeWidth="2" opacity="0.9" />
                    <ellipse cx={baseX + 600} cy={FIELD_H - GROUND_H + 30} rx={180} ry={90}
                      fill="#7BC57B" stroke="#1A1A1A" strokeWidth="2" opacity="0.9" />
                    <ellipse cx={baseX + 900} cy={FIELD_H - GROUND_H + 25} rx={240} ry={130}
                      fill="#5BB85B" stroke="#1A1A1A" strokeWidth="2" opacity="0.9" />
                  </g>
                );
              })}
            </g>

            {/* bomen, parallax 0.55 */}
            <g transform={`translate(${(-cam * 0.55).toFixed(1)} 0)`}>
              {treesRef.current.map(t => {
                const trunkX = t.x;
                const baseY = FIELD_H - GROUND_H + 4;
                if (t.kind === "pine") {
                  return (
                    <g key={t.id}>
                      <rect x={trunkX - 4} y={baseY - 30} width="8" height="34"
                        fill="#5A3A18" stroke="#1A1A1A" strokeWidth="2" />
                      <path d={`M ${trunkX - 22} ${baseY - 30}
                        L ${trunkX} ${baseY - t.h}
                        L ${trunkX + 22} ${baseY - 30}
                        L ${trunkX + 14} ${baseY - 35}
                        L ${trunkX + 18} ${baseY - 60}
                        L ${trunkX + 8} ${baseY - 55}
                        L ${trunkX} ${baseY - t.h - 5}
                        L ${trunkX - 8} ${baseY - 55}
                        L ${trunkX - 18} ${baseY - 60}
                        L ${trunkX - 14} ${baseY - 35} Z`}
                        fill="url(#sp-tree-pine)" stroke="#1A1A1A" strokeWidth="2" strokeLinejoin="round" />
                    </g>
                  );
                }
                return (
                  <g key={t.id}>
                    <rect x={trunkX - 5} y={baseY - 26} width="10" height="30"
                      fill="#7A4F25" stroke="#1A1A1A" strokeWidth="2" />
                    <ellipse cx={trunkX} cy={baseY - 50} rx="34" ry="32"
                      fill="url(#sp-tree-round)" stroke="#1A1A1A" strokeWidth="2.5" />
                    <ellipse cx={trunkX - 14} cy={baseY - 44} rx="14" ry="12"
                      fill="rgba(255,255,255,0.18)" />
                  </g>
                );
              })}
            </g>

            {/* wolken, parallax 0.6 */}
            <g transform={`translate(${(-cam * 0.6).toFixed(1)} 0)`}>
              {cloudsRef.current.map(c => (
                <g key={c.id} transform={`translate(${c.x} ${c.y}) scale(${c.s})`}>
                  <ellipse cx="2" cy="3" rx="44" ry="19" fill="rgba(0,0,0,0.1)" />
                  <ellipse cx="0" cy="0" rx="42" ry="20" fill="#FFF" stroke="#1A1A1A" strokeWidth="2.5" />
                  <ellipse cx="-22" cy="6" rx="20" ry="13" fill="#FFF" stroke="#1A1A1A" strokeWidth="2.5" />
                  <ellipse cx="24" cy="6" rx="22" ry="14" fill="#FFF" stroke="#1A1A1A" strokeWidth="2.5" />
                  <ellipse cx="-12" cy="-8" rx="14" ry="9" fill="#FFF" />
                </g>
              ))}
            </g>

            {/* vogels, parallax 0.5 */}
            <g transform={`translate(${(-cam * 0.5).toFixed(1)} 0)`}>
              {birdsRef.current.map(b => {
                const flap = Math.sin(b.flapT) * 6;
                return (
                  <g key={b.id} transform={`translate(${b.x} ${b.y})`}>
                    <path d={`M -10 0 Q -5 ${-4 - flap} 0 0 Q 5 ${-4 - flap} 10 0`}
                      stroke="#1A1A1A" strokeWidth="2" fill="none" strokeLinecap="round" />
                  </g>
                );
              })}
            </g>

            {/* wereld die scrollt: platforms, vijanden, peper, coins */}
            <g transform={`translate(${(-cam).toFixed(1)} 0)`}>
              {/* bloempjes als foreground decoratie op grond-tops */}
              {flowersRef.current.map(f => {
                // alleen tonen als x op een ground-platform valt
                const onGround = PLATFORMS.some(pf =>
                  pf.kind === "ground" && f.x >= pf.x + 4 && f.x <= pf.x + pf.w - 4
                );
                if (!onGround) return null;
                const flowerY = FIELD_H - GROUND_H - 6;
                return (
                  <g key={f.id} transform={`translate(${f.x} ${flowerY})`}>
                    <path d="M 0 0 L 0 -8" stroke="#1F6826" strokeWidth="1.5" />
                    <circle cx="-3" cy="-9" r="2" fill={f.c} stroke="#1A1A1A" strokeWidth="1" />
                    <circle cx="3" cy="-9" r="2" fill={f.c} stroke="#1A1A1A" strokeWidth="1" />
                    <circle cx="0" cy="-12" r="2" fill={f.c} stroke="#1A1A1A" strokeWidth="1" />
                    <circle cx="0" cy="-10" r="1.2" fill="#FFE56F" />
                  </g>
                );
              })}
              {/* platformen */}
              {PLATFORMS.map((pf, i) => (
                <PlatformShape key={i} pf={pf} />
              ))}

              {/* coins (pepertjes) met sparkle en glow */}
              {coinsRef.current.map(c => c.taken ? null : (
                <g key={c.id} transform={`translate(${c.x} ${c.y + Math.sin(animRef.current * 4 + c.x * 0.01) * 4})`}>
                  {/* glow halo */}
                  <circle cx="0" cy="0" r="22" fill="url(#sp-coin-glow)" />
                  <ellipse cx="0" cy="6" rx="10" ry="3" fill="rgba(0,0,0,0.25)" />
                  {/* peper-vorm */}
                  <path d="M -2 -14 Q -1 -18 2 -18 L 5 -22 L 8 -18 Q 11 -16 12 -8 Q 13 14 0 18 Q -13 14 -12 -6 Q -11 -16 -2 -14 Z"
                    fill="#E63946" stroke="#1A1A1A" strokeWidth="2" strokeLinejoin="round" />
                  {/* hooglicht op peper */}
                  <path d="M -8 -8 Q -10 0 -7 8 Q -4 4 -5 -2 Q -7 -6 -8 -8 Z"
                    fill="rgba(255,255,255,0.4)" />
                  {/* steeltje */}
                  <path d="M 5 -22 L 8 -18 L 6 -14 Q 4 -16 5 -22 Z"
                    fill="#3FA34D" stroke="#1A1A1A" strokeWidth="1.5" strokeLinejoin="round" />
                  {/* sparkle */}
                  <g opacity={(0.3 + 0.7 * (Math.sin(animRef.current * 6 + c.x * 0.02) * 0.5 + 0.5))}>
                    <path d={`M 14 -16 l 0 4 m -2 -2 l 4 0`}
                      stroke="#FFE56F" strokeWidth="1.5" strokeLinecap="round" />
                  </g>
                </g>
              ))}

              {/* vijanden */}
              {enemiesRef.current.map(e => {
                if (!e.alive) {
                  // squashed visualisation, fade out
                  const sq = Math.min(1, e.sq * 5);
                  if (sq >= 1) return null;
                  return (
                    <g key={e.id} transform={`translate(${e.x + e.w / 2} ${e.y + e.h - 4})`} opacity={1 - sq}>
                      <ellipse cx="0" cy="0" rx={e.w * 0.6} ry={6} fill="#C8C2B4" stroke="#1A1A1A" strokeWidth="2" />
                    </g>
                  );
                }
                return <WasknijperWalk key={e.id} x={e.x} y={e.y} w={e.w} h={e.h} t={animRef.current * 6 + e.x * 0.02} />;
              })}

              {/* einddoel: vlag met wapperende animatie */}
              <g transform={`translate(${GOAL_X + 30} ${FIELD_H - GROUND_H - 200})`}>
                {/* glow halo achter vlag */}
                <circle cx="40" cy="20" r="60" fill="url(#sp-coin-glow)" />
                {/* paal */}
                <rect x="-3" y="0" width="6" height="200" fill="#5A3A18" stroke="#1A1A1A" strokeWidth="2" />
                <rect x="-3" y="0" width="2" height="200" fill="rgba(255,255,255,0.3)" />
                {/* gouden bol bovenop */}
                <circle cx="0" cy="-2" r="8" fill="#FFD23F" stroke="#1A1A1A" strokeWidth="2" />
                <circle cx="-2" cy="-4" r="2.5" fill="rgba(255,255,255,0.7)" />
                {/* wapperende vlag */}
                <path d={`M 3 6
                  Q ${20 + Math.sin(animRef.current * 4) * 4} ${10 + Math.sin(animRef.current * 4) * 2}
                    ${44 + Math.sin(animRef.current * 4 + 1) * 5} ${14 + Math.sin(animRef.current * 4 + 1) * 3}
                  Q ${66 + Math.sin(animRef.current * 4 + 2) * 5} ${18 + Math.sin(animRef.current * 4 + 2) * 3}
                    80 22
                  Q ${66 + Math.sin(animRef.current * 4 + 2.5) * 5} ${24 + Math.sin(animRef.current * 4 + 2.5) * 2}
                    ${44 + Math.sin(animRef.current * 4 + 1.5) * 5} ${28 + Math.sin(animRef.current * 4 + 1.5) * 3}
                  Q ${20 + Math.sin(animRef.current * 4 + 0.5) * 4} ${30 + Math.sin(animRef.current * 4 + 0.5) * 2}
                    3 32 Z`}
                  fill="#E63946" stroke="#1A1A1A" strokeWidth="2.5" strokeLinejoin="round" />
                {/* peper-icoontje op vlag */}
                <text x="42" y="24" textAnchor="middle"
                  fontFamily="Bangers, sans-serif" fontSize="20" fill="#FFE56F"
                  stroke="#1A1A1A" strokeWidth="0.5"
                  letterSpacing="1">🌶️</text>
              </g>

              {/* speler */}
              <g transform={`translate(${p.x + PLAYER_W / 2} ${p.y + PLAYER_H / 2 + runBob}) scale(${p.facing} 1)`}>
                {/* glow als in de lucht (springen) */}
                {!p.grounded && (
                  <circle cx="0" cy="0" r={PLAYER_W * 0.7} fill="url(#sp-coin-glow)" opacity="0.6" />
                )}
                {/* schaduw op de grond */}
                <ellipse cx="0" cy={PLAYER_H / 2 - 4} rx={PLAYER_W * 0.5} ry={5} fill="rgba(0,0,0,0.35)" />
                {/* dust onder voeten als rennend */}
                {p.grounded && Math.abs(p.vx) > 100 && (
                  <g opacity="0.6">
                    <ellipse cx={-PLAYER_W * 0.45} cy={PLAYER_H / 2 - 6} rx={6 + Math.sin(p.run * 2) * 2} ry="3" fill="rgba(200,180,140,0.7)" />
                    <ellipse cx={-PLAYER_W * 0.65} cy={PLAYER_H / 2 - 8} rx={4 + Math.sin(p.run * 2 + 1) * 2} ry="2" fill="rgba(200,180,140,0.5)" />
                  </g>
                )}
                <image href="/assets/super-peper.png"
                  x={-PLAYER_W / 2 - 4} y={-PLAYER_H / 2 - 6}
                  width={PLAYER_W + 8} height={PLAYER_H + 8}
                  preserveAspectRatio="xMidYMid meet"
                  style={{ filter: "drop-shadow(2px 4px 0 rgba(0,0,0,0.4))" }} />
              </g>

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

            {/* HUD overlay (in viewport coords) */}
            {phase === "playing" && (
              <g>
                {/* level voortgang */}
                <rect x="20" y="20" width={FIELD_W - 40} height="10"
                  fill="rgba(0,0,0,0.35)" stroke="#FFF" strokeWidth="1.5" rx="3" />
                <rect x="20" y="20" width={(FIELD_W - 40) * Math.min(1, p.x / GOAL_X)} height="10"
                  fill="#FFD23F" stroke="#1A1A1A" strokeWidth="1" rx="3" />
              </g>
            )}
          </svg>

          {/* mobiele besturingsknoppen */}
          {phase === "playing" && (
            <div style={{
              position: "absolute", left: 0, right: 0, bottom: 12,
              display: "flex", justifyContent: "space-between",
              padding: "0 16px", pointerEvents: "none",
              userSelect: "none",
            }}>
              <div style={{ display: "flex", gap: 10, pointerEvents: "auto" }}>
                <ControlBtn label="◀" onDown={btnDown("left")} onUp={btnUp("left")} />
                <ControlBtn label="▶" onDown={btnDown("right")} onUp={btnUp("right")} />
              </div>
              <div style={{ pointerEvents: "auto" }}>
                <ControlBtn label="↑" big onDown={btnDown("jump")} onUp={btnUp("jump")} />
              </div>
            </div>
          )}

          {phase === "intro" && (
            <Overlay>
              <Title color="#3FA34D">SUPER PEPER</Title>
              <p style={overlayText}>
                Help Super Peper zijn weg naar de vlag!
                <br />Spring met <strong>Spatie</strong> / <strong>↑</strong>,
                loop met <strong>← →</strong>.
                Op de telefoon: gebruik de knoppen onderaan.
                Spring op wasknijpers om ze te verslaan, en verzamel pepers!
              </p>
              <BigButton onClick={startGame} color="#5BB85B" style={{ color: "#FFF" }}>
                ▶ START
              </BigButton>
            </Overlay>
          )}
          {phase === "won" && (
            <Overlay>
              <Title color="#FFD23F">LEVEL {levelIdx + 1} UIT!</Title>
              <p style={overlayText}>
                Score: <strong>{score}</strong> · 🏆 Beste: {best}
                <br />Pepers verzameld: {coinsCol} · Levens over: {lives}
                <br />Nog {LEVEL_COUNT - levelIdx - 1} levels te gaan!
              </p>
              <div style={{ display: "flex", gap: 10, justifyContent: "center", flexWrap: "wrap" }}>
                <BigButton onClick={gotoNextLevel} color="#5BB85B" style={{ color: "#FFF" }}>
                  ▶ VOLGEND LEVEL
                </BigButton>
                <BigButton onClick={startGame} color="#FFD23F">
                  ↻ OPNIEUW VANAF 1
                </BigButton>
              </div>
            </Overlay>
          )}
          {phase === "complete" && (
            <Overlay>
              <Title color="#3FA34D">ALLE LEVELS UIT!</Title>
              <p style={overlayText}>
                Wauw, je hebt alle {LEVEL_COUNT} levels gehaald!
                <br />Eindscore: <strong>{score + lives * 200}</strong> · 🏆 Beste: {best}
                <br />Pepers: {coinsCol} · Levens over: {lives} (×200 bonus)
              </p>
              <BigButton onClick={startGame} color="#5BB85B" style={{ color: "#FFF" }}>
                ↻ NOG EENS VANAF 1
              </BigButton>
            </Overlay>
          )}
          {phase === "lost" && (
            <Overlay>
              <Title color="#E63946">GAME OVER</Title>
              <p style={overlayText}>
                Je haalde level {levelIdx + 1}. Score: <strong>{score}</strong>.
                <br />Helaas, geen levens meer.
              </p>
              <BigButton onClick={retry} color="#5BB85B" style={{ color: "#FFF" }}>
                ↻ OPNIEUW
              </BigButton>
            </Overlay>
          )}
        </div>
      </div>
    </div>
  );
}

function overlap(ax, ay, aw, ah, bx, by, bw, bh) {
  return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
}

const overlayText = { fontSize: 17, lineHeight: 1.4, maxWidth: 460, margin: "0 0 16px" };

function Pill({ children, bg, color, narrow }) {
  return (
    <div style={{
      background: bg, color,
      border: "3px solid #1A1A1A", boxShadow: "3px 3px 0 #1A1A1A",
      padding: narrow ? "4px 10px" : "6px 12px",
      fontFamily: "'Bangers', sans-serif",
      fontSize: narrow ? 16 : 18, letterSpacing: "0.04em",
      whiteSpace: "nowrap",
    }}>{children}</div>
  );
}

function Title({ children, color }) {
  return (
    <div style={{
      fontFamily: "'Bangers', sans-serif", fontSize: 44,
      color, letterSpacing: "0.04em", lineHeight: 1,
      WebkitTextStroke: "1.5px #1A1A1A",
      textShadow: "4px 4px 0 #1A1A1A",
      marginBottom: 12,
    }}>{children}</div>
  );
}

function Overlay({ children }) {
  return (
    <div style={{
      position: "absolute", inset: 0,
      display: "flex", alignItems: "center", justifyContent: "center",
      background: "rgba(0,0,0,0.55)",
      padding: 16, textAlign: "center", color: "#FFF",
    }}>
      <div style={{
        background: "#FFF8EC",
        border: "5px solid #1A1A1A",
        boxShadow: "6px 6px 0 #1A1A1A",
        padding: "22px 26px",
        maxWidth: 520, color: "#1A1A1A",
        transform: "rotate(-0.5deg)",
      }}>
        {children}
      </div>
    </div>
  );
}

function ControlBtn({ label, onDown, onUp, big = false }) {
  const sz = big ? 76 : 60;
  return (
    <button
      onPointerDown={onDown}
      onPointerUp={onUp}
      onPointerCancel={onUp}
      onPointerLeave={onUp}
      style={{
        width: sz, height: sz, borderRadius: "50%",
        background: big ? "#FFD23F" : "rgba(255,255,255,0.8)",
        border: "3px solid #1A1A1A",
        boxShadow: "3px 3px 0 #1A1A1A",
        fontFamily: "'Bangers', sans-serif",
        fontSize: big ? 30 : 26,
        color: "#1A1A1A",
        cursor: "pointer", touchAction: "none",
      }}>{label}</button>
  );
}

function PlatformShape({ pf }) {
  if (pf.kind === "ground") {
    return (
      <g>
        {/* basislaag aarde met diepte */}
        <rect x={pf.x} y={pf.y + 14} width={pf.w} height={pf.h - 14} fill="url(#sp-ground)" stroke="#1A1A1A" strokeWidth="2.5" />
        {/* graslaag bovenop */}
        <rect x={pf.x} y={pf.y} width={pf.w} height="18" fill="url(#sp-grass-top)" stroke="#1A1A1A" strokeWidth="2.5" />
        {/* hooglicht op gras */}
        <rect x={pf.x + 1} y={pf.y + 1} width={pf.w - 2} height="3" fill="rgba(255,255,255,0.35)" />
        {/* gras-tufts in twee maten */}
        {Array.from({ length: Math.floor(pf.w / 22) }).map((_, i) => {
          const gx = pf.x + 10 + i * 22 + (i % 3) * 3;
          return (
            <path key={i}
              d={`M ${gx} ${pf.y + 1} l 2 -7 l 2 4 l 2 -8 l 2 8 l 2 -4 l 2 7`}
              stroke="#1F6826" strokeWidth="1.5" fill="none" strokeLinejoin="round" />
          );
        })}
        {/* steentjes en stippen in aarde */}
        {Array.from({ length: Math.floor(pf.w / 45) }).map((_, i) => (
          <g key={i}>
            <circle cx={pf.x + 22 + i * 45} cy={pf.y + 30 + (i % 2) * 8} r="3"
              fill="#3A2410" stroke="#1A1A1A" strokeWidth="1" />
            <circle cx={pf.x + 22 + i * 45 - 1} cy={pf.y + 29 + (i % 2) * 8} r="1"
              fill="rgba(255,255,255,0.3)" />
          </g>
        ))}
        {/* horizontale grond-detail-lijn */}
        <line x1={pf.x} y1={pf.y + 26} x2={pf.x + pf.w} y2={pf.y + 26}
          stroke="rgba(0,0,0,0.2)" strokeWidth="1" strokeDasharray="6 4" />
      </g>
    );
  }
  if (pf.kind === "brick") {
    const brickW = 22;
    const brickH = 12;
    const cols = Math.ceil(pf.w / brickW);
    const rows = Math.ceil(pf.h / brickH);
    return (
      <g>
        <rect x={pf.x} y={pf.y} width={pf.w} height={pf.h} fill="url(#sp-brick)" stroke="#1A1A1A" strokeWidth="2.5" />
        {/* bevels: lichte rand boven, donkere onder */}
        <rect x={pf.x + 2} y={pf.y + 2} width={pf.w - 4} height="3" fill="rgba(255,220,180,0.5)" />
        <rect x={pf.x + 2} y={pf.y + pf.h - 4} width={pf.w - 4} height="2" fill="rgba(0,0,0,0.4)" />
        {/* baksteen-patroon, in rijen verschoven */}
        {Array.from({ length: rows }).map((_, ri) => (
          <g key={ri}>
            <line x1={pf.x} y1={pf.y + (ri + 1) * brickH}
              x2={pf.x + pf.w} y2={pf.y + (ri + 1) * brickH}
              stroke="rgba(0,0,0,0.45)" strokeWidth="1.2" />
            {Array.from({ length: cols + 1 }).map((_, ci) => {
              const offset = ri % 2 === 0 ? 0 : brickW / 2;
              const lx = pf.x + ci * brickW + offset;
              if (lx <= pf.x || lx >= pf.x + pf.w) return null;
              return (
                <line key={ci}
                  x1={lx} y1={pf.y + ri * brickH}
                  x2={lx} y2={pf.y + (ri + 1) * brickH}
                  stroke="rgba(0,0,0,0.45)" strokeWidth="1.2" />
              );
            })}
          </g>
        ))}
        {/* zachte glans bovenaan voor 3D-effect */}
        <ellipse cx={pf.x + pf.w * 0.3} cy={pf.y + 4} rx={pf.w * 0.25} ry="3"
          fill="rgba(255,255,255,0.4)" />
      </g>
    );
  }
  if (pf.kind === "pipe") {
    return (
      <g>
        {/* schaduw onder pipe-cap */}
        <rect x={pf.x - 2} y={pf.y + 18} width={pf.w + 4} height="3" fill="rgba(0,0,0,0.3)" />
        {/* pipe-cap met cap-rand-detail */}
        <rect x={pf.x - 6} y={pf.y} width={pf.w + 12} height="20"
          fill="url(#sp-pipe-cap)" stroke="#1A1A1A" strokeWidth="2.5" />
        <rect x={pf.x - 6} y={pf.y + 1} width={pf.w + 12} height="3"
          fill="rgba(255,255,255,0.35)" />
        <line x1={pf.x - 6} y1={pf.y + 14} x2={pf.x + pf.w + 6} y2={pf.y + 14}
          stroke="rgba(0,0,0,0.4)" strokeWidth="1.5" />
        {/* pipe body met cylindrische shading */}
        <rect x={pf.x} y={pf.y + 20} width={pf.w} height={pf.h - 20}
          fill="url(#sp-pipe)" stroke="#1A1A1A" strokeWidth="2.5" />
        {/* hooglicht-streep */}
        <rect x={pf.x + 8} y={pf.y + 22} width="4" height={pf.h - 24}
          fill="rgba(255,255,255,0.5)" />
        {/* glans-vlek op cap */}
        <rect x={pf.x + 4} y={pf.y + 5} width="8" height="6"
          fill="rgba(255,255,255,0.7)" />
      </g>
    );
  }
  return null;
}

function WasknijperWalk({ x, y, w, h, t }) {
  const stride = Math.sin(t) * 4;
  return (
    <g transform={`translate(${x + w / 2} ${y + h / 2})`}>
      <ellipse cx="0" cy={h / 2 + 2} rx={w * 0.5} ry={4} fill="rgba(0,0,0,0.3)" />
      {/* benen met houten textuur */}
      <path d={`M ${-w * 0.18} ${-h * 0.05} L ${-w * 0.3 + stride} ${h * 0.5} L ${-w * 0.16 + stride} ${h * 0.5} L ${-w * 0.06} ${-h * 0.05} Z`}
        fill="#C8C2B4" stroke="#1A1A1A" strokeWidth="2.5" strokeLinejoin="round" />
      <path d={`M ${-w * 0.16 + stride / 2} ${-h * 0.05} L ${-w * 0.22 + stride * 0.7} ${h * 0.4}`}
        stroke="rgba(0,0,0,0.3)" strokeWidth="1.2" />
      <path d={`M ${w * 0.18} ${-h * 0.05} L ${w * 0.3 - stride} ${h * 0.5} L ${w * 0.16 - stride} ${h * 0.5} L ${w * 0.06} ${-h * 0.05} Z`}
        fill="#B5AD9C" stroke="#1A1A1A" strokeWidth="2.5" strokeLinejoin="round" />
      <path d={`M ${w * 0.16 - stride / 2} ${-h * 0.05} L ${w * 0.22 - stride * 0.7} ${h * 0.4}`}
        stroke="rgba(0,0,0,0.3)" strokeWidth="1.2" />
      {/* kop */}
      <path d={`M ${-w * 0.32} ${-h * 0.05} Q ${-w * 0.32} ${-h * 0.4} 0 ${-h * 0.45} Q ${w * 0.32} ${-h * 0.4} ${w * 0.32} ${-h * 0.05} L ${w * 0.24} 0 L ${-w * 0.24} 0 Z`}
        fill="#D8D0C2" stroke="#1A1A1A" strokeWidth="2.5" strokeLinejoin="round" />
      {/* hooglicht op kop */}
      <ellipse cx={-w * 0.14} cy={-h * 0.32} rx={w * 0.1} ry="6" fill="rgba(255,255,255,0.4)" />
      {/* houtnerf-detail */}
      <path d={`M ${-w * 0.2} ${-h * 0.1} Q 0 ${-h * 0.15} ${w * 0.2} ${-h * 0.1}`}
        stroke="rgba(0,0,0,0.25)" strokeWidth="1" fill="none" />
      {/* veer (metalen scharnier) */}
      <ellipse cx="0" cy={-h * 0.07} rx={w * 0.2} ry={w * 0.11}
        fill="#9B9485" stroke="#1A1A1A" strokeWidth="2" />
      <ellipse cx={-w * 0.05} cy={-h * 0.1} rx={w * 0.06} ry="3" fill="rgba(255,255,255,0.5)" />
      <circle cx="0" cy={-h * 0.07} r={w * 0.08} fill="#5A5247" stroke="#1A1A1A" strokeWidth="1.5" />
      {/* boze wenkbrauwen */}
      <path d={`M ${-w * 0.22} ${-h * 0.34} L ${-w * 0.04} ${-h * 0.24}`} stroke="#1A1A1A" strokeWidth="3" strokeLinecap="round" />
      <path d={`M ${w * 0.22} ${-h * 0.34} L ${w * 0.04} ${-h * 0.24}`} stroke="#1A1A1A" strokeWidth="3" strokeLinecap="round" />
      {/* ogen met wit */}
      <circle cx={-w * 0.13} cy={-h * 0.18} r="3.5" fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
      <circle cx={w * 0.13} cy={-h * 0.18} r="3.5" fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
      <circle cx={-w * 0.12} cy={-h * 0.17} r="2" fill="#1A1A1A" />
      <circle cx={w * 0.12} cy={-h * 0.17} r="2" fill="#1A1A1A" />
      <circle cx={-w * 0.11} cy={-h * 0.18} r="0.8" fill="#FFF" />
      <circle cx={w * 0.13} cy={-h * 0.18} r="0.8" fill="#FFF" />
      {/* mond, gefronst */}
      <path d={`M ${-w * 0.16} ${-h * 0.04} Q 0 ${-h * 0.1} ${w * 0.16} ${-h * 0.04}`}
        stroke="#1A1A1A" strokeWidth="2.5" fill="none" strokeLinecap="round" />
      {/* mini-tand */}
      <rect x={-1} y={-h * 0.075} width="2" height="3" fill="#FFF" stroke="#1A1A1A" strokeWidth="0.8" />
    </g>
  );
}

Object.assign(window, { SuperPeper });
