Applies the same sticky-zone pattern as the boss and quest panels.
The handleZoneSelect wrapper already existed — it just needed to write
to sessionStorage alongside updating state, and the useState initialiser
needed to read from sessionStorage on mount.
item.type only has three possible values (weapon/armour/trinket).
Using it as a React key is safe in practice because the equipment system
enforces one item per slot, but item.name is a stable, semantically
correct unique identifier that does not rely on that invariant.
The previous key `${reward.type}-${amount ?? ""}` collapsed to
"adventurer-" for every adventurer-unlock reward (which carries no
amount), producing duplicate-key React warnings on every render tick.
Because console.error is forwarded to the backend telemetry service,
this caused continuous email alerts.
The key now uses targetId (present on adventurer and upgrade rewards)
first, falls back to amount (present on gold/essence/crystal rewards),
and uses the map index only as a last resort.
Both the boss panel and the quest panel now read their active zone from
sessionStorage on mount and write back to it whenever the user selects
a new zone. The stored selections are cleared automatically when the
session ends, and fall back to verdant_vale when no stored value exists.
Closes#36
Reads the saved batch-size preference on mount and writes it back to
localStorage on every selection change, so the chosen multiplier
survives page refreshes. Falls back to 1 when no stored value is found
or the value is unrecognisable.
Closes#35