Code fixes:
- The narrow-screen fold was specified and never built (4/4). The tray and
notes are now closed <details> in the aside; above 1000px CSS alone
(::details-content) shows them and hides the summary. There is no
script. Browser-tested at 390 and 1400, JS on and off.
- The lightbox gated on parsed board rows, not page identity (3/4). It now
uses is_board, the lesson the bench panel already carried.
- wants_json returned True at the first good entry, so a malformed later
entry was never read (3/4). It now parses every entry first; any error
is False.
- One flag predicate, flagged_targets. It serves the Desk count, the tray,
the filmstrip, the tape and the review button. An unreadable flag entry
counts nowhere.
- The header's open count and lifetime line, and the no-set marks panel,
are now regions (they were stale after an in-place answer).
- Inline group headers render only when every group is one contiguous run.
Interleaved directories no longer reprint or misfile headers.
- A booth held unreadable has no open_since, even with a readable pick
beside the damage.
- The swap marks an absent region is-stale instead of leaving it looking
current. It carries disclosure state (except the sent form's). The
failure message is readable for 0.9 s before the reload.
Contract amended where the code was right and the text was not: the
wants_json and record_seen signatures, landed_at's three refinements, the
group position being ring-based, the end of the set offering every other
open pick, the Space-key player exception, and the fold mechanism.
New tests cover the parse order; a board with media; the header region; the
no-set panel; interleaved groups; mixed damage; the flag predicate; the
review recording .viewed; the fold at two widths with JS on and off; the
status message before the reload; a lost response after a landed write
(exactly one note); a stale absent region; stage node identity across a
swap; and F with a radio focused. The lost-response and stale tests turn
red under their mutations. 724 passed.