From c4e842f3e3c2ad81962a10a5bc87b661fc05f897 Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Wed, 2 Sep 2026 09:52:00 -0600 Subject: [PATCH] Stop the button's chip sitting on top of the name underneath it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A phone screenshot, mid-hand, eight-handed: the seat with the button reads "Christop" and then a white D. The name is centred across the whole puck and the chip sits in its top-right corner on a layer above, so a long name runs underneath and stops — measured, "Christopher" lost 20px of its 64px box. The bad part is the silence. The text believed it had the room it was being painted out of, so no ellipsis appeared: nothing on screen said the name went on. On the one seat at the table a dealer looks at most. The name now keeps out of the chip's corner on the seat that has the button, so a long one ends in an ellipsis before it gets there. Only that seat — every other puck has its full width, because the chip on those is invisible. And the audit has a check for it now. Nothing it had would have caught this: the occlusion check is about controls a thumb has to reach, and this is a label a dealer has to read. The new one measures every seat's name against its own chip and badges, and the fix was undone by hand to confirm it fires — "20px under button.dealerChip.active". 182 audits across 13 viewports, both input kinds, plain and straddled tables, every overlay: clean. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb --- JoshHeaps.Net/wwwroot/css/casino/holdem.css | 8 ++++ .../wwwroot/js/casino/holdem/render.js | 6 +++ tests/holdem/uiAudit.js | 39 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/JoshHeaps.Net/wwwroot/css/casino/holdem.css b/JoshHeaps.Net/wwwroot/css/casino/holdem.css index 99a20dc..2318c8d 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/holdem.css +++ b/JoshHeaps.Net/wwwroot/css/casino/holdem.css @@ -622,6 +622,14 @@ button, margin-top: 0.6rem; } +/* The button's chip sits in this puck's top-right corner, on a layer above the text. + Reserving its width means a long name ends in an ellipsis before it reaches the + chip, rather than disappearing underneath one — on the one seat at the table a + dealer looks at most. */ +.seat.seatHasButton .seatPuckName { + padding-right: 22px; +} + .seatPuckCards { font-size: 0.68rem; font-weight: 700; diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js index 25607fd..d275926 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js @@ -408,6 +408,12 @@ const Render = { const dealerChip = node.querySelector(".dealerChip"); const hasButton = index === dealerIndex; dealerChip.classList.toggle("active", hasButton); + // Marked on the seat as well as the chip, so the puck's own text can keep + // out from under it. A name is centred across the whole puck and the chip + // sits in the corner on a layer above: measured, "Christopher" on the + // button lost 20px of its 64px box to the chip and showed no ellipsis, + // because the text believed it had the room it was painted out of. + node.classList.toggle("seatHasButton", hasButton); dealerChip.classList.toggle("hidden", !!this.state.dedicatedDealer); // Every one of these announced itself as "D", so a screen reader heard a row // of nine identical buttons and couldn't tell which seat held the real one. diff --git a/tests/holdem/uiAudit.js b/tests/holdem/uiAudit.js index 4a9adb1..aebb402 100644 --- a/tests/holdem/uiAudit.js +++ b/tests/holdem/uiAudit.js @@ -739,6 +739,44 @@ const LayoutAudit = { return { name: "hidden means hidden", offenders }; }, + // A seat's name, painted under the decoration on its own puck. + // + // The chip that marks the button sits in the puck's top-right corner on a layer + // above the text, and the name is centred across the whole width. A long one + // therefore ran underneath it and stopped — measured, "Christopher" on the button + // lost 20px of its 64px box and showed no ellipsis, because as far as the text was + // concerned it had all the room it needed. Nothing else here would have caught it: + // the occlusion check is about controls a thumb has to reach, and this is a label + // a dealer has to read. + seatLabelsClear() { + const offenders = []; + document.querySelectorAll(".seat").forEach(seat => { + const name = seat.querySelector(".seatPuckName"); + if (!name || !name.textContent.trim()) return; + const box = name.getBoundingClientRect(); + if (!box.width || !box.height) return; + // Padding is room the text has already been kept out of, so it is not + // somewhere the text can be covered. + const style = getComputedStyle(name); + const textLeft = box.left + parseFloat(style.paddingLeft || 0); + const textRight = box.right - parseFloat(style.paddingRight || 0); + + seat.querySelectorAll(".dealerChip, .blindBadge").forEach(mark => { + const over = mark.getBoundingClientRect(); + if (!over.width || !over.height) return; + const marked = getComputedStyle(mark); + if (marked.display === "none" || marked.visibility === "hidden" || + parseFloat(marked.opacity) < 0.05) return; + const covered = Math.min(textRight, over.right) - Math.max(textLeft, over.left); + const vertical = Math.min(box.bottom, over.bottom) - Math.max(box.top, over.top); + if (covered > 1 && vertical > 1) { + offenders.push(`${this.describe(name)} :: ${Math.round(covered)}px under ${this.describe(mark)}`); + } + }); + }); + return { name: "seat names aren't painted under their own badges", offenders }; + }, + // ---- Runner ---- // Every check this file knows how to make, every time. @@ -768,6 +806,7 @@ const LayoutAudit = { this.seatOwnership(), this.oneDealerButton(), this.hiddenButPainted(), + this.seatLabelsClear(), this.contrast(options.contrast), this.touchTargets(options.minimumTarget, options.touchTargets), ]; -- 2.43.0