Function
A client component because progress lives in localStorage. It reads that
progress once, through useModuleRoute, and hands the same reading to the
panel and to every step, so the count in the panel and the steps on the
route can never disagree.
Until progress is read, every step renders as upcoming and the panel shows no figures — the server-rendered frame asserts nothing about the learner.
The prize is read once too, and handed to the panel's prize row and to the route's finale together with the route's own "read" signal: the ticket stores have none of their own, and the two surfaces must never disagree. The finale follows the list of steps rather than joining it, so the route keeps exactly one step per lesson.
The panel comes first in the DOM, so its figures are read before the list at
every width; from lg it moves to a sticky right-hand column.
The learner's route through a module: the progress panel, one step per lesson, each showing whether it is finished, current or upcoming, and the module's prize at the end of the route.