Appearance
2026-07-29 — Mobile lobby: cards, filters, create sheet, slim header
The lobby — the product's front door — now works one-handed on a phone. Before this, the phone lobby rendered about 2.5 columns of a 900px-minimum data grid, with the open/watch button in the last of 10 columns: off-screen on every phone, no way to act. The desktop grid is live and tuned, so it doesn't change — byte-identical, pinned by a committed-markup tripwire — and the phone gets the user-approved card model instead, chosen by the same deriveChromeMode authority as the table page (a pure function of the measured container + hysteresis; no CSS breakpoints, one definition of "mobile" app-wide).
Cards (the verb on every table). Each cash table is one tappable card carrying every grid fact — name, real-$ badge with the money-green rule, kind chip, blinds · buy-in, fill meter, status pill, rules — with open/watch on the card; tournament cards carry entry/pool/registered/payout/state with register/watch/+bot. Cards call the exact handlers the grid rows call: two renderings of one data model, field parity pinned by the card-completeness tests. Signed-out visitors browse and watch from the public feed; nothing gated leaks in.
Filters (one line + one sheet). The high-value chips (seats open, live, money, handed, type) ride a swipeable quick-filter line; the full six groups plus sort live in a bottom sheet. Line, sheet, and the desktop rail are views of ONE filter-state object — they can never disagree — and sheet sort drives the same comparators as the desktop column headers. Search collapses to a chip that expands to the full-width input (same name+code matcher).
Create (FAB → sheet, the same seam). A + new FAB floats above the claim bar (cash tab only — tournaments stay find-and-join) and opens a bottom sheet that re-shells the existing create-panel logic: the same createRoom handler and dynamic ★ Create <stakes> <size> … ★ CTA, the same server-driven fail-closed pickers (real-$ only when skpk_enabled, kinds and rule toggles only as the operator's endpoints allow), the same signed-out auth gate into the login modal — plus the room-code join row. The filter sheet's shell was extracted into one shared BottomSheet, so both sheets ride one pattern; the sheets sit modally above the claim bar (which had been overlaying their footers).
Slim header + hygiene. Collapsed, the page's top bar / hero / marquee tickers give way to one strip — brand · ★live · balance · agents link — and the lobby now writes the same <html data-chrome-mode> seam the table page writes, so the 56px site header parks off-canvas behind its grabber notch and the strip is the whole phone header. The P8 install nudge docks under it. Hero script decorations and edge-to-edge marquees are skipped (not hidden) collapsed, the page root clips horizontal overflow, and a structural 390px test pins zero body-level sideways scroll. Card-list padding and FAB offset ship as exported knobs, arithmetic-pinned so the claim bar can never silently cover the last card — and retunable at the Phase 4 real-phone gate.