From 1e1bdcccceb1b5a6d0b9e0d1e25972fb08bbc383 Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Mon, 31 Aug 2026 18:36:54 -0600 Subject: [PATCH] Make the four seat states readable across the table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A seat could be live in the hand, folded, sitting out, or empty, and three of those looked nearly the same: a plain dark puck, or a dimmed one. An unclaimed chair was indistinguishable from a nameless player, and nothing positively said "this player is in" — the dealer had to infer it from whether a dollar badge happened to be showing. Each state now has one look. Live gets a green edge. Folded gets a red edge and a struck-through name, so it reads as out rather than merely faint. An empty chair is the only dashed outline and says so. Sitting out just fades — and fades less than it used to, since that player is still someone the dealer may need to deal back in, and at 0.4 the name was nearly gone. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb --- JoshHeaps.Net/wwwroot/css/casino/holdem.css | 41 ++++++++++++++++++- .../wwwroot/js/casino/holdem/render.js | 20 ++++++++- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/JoshHeaps.Net/wwwroot/css/casino/holdem.css b/JoshHeaps.Net/wwwroot/css/casino/holdem.css index 45dc639..d121dae 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/holdem.css +++ b/JoshHeaps.Net/wwwroot/css/casino/holdem.css @@ -250,13 +250,50 @@ body { outline-offset: 2px; } +/* Four states a dealer needs to tell apart from across the table, without + reading anything: live in this hand, folded, sitting out, and nobody there. + Live gets a green edge, folded gets a red one and a struck-through name, + sitting-out just fades, and an empty chair is the only dashed outline. */ + +.seat.seatLive { + border-color: rgba(78, 201, 122, 0.45); + box-shadow: + 0 0 0 1px rgba(78, 201, 122, 0.18), + 0 3px 10px rgba(0, 0, 0, 0.5), + inset 0 1px 0 rgba(255, 255, 255, 0.05); +} + +/* Sitting out, not gone: still a person the dealer may need to deal back in, so + the name has to stay readable rather than fading almost to the felt. */ .seat.seatInactive { - opacity: 0.4; + opacity: 0.58; } .seat.seatFolded { + border-color: rgba(224, 123, 123, 0.4); + opacity: 0.5; +} + +.seat.seatFolded .seatPuckName { + text-decoration: line-through; + text-decoration-color: rgba(224, 123, 123, 0.75); +} + +.seat.seatEmpty { + background: rgba(255, 255, 255, 0.02); border-style: dashed; - opacity: 0.55; + border-color: rgba(255, 255, 255, 0.13); + box-shadow: none; + /* Deliberately louder than seatInactive: an open seat is information a + dealer wants, not something to squint at. */ + opacity: 0.7; +} + +.seatEmptyLabel { + color: #6d6d6d; + font-size: 0.6rem; + letter-spacing: 0.08em; + text-transform: uppercase; } .seat.seatSelected { diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js index 254c721..fbd6f90 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/render.js @@ -124,8 +124,22 @@ const Render = { return /[HD]$/i.test(card || ""); }, + // A chair nobody has claimed: no name typed, not dealt in, nothing in the pot. + // Worth calling out, because at a short-handed table the open seats are what + // the dealer is looking for. + isEmptySeat(player) { + const named = !!(player.name && player.name.trim()); + const contributing = + HoldemState.computeContribution(player, this.state.chipLegend, this.state.basePotAmount) > 0; + return !named && !player.inHand && !contributing; + }, + updatePuckContent(node, player, index) { - node.querySelector(".seatPuckName").textContent = player.name && player.name.trim() ? player.name.trim() : ""; + const empty = this.isEmptySeat(player); + const nameEl = node.querySelector(".seatPuckName"); + nameEl.textContent = empty ? "Empty" : (player.name || "").trim(); + nameEl.classList.toggle("seatEmptyLabel", empty); + const cardsEl = node.querySelector(".seatPuckCards"); cardsEl.innerHTML = ""; (player.cards || []).filter(Boolean).forEach((card, i) => { @@ -137,8 +151,10 @@ const Render = { }); const total = HoldemState.computeContribution(player, this.state.chipLegend, this.state.basePotAmount); node.querySelector(".seatPuckTotal").textContent = total > 0 ? Money.format(total) : ""; - node.classList.toggle("seatInactive", !player.inHand); + node.classList.toggle("seatEmpty", empty); + node.classList.toggle("seatInactive", !player.inHand && !empty); node.classList.toggle("seatFolded", player.folded); + node.classList.toggle("seatLive", player.inHand && !player.folded); }, // Cheaper than a full renderSeats() — used after edits so the seat editor's inputs -- 2.43.0