From 3be93cdadfc797ed89dd483c43d68ae44a32b120 Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Wed, 2 Sep 2026 00:24:07 -0600 Subject: [PATCH] Chop a side pot on the screen that worked it out, and fix Quick Split's contrast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quick Split lists the pots when somebody is all-in — main, sides, uncalled — and then leaves the dealer there. Two players tying for a side pot is ordinary, and working out each one's share meant switching to the other mode and retyping an amount the screen had just calculated. Retyping a number with money on it is a transcription error waiting to happen, and the number was already on screen. Each pot with two or more people who can win it now carries a Chop, opening underneath its own row: as many ways as there are contenders by default, a stepper for a chop between fewer of them, and the same odd-chip and dust wording the main split uses, because it is the same rule and the dealer shouldn't have to notice they are reading a different screen. Per-row state, so opening the main pot's chop doesn't disturb what the side pot below it says. Not offered on the uncalled row, which goes back to one player, nor on the total. Separately, this page had never been through the layout audit the dealer table gets every round, and it was carrying nine contrast failures: .unevenCurrency 4.11:1 the $ beside every amount typed .unevenRemoveBtn 3.66:1 the ✕ that deletes a player's entry .splitFootnote 3.94:1 the instruction for what to do with the pot list All under the 4.5:1 small-text minimum, the worst of them on a destructive control. Lifted to pass. The large $ on the even-mode pot input is left alone: at 1.6rem it is large text, where 3:1 is the bar and 4.11:1 clears it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015bnp7xKUPFFSpwkYNFaPgb --- .../wwwroot/css/casino/quicksplit.css | 87 +++++++++++++++++- .../wwwroot/js/casino/holdem/quickSplit.js | 88 ++++++++++++++++++- 2 files changed, 170 insertions(+), 5 deletions(-) diff --git a/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css b/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css index 582aa85..257c887 100644 --- a/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css +++ b/JoshHeaps.Net/wwwroot/css/casino/quicksplit.css @@ -143,7 +143,9 @@ button, } .unevenCurrency { - color: #777; + /* Was #777 — 4.11:1 on this background, under the 4.5:1 small text needs. It sits + against every amount a dealer types, so it is read constantly. */ + color: #8f8f8f; } .unevenAmount { @@ -184,7 +186,9 @@ button, height: 44px; border: none; background: none; - color: #6a6a6a; + /* Was #6a6a6a — 3.66:1, the worst on the page, on a control that deletes a + player's entry. A destructive action should not be the faintest thing in view. */ + color: #9a9a9a; font-size: 0.85rem; cursor: pointer; } @@ -209,11 +213,86 @@ button, .unevenPot { display: flex; align-items: baseline; + /* Wraps so a chop opens underneath its own pot rather than squeezing in beside the + eligible-players list and pushing it off the row. */ + flex-wrap: wrap; gap: 0.6rem; padding: 0.3rem 0; font-size: 0.85rem; } +.unevenChopToggle { + flex: none; + order: 3; + /* 44px on touch: it moves money, like everything else that does. */ + min-height: 32px; + padding: 0.2rem 0.6rem; + border: 1px solid rgba(216, 180, 106, 0.45); + border-radius: 999px; + background: rgba(216, 180, 106, 0.1); + color: #e3c887; + font: inherit; + font-size: 0.74rem; + cursor: pointer; +} + +.unevenChopToggle:hover { + background: rgba(216, 180, 106, 0.18); +} + +.unevenChopToggle:focus-visible { + outline: 2px solid #d8b46a; + outline-offset: 2px; +} + +.unevenChopDetail { + order: 4; + flex: 0 0 100%; + /* Or the padding is added on top of the 100% basis and the panel sits wider than + the row it belongs to — measured 328px inside a 309px row on a phone. */ + box-sizing: border-box; + margin: 0.15rem 0 0.2rem; + padding: 0.45rem 0.6rem; + border-radius: 8px; + background: rgba(255, 255, 255, 0.04); +} + +.unevenChopWays { + display: flex; + align-items: center; + gap: 0.45rem; + margin-bottom: 0.3rem; +} + +.unevenChopWaysLabel { + color: #cfcfcf; + font-size: 0.78rem; + font-variant-numeric: tabular-nums; +} + +.unevenChopEach { + margin: 0; + color: #f2f2f2; + font-weight: 600; +} + +.unevenChopNote { + margin: 0.2rem 0 0; + color: #9a9a9a; + font-size: 0.76rem; +} + +.unevenChopDust { + color: #e0b169; +} + +@media (max-width: 700px), (pointer: coarse) { + .unevenChopToggle { + min-height: 44px; + padding: 0.4rem 0.9rem; + } +} + .unevenPot + .unevenPot { border-top: 1px solid rgba(255, 255, 255, 0.06); } @@ -510,7 +589,9 @@ button, .splitFootnote { margin-top: 1.5rem; - color: #6f6f6f; + /* Was #6f6f6f — 3.94:1. It carries the instruction for what to do with the pot + list, which is not a decorative line. */ + color: #8d8d8d; font-size: 0.78rem; line-height: 1.5; text-align: center; diff --git a/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js b/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js index 3ffbcef..73a4c03 100644 --- a/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js +++ b/JoshHeaps.Net/wwwroot/js/casino/holdem/quickSplit.js @@ -197,6 +197,80 @@ const QuickSplit = { }); }, + // Chopping one of the pots listed above, without leaving the screen that worked it + // out. Starts closed and at as many ways as there are players who can win the pot, + // which is the common case; the stepper covers a chop between fewer of them, which + // is the other one. + // + // The per-pot ways live on the row rather than in `this.ways`, so opening a chop on + // the main pot doesn't change what the side pot below it is saying. + addChopControl(row, amount, contenderCount) { + let ways = contenderCount; + let open = false; + + const toggle = document.createElement("button"); + toggle.type = "button"; + toggle.className = "unevenChopToggle"; + + const detail = document.createElement("div"); + detail.className = "unevenChopDetail"; + detail.hidden = true; + + const draw = () => { + toggle.textContent = open ? "Hide chop" : "Chop"; + toggle.setAttribute("aria-expanded", String(open)); + detail.hidden = !open; + if (!open) return; + + const result = SplitCalculator.split(amount, ways, this.chip); + detail.innerHTML = ""; + + const stepper = document.createElement("div"); + stepper.className = "unevenChopWays"; + stepper.appendChild(this.makeStepButton("−", () => { + if (ways > 2) { ways -= 1; draw(); } + })); + const label = document.createElement("span"); + label.className = "unevenChopWaysLabel"; + label.textContent = `${ways} ways`; + stepper.appendChild(label); + stepper.appendChild(this.makeStepButton("+", () => { + if (ways < Math.max(contenderCount, this.MAX_WAYS)) { ways += 1; draw(); } + })); + detail.appendChild(stepper); + + const each = document.createElement("p"); + each.className = "unevenChopEach"; + each.textContent = `${Money.format(result.each)} each`; + detail.appendChild(each); + + // Same wording as the main split, because it is the same rule and a dealer + // shouldn't have to notice they're reading a different screen. + if (result.valid && result.oddChips > 0) { + const odd = document.createElement("p"); + odd.className = "unevenChopNote"; + odd.textContent = result.oddChips === 1 + ? `plus one odd ${Money.format(result.chip)} chip to the first player left of the button` + : `plus ${result.oddChips} odd ${Money.format(result.chip)} chips — one each to the ` + + `first ${result.oddChips} players left of the button`; + detail.appendChild(odd); + } + if (result.valid && result.dust > 0) { + const dust = document.createElement("p"); + dust.className = "unevenChopNote unevenChopDust"; + dust.textContent = + `${Money.format(result.dust)} doesn't divide into ${Money.format(result.chip)} chips — ` + + `pick a smaller denomination.`; + detail.appendChild(dust); + } + }; + + toggle.addEventListener("click", () => { open = !open; draw(); }); + draw(); + row.appendChild(toggle); + row.appendChild(detail); + }, + updateUneven() { const players = this.entries .map((entry, index) => ({ id: `P${index + 1}`, contribution: Number(entry.amount) || 0, folded: entry.folded })) @@ -218,7 +292,7 @@ const QuickSplit = { } empty.hidden = true; - const addRow = (label, amount, who, className) => { + const addRow = (label, amount, who, className, chopWays) => { const row = document.createElement("div"); row.className = `unevenPot ${className || ""}`; const name = document.createElement("span"); @@ -234,9 +308,19 @@ const QuickSplit = { row.appendChild(value); row.appendChild(eligible); host.appendChild(row); + + // Two players tying for a side pot is ordinary, and working out each one's + // share meant copying the amount into the other mode by hand — retyping a + // number the screen had just worked out, which is a transcription error + // waiting to happen with money on it. The chop happens here instead. + // + // Only offered where it means something: a pot with at least two people + // who can win it. Not the uncalled row, which goes back to one player, and + // not the total. + if (chopWays >= 2) this.addChopControl(row, amount, chopWays); }; - pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", "))); + pots.forEach(pot => addRow(pot.label, pot.amount, pot.eligible.join(", "), "", pot.eligible.length)); returns.forEach(ret => addRow("Uncalled", ret.amount, `back to ${ret.id}`, "unevenPotReturn")); const total = players.reduce((sum, p) => sum + p.contribution, 0);