// pac-peper.jsx, Pac-Man-achtige variant met Hete Peper. Eet alle pepertjes
// op in het doolhof terwijl je wasknijpers, ijsheksen en slijmpjes ontwijkt.
// Power-pepers maken vijanden tijdelijk bang, dan kan je ze opeten.

function PacPeper({ onClose }) {
  // doolhof, 1=muur, 0=pad, .=pellet, o=power-pellet, P=spawn, G=ghost spawn
  const RAW_MAZE = [
    "1111111111111111111",
    "1........1........1",
    "1o11.111.1.111.11o1",
    "1.................1",
    "1.11.1.11111.1.11.1",
    "1....1...1...1....1",
    "1111.111 1 111.1111",
    "   1.1       1.1   ",
    "11 1.1 11 11 1.1 11",
    "    .  1GGG1  .    ",
    "11 1.1 11111 1.1 11",
    "   1.1       1.1   ",
    "1111.1 11111 1.1111",
    "1........1........1",
    "1.11.111.1.111.11.1",
    "1o.1.....P.....1.o1",
    "11.1.1.11111.1.1.11",
    "1....1...1...1....1",
    "1.111111.1.111111.1",
    "1.................1",
    "1111111111111111111",
  ];

  const ROWS = RAW_MAZE.length;
  const COLS = RAW_MAZE[0].length;
  const CELL = 28;
  const FIELD_W = COLS * CELL;
  const FIELD_H = ROWS * CELL + 40; // ruimte voor HUD onderaan
  const PLAYER_R = CELL * 0.4;
  const GHOST_R = CELL * 0.4;
  const PLAYER_SPEED = 110; // px/s
  const GHOST_SPEED = 95;
  const SCARED_SPEED = 65;
  const SCARED_TIME = 6;

  const initGrid = React.useMemo(() => {
    return RAW_MAZE.map(row => row.split("").map(c => {
      if (c === "1") return { wall: true };
      return { wall: false, pellet: c === "." || (c !== " " && c !== "P" && c !== "G" && c !== "o") ? false : false };
    }));
    // We process pellets separately below
  }, []);

  const PELLETS_INIT = React.useMemo(() => {
    const list = [];
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        const ch = RAW_MAZE[r][c];
        if (ch === ".") list.push({ id: 'p' + r + '_' + c, r, c, power: false });
        else if (ch === "o") list.push({ id: 'p' + r + '_' + c, r, c, power: true });
      }
    }
    return list;
  }, []);

  // standaard speler-spawn en geest-spawn-cellen
  const PLAYER_SPAWN = React.useMemo(() => {
    for (let r = 0; r < ROWS; r++) {
      const c = RAW_MAZE[r].indexOf("P");
      if (c !== -1) return { r, c };
    }
    return { r: 9, c: 9 };
  }, []);
  const GHOST_SPAWNS = React.useMemo(() => {
    const list = [];
    for (let r = 0; r < ROWS; r++) {
      for (let c = 0; c < COLS; c++) {
        if (RAW_MAZE[r][c] === "G") list.push({ r, c });
      }
    }
    return list;
  }, []);
  const GHOST_TYPES = ["wasknijper", "ijsheks", "slijm", "wasknijper"];

  const [scale, setScale] = React.useState(1);
  const [narrow, setNarrow] = React.useState(typeof window !== "undefined" && window.innerWidth <= 600);
  const [phase, setPhase] = React.useState("intro");
  const [score, setScore] = React.useState(0);
  const [lives, setLives] = React.useState(3);
  const [best, setBest] = React.useState(() => {
    try { return parseInt(localStorage.getItem("pac-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);
  // speler en geesten worden opgeslagen in pixelposities (continu) plus richting
  const playerRef = React.useRef({ x: 0, y: 0, dir: "left", nextDir: "left", mouth: 0 });
  const ghostsRef = React.useRef([]);
  const pelletsRef = React.useRef([]);
  const scaredRef = React.useRef(0); // seconden over voor scared-mode
  const animRef = React.useRef(0);
  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);
    };
  }, [FIELD_W, FIELD_H]);

  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]);

  function isWall(r, c) {
    if (r < 0 || r >= ROWS || c < 0 || c >= COLS) return true;
    return RAW_MAZE[r][c] === "1";
  }

  function reset(fullReset = false) {
    playerRef.current = {
      x: PLAYER_SPAWN.c * CELL + CELL / 2,
      y: PLAYER_SPAWN.r * CELL + CELL / 2,
      dir: "left", nextDir: "left", mouth: 0,
    };
    ghostsRef.current = GHOST_TYPES.map((type, i) => {
      const sp = GHOST_SPAWNS[i % GHOST_SPAWNS.length] || { r: 9, c: 9 };
      return {
        id: 'g' + i, type,
        x: sp.c * CELL + CELL / 2, y: sp.r * CELL + CELL / 2,
        dir: ["up", "left", "right", "down"][i % 4],
        scared: false, eaten: false,
        spawn: sp,
        wob: i,
      };
    });
    if (fullReset) {
      pelletsRef.current = PELLETS_INIT.map(p => ({ ...p }));
      setScore(0);
      setLives(3);
      scaredRef.current = 0;
    }
  }

  function startGame() {
    reset(true);
    setPhase("playing");
  }

  // input: pijltjes, WASD, swipe
  const inputDirRef = React.useRef(null);
  React.useEffect(() => {
    function down(e) {
      let d = null;
      if (e.key === "ArrowUp" || e.key === "w" || e.key === "W") d = "up";
      else if (e.key === "ArrowDown" || e.key === "s" || e.key === "S") d = "down";
      else if (e.key === "ArrowLeft" || e.key === "a" || e.key === "A") d = "left";
      else if (e.key === "ArrowRight" || e.key === "d" || e.key === "D") d = "right";
      if (d) { inputDirRef.current = d; e.preventDefault(); }
    }
    window.addEventListener("keydown", down);
    return () => window.removeEventListener("keydown", down);
  }, []);

  // swipe op de canvas
  const swipeRef = React.useRef({ active: false, x: 0, y: 0 });
  function onPointerDown(e) {
    if (phase !== "playing") return;
    swipeRef.current = { active: true, x: e.clientX, y: e.clientY };
  }
  function onPointerMove(e) {
    if (!swipeRef.current.active) return;
    const dx = e.clientX - swipeRef.current.x;
    const dy = e.clientY - swipeRef.current.y;
    if (Math.abs(dx) > 18 || Math.abs(dy) > 18) {
      let d;
      if (Math.abs(dx) > Math.abs(dy)) d = dx > 0 ? "right" : "left";
      else d = dy > 0 ? "down" : "up";
      inputDirRef.current = d;
      swipeRef.current = { active: true, x: e.clientX, y: e.clientY };
    }
  }
  function onPointerUp() {
    swipeRef.current.active = false;
  }

  function setMobileDir(d) {
    inputDirRef.current = d;
  }

  // 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;

      // input toepassen: bij richtings-input proberen
      if (inputDirRef.current) p.nextDir = inputDirRef.current;

      // beweeg speler in dir of probeer naar nextDir te draaien
      moveEntity(p, PLAYER_SPEED, dt, true);

      // pellets eten
      const pr = Math.round((p.y - CELL / 2) / CELL);
      const pc = Math.round((p.x - CELL / 2) / CELL);
      for (const pl of pelletsRef.current) {
        if (pl.taken) continue;
        if (pl.r === pr && pl.c === pc) {
          pl.taken = true;
          setScore(s => s + (pl.power ? 50 : 10));
          if (pl.power) {
            scaredRef.current = SCARED_TIME;
            ghostsRef.current.forEach(g => { if (!g.eaten) g.scared = true; });
          }
        }
      }

      // scared-timer
      if (scaredRef.current > 0) {
        scaredRef.current -= dt;
        if (scaredRef.current <= 0) {
          scaredRef.current = 0;
          ghostsRef.current.forEach(g => { g.scared = false; });
        }
      }

      // beweeg geesten met simpele AI
      for (const g of ghostsRef.current) {
        const speed = g.eaten ? GHOST_SPEED * 1.6 : (g.scared ? SCARED_SPEED : GHOST_SPEED);
        if (g.eaten) {
          // ga terug naar spawn, dan gewoon
          const tx = g.spawn.c * CELL + CELL / 2;
          const ty = g.spawn.r * CELL + CELL / 2;
          if (Math.hypot(tx - g.x, ty - g.y) < 4) {
            g.eaten = false;
            g.scared = false;
            g.x = tx; g.y = ty;
          } else {
            // doelgerichte beweging negeren maze, ghosts kunnen door muren als ze "eaten" zijn
            const dx = tx - g.x, dy = ty - g.y;
            const d = Math.hypot(dx, dy) || 1;
            g.x += (dx / d) * speed * dt;
            g.y += (dy / d) * speed * dt;
            continue;
          }
        }
        // intersectie-check: alleen op grid-kruisingen kiezen
        if (atGridCenter(g)) {
          const target = g.scared
            ? { x: -1000, y: -1000 } // gewoon "weg"
            : { x: p.x, y: p.y };
          g.dir = pickGhostDir(g, target);
        }
        moveEntity(g, speed, dt, false);
      }

      // botsing speler-ghost
      for (const g of ghostsRef.current) {
        if (g.eaten) continue;
        if (Math.hypot(g.x - p.x, g.y - p.y) < PLAYER_R + GHOST_R - 4) {
          if (g.scared) {
            g.eaten = true;
            g.scared = false;
            setScore(s => s + 200);
          } else {
            // leven kwijt
            const newLives = lives - 1;
            if (newLives <= 0) {
              setPhase("lost");
              setBest(prev => {
                if (score > prev) {
                  try { localStorage.setItem("pac-peper-best", String(score)); } catch {}
                  return score;
                }
                return prev;
              });
              return;
            }
            setLives(newLives);
            // herstart speler en geest-posities maar behoud score en pellets
            const px = PLAYER_SPAWN.c * CELL + CELL / 2;
            const py = PLAYER_SPAWN.r * CELL + CELL / 2;
            playerRef.current = { x: px, y: py, dir: "left", nextDir: "left", mouth: 0 };
            ghostsRef.current.forEach((gg, i) => {
              const sp = GHOST_SPAWNS[i % GHOST_SPAWNS.length] || { r: 9, c: 9 };
              gg.x = sp.c * CELL + CELL / 2;
              gg.y = sp.r * CELL + CELL / 2;
              gg.scared = false; gg.eaten = false;
              gg.dir = ["up", "left", "right", "down"][i % 4];
            });
            scaredRef.current = 0;
            return;
          }
        }
      }

      // win-check
      if (pelletsRef.current.every(pl => pl.taken)) {
        setBest(prev => {
          if (score > prev) {
            try { localStorage.setItem("pac-peper-best", String(score)); } catch {}
            return score;
          }
          return prev;
        });
        setPhase("won");
        return;
      }

      // mond animatie
      p.mouth = (Math.sin(animRef.current * 14) + 1) / 2;

      forceRender();
      raf = requestAnimationFrame(frame);
    }

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

  function atGridCenter(e) {
    const cx = ((e.x - CELL / 2) % CELL);
    const cy = ((e.y - CELL / 2) % CELL);
    const ax = ((cx + CELL) % CELL);
    const ay = ((cy + CELL) % CELL);
    return Math.abs(ax) < 2.5 && Math.abs(ay) < 2.5;
  }

  function dirVec(d) {
    if (d === "up") return [0, -1];
    if (d === "down") return [0, 1];
    if (d === "left") return [-1, 0];
    if (d === "right") return [1, 0];
    return [0, 0];
  }

  function opposite(d) {
    return { up: "down", down: "up", left: "right", right: "left" }[d];
  }

  function canMove(x, y, d) {
    const [vx, vy] = dirVec(d);
    const nx = x + vx * (CELL * 0.5);
    const ny = y + vy * (CELL * 0.5);
    const r = Math.floor(ny / CELL);
    const c = Math.floor(nx / CELL);
    return !isWall(r, c);
  }

  function moveEntity(e, speed, dt, isPlayer) {
    // probeer eerst nextDir als we op een grid-cel zitten
    if (isPlayer && e.nextDir && e.nextDir !== e.dir) {
      if (atGridCenter(e) && canMove(e.x, e.y, e.nextDir)) {
        // snap aan grid-center
        e.x = Math.round((e.x - CELL / 2) / CELL) * CELL + CELL / 2;
        e.y = Math.round((e.y - CELL / 2) / CELL) * CELL + CELL / 2;
        e.dir = e.nextDir;
      }
    }
    const [vx, vy] = dirVec(e.dir);
    const nx = e.x + vx * speed * dt;
    const ny = e.y + vy * speed * dt;
    if (canMoveTo(nx, ny, vx, vy)) {
      e.x = nx; e.y = ny;
    } else {
      // snap aan grid-center wanneer we tegen muur botsen
      e.x = Math.round((e.x - CELL / 2) / CELL) * CELL + CELL / 2;
      e.y = Math.round((e.y - CELL / 2) / CELL) * CELL + CELL / 2;
    }
    // tunnel-warp links/rechts
    if (e.x < -CELL / 2) e.x = FIELD_W - CELL / 2 + (CELL * 0.49);
    else if (e.x > FIELD_W + CELL / 2) e.x = -CELL / 2 + (CELL * 0.51);
  }

  function canMoveTo(nx, ny, vx, vy) {
    // neem het punt iets in de bewegingsrichting van de centerpunt
    const tx = nx + vx * (CELL * 0.45);
    const ty = ny + vy * (CELL * 0.45);
    const r = Math.floor(ty / CELL);
    const c = Math.floor(tx / CELL);
    return !isWall(r, c);
  }

  function pickGhostDir(g, target) {
    const dirs = ["up", "down", "left", "right"];
    const cur = g.dir;
    const opt = [];
    for (const d of dirs) {
      if (d === opposite(cur)) continue;
      const [vx, vy] = dirVec(d);
      const nx = g.x + vx * (CELL * 0.55);
      const ny = g.y + vy * (CELL * 0.55);
      const r = Math.floor(ny / CELL);
      const c = Math.floor(nx / CELL);
      if (isWall(r, c)) continue;
      const dist = Math.hypot(target.x - (c * CELL + CELL / 2), target.y - (r * CELL + CELL / 2));
      opt.push({ d, dist });
    }
    if (opt.length === 0) return opposite(cur);
    if (g.scared) {
      // willekeurige keuze als bang
      return opt[Math.floor(Math.random() * opt.length)].d;
    }
    opt.sort((a, b) => a.dist - b.dist);
    // kleine kans op willekeur, voor variatie
    if (Math.random() < 0.15 && opt.length > 1) return opt[1].d;
    return opt[0].d;
  }

  // visualisatie helpers
  function ghostColor(g) {
    if (g.eaten) return "#666";
    if (g.scared) return scaredRef.current < 1.5 && Math.floor(animRef.current * 6) % 2 === 0
      ? "#FFF" : "#3A4FB0";
    if (g.type === "wasknijper") return "#C8C2B4";
    if (g.type === "ijsheks") return "#8ECFF0";
    return "#7FDBA3";
  }
  function ghostStroke() { return "#1A1A1A"; }

  const pelletsLeft = pelletsRef.current.filter(p => !p.taken).length;

  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 200,
      background: "#0E0E2A",
      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: "#FFD23F",
          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 ? "PAC" : "PAC-PEPER"}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: narrow ? 6 : 10 }}>
          <Pill bg="#E63946" color="#FFF" narrow={narrow}>❤ {lives}</Pill>
          <Pill bg="#FF8C1A" color="#FFF" narrow={narrow}>🌶️ {pelletsLeft}</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}
            onPointerDown={onPointerDown}
            onPointerMove={onPointerMove}
            onPointerUp={onPointerUp}
            onPointerCancel={onPointerUp}
            style={{
              display: "block",
              border: "4px solid #1A1A1A",
              boxShadow: "5px 5px 0 #1A1A1A",
              touchAction: "none", userSelect: "none",
              cursor: "default",
            }}>
            <defs>
              <linearGradient id="pp-bg" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#15163E" />
                <stop offset="100%" stopColor="#080820" />
              </linearGradient>
              <linearGradient id="pp-wall" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#3A6FE0" />
                <stop offset="100%" stopColor="#1A3FA0" />
              </linearGradient>
              <radialGradient id="pp-power" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0%" stopColor="#FFEB78" />
                <stop offset="100%" stopColor="rgba(255,235,120,0.0)" />
              </radialGradient>
            </defs>

            <rect x="0" y="0" width={FIELD_W} height={FIELD_H} fill="url(#pp-bg)" />

            {/* muren */}
            {RAW_MAZE.map((row, r) => row.split("").map((ch, c) => {
              if (ch !== "1") return null;
              return (
                <rect key={`w${r}_${c}`}
                  x={c * CELL + 2} y={r * CELL + 2}
                  width={CELL - 4} height={CELL - 4}
                  fill="url(#pp-wall)" stroke="#80B0FF" strokeWidth="1.5" rx="3" />
              );
            }))}

            {/* pellets */}
            {pelletsRef.current.map(pl => pl.taken ? null : (
              pl.power ? (
                <g key={pl.id} transform={`translate(${pl.c * CELL + CELL / 2} ${pl.r * CELL + CELL / 2})`}>
                  <circle cx="0" cy="0" r={CELL * 0.4} fill="url(#pp-power)" opacity={0.6 + Math.sin(animRef.current * 8) * 0.3} />
                  <path d="M -2 -7 L 1 -10 L 4 -7 L 7 -8 L 6 -3 Q 6 6 0 9 Q -6 6 -6 -3 L -7 -8 Z"
                    fill="#E63946" stroke="#1A1A1A" strokeWidth="1.5" strokeLinejoin="round" />
                  <path d="M 4 -7 L 7 -8 L 5 -4 Z" fill="#3FA34D" stroke="#1A1A1A" strokeWidth="1" />
                </g>
              ) : (
                <circle key={pl.id}
                  cx={pl.c * CELL + CELL / 2}
                  cy={pl.r * CELL + CELL / 2}
                  r={3.5}
                  fill="#FFD23F" stroke="#1A1A1A" strokeWidth="0.8" />
              )
            ))}

            {/* spookhuis-deur visualisatie */}
            <line x1={(GHOST_SPAWNS[0]?.c || 9) * CELL}
              y1={(GHOST_SPAWNS[0]?.r || 9) * CELL}
              x2={((GHOST_SPAWNS[2]?.c || 11) + 1) * CELL}
              y2={(GHOST_SPAWNS[0]?.r || 9) * CELL}
              stroke="#FFB0D0" strokeWidth="3" />

            {/* speler (PacPeper) */}
            <PacPlayer player={playerRef.current} r={PLAYER_R} t={animRef.current} />

            {/* geesten */}
            {ghostsRef.current.map(g => (
              <Ghost key={g.id} g={g} r={GHOST_R}
                color={ghostColor(g)} stroke={ghostStroke()}
                t={animRef.current + g.wob} />
            ))}

            {/* footer-bar met scared-timer */}
            <g transform={`translate(0 ${ROWS * CELL})`}>
              <rect x="0" y="0" width={FIELD_W} height="40" fill="#0A0A1A" stroke="#80B0FF" strokeWidth="1.5" />
              <text x="14" y="24" fontFamily="Bangers, sans-serif" fontSize="18" fill="#FFD23F" letterSpacing="2">
                PEPERS: {PELLETS_INIT.length - pelletsLeft} / {PELLETS_INIT.length}
              </text>
              {scaredRef.current > 0 && (
                <g transform={`translate(${FIELD_W - 130} 14)`}>
                  <rect x="0" y="0" width="100" height="14"
                    fill="rgba(0,0,0,0.5)" stroke="#FFF" strokeWidth="1" rx="2" />
                  <rect x="0" y="0" width={100 * (scaredRef.current / SCARED_TIME)} height="14"
                    fill="#3A4FB0" stroke="#FFF" strokeWidth="1" rx="2" />
                  <text x="50" y="12" textAnchor="middle"
                    fontFamily="Bangers, sans-serif" fontSize="11" fill="#FFF">BANG!</text>
                </g>
              )}
            </g>
          </svg>

          {/* mobiele besturingsknoppen */}
          {phase === "playing" && (
            <div style={{
              position: "absolute",
              bottom: 12, right: 12,
              display: "grid",
              gridTemplateColumns: "repeat(3, 50px)",
              gridTemplateRows: "repeat(3, 50px)",
              gap: 4,
              pointerEvents: "none",
            }}>
              <div></div>
              <DPadBtn label="↑" onClick={() => setMobileDir("up")} />
              <div></div>
              <DPadBtn label="←" onClick={() => setMobileDir("left")} />
              <div></div>
              <DPadBtn label="→" onClick={() => setMobileDir("right")} />
              <div></div>
              <DPadBtn label="↓" onClick={() => setMobileDir("down")} />
              <div></div>
            </div>
          )}

          {phase === "intro" && (
            <Overlay>
              <Title color="#FFD23F">PAC-PEPER</Title>
              <p style={overlayText}>
                Eet alle pepertjes op in het doolhof! Wijk uit aan de wasknijpers,
                ijsheksen en slijmpjes. Pak de grote pepers (power-pepers) om ze
                tijdelijk bang te maken, dan kan je ze opeten!
                <br /><br />
                Pijltjes / WASD op desktop, swipe of D-pad op mobiel.
              </p>
              <BigButton onClick={startGame} color="#5BB85B" style={{ color: "#FFF" }}>
                ▶ START
              </BigButton>
            </Overlay>
          )}
          {phase === "won" && (
            <Overlay>
              <Title color="#FFD23F">PEPERS OP!</Title>
              <p style={overlayText}>
                Score: <strong>{score}</strong> · 🏆 Beste: {best}
              </p>
              <BigButton onClick={startGame} color="#5BB85B" style={{ color: "#FFF" }}>
                ↻ NOG EENS
              </BigButton>
            </Overlay>
          )}
          {phase === "lost" && (
            <Overlay>
              <Title color="#E63946">GAME OVER</Title>
              <p style={overlayText}>
                Score: <strong>{score}</strong> · 🏆 Beste: {best}
              </p>
              <BigButton onClick={startGame} color="#5BB85B" style={{ color: "#FFF" }}>
                ↻ OPNIEUW
              </BigButton>
            </Overlay>
          )}
        </div>
      </div>
    </div>
  );
}

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.65)",
      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 DPadBtn({ label, onClick }) {
  return (
    <button
      onPointerDown={(e) => { e.preventDefault(); onClick(); }}
      style={{
        width: 50, height: 50, borderRadius: 10,
        background: "rgba(255,210,63,0.92)",
        border: "3px solid #1A1A1A",
        boxShadow: "2px 2px 0 #1A1A1A",
        fontFamily: "'Bangers', sans-serif", fontSize: 24,
        color: "#1A1A1A",
        cursor: "pointer", touchAction: "none",
        pointerEvents: "auto",
      }}>{label}</button>
  );
}

function PacPlayer({ player, r, t }) {
  // Gebruikt de getekende Pac-Peper-asset, geroteerd of geflipt per richting.
  // Asset wijst standaard naar rechts.
  const dir = player.dir;
  let rot = 0, flipX = 1;
  if (dir === "right") { rot = 0; flipX = 1; }
  else if (dir === "down") { rot = 90; flipX = 1; }
  else if (dir === "left") { rot = 0; flipX = -1; }
  else if (dir === "up") { rot = -90; flipX = 1; }

  // Subtiele chomp-animatie via verticale schaal van de afbeelding
  const chomp = (Math.sin(t * 14) + 1) / 2; // 0..1
  const sy = 0.94 + chomp * 0.06;

  const size = r * 2.5;
  return (
    <g transform={`translate(${player.x.toFixed(1)} ${player.y.toFixed(1)})`}>
      {/* glow achter de peper */}
      <circle cx="0" cy="0" r={r + 6} fill="rgba(255,210,63,0.35)" />
      <g transform={`rotate(${rot}) scale(${flipX} 1)`}>
        <g transform={`scale(1 ${sy})`}>
          <image href="/assets/pac-peper.png"
            x={-size / 2} y={-size / 2}
            width={size} height={size}
            preserveAspectRatio="xMidYMid meet"
            style={{ filter: "drop-shadow(2px 3px 0 rgba(0,0,0,0.4))" }} />
        </g>
      </g>
    </g>
  );
}

function Ghost({ g, r, color, stroke, t }) {
  const wob = Math.sin(t * 4) * 1.5;
  const eyeOffset = (() => {
    if (g.dir === "left") return -2;
    if (g.dir === "right") return 2;
    return 0;
  })();
  const eyeY = (() => {
    if (g.dir === "up") return -r * 0.45;
    if (g.dir === "down") return -r * 0.2;
    return -r * 0.32;
  })();
  return (
    <g transform={`translate(${g.x.toFixed(1)} ${(g.y + wob).toFixed(1)})`}>
      <ellipse cx="0" cy={r + 4} rx={r * 0.85} ry={3} fill="rgba(0,0,0,0.3)" />
      {/* spook-vorm */}
      <path
        d={`M ${-r} ${r * 0.7} L ${-r} 0 A ${r} ${r} 0 1 1 ${r} 0 L ${r} ${r * 0.7} L ${r * 0.66} ${r * 0.45} L ${r * 0.33} ${r * 0.7} L 0 ${r * 0.45} L ${-r * 0.33} ${r * 0.7} L ${-r * 0.66} ${r * 0.45} Z`}
        fill={color} stroke={stroke} strokeWidth="2.5" strokeLinejoin="round" />
      {g.eaten ? (
        <>
          <circle cx={-r * 0.3} cy={-r * 0.32} r={r * 0.18} fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
          <circle cx={r * 0.3} cy={-r * 0.32} r={r * 0.18} fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
          <circle cx={-r * 0.3} cy={-r * 0.32} r={r * 0.08} fill="#1A1A1A" />
          <circle cx={r * 0.3} cy={-r * 0.32} r={r * 0.08} fill="#1A1A1A" />
        </>
      ) : g.scared ? (
        <>
          <circle cx={-r * 0.3} cy={-r * 0.32} r={r * 0.12} fill="#FFF" />
          <circle cx={r * 0.3} cy={-r * 0.32} r={r * 0.12} fill="#FFF" />
          <path d={`M ${-r * 0.6} ${r * 0.05} L ${-r * 0.4} ${-r * 0.05} L ${-r * 0.2} ${r * 0.05} L 0 ${-r * 0.05} L ${r * 0.2} ${r * 0.05} L ${r * 0.4} ${-r * 0.05} L ${r * 0.6} ${r * 0.05}`}
            stroke="#FFF" strokeWidth="2" fill="none" strokeLinecap="round" />
        </>
      ) : (
        <>
          <circle cx={-r * 0.32} cy={eyeY} r={r * 0.2} fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
          <circle cx={r * 0.32} cy={eyeY} r={r * 0.2} fill="#FFF" stroke="#1A1A1A" strokeWidth="1.5" />
          <circle cx={-r * 0.32 + eyeOffset * 1.5} cy={eyeY} r={r * 0.1} fill="#1A1A1A" />
          <circle cx={r * 0.32 + eyeOffset * 1.5} cy={eyeY} r={r * 0.1} fill="#1A1A1A" />
        </>
      )}
    </g>
  );
}

Object.assign(window, { PacPeper });
