feat: settings become five groups that state their own answer

The panel was one open block of everything in two columns. That reads fine at
four games and stops working at eighteen: the game list alone is eighteen rows
of four controls each, and it sat above the checkbox somebody had scrolled down
here to tick. Nothing was findable and everything was in the way.

Collapsing it into groups is only half an answer, though — a group showing
nothing but its name turns "what is my region set to?" into a click, which
trades one kind of friction for another. So each summary carries its group's
current state: "Europe · Dark", "17 of 18 on · A–Z", "plus finished, not
started". Closed, the panel is a five-line report of how the app is configured;
opening one is for changing an answer rather than reading it. The states are
derived from `prefs` at render, never stored, so they cannot drift from the
controls they describe.

Native `<details>`, for the reason the reorder arrows are ordinary buttons:
keyboard and screen reader reach it with no second implementation. `summary` is
not an `a`, `button` or `[tabindex]`, so it needed its own focus-visible rule —
the shared one does not reach it.

Two things fell out along the way. The region and appearance rows had no
accessible name at all, so a screen reader read six unlabelled buttons in a row;
they and the board's split pills are one `PillGroup` now, with the `role="group"`
the board's own controls already carry. And the empty states that point at
"Show events that haven't started" now name the group holding it, which is what
makes shipping the groups closed safe.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-08-20 06:29:28 +02:00
co-authored by Claude Opus 5
parent 14f6f2f0dc
commit fb390c1af8
8 changed files with 498 additions and 215 deletions
+14
View File
@@ -203,6 +203,20 @@ but de-emphasized; a filter toggles them out entirely.
Filter by game (multi-select, persisted) and by event type. Hiding a game hides it from both views.
Preferences persist in `localStorage`.
The panel holding them is **five collapsed groups, each stating its own answer on the summary line**
— games, reading, what you see, your own games and events, your progress. It was one open block of
everything, laid out in two columns on a wide screen, which read fine at four games and stopped
working at eighteen: the game list alone is eighteen rows of four controls, and it sat above the
checkbox a reader had come down here to tick. Collapsing on its own would only trade that friction
for another, though — a group that shows nothing but its name turns *what is my region set to?* into
a click — so each summary answers its group's question, and the closed panel is a five-line report
of how the app is configured. Opening one is for changing an answer, not for reading it.
Two things follow. **The groups ship closed**, including the one holding the filters that other copy
points at: the empty states name both the switch and the group it is in, which is more findable than
a checkbox in a wall was. And **the summary states are derived, never stored** — they are a reading
of `prefs`, so they cannot disagree with the controls inside.
**F4a — Focus one game at a time.**
Switching games on and off says *which games the reader plays*, and is set once. It is the wrong
tool for the thing a player of four games actually does while reading: clear one game, move to the