I want different style visual when swioing: <!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"
  />
  <meta name="description" content="Play Cyber-Neon Snake, a modern twist on the classic snake game with vibrant visuals and effects.">
  <title>Cyber‑Neon Snake</title>
  <style>
    :root {
      --neon-green: #0f9;
      --neon-green-light: #0cffaa;
      --neon-green-dark: #0c7;
      --neon-cyan: #0ff;
      --neon-cyan-medium: #0cc; /* For hover/focus states */
      --neon-cyan-dark: #099;   /* For active states */
      
      --text-color-on-neon: #000;
      --text-color-primary: var(--neon-green);
      --text-color-flash: #fff;

      --bg-dark-primary: #111;
      --bg-gradient-1: #0f2027;
      --bg-gradient-2: #203a43;
      --bg-gradient-3: #2c5364;
      --bg-grid-lines: #222;
      --bg-modal-overlay: rgba(0,0,0,0.85);

      --border-radius-lg: 20px;
      --border-radius-md: 12px;

      --font-primary: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }

    /* Reset & Base */
    *, *::before, *::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    html, body {
      height: 100%;
      overflow: hidden;
      user-select: none; /* Applied globally */
      background: linear-gradient(45deg, var(--bg-gradient-1), var(--bg-gradient-2), var(--bg-gradient-3));
      background-size: 600% 600%;
      animation: bgShift 20s ease infinite;
      font-family: var(--font-primary);
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      color: var(--text-color-primary);
    }
    @keyframes bgShift {
      0% { background-position: 0% 50%; }
      50% { background-position: 100% 50%; }
      100% { background-position: 0% 50%; }
    }

    /* Game Frame */
    #game {
      position: relative;
      width: 90vmin;
      height: 90vmin;
      background: var(--bg-dark-primary);
      border: 4px solid var(--neon-green);
      border-radius: var(--border-radius-lg);
      box-shadow: inset 0 0 20px rgba(0, 255, 153, 0.66); /* #0f9a */
      touch-action: none;
      outline: none; /* For the main game container itself if focused */
      overflow: visible; /* Allow effects container visibility */
    }
    canvas {
      width: 100%;
      height: 100%;
      display: block;
      background: var(--bg-dark-primary); /* Match game background */
      border-radius: calc(var(--border-radius-lg) - 4px); /* Account for border */
    }

    /* Container for swipe effects overlays */
    #swipeEffectContainer {
      position: absolute;
      inset: 0;
      pointer-events: none;
      overflow: visible; /* Allow animation outside bounds */
      border-radius: calc(var(--border-radius-lg) - 4px);
      z-index: 10;
    }

    /* Swipe effect styles and animations */
    .swipe-effect {
      position: absolute;
      pointer-events: none;
      border-radius: 50%;
      opacity: 0.8;
      animation: swipePulse 0.5s ease forwards;
      filter: drop-shadow(0 0 8px cyan);
      mix-blend-mode: screen;
      will-change: transform, opacity;
    }
    .swipe-up {
      background: linear-gradient(180deg, var(--neon-cyan) 0%, transparent 80%);
      width: 80px;
      height: 160px;
      left: 50%;
      bottom: 10%;
      transform: translateX(-50%) translateY(0);
    }
    .swipe-down {
      background: linear-gradient(0deg, var(--neon-cyan) 0%, transparent 80%);
      width: 80px;
      height: 160px;
      left: 50%;
      top: 10%;
      transform: translateX(-50%) translateY(0);
    }
    .swipe-left {
      background: linear-gradient(90deg, var(--neon-cyan) 0%, transparent 80%);
      width: 160px;
      height: 80px;
      top: 50%;
      right: 10%;
      transform: translateY(-50%) translateX(0);
    }
    .swipe-right {
      background: linear-gradient(270deg, var(--neon-cyan) 0%, transparent 80%);
      width: 160px;
      height: 80px;
      top: 50%;
      left: 10%;
      transform: translateY(-50%) translateX(0);
    }

    @keyframes swipePulse {
      0% {
        transform: translateX(0) translateY(0) scale(1);
        opacity: 0.8;
      }
      50% {
        opacity: 0.5;
        scale: 1.3;
      }
      100% {
        opacity: 0;
        scale: 1.8;
      }
    }

    /* Neon Scoreboard */
    @keyframes neonFlicker {
      0%, 18%, 22%, 25%, 53%, 57%, 100% {
        text-shadow:
          0 0 5px var(--neon-green),
          0 0 10px var(--neon-green),
          0 0 20px var(--neon-green),
          0 0 40px var(--neon-cyan),
          0 0 80px var(--neon-cyan);
      }
      20%, 24%, 55% {
        text-shadow: none;
      }
    }
    #scoreboard {
      margin-top: 12px;
      text-align: center;
      font-size: 1.5rem;
      font-weight: 700;
      animation: neonFlicker 3s infinite;
    }
    #scoreboard.flash {
      color: var(--text-color-flash);
      text-shadow:
        0 0 25px var(--neon-cyan),
        0 0 50px var(--neon-cyan),
        0 0 75px var(--neon-cyan);
      transition: text-shadow 0.2s, color 0.2s;
    }

    /* Controls Buttons */
    .btn {
      background: var(--neon-green);
      border: none;
      border-radius: var(--border-radius-md);
      padding: 14px 0;
      font-size: 1.4rem;
      font-weight: 700;
      box-shadow: 0 0 20px var(--neon-green);
      cursor: pointer;
      transition: background 0.2s, box-shadow 0.2s, transform 0.1s, outline-color 0.2s;
      color: var(--text-color-on-neon);
      outline: 2px solid transparent; /* Base for focus transition */
      outline-offset: 2px;
    }
    .btn:hover,
    .btn:focus-visible {
      background: var(--neon-green-light);
      box-shadow: 0 0 30px var(--neon-green-light);
      outline-color: var(--neon-green-light);
      transform: scale(1.05);
    }
    .btn:active {
      background: var(--neon-green-dark);
      box-shadow: inset 0 0 30px var(--neon-green-dark);
      transform: scale(0.95);
    }
    #controls { /* Grid for control buttons */
      margin-top: 12px;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 12px;
      width: 90vmin;
      max-width: 400px;
    }
    @media (max-width: 400px) {
      .btn {
        font-size: 1.2rem;
        padding: 10px 0;
      }
    }

    /* Restart button (page) & Modal Button (shared styles) */
    .action-button { /* Common base for restart/modal buttons */
      background: var(--neon-cyan);
      color: var(--text-color-on-neon);
      border: none;
      border-radius: var(--border-radius-md);
      padding: 12px 0;
      font-size: 1.3rem;
      font-weight: 700;
      box-shadow: 0 0 25px var(--neon-cyan);
      cursor: pointer;
      transition: background 0.3s, box-shadow 0.3s, transform 0.2s, outline-color 0.2s;
      outline: 2px solid transparent; /* Base for focus transition */
      outline-offset: 2px;
    }
    .action-button:hover,
    .action-button:focus-visible {
      background: var(--neon-cyan-medium);
      box-shadow: 0 0 40px var(--neon-cyan-medium);
      outline-color: var(--neon-cyan-medium);
      transform: scale(1.05);
    }
    .action-button:active {
      background: var(--neon-cyan-dark);
      box-shadow: inset 0 0 30px var(--neon-cyan-dark);
      transform: scale(0.95);
    }

    #restartBtn {
      composes: action-button; /* Conceptual, apply class in HTML */
      margin-top: 16px;
      width: 90vmin;
      max-width: 400px;
      display: none; /* Controlled by JS */
    }

    /* Game Over Modal */
    #gameOverModal {
      position: fixed;
      top: 0; left: 0; right: 0; bottom: 0;
      background: var(--bg-modal-overlay);
      display: flex;
      align-items: center;
      justify-content: center;
      color: var(--text-color-primary);
      font-size: 2rem;
      font-weight: 700;
      text-align: center;
      padding: 1rem;
      z-index: 1000;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.3s ease;
      /* border-radius applied to inner content if needed, not overlay */
    }
    #gameOverModal.show {
      opacity: 1;
      pointer-events: auto;
    }
    #gameOverModal div { /* Inner content wrapper */
        background: var(--bg-dark-primary);
        padding: 2rem;
        border-radius: var(--border-radius-md);
        border: 2px solid var(--neon-cyan);
        box-shadow: 0 0 30px var(--neon-cyan);
    }
    #gameOverModal h2 {
        margin-bottom: 0.5rem;
    }
    #gameOverModal p {
        font-size: 1.2rem; /* Smaller than title */
        font-weight: normal;
        margin-bottom: 1.5rem;
    }
    #gameOverModal button { /* Specifically the button inside the modal */
      composes: action-button; /* Conceptual, apply class in HTML */
      margin-top: 1rem; /* Overrides if any from action-button */
      padding: 12px 24px; /* Specific padding for modal button */
      /* width: auto; /* Allow content to size it */
    }
  </style>
</head>
<body>
  <main id="game" role="region" aria-label="Snake game area" tabindex="0">
    <canvas id="canvas" aria-label="Game canvas"></canvas> <!-- aria-live removed, scoreboard handles announcements -->
    <div id="swipeEffectContainer" aria-hidden="true"></div>
  </main>

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

  <div id="scoreboard" aria-live="polite" aria-atomic="true" role="status">
    Score: <span id="currentScore">0</span> | High: <span id="highScore">0</span>
  </div>

  <button id="restartBtn" class="action-button" type="button" aria-label="Restart game">Restart Game</button>

  <!-- Game Over Modal -->
  <div id="gameOverModal" role="dialog" aria-modal="true" aria-labelledby="gameOverTitle" aria-describedby="gameOverDesc" tabindex="-1">
    <div>
      <h2 id="gameOverTitle">Game Over!</h2>
      <p id="gameOverDesc">Your final score is <span id="finalScore">0</span>.</p>
      <button id="modalRestartBtn" class="action-button" type="button">Play Again</button>
    </div>
  </div>

  <!-- Sound effect file must be in same folder -->
  <audio id="eatSfx" src="eat.mp3" preload="auto" aria-hidden="true"></audio>

  <script>
  (function(){
    'use strict';

    // --- Game Configuration ---
    const GAME_CONFIG = Object.freeze({
      TILE_COUNT: 24,
      FPS: 10, // Target frames per second for game logic
      MAX_APPLES: 3,
      SNAKE_INITIAL_LENGTH: 3,
      SNAKE_INITIAL_POS: { x: 12, y: 12 }, // Head position
      INITIAL_VELOCITY: { x: 1, y: 0 }, // Moving right
      POINTS_PER_APPLE: 10,
      TIME_BONUS_MS: 3000, // Milliseconds for time bonus window
      TIME_BONUS_POINTS: 5,
      COMBO_BONUS_MULTIPLIER: 2,
      PARTICLE_COUNT_ON_EAT: 12,
      MIN_SWIPE_DISTANCE: 30, // Pixels
      LOCAL_STORAGE_HIGH_SCORE_KEY: 'cyberNeonSnakeHighScore_v2', // v2 to avoid conflicts if structure changed
      // Visuals for JS drawing
      SNAKE_SEGMENT_PADDING_FACTOR: 0.05, // e.g., 5% of gridSize
      SNAKE_SEGMENT_RADIUS_FACTOR: 0.2,   // e.g., 20% of gridSize
      APPLE_BODY_RADIUS_X_FACTOR: 0.4,
      APPLE_BODY_RADIUS_Y_FACTOR: 0.55,
      APPLE_STEM_OFFSET_Y_FACTOR: -0.3,
      APPLE_STEM_RADIUS_X_FACTOR: 0.15,
      APPLE_STEM_RADIUS_Y_FACTOR: 0.3,
    });

    // --- DOM & Audio References ---
    const gameEl     = document.getElementById('game');
    const canvas     = document.getElementById('canvas');
    const ctx        = canvas.getContext('2d');
    const scoreEl    = document.getElementById('currentScore');
    const highEl     = document.getElementById('highScore');
    const scoreboardEl = document.getElementById('scoreboard');
    const eatSfx     = document.getElementById('eatSfx');
    const controlBtns= document.querySelectorAll('#controls .btn'); // More specific selector
    const restartBtn = document.getElementById('restartBtn');
    const gameOverModalEl = document.getElementById('gameOverModal');
    const finalScoreEl = document.getElementById('finalScore');
    const modalRestartBtn = document.getElementById('modalRestartBtn');
    const swipeEffectContainer = document.getElementById('swipeEffectContainer');

    // --- Game State Variables ---
    let gridSize; // Size of each grid cell in pixels
    let snake, velocity, nextVel, apples, score, gameOver;
    let comboCounter, lastAppleTime, hue; // hue for dynamic coloring
    let effects; // For particles and score pop-ups

    let highScore = 0;
    try {
      highScore = parseInt(localStorage.getItem(GAME_CONFIG.LOCAL_STORAGE_HIGH_SCORE_KEY), 10) || 0;
    } catch (e) {
      console.warn(`Could not access localStorage to retrieve high score: ${e.message}`);
    }
    highEl.textContent = highScore;

    // Timing for fixed FPS
    let lastTime = 0;
    let accumulatedTime = 0; // Renamed delta for clarity
    const gameLogicInterval = 1000 / GAME_CONFIG.FPS;

    // --- Game Initialization & Reset ---
    function initGame() {
      snake = [];
      for (let i = 0; i < GAME_CONFIG.SNAKE_INITIAL_LENGTH; i++) {
        snake.push({
            x: GAME_CONFIG.SNAKE_INITIAL_POS.x - i * (GAME_CONFIG.INITIAL_VELOCITY.x !== 0 ? Math.sign(GAME_CONFIG.INITIAL_VELOCITY.x) : 0),
            y: GAME_CONFIG.SNAKE_INITIAL_POS.y - i * (GAME_CONFIG.INITIAL_VELOCITY.y !== 0 ? Math.sign(GAME_CONFIG.INITIAL_VELOCITY.y) : 0)
        });
      }

      velocity = { ...GAME_CONFIG.INITIAL_VELOCITY };
      nextVel = { ...GAME_CONFIG.INITIAL_VELOCITY };
      apples = [];
      score = 0;
      comboCounter = 0;
      lastAppleTime = 0;
      hue = 0; // Reset hue for color cycle
      effects = { score: [], particles: [] };
      gameOver = false;

      scoreEl.textContent = score;
      restartBtn.style.display = 'none';
      gameOverModalEl.classList.remove('show');

      spawnApples();
      gameEl.focus(); // For keyboard controls
      
      // Clear any existing swipe effects on new game start
      clearSwipeEffects();
    }

    // --- Canvas Sizing ---
    function resizeCanvas(){
      const gameAreaSize = gameEl.clientWidth;
      canvas.width  = gameAreaSize;
      canvas.height = gameAreaSize;
      gridSize      = gameAreaSize / GAME_CONFIG.TILE_COUNT;
      if (!gameOver && snake) drawGame(); 
    }
    window.addEventListener('resize', resizeCanvas);

    // --- Drawing Helpers ---
    function dynamicColorGradient(isSnakeSegment){
      hue = (hue + 1) % 360;
      if(isSnakeSegment){
        const c1 = `hsl(${hue}, 100%, 50%)`;
        const c2 = `hsl(${(hue + 40) % 360}, 100%, 60%)`;
        const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
        gradient.addColorStop(0, c1);
        gradient.addColorStop(1, c2);
        return gradient;
      } else {
        const gradient = ctx.createRadialGradient(0, 0, gridSize * 0.1, 0, 0, gridSize * 0.6);
        gradient.addColorStop(0, `hsl(${hue}, 100%, 70%)`);
        gradient.addColorStop(1, `hsl(${(hue + 60) % 360}, 80%, 40%)`);
        return gradient;
      }
    }

    function drawRoundedRect(x, y, width, height, radius){
      ctx.beginPath();
      ctx.moveTo(x + radius, y);
      ctx.lineTo(x + width - radius, y);
      ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
      ctx.lineTo(x + width, y + height - radius);
      ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
      ctx.lineTo(x + radius, y + height);
      ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
      ctx.lineTo(x, y + radius);
      ctx.quadraticCurveTo(x, y, x + radius, y);
      ctx.closePath();
      ctx.fill();
    }

    function isCellEmpty(x, y){
      return !snake.some(segment => segment.x === x && segment.y === y) &&
             !apples.some(apple => apple.x === x && apple.y === y);
    }

    // --- Apple Management ---
    function spawnApples(){
      while(apples.length < GAME_CONFIG.MAX_APPLES){
        const newApple = {
          x: Math.floor(Math.random() * GAME_CONFIG.TILE_COUNT),
          y: Math.floor(Math.random() * GAME_CONFIG.TILE_COUNT)
        };
        if(isCellEmpty(newApple.x, newApple.y)) {
          apples.push(newApple);
        }
      }
    }

    // --- Visual Effects ---
    function addScoreEffect(x, y, amount){
      effects.score.push({
        x: x * gridSize + gridSize / 2,
        y: y * gridSize + gridSize / 2,
        alpha: 1, text: `+${amount}`, size: 24, life: 60
      });
    }

    function addEatParticles(x, y){
      for(let i = 0; i < GAME_CONFIG.PARTICLE_COUNT_ON_EAT; i++){
        effects.particles.push({
          x: x * gridSize + gridSize / 2,
          y: y * gridSize + gridSize / 2,
          dx: (Math.random() - 0.5) * 8,
          dy: (Math.random() - 0.5) * 8,
          alpha: 1, size: Math.random() * 4 + 2, life: 30
        });
      }
    }

    function updateEffects(){
      for(let i = effects.score.length - 1; i >= 0; i--){
        const effect = effects.score[i];
        effect.y -= 1;
        effect.alpha -= (1 / effect.life);
        effect.size += 0.2;
        if(effect.alpha <= 0) effects.score.splice(i, 1);
      }
      for(let i = effects.particles.length - 1; i >= 0; i--){
        const particle = effects.particles[i];
        particle.x += particle.dx;
        particle.y += particle.dy;
        particle.alpha -= (1 / particle.life);
        particle.color = `hsla(${(hue + i * 20) % 360}, 100%, 70%, ${particle.alpha})`;
        if(particle.alpha <= 0) effects.particles.splice(i, 1);
      }
    }

    function flashScoreboard(){
      scoreboardEl.classList.add('flash');
      setTimeout(() => scoreboardEl.classList.remove('flash'), 200);
      try {
        eatSfx.currentTime = 0;
        eatSfx.play();
      } catch(e) {
        console.warn("Audio playback failed (eatSfx):", e.message);
      }
    }

    // --- Game Logic Update ---
    function updateGameLogic(){
      if(gameOver) return;

      if (!((nextVel.x === -velocity.x && velocity.x !==0) || (nextVel.y === -velocity.y && velocity.y !==0))) {
        velocity = { ...nextVel };
      }

      const head = {
        x: (snake[0].x + velocity.x + GAME_CONFIG.TILE_COUNT) % GAME_CONFIG.TILE_COUNT,
        y: (snake[0].y + velocity.y + GAME_CONFIG.TILE_COUNT) % GAME_CONFIG.TILE_COUNT
      };

      const checkCollisionAgainst = snake.slice(0, snake.length -1);
      if(checkCollisionAgainst.some(segment => segment.x === head.x && segment.y === head.y)){
        gameOver = true;
        displayGameOver();
        return;
      }

      snake.unshift(head);

      let ateApple = false;
      for(let i = apples.length - 1; i >= 0; i--){
        if(apples[i].x === head.x && apples[i].y === head.y){
          const currentTime = Date.now();
          const timeBonus = (currentTime - lastAppleTime < GAME_CONFIG.TIME_BONUS_MS) ? GAME_CONFIG.TIME_BONUS_POINTS : 0;
          const comboBonus = comboCounter * GAME_CONFIG.COMBO_BONUS_MULTIPLIER;
          const pointsGained = GAME_CONFIG.POINTS_PER_APPLE + timeBonus + comboBonus;

          score += pointsGained;
          comboCounter++;
          lastAppleTime = currentTime;
          scoreEl.textContent = score;

          if(score > highScore){
            highScore = score;
            try {
              localStorage.setItem(GAME_CONFIG.LOCAL_STORAGE_HIGH_SCORE_KEY, highScore.toString());
            } catch (e) {
              console.warn(`Could not save high score to localStorage: ${e.message}`);
            }
            highEl.textContent = highScore;
          }

          addScoreEffect(head.x, head.y, pointsGained);
          addEatParticles(head.x, head.y);
          flashScoreboard();

          apples.splice(i, 1);
          spawnApples();
          ateApple = true;
          break; 
        }
      }

      if(!ateApple){
        comboCounter = 0;
        snake.pop();
      }
    }

    // --- Drawing Functions ---
    function drawGame(){
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      ctx.strokeStyle = 'var(--bg-grid-lines)';
      ctx.lineWidth = 1;
      for(let i = 0; i <= GAME_CONFIG.TILE_COUNT; i++){
        const pos = i * gridSize;
        ctx.beginPath(); ctx.moveTo(pos, 0); ctx.lineTo(pos, canvas.height); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(0, pos); ctx.lineTo(canvas.width, pos); ctx.stroke();
      }

      apples.forEach(apple => {
        const appleCenterX = apple.x * gridSize + gridSize / 2;
        const appleCenterY = apple.y * gridSize + gridSize / 2;
        ctx.save();
        ctx.translate(appleCenterX, appleCenterY);

        ctx.shadowColor = '#f44';
        ctx.shadowBlur = 18;
        ctx.fillStyle = dynamicColorGradient(false);

        ctx.beginPath();
        ctx.ellipse(0, 0, 
                    gridSize * GAME_CONFIG.APPLE_BODY_RADIUS_X_FACTOR, 
                    gridSize * GAME_CONFIG.APPLE_BODY_RADIUS_Y_FACTOR, 
                    Math.PI / 6, 0, 2 * Math.PI);
        ctx.fill();

        ctx.fillStyle = '#282';
        ctx.beginPath();
        ctx.ellipse(0, gridSize * GAME_CONFIG.APPLE_STEM_OFFSET_Y_FACTOR, 
                    gridSize * GAME_CONFIG.APPLE_STEM_RADIUS_X_FACTOR, 
                    gridSize * GAME_CONFIG.APPLE_STEM_RADIUS_Y_FACTOR, 
                    Math.PI / 4, 0, 2 * Math.PI);
        ctx.fill();
        ctx.restore();
      });

      const segmentPadding = gridSize * GAME_CONFIG.SNAKE_SEGMENT_PADDING_FACTOR;
      const segmentRadius = gridSize * GAME_CONFIG.SNAKE_SEGMENT_RADIUS_FACTOR;
      snake.forEach((segment, index) => {
        const segX = segment.x * gridSize;
        const segY = segment.y * gridSize;
        ctx.save();
        ctx.fillStyle = dynamicColorGradient(true);
        ctx.shadowColor = 'var(--neon-cyan)';
        ctx.shadowBlur = (index === 0 ? 25 : 18);

        drawRoundedRect(
          segX + segmentPadding, 
          segY + segmentPadding, 
          gridSize - (2 * segmentPadding), 
          gridSize - (2 * segmentPadding), 
          segmentRadius
        );
        ctx.restore();
      });

      effects.particles.forEach(p => {
        ctx.fillStyle = p.color;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.size, 0, 2 * Math.PI);
        ctx.fill();
      });
      effects.score.forEach(e => {
        ctx.fillStyle = `rgba(0, 255, 153, ${e.alpha})`;
        ctx.font = `${e.size}px ${getComputedStyle(document.body).fontFamily.split(',')[0] || 'Arial'}`;
        ctx.textAlign = 'center';
        ctx.shadowColor = 'var(--neon-green)';
        ctx.shadowBlur = 10;
        ctx.fillText(e.text, e.x, e.y);
        ctx.shadowColor = 'transparent';
      });
    }

    // --- Swipe Visual Effects ---
    // Append a swipe effect element inside #swipeEffectContainer and auto-remove after animation
    function showSwipeEffect(direction){
      // Clear existing effects to avoid clutter (optional — can keep if prefer multiple)
      clearSwipeEffects();

      const effect = document.createElement('div');
      effect.classList.add('swipe-effect');
      switch(direction) {
        case 'up': effect.classList.add('swipe-up'); break;
        case 'down': effect.classList.add('swipe-down'); break;
        case 'left': effect.classList.add('swipe-left'); break;
        case 'right': effect.classList.add('swipe-right'); break;
        default: return;
      }
      swipeEffectContainer.appendChild(effect);

      // Remove from DOM after animation ends
      effect.addEventListener('animationend', () => {
        effect.remove();
      });
    }
    function clearSwipeEffects(){
      while(swipeEffectContainer.firstChild) swipeEffectContainer.removeChild(swipeEffectContainer.firstChild);
    }

    // --- Input Handling ---
    let touchStartCoords = null;

    canvas.addEventListener('touchstart', e => {
      if(e.touches.length === 1) {
        touchStartCoords = { x: e.touches[0].clientX, y: e.touches[0].clientY };
      }
    }, { passive: true });

    canvas.addEventListener('touchmove', e => {
      if(!touchStartCoords || gameOver) return;
      const dx = e.touches[0].clientX - touchStartCoords.x;
      const dy = e.touches[0].clientY - touchStartCoords.y;

      if(Math.abs(dx) > GAME_CONFIG.MIN_SWIPE_DISTANCE || Math.abs(dy) > GAME_CONFIG.MIN_SWIPE_DISTANCE){
        let direction;
        if (Math.abs(dx) > Math.abs(dy)) {
          direction = dx > 0 ? 'right' : 'left';
        } else {
          direction = dy > 0 ? 'down' : 'up';
        }
        changeDirection(direction);
        showSwipeEffect(direction);
        touchStartCoords = null; // Reset after a swipe is registered
      }
    }, { passive: true });

    canvas.addEventListener('touchend', () => { touchStartCoords = null; });

    controlBtns.forEach(button => button.addEventListener('click', () => {
        if (gameOver) return;
        const dir = button.dataset.dir;
        changeDirection(dir);
        showSwipeEffect(dir);
    }));

    window.addEventListener('keydown', e => {
      if(gameOver && e.key !== 'Enter' && e.key !== ' ') return; // Allow Enter/Space to restart from modal

      if (gameOverModalEl.classList.contains('show') && (e.key === 'Enter' || e.key === ' ')) {
          e.preventDefault();
          initGame();
          return;
      }
      if (gameOver) return;

      const keyDirectionMap = {
        ArrowUp: 'up', w: 'up', W: 'up',
        ArrowDown: 'down', s: 'down', S: 'down',
        ArrowLeft: 'left', a: 'left', A: 'left',
        ArrowRight: 'right', d: 'right', D: 'right'
      };
      const direction = keyDirectionMap[e.key];
      if(direction) {
        e.preventDefault();
        changeDirection(direction);
        showSwipeEffect(direction);
      }
    });

    function changeDirection(direction){
      const directionVectors = {
        up:    {x:0, y:-1},
        down:  {x:0, y:1},
        left:  {x:-1,y:0},
        right: {x:1, y:0}
      };
      const newVel = directionVectors[direction];
      if(newVel) {
        nextVel = newVel;
      }
    }

    // --- Game Over & Restart ---
    function displayGameOver(){
      finalScoreEl.textContent = score;
      gameOverModalEl.classList.add('show');
      modalRestartBtn.focus();
    }

    restartBtn.addEventListener('click', initGame);
    modalRestartBtn.addEventListener('click', initGame);

    // --- Main Game Loop ---
    function gameLoop(currentTime = 0){
      if (!lastTime) lastTime = currentTime;
      accumulatedTime += currentTime - lastTime;
      lastTime = currentTime;

      while(accumulatedTime >= gameLogicInterval){
        updateGameLogic();
        updateEffects();
        accumulatedTime -= gameLogicInterval;
      }
      
      drawGame();
      requestAnimationFrame(gameLoop);
    }

    // --- Start Game ---
    resizeCanvas();
    initGame();
    requestAnimationFrame(gameLoop);

  })();
  </script>
</body>
</html>