diff --git a/plans/260412-1113-svelte5-rewrite/phase-01-scaffold-project.md b/plans/260412-1113-svelte5-rewrite/phase-01-scaffold-project.md
deleted file mode 100644
index d20a15a..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-01-scaffold-project.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Phase 1: Scaffold Svelte 5 Project
-
-**Priority:** Critical | **Status:** pending | **Effort:** Small
-
-## Overview
-Set up a fresh Svelte 5 + Vite project structure alongside existing code. Replace Phaser dependency with Svelte.
-
-## Steps
-
-1. Remove Phaser and related deps from `package.json`
-2. Install Svelte 5 + vite-plugin-svelte
- ```bash
- npm install svelte && npm install -D @sveltejs/vite-plugin-svelte
- ```
-3. Replace Vite config files (`vite/config.dev.mjs`, `vite/config.prod.mjs`) with single `vite.config.js` using svelte plugin
-4. Create directory structure:
- ```
- src/lib/ # Pure JS game logic
- src/lib/locales/ # Locale JSON files
- src/lib/levels/ # Level data
- src/lib/game/ # Game logic classes
- src/components/ # Reusable Svelte components
- src/scenes/ # Scene components
- src/styles/ # CSS
- ```
-5. Create `src/main.js` — mount Svelte app to `#app`
-6. Create minimal `src/App.svelte` — renders "Hello NNTV" placeholder
-7. Create `src/styles/theme.css` — port color/font constants from `theme.js` as CSS variables
-8. Update `index.html` — remove Phaser-specific meta, keep basic structure
-9. Update `package.json` scripts to use new vite config
-10. Verify `npm run dev` serves the placeholder app
-
-## Files to Create
-- `vite.config.js`
-- `src/main.js` (replace existing)
-- `src/App.svelte`
-- `src/styles/theme.css`
-
-## Files to Delete
-- `vite/config.dev.mjs`
-- `vite/config.prod.mjs`
-- `vite/` directory
-- `log.js`
-- `src/game/theme.js`
-
-## Success Criteria
-- `npm run dev` opens browser with "Hello NNTV"
-- `npm run build` produces working dist/
-- Zero Phaser imports remain
-- CSS variables available globally
diff --git a/plans/260412-1113-svelte5-rewrite/phase-02-port-game-logic.md b/plans/260412-1113-svelte5-rewrite/phase-02-port-game-logic.md
deleted file mode 100644
index 9f4d446..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-02-port-game-logic.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Phase 2: Port Pure Game Logic
-
-**Priority:** Critical | **Status:** pending | **Effort:** Medium
-
-## Overview
-Move all framework-agnostic game logic into `src/lib/`. Strip Phaser imports. Separate data/logic from rendering.
-
-## Steps
-
-1. **Copy as-is** (just move files):
- - `locales/en.json` → `src/lib/locales/en.json`
- - `locales/vi.json` → `src/lib/locales/vi.json`
- - `levels/Levels.js` → `src/lib/levels/levels.js`
- - `progress.js` → `src/lib/progress.js`
- - `localization.js` → `src/lib/localization.js`
-
-2. **Port TurnManager** → `src/lib/game/turn-manager.js`
- - Remove `import Phaser` (line 1)
- - Remove `this.scene` references
- - Make it accept callbacks instead of calling scene methods directly
- - Constructor takes `{ onLevelComplete, onDetected, getPlayerPos, getGrid, getGuards, getLightSystem }`
-
-3. **Port GridSystem** → `src/lib/game/grid-system.js`
- - Keep: grid data model, isValidPosition, setWall/setGoal/setLight, gridToPixel, pixelToGrid
- - Remove: `scene.add.graphics()`, `render()` method, all Phaser graphics calls
- - Merge LightingSystem's `clearAllLight()` into GridSystem
- - Add `getCellState(row, col)` returning `{ isWall, isGoal, isLight }`
-
-4. **Port Guards** → `src/lib/game/guards.js`
- - Keep: all guard logic (updateLight, onTurnChange, patrol path, rotation, blinking)
- - Remove: `createSprite()`, `update()` (sprite positioning), `scene.add.circle/line`
- - Remove: `destroy()` sprite cleanup (no sprites to destroy)
- - Each guard exposes: `{ row, col, color, type, direction, isOn }` for rendering
-
-5. **Port Player** → `src/lib/game/player.js`
- - Keep: `moveTo()`, `move()`, `isInLitCell()`, `isAtGoal()`
- - Remove: `createSprite()`, `update()` (sprite), tweens
- - Pure data: `{ row, col }` position tracking
-
-6. **Port LevelManager** → `src/lib/game/level-manager.js`
- - Rewrite as a pure function: `loadLevel(levelId, grid)` → returns `{ player, guards, isFinalLevel }`
- - No scene references
- - Creates guard instances, sets up grid walls/goals
-
-## Files to Create
-- `src/lib/game/grid-system.js`
-- `src/lib/game/guards.js`
-- `src/lib/game/player.js`
-- `src/lib/game/turn-manager.js`
-- `src/lib/game/level-manager.js`
-- `src/lib/localization.js`
-- `src/lib/progress.js`
-- `src/lib/locales/en.json`
-- `src/lib/locales/vi.json`
-- `src/lib/levels/levels.js`
-
-## Files to Delete (after all phases complete)
-- Entire `src/game/` directory
-
-## Success Criteria
-- All game logic files import zero Phaser code
-- Guard logic can be tested independently (no DOM/canvas needed)
-- `loadLevel()` returns a complete game state object
diff --git a/plans/260412-1113-svelte5-rewrite/phase-03-game-board-components.md b/plans/260412-1113-svelte5-rewrite/phase-03-game-board-components.md
deleted file mode 100644
index 9d664ac..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-03-game-board-components.md
+++ /dev/null
@@ -1,87 +0,0 @@
-# Phase 3: Build Game Board + Sprite Components
-
-**Priority:** Critical | **Status:** pending | **Effort:** Medium
-
-## Overview
-Create Svelte components that render the game grid, player, and guards using HTML/CSS instead of Phaser canvas.
-
-## Steps
-
-1. **Button.svelte** — reusable styled button
- - Props: `text`, `onclick`, `small` (boolean for compact variant)
- - Styled with CSS variables from theme.css
- - Hover/active states via CSS
-
-2. **GameBoard.svelte** — renders the grid
- - Props: `grid` (2D array of cell states), `rows`, `cols`, `cellSize`
- - CSS Grid layout: `grid-template-columns: repeat(cols, cellSize)`
- - Each cell is a `
` with class based on state: `.wall`, `.goal`, `.lit`, `.empty`
- - Click handler on cells for tap-to-move (emits `oncellclick` with row, col)
- - Cell colors from CSS variables
-
-3. **PlayerSprite.svelte** — renders the player
- - Props: `row`, `col`, `cellSize`, `gridOffset`
- - Positioned absolutely over the grid
- - CSS `transition: top 100ms, left 100ms` for smooth movement (replaces Phaser tweens)
- - Black circle via `border-radius: 50%`
-
-4. **GuardSprite.svelte** — renders a guard
- - Props: `guard` object `{ row, col, type, direction, isOn }`
- - Props: `cellSize`, `gridOffset`
- - Positioned absolutely over the grid
- - Circle colored by type (CSS class: `.guard-static`, `.guard-rotating`, etc.)
- - Direction indicator for rotating/patrolling: rotated CSS triangle or line
- - Blinking guard dim state: reduced opacity via class toggle
-
-5. **GameHud.svelte** — top HUD bar
- - Props: `lives`, `level`, `turns`
- - Events: `onpause`, `onmenu`
- - Fixed position, not part of game board
- - Uses Button.svelte for pause/menu
-
-6. **DetectionPopup.svelte** — detection overlay
- - Props: `visible`
- - Events: `onplayagain`
- - Dark overlay with centered message + button
- - Uses `transition:fade`
-
-7. **PauseMenu.svelte** — pause overlay
- - Props: `visible`
- - Events: `onresume`, `onrestart`, `onmainmenu`
- - Dark overlay with 3 buttons
- - Uses `transition:fade`
-
-## Rendering Strategy
-
-```
-┌─ GameBoard.svelte (CSS Grid) ─────────┐
-│ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │
-│ │ │ │ │ │ │ │ │ │ │ │ │ ... │
-│ └──┘ └──┘ └──┘ └──┘ └──┘ └──┘ │
-│ (each cell = div with bg color) │
-│ │
-│ PlayerSprite (absolute positioned) │
-│ GuardSprite × N (absolute positioned)│
-└────────────────────────────────────────┘
-```
-
-## CSS Class Map
-
-| Game State | CSS Class | Color Variable |
-|---|---|---|
-| Empty cell | `.cell` | `--grid-empty` |
-| Wall | `.cell.wall` | `--grid-wall` |
-| Goal | `.cell.goal` | `--grid-goal` |
-| Lit | `.cell.lit` | `--grid-lit` |
-| Static guard | `.guard.static` | `--guard-static` |
-| Rotating guard | `.guard.rotating` | `--guard-rotating` |
-| Blinking guard (on) | `.guard.blinking` | `--guard-blinking` |
-| Blinking guard (off) | `.guard.blinking.off` | `--guard-blinking-off` |
-| Patrolling guard | `.guard.patrolling` | `--guard-patrolling` |
-
-## Success Criteria
-- GameBoard renders correct grid for any level (6x6 through 10x10)
-- Player circle moves smoothly with CSS transitions
-- Guards display correct colors and direction indicators
-- All overlays (detection, pause) fade in/out
-- Components accept plain JS data — no Phaser objects
diff --git a/plans/260412-1113-svelte5-rewrite/phase-04-scene-components.md b/plans/260412-1113-svelte5-rewrite/phase-04-scene-components.md
deleted file mode 100644
index ba527af..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-04-scene-components.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# Phase 4: Build Scene Components
-
-**Priority:** High | **Status:** pending | **Effort:** Medium
-
-## Overview
-Replace all Phaser Scene classes with Svelte components. App.svelte acts as the scene router using reactive state + transitions.
-
-## Steps
-
-1. **App.svelte** — scene router
- - Module-level `$state` for `currentScene` and `sceneData`
- - `{#if currentScene === 'MainMenu'}` blocks for each scene
- - Each block wrapped in `transition:fade={{ duration: 300 }}`
- - Export `navigate(scene, data)` function for child components
- - Initialize with `currentScene = 'MainMenu'`
-
-2. **MainMenu.svelte**
- - Starfield background (random positioned dots via `{#each}`)
- - Title, ninja icon, 4 buttons (Start, Level Select, Guide, Settings)
- - Buttons call `navigate('StoryIntro')` etc.
-
-3. **StoryIntro.svelte**
- - Dark background, scrolling story text
- - CSS animation `@keyframes scroll` moves text upward
- - Skip button → navigates to LevelIntro
- - Auto-advance after scroll completes
-
-4. **LevelIntro.svelte**
- - Props via sceneData: `{ level, lives }`
- - Shows level number, name (from levels.js), story text (from localization)
- - Continue button → navigates to Game
-
-5. **LevelSelect.svelte**
- - Grid of 12 level buttons (CSS Grid, 4 columns)
- - Reads progress from `getProgress()`
- - Locked/unlocked/completed states via CSS classes
- - Checkmark on completed levels
- - Click → navigate to LevelIntro with level data
-
-6. **GameOver.svelte**
- - Props via sceneData: `{ level, isLastLevel }`
- - Different message for final level vs normal game over
- - Try Again + Main Menu buttons
-
-7. **Settings.svelte**
- - Language toggle (EN/VI)
- - Calls `setLanguage()` from localization.js
- - Re-renders text reactively via `$derived` on language
-
-8. **Guide.svelte**
- - Scrollable content area (native CSS `overflow-y: auto`)
- - Sections: objectives, controls, enemy types
- - Back button
-
-## Scene Navigation Pattern
-
-```svelte
-
-
-
-{#if currentScene === 'MainMenu'}
-
-
-
-{:else if currentScene === 'Game'}
-
-
-
-{/if}
-```
-
-## Success Criteria
-- All 8 scenes render correctly
-- Scene transitions fade smoothly
-- Language switching updates all visible text
-- Level select shows correct progress state
-- Story intro scrolls and auto-advances
diff --git a/plans/260412-1113-svelte5-rewrite/phase-05-game-scene-input.md b/plans/260412-1113-svelte5-rewrite/phase-05-game-scene-input.md
deleted file mode 100644
index de228a6..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-05-game-scene-input.md
+++ /dev/null
@@ -1,96 +0,0 @@
-# Phase 5: Wire Game Scene + Input
-
-**Priority:** Critical | **Status:** pending | **Effort:** Large
-
-## Overview
-The main Game.svelte scene — connects game logic (grid, guards, turns, player) to the visual components and handles keyboard/click input.
-
-## Steps
-
-1. **Game.svelte** — main game orchestrator
- - `$state` for: grid, player, guards, lives, level, turns, isPaused, detected, isFinalLevel
- - `onMount`: call `loadLevel()` to get initial state, set up keyboard listener
- - `onDestroy`: clean up keyboard listener
- - Render: GameBoard + PlayerSprite + GuardSprites + GameHud + overlays
-
-2. **Keyboard input**
- ```js
- function onKeyDown(e) {
- if (isPaused || !inputEnabled) return;
- const dirMap = {
- ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right',
- w: 'up', s: 'down', a: 'left', d: 'right',
- };
- const dir = dirMap[e.key];
- if (dir) handleMove(dir);
- }
- ```
- - Bind to `window` via `svelte:window` directive: `
`
-
-3. **Click-to-move input**
- - GameBoard emits `oncellclick(row, col)`
- - Game.svelte checks if cell is adjacent to player, calls `handleMove()`
-
-4. **Turn flow** (handleMove function)
- ```
- 1. player.move(direction)
- 2. If moved successfully:
- a. Check if player at goal → handleLevelComplete()
- b. clearAllLight()
- c. Each guard.onTurnChange()
- d. grid.render state update (triggers Svelte reactivity)
- e. Check if player in lit cell → showDetection()
- f. turns++
- ```
-
-5. **Level 12 special mechanic**
- - On each move, check `isFinalLevel && Manhattan distance to goal <= 2`
- - If triggered: set ALL non-wall cells to `isLight = true`
- - Show princess detected message
- - This looks like normal gameplay — player won't know it's impossible until they experience it
-
-6. **Detection flow**
- - Set `detected = true` → shows DetectionPopup
- - On "Play Again": `lives--`, if lives > 0 reload level, else navigate to GameOver
-
-7. **Level complete flow**
- - Call `completeLevel()` from progress.js
- - Brief CSS flash animation on board
- - Navigate to LevelIntro for next level (or GameOver for final)
-
-8. **Pause flow**
- - Toggle `isPaused` → shows PauseMenu
- - Resume / Restart / Main Menu actions
-
-## Reactive State Shape
-
-```js
-// In Game.svelte
-let grid = $state(null); // GridSystem instance
-let player = $state(null); // Player instance
-let guards = $state([]); // Guard instances
-let lives = $state(3);
-let currentLevel = $state(1);
-let turns = $state(0);
-let isPaused = $state(false);
-let detected = $state(false);
-let isFinalLevel = $state(false);
-
-// Derived for rendering
-let cells = $derived(grid ? grid.getAllCells() : []);
-let playerPos = $derived(player ? { row: player.row, col: player.col } : null);
-let guardData = $derived(guards.map(g => ({
- row: g.row, col: g.col, type: g.constructor.name,
- direction: g.direction, isOn: g.isOn,
-})));
-```
-
-## Success Criteria
-- Arrow keys / WASD move player through grid
-- Click adjacent cell moves player
-- Guards update correctly each turn (static lit, rotating beam, blinking toggle, patrol movement)
-- Detection popup shows when stepping on lit cell
-- Level completes when reaching goal
-- Level 12 lights up entire map near goal
-- Pause menu works
-- Lives decrement and game over triggers at 0
diff --git a/plans/260412-1113-svelte5-rewrite/phase-06-polish-verify.md b/plans/260412-1113-svelte5-rewrite/phase-06-polish-verify.md
deleted file mode 100644
index 7d1ee6d..0000000
--- a/plans/260412-1113-svelte5-rewrite/phase-06-polish-verify.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Phase 6: Polish + Verify
-
-**Priority:** High | **Status:** pending | **Effort:** Small
-
-## Overview
-Final pass — visual polish, cleanup old Phaser code, update docs, verify all 12 levels.
-
-## Steps
-
-1. **Delete old Phaser code**
- - Remove entire `src/game/` directory
- - Remove `vite/` directory
- - Remove `log.js`
- - Remove `public/style.css` (styles now in Svelte components + theme.css)
- - Remove `phaser` from package.json dependencies
- - Remove `terser` from devDependencies (Vite handles minification)
- - Run `npm install` to clean lockfile
-
-2. **Visual polish**
- - Verify dark theme renders correctly on all scenes
- - Test responsive scaling (Scale.FIT equivalent via CSS `max-width` + `aspect-ratio`)
- - Ensure grid is centered on all level sizes (6x6 through 10x10)
- - Test direction indicators on rotating/patrolling guards
- - Verify blinking guard color toggle
-
-3. **Test all 12 levels**
- - Level 1: move freely, reach goal
- - Levels 2-5: static guard lit cells block correct positions
- - Level 6: rotating guard beam sweeps and blocks cells
- - Levels 7-8: mixed guard interactions
- - Level 9: blinking guard toggles on/off
- - Level 10: patrolling guard moves along path
- - Level 11: all 4 guard types simultaneously
- - Level 12: approach goal → entire map lights up (unbeatable)
-
-4. **Test game flows**
- - Lives system: lose 3 lives → game over screen
- - Level progression: complete level → intro → next level
- - Level select: locked/unlocked/completed states correct
- - Progress persistence: refresh browser, progress retained
- - Language switch: EN ↔ VI updates all text
- - Pause menu: resume, restart, main menu all work
-
-5. **Update docs**
- - Update `docs/system-architecture.md` — Svelte 5 architecture
- - Update `docs/codebase-summary.md` — new file listing
- - Update `docs/code-standards.md` — Svelte conventions
- - Update `README.md` — remove Phaser references, add Svelte info
-
-6. **Build verification**
- - `npm run build` produces working dist/
- - Serve dist/ locally, test full game
- - Check bundle size (target: <50KB app code, down from ~1MB with Phaser)
-
-## Success Criteria
-- Zero Phaser code remains
-- All 12 levels playable with correct guard behavior
-- Level 12 secret mechanic works
-- Bundle size < 50KB (excluding assets)
-- Docs updated to reflect new stack
diff --git a/plans/260412-1113-svelte5-rewrite/plan.md b/plans/260412-1113-svelte5-rewrite/plan.md
deleted file mode 100644
index 4214959..0000000
--- a/plans/260412-1113-svelte5-rewrite/plan.md
+++ /dev/null
@@ -1,124 +0,0 @@
----
-title: Rewrite NNTV from Phaser 3 to Svelte 5
-status: ready
-created: 2026-04-12
-branch: main
-blockedBy: []
-blocks: []
----
-
-# Rewrite NNTV: Phaser 3 → Svelte 5 + Vite
-
-## Overview
-
-Replace Phaser 3 game engine (~1MB) with plain Svelte 5 + Vite for a turn-based grid puzzle game that only uses rectangles, circles, and text. All game logic (guards, turns, levels, lighting) ports as-is. Only the rendering/UI layer changes.
-
-## Architecture: Before → After
-
-```
-BEFORE (Phaser 3) AFTER (Svelte 5)
-───────────────── ────────────────
-Phaser.Game config → App.svelte (scene router)
-Phaser.Scene classes → Svelte components per scene
-scene.add.circle/rect/text → HTML/CSS elements
-scene.input.keyboard → window keydown events
-scene.tweens.add → CSS transitions
-this.scene.start() → reactive scene state
-camera.fadeIn/fadeOut → svelte/transition (fade)
-Phaser physics (unused) → DELETE
-```
-
-## File Migration Map
-
-| Current File | Action | New Location |
-|---|---|---|
-| `locales/en.json`, `vi.json` | PORT AS-IS | `src/lib/locales/` |
-| `levels/Levels.js` | PORT AS-IS | `src/lib/levels/levels.js` |
-| `progress.js` | PORT AS-IS | `src/lib/progress.js` |
-| `localization.js` | PORT AS-IS | `src/lib/localization.js` |
-| `TurnManager.js` | PORT (remove Phaser import) | `src/lib/game/turn-manager.js` |
-| `GridSystem.js` | SPLIT: data logic → pure JS, rendering → Svelte | `src/lib/game/grid-system.js` + `GameBoard.svelte` |
-| `Guard.js` | SPLIT: logic → pure JS, rendering → Svelte | `src/lib/game/guards.js` + `GuardSprite.svelte` |
-| `Player.js` | SPLIT: logic → pure JS, rendering → Svelte | `src/lib/game/player.js` + `PlayerSprite.svelte` |
-| `LightingSystem.js` | MERGE into grid-system.js | `src/lib/game/grid-system.js` |
-| `LevelManager.js` | REWRITE as pure function | `src/lib/game/level-manager.js` |
-| `theme.js` | REWRITE as CSS variables | `src/styles/theme.css` |
-| All scenes/*.js | REWRITE as Svelte components | `src/scenes/*.svelte` |
-| `main.js` | REWRITE | `src/main.js` + `src/App.svelte` |
-| `LevelTester.js` | DELETE | — |
-
-## New Project Structure
-
-```
-src/
-├── main.js # Mount Svelte app
-├── App.svelte # Scene router + transitions
-├── styles/
-│ └── theme.css # CSS variables (colors, fonts)
-├── lib/
-│ ├── localization.js # getText, setLanguage (ported)
-│ ├── progress.js # localStorage persistence (ported)
-│ ├── locales/
-│ │ ├── en.json # English (ported)
-│ │ └── vi.json # Vietnamese (ported)
-│ ├── levels/
-│ │ └── levels.js # Level data (ported)
-│ └── game/
-│ ├── grid-system.js # Grid data model + lighting (pure JS)
-│ ├── guards.js # Guard classes, logic only (pure JS)
-│ ├── player.js # Player position + movement (pure JS)
-│ ├── turn-manager.js # Turn logic (pure JS)
-│ └── level-manager.js # Level loading (pure JS)
-├── components/
-│ ├── GameBoard.svelte # CSS Grid rendering of cells
-│ ├── PlayerSprite.svelte # Player circle element
-│ ├── GuardSprite.svelte # Guard circle + direction indicator
-│ ├── GameHud.svelte # Lives, level, turns, pause/menu buttons
-│ ├── DetectionPopup.svelte # "You've been detected" overlay
-│ ├── PauseMenu.svelte # Pause overlay
-│ └── Button.svelte # Reusable styled button
-└── scenes/
- ├── MainMenu.svelte
- ├── StoryIntro.svelte
- ├── LevelSelect.svelte
- ├── LevelIntro.svelte
- ├── Game.svelte # Main game scene
- ├── GameOver.svelte
- ├── Settings.svelte
- └── Guide.svelte
-```
-
-## Key Design Decisions
-
-1. **Plain Svelte + Vite** (not SvelteKit) — no routing needed for SPA game
-2. **Svelte 5 runes** (`$state`, `$derived`, `$effect`) — reactive game state
-3. **CSS Grid** for game board — native, responsive, zero dependencies
-4. **CSS transitions** for player movement — replace Phaser tweens
-5. **`svelte/transition`** for scene switching — fade between screens
-6. **Pure JS game logic** — all guard/turn/level logic stays framework-agnostic
-7. **Game state as module-level `$state`** in `.svelte.js` files — shared across components
-
-## Phases
-
-| # | Phase | Status | File |
-|---|-------|--------|------|
-| 1 | Scaffold Svelte 5 project | pending | [phase-01](phase-01-scaffold-project.md) |
-| 2 | Port pure game logic | pending | [phase-02](phase-02-port-game-logic.md) |
-| 3 | Build game board + sprites | pending | [phase-03](phase-03-game-board-components.md) |
-| 4 | Build scene components | pending | [phase-04](phase-04-scene-components.md) |
-| 5 | Wire game scene + input | pending | [phase-05](phase-05-game-scene-input.md) |
-| 6 | Polish + verify | pending | [phase-06](phase-06-polish-verify.md) |
-
-## Risk Assessment
-
-| Risk | Impact | Mitigation |
-|---|---|---|
-| Grid reactivity perf on 10x10 | Low | Svelte fine-grained updates; only changed cells re-render |
-| CSS transition timing mismatch with game turns | Medium | Use fixed duration, test each guard type |
-| Level 12 special mechanic (lightUpEntireMap) | Low | Direct DOM class toggle on all cells |
-
-## Dependencies
-
-- Svelte 5 (latest)
-- Vite 6.x (already used)
-- No other runtime dependencies
diff --git a/plans/260413-1416-gameplay-improvements/phase-01-wait-action.md b/plans/260413-1416-gameplay-improvements/phase-01-wait-action.md
deleted file mode 100644
index 691cef3..0000000
--- a/plans/260413-1416-gameplay-improvements/phase-01-wait-action.md
+++ /dev/null
@@ -1,54 +0,0 @@
-## Phase 1: Wait Action
-
-**Priority:** P1 | **Status:** Pending | **Effort:** 15min
-
-### Overview
-
-Spacebar (and tap-on-player for mobile) skips the player's move but still advances guards.
-Creates timing puzzles — player must wait for a safe window.
-
-### Data Flow
-
-1. User presses Space / taps player cell
-2. `handleMove` is NOT called; instead new `handleWait()` fires
-3. `handleWait` calls `turnManager.nextTurn(grid, player, guards)` without moving player
-4. Same detection/completion checks run
-5. `renderVersion++` triggers re-render
-
-### Files to Modify
-
-**`src/scenes/Game.svelte`** (input handler only)
-
-### Implementation Steps
-
-- [ ] 1. In `onKeyDown`, add `' '` (Space) key check before direction map lookup
-- [ ] 2. When Space detected, call `handleWait()` and `e.preventDefault()`
-- [ ] 3. Create `handleWait()` function:
- ```js
- function handleWait() {
- if (!player || !grid) return;
- const result = turnManager.nextTurn(grid, player, guards);
- if (isFinalLevel && checkFinalLevel()) { renderVersion++; return; }
- renderVersion++;
- if (result.levelComplete) handleLevelComplete();
- else if (result.detected) detected = true;
- }
- ```
-- [ ] 4. In `onCellClick`, if clicked cell === player position, call `handleWait()`
-
-### Edge Cases
-
-- Wait on level 12 still triggers princess detection expansion (covered — same `checkFinalLevel` path)
-- Wait when already at goal: `nextTurn` returns `levelComplete: true` (correct)
-- Wait counts as a turn for move counter (correct — `turnManager.turnCount++` happens in `nextTurn`)
-
-### Success Criteria
-
-- Space key advances turn without moving player
-- Guards rotate/patrol/blink as normal
-- Turn counter increments
-- Detection still works if guard light reaches player after wait
-
-### Rollback
-
-Revert single commit. No schema changes.
diff --git a/plans/260413-1416-gameplay-improvements/phase-02-star-rating.md b/plans/260413-1416-gameplay-improvements/phase-02-star-rating.md
deleted file mode 100644
index fb1d757..0000000
--- a/plans/260413-1416-gameplay-improvements/phase-02-star-rating.md
+++ /dev/null
@@ -1,89 +0,0 @@
-## Phase 2: Star Rating + Par Moves
-
-**Priority:** P1 | **Status:** Pending | **Effort:** 2h
-
-### Overview
-
-Each level gets a `parMoves` value. On completion, show 1-3 star rating.
-Persist best stars + best moves in localStorage. Display stars on level select.
-
-### Data Flow
-
-```
-Level complete → turnManager.turnCount vs level.parMoves → star rating
- → completeLevel(levelNum, totalLevels, moves) → localStorage update
- → LevelSelect reads stars from progress
-```
-
-### Star Calculation
-
-| Condition | Stars |
-|-----------|-------|
-| moves <= parMoves | 3 |
-| moves <= parMoves + 3 | 2 |
-| completed | 1 |
-
-### Files to Modify
-
-#### 1. `src/lib/levels/levels.js`
-- [ ] Add `parMoves` field to each level definition
-- [ ] Placeholder values (will be finalized in Phase 3 after redesign):
- - L1: 10, L2: 12, L3: 14, L4: 14, L5: 14, L6: 16
- - L7: 16, L8: 18, L9: 18, L10: 20, L11: 22, L12: 99 (unbeatable)
-
-#### 2. `src/lib/progress.js`
-- [ ] Extend schema: add `levelStars: {}` and `levelBestMoves: {}` to DEFAULT_PROGRESS
-- [ ] `getProgress()`: merge missing keys for backwards compat
-- [ ] Update `completeLevel(levelNum, totalLevels, moves, parMoves)`:
- - Calculate stars
- - Store best stars (only if better than existing)
- - Store best moves (only if fewer than existing)
- - Return `{ ...progress, stars }` so caller can display
-
-#### 3. `src/scenes/Game.svelte`
-- [ ] Import `LEVELS` to access `parMoves` for current level
-- [ ] Pass `turnManager.turnCount` and `parMoves` to `completeLevel()`
-- [ ] After level complete, show star rating overlay before navigating
-- [ ] Add `LevelComplete` popup component (inline or separate small component)
- - Shows 1-3 stars with animation
- - Shows move count vs par
- - "Next Level" button
-
-#### 4. `src/scenes/LevelSelect.svelte`
-- [ ] Read `progress.levelStars` in addition to `completedLevels`
-- [ ] Replace checkmark with star display (1-3 stars shown as filled/empty)
-- [ ] Show best move count under level number
-
-#### 5. `src/components/GameHud.svelte`
-- [ ] No changes needed — already shows turn count
-
-### localStorage Schema (backwards compatible)
-
-```js
-// Old format still works — missing keys get defaults
-{
- maxLevel: 5,
- completedLevels: [1, 2, 3, 4],
- // NEW — absent in old saves, defaults to {}
- levelStars: { "1": 3, "2": 2, "3": 1 },
- levelBestMoves: { "1": 8, "2": 14, "3": 20 }
-}
-```
-
-### Edge Cases
-
-- Old localStorage without `levelStars`/`levelBestMoves` → defaults to `{}`
-- Level 12 unbeatable → `parMoves: 99` never matters
-- Player completes level with worse score → keep existing best
-- `completeLevel` called with no moves param (old code path) → skip star calc
-
-### Success Criteria
-
-- Star rating appears on level complete
-- Best stars persist in localStorage
-- Level select shows stars per level
-- Old saves don't break (backwards compat)
-
-### Rollback
-
-Revert commit. Old localStorage data unaffected (new keys simply disappear).
diff --git a/plans/260413-1416-gameplay-improvements/phase-03-level-redesign.md b/plans/260413-1416-gameplay-improvements/phase-03-level-redesign.md
deleted file mode 100644
index c123cc2..0000000
--- a/plans/260413-1416-gameplay-improvements/phase-03-level-redesign.md
+++ /dev/null
@@ -1,89 +0,0 @@
-## Phase 3: Level Redesign + Chaser Guard
-
-**Priority:** P1 | **Status:** Pending | **Effort:** 3h
-
-### Overview
-
-Redesign existing 12 levels for more challenge. Add **Chaser guard** type.
-Finalize `parMoves` values after redesign. Level 12 remains unbeatable.
-
-### New Guard Type: ChaserGuard
-
-**Behavior:** Dormant until player enters Manhattan distance <= `detectionRadius` (default 3).
-Once triggered, moves 1 cell toward player's **last known position** each turn.
-Lights its own cell + adjacent cell in movement direction. Returns to start if reaches
-last known position and player not visible.
-
-**Why Chaser over Sentry:** Chaser creates dynamic panic — player must change route.
-Sentry is just a fancy static guard (cone vision = static pattern). Chaser adds genuine
-reactive gameplay with minimal code.
-
-#### Implementation in `src/lib/game/guards.js`
-
-- [ ] Add `ChaserGuard` class extending `Guard`:
- ```
- Properties: detectionRadius, startRow, startCol, targetRow, targetCol,
- isChasing, lastKnownRow, lastKnownCol
- Methods:
- - onTurnChange(allGuards, player): check distance to player
- - If within radius and not blocked by wall: set isChasing, record lastKnownPos
- - If chasing: move 1 step toward lastKnownPos (prefer row then col)
- - If reached lastKnownPos and player not in radius: return to start
- - updateLight(): light own cell + 1 cell in facing direction
- ```
-- [ ] Key: `onTurnChange` needs player reference — update signature
-
-#### Turn Manager Change (`src/lib/game/turn-manager.js`)
-
-- [ ] Pass `player` to `guard.onTurnChange(guards, player)` — non-breaking since
- existing guards ignore extra params
-
-#### Level Manager Change (`src/lib/game/level-manager.js`)
-
-- [ ] Add `case 'chaser'` to guard factory switch
-
-#### Guard Sprite (`src/components/GuardSprite.svelte`)
-
-- [ ] Add chaser visual (red-tinted sprite, or different emoji/icon)
-- [ ] Show "alert" state when `isChasing` is true
-
-### Level Redesign Principles
-
-1. **Tighter corridors** — reduce open space, force specific paths
-2. **More guards per level** — current levels are sparse
-3. **Timing windows** — require waiting (Phase 1) for safe passage
-4. **Chaser placement** — put chasers near obvious paths to force detours
-5. **Level 12** — keep walls + guard placement, only verify light wave still covers all paths
-
-### Level-by-Level Notes
-
-- [ ] **L1-2** (tutorial): Keep simple but add 1 more wall each to reduce trivial paths
-- [ ] **L3-4** (rotating intro): Add extra static guard, narrow corridors
-- [ ] **L5-6** (blinking): Tighter timing — reduce safe windows from 2 turns to 1
-- [ ] **L7-8** (patrolling): Add walls to force player into patrol paths, require waiting
-- [ ] **L9** (decoy): Add chaser near the "obvious" short path — punishes rushing
-- [ ] **L10** (mirrors): Add more mirror bounces, tighter spaces
-- [ ] **L11** (throne room): Add chaser + extra patrolling guard
-- [ ] **L12** (princess): DO NOT CHANGE core mechanic. May add 1-2 more guards in upper sections
-- [ ] **Finalize parMoves** for each level after redesign (playtest manually)
-
-### Edge Cases / Risks
-
-| Risk | Likelihood | Impact | Mitigation |
-|------|-----------|--------|------------|
-| Level becomes unsolvable | Medium | High | Playtest each level; keep at least 1 valid path |
-| Chaser pathfinding hits wall | Medium | Medium | Simple Manhattan step; skip move if blocked by wall |
-| Level 12 becomes beatable | Low | High | Verify: expanding light wave from (9,9) covers all reachable cells within player's max possible steps |
-| ChaserGuard makes levels too hard | Medium | Low | Tune detectionRadius per level (2-4 range) |
-
-### Success Criteria
-
-- All levels 1-11 are solvable but require thought
-- At least 3 levels benefit from wait action
-- Chaser guard creates noticeable tension when triggered
-- Level 12 remains provably unbeatable
-- parMoves set to optimal-path length for each level
-
-### Rollback
-
-Revert commit restores old level definitions and removes ChaserGuard class.
diff --git a/plans/260413-1416-gameplay-improvements/phase-04-vision-preview.md b/plans/260413-1416-gameplay-improvements/phase-04-vision-preview.md
deleted file mode 100644
index 255b325..0000000
--- a/plans/260413-1416-gameplay-improvements/phase-04-vision-preview.md
+++ /dev/null
@@ -1,49 +0,0 @@
-## Phase 4: Guard Vision Preview (Optional)
-
-**Priority:** P3 | **Status:** Pending | **Effort:** 45min
-
-### Overview
-
-Show semi-transparent overlay of cells that will be lit NEXT turn.
-Helps player plan without trial-and-error. Toggle via button or hotkey.
-
-### Data Flow
-
-1. Before rendering, simulate next turn's guard positions/lights on a **cloned grid**
-2. Diff current lit cells vs next-turn lit cells
-3. Render "preview" cells with distinct CSS class (e.g., `cell-preview` with 20% opacity warning color)
-
-### Implementation
-
-#### `src/lib/game/turn-manager.js`
-- [ ] Add `previewNextTurn(grid, guards)` method:
- - Deep-clone guard states (row, col, direction, isOn, currentPathIndex, isReversing)
- - Create temporary grid clone
- - Run `onTurnChange` on clones
- - Return Set of `"row,col"` strings for next-turn lit cells
-
-#### `src/scenes/Game.svelte`
-- [ ] Add `showPreview` toggle state (default false)
-- [ ] Bind `v` key or HUD button to toggle
-- [ ] Compute `previewCells` derived from `turnManager.previewNextTurn()` when toggle on
-- [ ] Pass `previewCells` to `GameBoard`
-
-#### `src/components/GameBoard.svelte`
-- [ ] Accept optional `previewCells` prop
-- [ ] Add `cell-preview` CSS class to cells in preview set
-
-### Edge Cases
-
-- Chaser guard preview needs player position — pass current player pos to preview
-- Level 12 expanding wave — preview should show next ring expansion
-- Performance: cloning 5-10 guards per frame is trivial for grid sizes <= 10x10
-
-### Success Criteria
-
-- Toggle shows/hides next-turn danger zones
-- Preview visually distinct from current lit cells (different opacity/color)
-- No performance impact on turn processing
-
-### Rollback
-
-Revert commit. Preview is purely additive UI — no game logic changes.
diff --git a/plans/260413-1416-gameplay-improvements/plan.md b/plans/260413-1416-gameplay-improvements/plan.md
deleted file mode 100644
index 9bf2fba..0000000
--- a/plans/260413-1416-gameplay-improvements/plan.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: "Gameplay Improvements: Wait Action, Star Rating, Level Redesign"
-description: "Add wait mechanic, star/par rating system, and redesign levels for challenge"
-status: done
-priority: P1
-effort: 6h
-branch: main
-tags: [gameplay, levels, ux]
-created: 2026-04-13
----
-
-# Gameplay Improvements Plan
-
-## Phases
-
-| # | Phase | Effort | Status | Files Modified |
-|---|-------|--------|--------|----------------|
-| 1 | [Wait Action](phase-01-wait-action.md) | 15min | Done | Game.svelte |
-| 2 | [Star Rating + Par Moves](phase-02-star-rating.md) | 2h | Done | levels.js, progress.js, Game.svelte, LevelSelect.svelte, LevelCompletePopup.svelte |
-| 3 | [Level Redesign + Chaser Guard](phase-03-level-redesign.md) | 3h | Done | levels.js, guards.js, level-manager.js, GuardSprite.svelte, theme.css |
-| 4 | [Guard Vision Preview](phase-04-vision-preview.md) | 45min | Done | GameBoard.svelte, Game.svelte, turn-manager.js, GameHud.svelte |
-
-## Dependency Graph
-
-```
-Phase 1 (Wait) ── no deps, standalone
-Phase 2 (Stars) ── no deps, standalone
-Phase 3 (Levels) ── after Phase 1 + 2 (par values depend on wait mechanic existing)
-Phase 4 (Preview) ── after Phase 3 (needs final guard configs)
-```
-
-## File Ownership (no parallel conflicts)
-
-- Phase 1: Game.svelte only (input handler)
-- Phase 2: progress.js, LevelSelect.svelte, GameHud.svelte, + level complete flow in Game.svelte
-- Phase 3: levels.js, guards.js, level-manager.js, GuardSprite.svelte
-- Phase 4: GameBoard.svelte (new overlay layer)
-
-## Key Constraints
-
-- Level 12 MUST remain unbeatable (expanding light wave from goal covers all paths)
-- No new npm dependencies
-- All state stays in pure JS classes; Svelte 5 reactivity via renderVersion bump pattern
-- localStorage schema must be backwards-compatible (existing `nntv-progress` key)
-
-## Rollback
-
-Each phase is a single commit. Revert commit to rollback. No data migrations needed
-(localStorage schema only adds optional fields, old data still works).
-
-## Success Criteria
-
-1. Spacebar wait works, guards advance, player stays
-2. Stars show on level complete + level select; persist across sessions
-3. Levels require more thought; at least 3 levels need wait action to solve optimally
-4. Level 12 still unbeatable (manual verification)
-5. (Optional) Ghost overlay shows next-turn danger zones
diff --git a/plans/reports/researcher-260412-1127-svelte5-grid-puzzle-game.md b/plans/reports/researcher-260412-1127-svelte5-grid-puzzle-game.md
deleted file mode 100644
index ae480b3..0000000
--- a/plans/reports/researcher-260412-1127-svelte5-grid-puzzle-game.md
+++ /dev/null
@@ -1,293 +0,0 @@
-# Svelte 5 Research: Grid Puzzle Game Rewrite
-
-**Status:** Complete | **Focus:** Runes, setup, transitions, grid patterns, state management
-**Date:** 2026-04-12 | **Scope:** Actionable patterns for turn-based grid game
-
----
-
-## 1. Svelte 5 Runes Syntax — Reactive State
-
-### Core Pattern: $state for Grid
-Runes are compiler keywords (not functions), prefixed with `$`. Use `$state` to declare reactive cell data.
-
-**Grid state pattern (array of cells):**
-```javascript
-let grid = $state([
- { id: 0, type: 'wall' },
- { id: 1, type: 'floor' },
- // ... 16+ cells
-]);
-```
-
-**For object-based grid:**
-```javascript
-let gridMap = $state(new Map([
- ['0,0', { type: 'wall', solved: false }],
- ['0,1', { type: 'puzzle', value: 5 }],
-]));
-```
-
-### $derived — Computed Grid State
-Auto-updates when dependencies change (memoized). Zero side-effects allowed.
-
-```javascript
-let solvedCount = $derived(grid.filter(c => c.solved).length);
-let isWon = $derived(solvedCount === grid.length);
-let gridDisplay = $derived(grid.map(c => c.type)); // safe memo
-```
-
-### $effect — Side Effects (Subscriptions, DOM, Analytics)
-Runs after DOM update. Return cleanup function for teardown.
-
-```javascript
-$effect(() => {
- console.log('Game state changed:', grid);
- localStorage.setItem('game', JSON.stringify(grid));
-});
-
-$effect(() => {
- return () => console.log('Component unmounting'); // cleanup
-});
-```
-
-### Key Gotchas
-- Avoid mutations inside `$derived`: `$derived(count++)` **fails**.
-- `$state` works outside `.svelte` files (in `.svelte.js` / `.svelte.ts`).
-- Runes replace old `let x = 0; $: x = x + 1` reactive declarations.
-
----
-
-## 2. Svelte 5 + Vite Setup
-
-### Recommended: Use `sv` CLI (SvelteKit)
-```bash
-npx sv create my-puzzle-game
-# Select: Svelte, TypeScript, Vitest, Prettier
-cd my-puzzle-game
-npm run dev
-```
-
-Scaffold includes: Vite (pre-configured), TypeScript, dev server at `localhost:5173`.
-
-### Alternative: Bare Svelte + Vite
-```bash
-npm create vite@latest my-game -- --template svelte-ts
-npm install
-npm run dev
-```
-
-Simpler but misses SvelteKit's routing/build optimizations. **For a static SPA game, either works.**
-
-### Vite Config (if bare Svelte)
-`vite.config.ts` auto-includes `vite-plugin-svelte`. No manual config needed for basic setup.
-
----
-
-## 3. Scene Transitions (Fade/Fly/Slide)
-
-### Pattern: Conditional Scenes
-```svelte
-
-
-{#if currentScene === 'intro'}
-
-
Intro Scene
-
-
-{:else if currentScene === 'game'}
-
-
-
-{:else if currentScene === 'win'}
-
-
You Won!
-
-{/if}
-```
-
-### Available Transitions
-| Name | Use | Params |
-|------|-----|--------|
-| `fade` | Opacity 0→1 | `duration`, `delay`, `easing` |
-| `fly` | Position + opacity | `x`, `y`, `duration` |
-| `slide` | Axis-based slide | `axis` ('x'/'y'), `duration` |
-| `scale`, `blur` | Also available | config object |
-
-### Bidirectional
-`transition:` works both in and out. Reverses smoothly mid-animation if toggled.
-
----
-
-## 4. CSS Grid for Game Board
-
-### Reactive Grid Layout
-```svelte
-
-
-
- {#each grid as cell (cell.id)}
-
handleCellClick(cell.id)}>
- {cell.id}
-
- {/each}
-
-
-
-```
-
-### Performance Note
-Svelte's fine-grained reactivity means updating a single cell **doesn't re-render all others**. Safe for responsive grids (6x6, 8x8).
-
----
-
-## 5. State Management: Stores vs. Runes
-
-### For Game Progress + Localization: Use Runes in `.svelte.js`
-
-**gameState.svelte.js:**
-```javascript
-export const game = $state({
- level: 1,
- moves: 0,
- isWon: false,
- grid: [],
-});
-
-export const i18n = $state({
- lang: 'en',
- strings: { title: 'Puzzle Game', play: 'Play' },
-});
-
-export function resetLevel() {
- game.level = 1;
- game.moves = 0;
- game.isWon = false;
-}
-```
-
-**App.svelte:**
-```svelte
-
-
-
{i18n.strings.title}
-
Level {game.level} • Moves: {game.moves}
-
-```
-
-### When to Use Stores (Deprecated Pattern)
-Only for **async data streams** (polling, WebSocket). Most games don't need this.
-
-### Why Runes > Stores
-- No boilerplate (no `writable()`, `.subscribe()`).
-- Works in plain `.js` files (shared logic).
-- Memoization via `$derived`.
-
----
-
-## 6. SvelteKit vs. Plain Svelte for Static Game
-
-### Recommendation: **Use Plain Svelte + Vite**
-
-| Criteria | Plain Svelte | SvelteKit |
-|----------|--------------|-----------|
-| **Setup time** | 2 min | 3 min |
-| **Routing** | Manual | File-based (unnecessary) |
-| **Build output** | Single HTML/JS | Server capable |
-| **Static deploy** | ✅ Simpler | ✅ Needs adapter-static |
-| **DevTools** | Vite only | Vite + SvelteKit CLI |
-| **Scaling** | Hits limits ~2-3 scenes | Extensible |
-
-### For a Static SPA Game
-```bash
-npm create vite@latest my-game -- --template svelte-ts
-```
-
-This is **KISS**. No file-based routing overhead, no server code, direct control.
-
-### Only Use SvelteKit If
-- Game needs **server-side scoring/leaderboards** (then use SvelteKit backend).
-- Game will expand to **10+ pages** (use file-based routing).
-- Team prefers **unified framework** across multiple projects.
-
----
-
-## Implementation Checklist
-
-### Phase 1: Setup
-- [ ] `npm create vite@latest` (svelte-ts template)
-- [ ] Replace Vite's default App.svelte with game component
-- [ ] Verify `npm run dev` opens at localhost:5173
-
-### Phase 2: Grid & State
-- [ ] Create `gameState.svelte.js` with `$state(grid)`
-- [ ] Build `GameBoard.svelte` with CSS Grid + `{#each grid}`
-- [ ] Wire `$derived(isWon)` from grid state
-
-### Phase 3: Interactions
-- [ ] Add cell click handlers → update grid state
-- [ ] Bind to `$effect` for persistence (localStorage)
-- [ ] Test fine-grained reactivity (click cell, only that cell re-renders)
-
-### Phase 4: Transitions
-- [ ] Import `fade`, `fly`, `slide` from `svelte/transition`
-- [ ] Wrap scenes in conditional blocks with `transition:` directives
-- [ ] Test bidirectional transitions (scene switches)
-
-### Phase 5: Deploy
-- [ ] `npm run build` → outputs `dist/` (static)
-- [ ] Upload `dist/` to any static host (Vercel, GitHub Pages, Netlify)
-
----
-
-## Trade-offs & Adoption Risk
-
-| Risk | Mitigation |
-|------|-----------|
-| Svelte 5 is new (2024+) | Use LTS minor versions; runes are stable now |
-| Team unfamiliar with runes | Runes are **simpler** than Vue/React hooks; quick ramp |
-| Grid performance at scale | Fine-grained reactivity handles 100+ cells easily |
-| Transitions can stutter | Use `duration: 200–400ms`; test on target devices |
-
----
-
-## Sources
-
-- [Svelte Runes Documentation](https://svelte.dev/docs/svelte/what-are-runes)
-- [Svelte Transitions](https://svelte.dev/docs/svelte/svelte-transition)
-- [Svelte Stores](https://svelte.dev/docs/svelte/stores)
-- [SvelteKit Single-Page Apps](https://svelte.dev/docs/kit/single-page-apps)
-- [Getting Started](https://svelte.dev/docs/svelte/getting-started)
-- [Mainmatter: Runes and Global State](https://mainmatter.com/blog/2025/03/11/global-state-in-svelte-5/)
-- [Frontend Masters: Game Board Grid](https://frontendmasters.com/courses/svelte-v2/game-board-grid/)
-
----
-
-## Unresolved Questions
-
-- **WebSocket multiplayer?** Not covered; requires SvelteKit backend or third-party service.
-- **Mobile touch events?** Standard DOM events work; no Svelte-specific guidance needed.
-- **Save file encryption?** Depends on backend; out of scope for static game.