Files
noitu/web/tests
tiennm99 db7093bbe5 fix(web): make the game comfortable to play on a phone and in both themes
Applies the findings of the three UI/UX reviews. The two that cost a
player something every single turn:

- The countdown reddened during the opponent's turn. It read the deadline,
  which the server rewrites on every handover, and never asked whose turn
  it was — a panic spike, every turn, about nothing the player could act
  on. It now mutes when the clock is not theirs, and signals urgency by
  thickening as well as reddening, because green to red is the pair a
  red-green colour blindness cannot separate.

- On a phone the keyboard closed on every turn and could not be reopened.
  `disabled` on the focused word field blurs it, and the recovering
  focus() ran on a WebSocket message, which iOS will not open a keyboard
  for. The field stays editable and the submit button carries the turn
  instead; focus is asked for inside the gesture that submitted. A draft
  aimed at a syllable the game has moved past is now corrected rather
  than kept.

The board was also not holding together as the game grew. `min-height`
on the shell left nothing with a definite height to shrink against, so
the chain kept its full height and the page got taller every turn,
walking the word field and the chat off the bottom of the screen. The
shell now has a real height, the chain gives up its space first with a
floor so it cannot vanish, and `main` scrolls only as a last resort.

Online play had one true dead end: nothing on the pre-room screen showed
the connection at all, so a server that was down left an enabled button
and a screen that never changed — while each impatient tap sent a real
CreateRoom until the rate limiter answered. The badge is there now,
requests disable their button, a stall says so, and the lobby draws the
room's refusals beside the button that produced them instead of in a
chat panel below the fold. A dropped player gets a retry rather than
waiting out the backoff. An invite link asks a first-time guest for a
name instead of seating them as "Người chơi" with no way to fix it.

Accessibility and palette:

- The turn change is announced. It is the state the whole game hangs on
  and it reached nobody who was not looking at that line.
- --accent darkened to #12692f: accent text on its own tint measured
  4.29:1. Every existing pair improves, white-on-accent included.
- --border-strong added for the boundary of anything you type into or
  press, which needs 3:1 and had 1.47:1 light, 1.78:1 dark.
- One focus ring, one 44px icon-button recipe, spacing and type scales,
  safe-area gutters, per-route titles, a heading per screen, a skip
  link, and reduced motion that stops the connection dot pulsing rather
  than flickering it a hundred thousand times a frame.

Tests follow the two interactions that changed shape: resign and kick
confirm inline with a second press, because confirm() blocks the frame
loop the countdown runs on and hesitating could cost the turn it was
protecting. joinRoomSeated waits for the seat before anybody speaks —
the server replays a seat only the conversation from when it joined, so
the old helper was racing the handshake.

Verified: 189 unit tests, 40 end-to-end, no type errors, and the
palette and layout measured at 360/400/768/1280 in both themes.
2026-09-10 13:04:13 +07:00
..