- selection: clearAllGames() wipes seen/caught for every game but keeps
the global favorites/notes record.
- Progress view: a "Reset caught / seen…" action (custom dialog) that
calls clearAllGames — the soft, favorites-preserving reset. Settings →
"Clear tracking data" stays as the full wipe (now spells out that it
also drops favorites and notes, and points here for the softer one).
- Swept the remaining window.confirm / window.alert calls
(Settings clear-tracking, clear-cache, backup import result;
ShinyView delete-hunt) onto chooseDialog for a consistent look.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
Progress view "Your games" now has an Edit mode: tap a game to open a
dialog to **reset** its caught/seen (keeps it listed) or **remove** it
from the list (also clears its bucket). The currently-selected game can't
be removed (it'd re-add on next launch) — reset only. New
`clearGame(vgKey)` in the selection store.
Lighthouse pass (headless, local): SEO 100, a11y 96, best-practices 96.
- add public/robots.txt (SEO 92 → 100)
- ProgressRing: keep the aria-label in sync with the visible count
(fixes label-content-name-mismatch)
- .type-chip: text-shadow for white-on-bright-type-colour legibility,
0.68 → 0.7rem
Still open (design calls, see notes): type-chip colour contrast is
~2–3.7:1 for the lighter types (white on the canonical type colours);
some sub-12px labels; performance is dominated by the ~1 MB snapshot and
the ~1000-card grid.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
Pure formatting — no behaviour change. Verified: build passes, all 14
routes render, service worker active, no console errors.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
Catching a Pokémon in Blue was counting it as caught in Gold, Emerald and
every other game, because the whole app ran on one caught record keyed by
National Dex id. Progress by game just intersected that set with each
game's species list, so the per-game bars were meaningless.
selection store is now:
pokemon: { [id]: { favorite, note } } -- global (describe the mon)
games: { [vg]: { [id]: { seen, caught } } } -- per game
- entry(id) / toggle(id, field) / stats(ids) default to the selected game;
favorite/note stay global. 'all' (All-games mode) reads as the union of
every game -- "caught anywhere" -- and is a real bucket you write to when
no specific game is selected.
- v2 stores migrate on load (normalizeSelection): favorite/note lift out,
seen/caught drop into the 'all' bucket so nothing is falsely attributed
to a game. Same path runs on JSON backup import.
- ProgressView: each game row counts its own bucket; National row =
statsNational (union). Intro text slimmed.
- Save import writes into one game bucket -- the selected game if it's a
candidate for that save, else the parser's first guess -- and the dialog
names which game it's importing to.
- DexGrid feed (ring, filter counts, caught-sort), PokemonDetail track
buttons, search dots, shiny "found it" all follow the selected game.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
- Save import now opens a small choice dialog (new lib/dialog.js) instead
of a confirm(): "Add to my Pokédex" (merge, keeps everything) or
"Replace mine with this". Replace resets seen/caught to exactly the
save but keeps favourites and notes (new selection.replaceFlags). The
dialog also explains that caught state is shared across games, so an
imported save only ever adds species that game has and they count
toward the National Dex too — no per-game caught flag, by design.
- The dex-feed progress ring is now an <a href="#/progress"> with a
hover/press nudge — tapping it opens the per-game breakdown.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
lib/savedex.js parses a Generation III save (Ruby/Sapphire/Emerald/
FireRed/LeafGreen): picks the newer of the two save slots, resolves the
rotated section order via each section's footer, and reads the seen /
owned bitfields out of `struct Pokedex` in section 0 (bit dexNo-1, 386
species). Also decodes the trainer name and detects the national-dex
magic byte. Soft checksum check.
Settings > Your data: "Import from a GBA save" — file picker → confirm →
selection.importFlags() merges seen/caught in (never removes). Verified
against synthetic saves (slot selection, rotation, FRLG vs RSE, bit
decode) and end-to-end through the Settings UI.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu