Please remove the buttons at the bottom: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, viewport-fit=cover" />
<title>Touchscreen Snake Game with 3 Apples</title>
<style>
  /* Reset */
  * {
    box-sizing: border-box;
  }
  html, body {
    margin: 0; padding: 0;
    height: 100%;
    background: #111;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    overscroll-behavior: none;
    user-select: none;
  }
  body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    height: 100vh;
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
    background: linear-gradient(45deg, #0f2027, #203a43, #2c5364);
  }
  #game {
    position: relative;
    width: 90vmin;
    height: 90vmin;
    max-width: 720px;
    max-height: 720px;
    border: 5px solid #00ff99;
    border-radius: 24px;
    background: #111;
    box-shadow: 0 0 30px #00ff99cc inset;
    touch-action: none; /* prevent default gestures */
  }
  canvas {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 24px;
    background: #111;
  }
  #scoreboard {
    position: absolute;
    top: 12px;
    left: 50%;
    transform: translateX(-50%);
    color: #00ff99;
    font-weight: 700;
    font-size: 2rem;
    text-shadow: 0 0 20px #00ff99;
    user-select: none;
    pointer-events: none;
    z-index: 10;
    font-variant-numeric: tabular-nums;
  }

  /* Controls container with 4 buttons spaced as requested */
  #controls {
    width: 100%;
    max-width: 720px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    padding: 16px 14px;
    background: #0c1a20;
    border-top: 3px solid #00ff99;
    box-shadow: 0 -6px 20px #00ff9977;
    border-radius: 0 0 24px 24px;
    user-select: none;
    gap: 16px;
  }
  .btn {
    background: #00ff99;
    border: none;
    border-radius: 16px;
    padding: 22px 0;
    color: #111;
    font-weight: 700;
    font-size: 2rem;
    box-shadow: 0 0 30px #00ff99;
    cursor: pointer;
    user-select: none;
    transition: background 0.2s ease, box-shadow 0.3s ease;
    width: 100%;
    max-width: none;
    text-align: center;
    touch-action: manipulation;
    /* Make buttons easier to tap */
    min-height: 64px;
  }
  .btn:active {
    background: #00cc77;
    box-shadow: 0 0 40px #00cc77 inset;
  }
  /* Position buttons as per requirement:
     Left button on far left (grid column 1)
     Up button second from left (grid column 2)
     Down button second from right (grid column 3)
     Right button far right (grid column 4)
  */
  button[data-dir="left"] {
    grid-column: 1 / 2;
  }
  button[data-dir="up"] {
    grid-column: 2 / 3;
  }
  button[data-dir="down"] {
    grid-column: 3 / 4;
  }
  button[data-dir="right"] {
    grid-column: 4 / 5;
  }

  @media (max-width: 480px) {
    #game {
      width: 95vmin;
      height: 95vmin;
      max-width: 100vw;
      max-height: 100vw;
      border-width: 4px;
      border-radius: 20px;
      box-shadow: 0 0 20px #00ff99aa inset;
    }
    #scoreboard {
      font-size: 1.6rem;
      top: 8px;
    }
    #controls {
      max-width: 100vw;
      padding: 12px 10px;
      gap: 12px;
      border-top-width: 2px;
      border-radius: 0 0 20px 20px;
      box-shadow: 0 -5px 15px #00ff9977;
    }
    .btn {
      font-size: 1.6rem;
      padding: 18px 0;
      min-height: 56px;
      border-radius: 12px;
      box-shadow: 0 0 20px #00ff99;
    }
  }
</style>
</head>
<body>

<div id="game">
  <canvas id="canvas" width="720" height="720" aria-label="Snake game canvas" role="img"></canvas>
  <div id="scoreboard" aria-live="polite" aria-atomic="true">Score: 0</div>
</div>

<div id="controls" aria-label="Directional controls">
  <button class="btn" data-dir="left" aria-label="Move left" type="button">←</button>
  <button class="btn" data-dir="up" aria-label="Move up" type="button">↑</button>
  <button class="btn" data-dir="down" aria-label="Move down" type="button">↓</button>
  <button class="btn" data-dir="right" aria-label="Move right" type="button">→</button>
</div>

<script>
(() => {
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  const scoreboard = document.getElementById('scoreboard');
  const controls = document.querySelectorAll('.btn');

  // Increase grid size for larger screen and smoother visuals
  const gridSize = 30; // size of one square (increased from 20)
  const tileCount = canvas.width / gridSize; // 24x24 grid (720/30=24)

  // Initial snake state
  let snake = [
    { x: 12, y: 12 },
    { x: 11, y: 12 },
    { x: 10, y: 12 }
  ];
  let velocity = { x: 1, y: 0 };
  let nextVelocity = { x: 1, y: 0 };
  let apples = [];
  const maxApples = 3;
  let score = 0;
  let gameOver = false;

  // Create gradients every frame for dynamic glow effect
  function createSnakeGradient() {
    const grad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
    grad.addColorStop(0, "#00ff99");
    grad.addColorStop(1, "#00ffaa");
    return grad;
  }
  function createAppleGradient() {
    const grad = ctx.createRadialGradient(0, 0, 7, 0, 0, 18);
    grad.addColorStop(0, "#ff4444");
    grad.addColorStop(1, "#990000");
    return grad;
  }

  // Draw rounded rect helper
  function roundedRect(x, y, w, h, r) {
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.lineTo(x + w - r, y);
    ctx.quadraticCurveTo(x + w, y, x + w, y + r);
    ctx.lineTo(x + w, y + h - r);
    ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
    ctx.lineTo(x + r, y + h);
    ctx.quadraticCurveTo(x, y + h, x, y + h - r);
    ctx.lineTo(x, y + r);
    ctx.quadraticCurveTo(x, y, x + r, y);
    ctx.closePath();
    ctx.fill();
  }

  // Spawn apples on empty tiles
  function spawnApples() {
    while (apples.length < maxApples) {
      let pos = {
        x: Math.floor(Math.random() * tileCount),
        y: Math.floor(Math.random() * tileCount)
      };
      if (isCellEmpty(pos.x, pos.y)) {
        apples.push(pos);
      }
    }
  }

  // Check if a tile is free (no snake, no apple)
  function isCellEmpty(x, y) {
    for (let s of snake) {
      if (s.x === x && s.y === y) return false;
    }
    for (let a of apples) {
      if (a.x === x && a.y === y) return false;
    }
    return true;
  }

  // Draw everything
  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Background subtle grid lines
    ctx.strokeStyle = "#222";
    ctx.lineWidth = 1;
    for (let i = 0; i <= tileCount; i++) {
      ctx.beginPath();
      ctx.moveTo(i * gridSize, 0);
      ctx.lineTo(i * gridSize, canvas.height);
      ctx.stroke();
      ctx.beginPath();
      ctx.moveTo(0, i * gridSize);
      ctx.lineTo(canvas.width, i * gridSize);
      ctx.stroke();
    }

    // Draw apples with glow
    apples.forEach(({x, y}) => {
      const cx = x * gridSize + gridSize/2;
      const cy = y * gridSize + gridSize/2;

      ctx.save();
      ctx.translate(cx, cy);
      ctx.shadowColor = '#ff4444';
      ctx.shadowBlur = 24;
      ctx.fillStyle = createAppleGradient();
      ctx.beginPath();
      ctx.ellipse(0, 0, gridSize * 0.45, gridSize * 0.6, Math.PI / 6, 0, 2 * Math.PI);
      ctx.fill();

      // Apple leaf
      ctx.fillStyle = '#228822';
      ctx.beginPath();
      ctx.ellipse(0, -gridSize * 0.35, gridSize * 0.18, gridSize * 0.35, Math.PI / 4, 0, 2 * Math.PI);
      ctx.fill();

      ctx.restore();
    });

    // Draw snake with brighter glow
    ctx.fillStyle = createSnakeGradient();
    for (let i = 0; i < snake.length; i++) {
      const s = snake[i];
      const px = s.x * gridSize;
      const py = s.y * gridSize;

      ctx.save();
      ctx.shadowColor = '#00ffcc';
      ctx.shadowBlur = i === 0 ? 32 : 22; // brighter glow for head
      roundedRect(px + 3, py + 3, gridSize - 6, gridSize - 6, 10);
      ctx.restore();
    }
  }

  // Move snake and handle game logic
  function update() {
    if (gameOver) return;

    // Update velocity from buffered direction
    if ((nextVelocity.x !== -velocity.x || nextVelocity.y !== -velocity.y) &&
        (nextVelocity.x !== velocity.x || nextVelocity.y !== velocity.y)) {
      velocity = nextVelocity;
    }

    // New head position
    const head = { x: snake[0].x + velocity.x, y: snake[0].y + velocity.y };

    // Wrap around screen edges
    if (head.x < 0) head.x = tileCount - 1;
    else if (head.x >= tileCount) head.x = 0;
    if (head.y < 0) head.y = tileCount - 1;
    else if (head.y >= tileCount) head.y = 0;

    // Check collision with self
    for (let part of snake) {
      if (part.x === head.x && part.y === head.y) {
        gameOver = true;
        setTimeout(() => alert(`Game Over! Your score was ${score}. Refresh to play again.`), 100);
        return;
      }
    }

    snake.unshift(head);

    // Check apple eat
    let ateApple = false;
    for (let i = 0; i < apples.length; i++) {
      if (apples[i].x === head.x && apples[i].y === head.y) {
        apples.splice(i, 1);
        score++;
        ateApple = true;
        break;
      }
    }

    if (!ateApple) {
      snake.pop();
    } else {
      spawnApples();
    }

    scoreboard.textContent = `Score: ${score}`;
  }

  // Touch controls: improved swipe detection
  let touchStartX = null;
  let touchStartY = null;
  let touchStartTime = 0;
  const minSwipeDistance = 30;
  const maxSwipeTime = 500; // max time in ms for swipe to count

  canvas.addEventListener('touchstart', e => {
    if (e.touches.length === 1) {
      const t = e.touches[0];
      touchStartX = t.clientX;
      touchStartY = t.clientY;
      touchStartTime = e.timeStamp;
    }
  }, { passive: true });

  canvas.addEventListener('touchmove', e => {
    if (touchStartX === null || touchStartY === null) return;
    const t = e.touches[0];
    const dx = t.clientX - touchStartX;
    const dy = t.clientY - touchStartY;
    const dt = e.timeStamp - touchStartTime;

    if (dt > maxSwipeTime) {
      // Too slow, ignore swipe
      touchStartX = null;
      touchStartY = null;
      return;
    }

    if (Math.abs(dx) >= minSwipeDistance || Math.abs(dy) >= minSwipeDistance) {
      if (Math.abs(dx) > Math.abs(dy)) {
        // Horizontal swipe
        if (dx > 0) tryChangeDirection('right');
        else tryChangeDirection('left');
      } else {
        // Vertical swipe
        if (dy > 0) tryChangeDirection('down');
        else tryChangeDirection('up');
      }
      touchStartX = null;
      touchStartY = null;
    }
  }, { passive: true });

  canvas.addEventListener('touchend', e => {
    // Reset on touch end to avoid stuck state
    touchStartX = null;
    touchStartY = null;
  }, { passive: true });

  // Buttons for touch UI controls
  controls.forEach(btn => {
    btn.addEventListener('click', () => {
      tryChangeDirection(btn.dataset.dir);
    });
    // Also support touchstart for immediate response
    btn.addEventListener('touchstart', e => {
      e.preventDefault(); // prevent focus and ghost clicks
      tryChangeDirection(btn.dataset.dir);
    }, { passive: false });
  });

  // Change direction helper
  function tryChangeDirection(dir) {
    switch(dir) {
      case 'up':
        if (velocity.y === 0) nextVelocity = { x: 0, y: -1 };
        break;
      case 'down':
        if (velocity.y === 0) nextVelocity = { x: 0, y: 1 };
        break;
      case 'left':
        if (velocity.x === 0) nextVelocity = { x: -1, y: 0 };
        break;
      case 'right':
        if (velocity.x === 0) nextVelocity = { x: 1, y: 0 };
        break;
    }
  }

  // Game loop
  const fps = 10;
  let lastRender = 0;
  function gameLoop(time = 0) {
    if (time - lastRender > 1000 / fps) {
      lastRender = time;
      update();
      draw();
    }
    requestAnimationFrame(gameLoop);
  }

  // Initialize
  spawnApples();
  draw();
  requestAnimationFrame(gameLoop);
})();
</script>

</body>
</html>