Build a complete, polished match-3 puzzle game as a single-page mobile-portrait web app.

REQUIREMENTS:
- Mobile-portrait viewport (390x844-ish), but render at full window if possible
- Vite + TypeScript scaffold in the current directory. Use `npm create vite@latest . -- --template vanilla-ts` to scaffold, or write the structure by hand if you prefer
- Render to a single canvas or DOM grid (your call — I want this to look GOOD)
- Match-3 mechanics:
  - 8x8 board minimum
  - At least 5 distinct gem/tile types (use clear colors + simple shapes/icons, don't just use letters)
  - Swap two adjacent tiles by drag or tap-tap
  - Match detection: horizontal or vertical runs of 3+
  - Matched tiles clear, gravity drops remaining tiles down, new tiles spawn at top
  - Cascading matches chain and award bonus
  - Reject swaps that don't create a match (or be lenient — your call, but document the choice)
- Scoring: score increases on match, multiplier on cascade
- Smooth animations: swap, fall, clear (don't snap-cut between states)
- Title screen with "Start", in-game HUD with score + moves remaining (or time), game-over screen
- Sound: optional but appreciated. If you add it, gate behind a mute toggle and use Web Audio API tones (no external assets)
- Final build at `dist/` via `npm run build`. The dist must be self-contained and openable from a python http.server

WHAT MATTERS:
- The game must actually work end-to-end. Title -> game -> game-over -> title.
- It should look like a real game, not a tech demo. Consider: a coherent color palette, a font that isn't browser default, micro-animations.
- Clean code, but PRIORITY is shipping a working playable build over code purity.

WHEN DONE:
- Run `npm run build` and confirm dist/ exists
- Print a brief summary: what mechanics shipped, what didn't, any known bugs
- Do NOT ask clarifying questions — make opinionated calls and ship

Take your time. Aim for a quality bar similar to a small indie web puzzle game.
