v0.9.0

 - A blue team check page. Each check a team is scored on now has its own page, showing the fields
   that team controls, how the check has been going for them, and the recent rounds with the reason
   for each failure
 - Check names on the scoreboard are links. A blue teamer lands on their own team's view of that
   check, staff land on the check's settings in the admin panel, and an anonymous viewer gets no
   link, since the scoreboard is public and the destinations are not
 - Blue teams can set their own values for a check's declared variables. Everything on the card
   saves in one request, and a rejected variable takes the whole batch with it, so the form can
   never half-apply. A secret stays write-only, so its box starts empty and a badge says whether the
   team has already set one
 - Per-check statistics for a team: passed, failed, uptime, the points the check has earned, and
   average and most recent response time
 - Two charts on the check page, drawn with @tanstack/charts. An uptime strip with one bar per
   round, and a response time line. Hovering either names the round, the result and the points, or
   the latency
 - A paginated table of recent rounds, with page sizes, a Refresh button and a last-updated time.
   It also polls on the round interval, so a team watching a fix land sees it without pressing
   anything
 - Chain checks show which step failed and which never ran. The runner stops at the first required
   failure and records nothing for the steps after it, so the page reads the chain's declared steps
   and marks those as never run rather than leaving them off the list
 - `GET /api/checks/{id}/results/mine` and `GET /api/checks/{id}/stats/mine`, both blue team gated,
   both scoped to the calling team by its token rather than by anything in the request
 - Check fields can be hidden by a condition. An http request body is now hidden until a content
   type is chosen, instead of sitting there asking to be filled in for a request that will not
   carry it
 - The browser tab reads "(DEV) Hermes" when the frontend runs in development, so a dev tab is not
   mistaken for the live one

 ## Changed
 - `PUT /api/checks/{id}/variables/mine` takes the whole set of variables in one `variables` JSON
   array instead of one `variable_name` and `variable_value` per request. This breaks any existing
   caller. The saved Bruno requests are updated
 - A check's status on the scoreboard is now derived from whether the check succeeded, with its
   status text asked only whether the check reached a verdict at all. The scoreboard and the blue
   team check page read the same four states with the same wording, so a round cannot be labelled
   one way in one place and another way in the other. Each theme keeps its own colours
 - Blue team check code gathered into one `blue_checks.go` per package, and the blue team requests
   moved out of the Bruno collection's "admin actions" folder into their own
 - The blue team check page split into a page plus three components, in line with how the admin
   check pages are laid out
 - A new index on `Round_Ledger (user_id, check_id, round_id DESC)`. A team's history for one check
   used to scan the whole ledger, since the existing unique constraint leads with `round_id`.
   `setup_db.go` only runs against a fresh database, so an existing deployment needs the statement
   applied by hand

 ## Fixed
 - The scoreboard logged `retrieved unknown check status` to the console on every cell, every
   render, for any status outside a fixed list it matched against. That list had fallen behind the
   engine: a cancelled check was never in it, and neither were rows left over from an earlier
   version. Both now resolve without the noise