Stop a wrapped label costing twelve seats their room

The sweep had carried the same residual for rounds: on the two smallest
phones with twelve players, seats painting over each other's names and
stacks. It read like a geometry problem. It was a wrapped label.

"ALL IN" is the only thing that ever lands on the stack line with a space in
it. A stack figure has no spaces, so it can only overflow, and the
puckAmountLong/Huge sizes exist to stop that; nothing had asked what the line
does when it can break. Measured at 360x640 with twelve players all-in, it
wanted 36px and had 34, broke onto a second line, and an 11px line became 22.

That is not a typography complaint, which is why it survived: it looks fine.
The puck went from 55px tall to 66, and puck height is what the ring is short
of -- at the ends of an ellipse consecutive seats are separated vertically, so
a puck 11px taller is a puck 11px further into its neighbour. The layout
search then did exactly what it is written to do: tried every width it has,
found none that cleared, and fell back to the narrowest, which is also the one
that wraps hardest.

So the rule every design system gives a badge applies here too: one line,
always. Not wrapping is only half of it -- a line that cannot wrap and still
does not fit paints over the seat next door instead -- so on the tight tier
the mark gives up its letter-spacing, 3.6px of the 36 it wanted, and keeps the
warm colour and the bold weight that do the same job.

Halving the overlap did not clear it, and the rest of the shortage was not on
the felt. The sweep had been saying so in a warning rather than a failure: at
360x640 the bar was 267px of a 640px window, 42%, against its own "persistent
chrome under 30%". Two things in it were being shown when they could not be
used. The side-pot list is decision support, and during a run-out there is no
decision to support -- it collapses to the main pot and one line for the rest.
The status row said the player count twice in the same breath, as a chip and
again inside the run-out sentence beside it.

Measured: bar 267 -> 249 on a Galaxy S8 and 267 -> 227 on an iPhone SE, felt
243 -> 283 there, worst seat overlap 34px -> 4px. Across the sweep, overlap
offender lines 33 -> 9, chips behind seats 30 -> 5, failing audits 6 -> 5, and
the iPhone SE's seat-text overlap gone entirely. No new failures.

894 tests pass, 9 of them new. Seven fault injections are each caught.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb
This commit is contained in:
2026-09-09 05:01:56 -06:00
co-authored by Claude Opus 5
parent e2bb935b43
commit 7216f3da4d
6 changed files with 295 additions and 4 deletions
+82
View File
@@ -621,6 +621,88 @@ still names whoever didn't turn over; closing it leaves **Showdown — resolve p
bar; and pressing it again resumes at the player the dealer stopped on, because the list
is computed from the cards on the table rather than remembered from the last attempt.
## Two pixels, and every seat on the felt paid for them
The sweep had carried the same residual for several rounds: on the two smallest phones
with twelve players, seats painted over each other's names and stacks. It read like a
geometry problem — twelve pucks, not enough rim — and the layout code had already been
round that loop twice, deriving the ring from the felt and searching for a puck width
that clears.
It was a wrapped label.
`"ALL IN"` is the only thing that ever lands on the stack line with a space in it. A
stack figure has no spaces, so it can only overflow, and the `puckAmountLong` and
`puckAmountHuge` sizes exist to stop it doing that. Nothing had ever asked what the line
does when it *can* break. Measured at 360x640 with twelve players all-in: it wanted 36px
and had 34, so it broke onto a second line, and an 11px line became 22.
That is not a typography complaint, which is why it survived so long — it looks fine.
The puck went from 55px tall to 66, and puck height is precisely what the ring is short
of. At the ends of an ellipse consecutive seats are separated *vertically*, so a puck
11px taller is a puck 11px further into its neighbour. The layout search then did exactly
what it is written to do: tried every width it has, found none that cleared, and fell
back to the narrowest — which, being the narrowest, is also the one that wraps hardest.
So the fix is the rule every design system already gives a badge: one line, always.
### Not wrapping is only half an answer
A line that cannot wrap and still does not fit paints over the seat next door instead —
the same failure, arriving sideways. So the mark has to actually *fit* 34px, and it
wanted 36.
Of the three things that separate "ALL IN" from a grey money figure at a glance — a warm
colour, a bold weight, and wider letters — the letter-spacing is the one that costs
pixels: 3.6px of the 36. On the tight tier it goes, and the other two stay. Measured
after: 33px of ink in a 34px box on a Galaxy S8, and the full spacing everywhere else,
because no other puck is short of the room.
The three of them are pinned in `allInMarker.test.js` against the stylesheet itself —
including the assertion that the *ordinary* spacing still doesn't fit, so that if someone
later widens the puck and makes the whole problem moot, the test says it is measuring the
wrong thing rather than passing quietly.
### And the bar was standing on the felt while nobody could act
Halving the overlap was not clearing it, and the rest of the shortage was not on the
felt at all. The sweep had been saying so for rounds, in a warning rather than a failure:
at 360x640 with twelve players all-in the action bar was **267px of a 640px window — 42%**,
against its own "persistent chrome under 30%".
Two things in it were being shown at a moment when they could not be used.
The **side-pot list** is decision support. A player working out whether to call is owed
the side pot they would be calling into, and that is worth three rows of a fixed bar.
Once everyone is all-in there is no decision left to support — the only thing that
happens for the rest of the hand is the dealer turning cards — and the list went on
standing there. During a run-out it now collapses to the main pot, which is the number a
dealer says out loud, and one line for everything else, which is what the pot wizard is
for and what that row has always said in as many words.
The **status row** said the player count twice in the same breath: a `12 players` chip,
and then `All-in — running out the board (12 players)` immediately to its right. That
reads like two different figures being quoted, and on a 360px phone it cost the sentence
a second line.
Measured across the three, on the table shape with the most seats to fit:
| | before | after |
|---|---|---|
| Bar, Galaxy S8 | 267px (42%) | 249px (39%) |
| Bar, iPhone SE | 267px (40%) | 227px (34%) |
| Bar, Pixel 7 | 267px (32%) | 227px (25%) |
| Felt height, Galaxy S8 | 192px | 210px |
| Felt height, iPhone SE | 243px | 283px |
| Worst seat overlap, iPhone SE | 34px | 4px |
| Worst seat overlap, Galaxy S8 | 34px | 17px |
The summary row is held to the same rule as the elision above it, and it is the rule that
matters most for anything that hides a number: **it must not lose a chip.** A dealer
counting the announcement against the chips in the middle of the table must not find a
shortfall the tool invented, so every row count is checked to add up to the pots it
stands for, at every table size from three players to twelve.
## The failures that only happen at the table
Everything above this line is about a tool being easy to read and quick to press. This