From 382238e7085d264a86ba7b988ef4752c3fd3fd79 Mon Sep 17 00:00:00 2001 From: JoshHeaps Date: Fri, 11 Sep 2026 18:00:05 -0600 Subject: [PATCH] Tell the browser the page is dark, and stop painting over it instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything in this stylesheet is a colour it paints. `color-scheme` is the half it cannot: the browser draws the checkboxes, the menu a opens, the scrollbars, the caret, the spellcheck underline and the + autofill wash itself, and with no scheme declared it draws all of them for a + light page. Measured before this line: `color-scheme: normal`, three checkboxes + rendering as bright white squares in the Table Setup panel — the loudest objects + on a near-black screen, brighter than the gold — and a opens, the scrollbars, the +// caret, the spellcheck underline and the autofill wash, and it draws all of them for a +// light page unless the page says otherwise. This one never did: measured, +// `color-scheme: normal` on a #141414 ground, with three checkboxes in the Table Setup +// panel rendering as bright white squares — the loudest objects on the screen, brighter +// than the gold — and two more in the seat sheet doing the same over the felt. +// +// The comment on the pot wizard's hand-painted checkbox called it "the last raw browser +// control in the tool". Six others were still the platform's, and three of those were +// still 13x13 against a 24px floor this stylesheet had already written down once and +// applied to exactly one box. +// +// Painting is the expensive way to fix that, and the pot wizard's box shows the bill: +// a tick drawn as a `background` on a pseudo-element is not a colour forced-colors mode +// knows how to replace, so it simply disappears — no visible checked state at all, on +// the dialog that pays the table. Declaring the scheme fixes six controls natively and +// costs nothing; the seventh stays painted on purpose and pays its own way. +const test = require("node:test"); +const { describe } = require("node:test"); +const assert = require("node:assert"); +const fs = require("fs"); +const path = require("path"); + +const CSS = fs.readFileSync( + path.join(__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "css", "casino", "holdem.css"), "utf8"); + +const ruleFor = selector => { + const at = CSS.indexOf(`\n${selector} {`); + assert.ok(at >= 0, `there is no \`${selector}\` rule`); + return CSS.slice(at, CSS.indexOf("}", at)); +}; + +// The body of a whole at-rule block, braces balanced. +const atRule = query => { + const at = CSS.indexOf(`@media ${query} {`); + assert.ok(at >= 0, `there is no \`@media ${query}\` block`); + let depth = 0; + for (let i = CSS.indexOf("{", at); i < CSS.length; i++) { + if (CSS[i] === "{") depth++; + else if (CSS[i] === "}" && --depth === 0) return CSS.slice(at, i + 1); + } + assert.fail(`\`@media ${query}\` never closes`); +}; + +// --------------------------------------------------------------------------- + +describe("the page says what colour it is", () => { + const root = ruleFor(":root"); + + test("dark, to the browser and not only to the eye", () => { + assert.match(root, /color-scheme:\s*dark/); + }); + + // The checked colour is the green this tool already uses for yes, so the one + // painted checkbox and the six native ones agree rather than nearly agree. + test("and the checked colour is the tool's own green, not the platform's blue", () => { + assert.match(root, /--accent-on:\s*#1e8449/); + assert.match(root, /accent-color:\s*var\(--accent-on\)/); + assert.match(ruleFor(".potWizardChoice input:checked"), /background:\s*#1e8449/); + }); +}); + +describe("a checkbox is one size", () => { + test("every one of them, not the one that was noticed", () => { + assert.match(ruleFor('input[type="checkbox"]'), /width:\s*24px/); + assert.match(ruleFor('input[type="checkbox"]'), /height:\s*24px/); + }); + + test("and no box carries a size of its own any more", () => { + assert.ok(!/#dedicatedDealerToggle\s*\{/.test(CSS), + "one checkbox is still sized by id, which is how five got left behind"); + assert.ok(!/width:\s*22px/.test(ruleFor(".potWizardChoice input")), + "the painted box restates its size instead of taking the one above"); + }); + + // A stated width is only a suggestion to a flex item. The coarse-pointer block had + // already been bitten by this and said so; the mouse case had not. + test("a swatch in a crowded row keeps the width it was given", () => { + assert.match(ruleFor(".chipColorInput"), /flex:\s*none/); + }); +}); + +describe("what painting a control costs, and who pays it", () => { + // If a future round paints another one, this is the bill it has to settle too. + test("nothing gives up the platform's drawing without answering forced colours", () => { + const forced = atRule("(forced-colors: active)"); + const painted = [...CSS.matchAll(/\n([^\n{}]+)\s*\{[^}]*appearance:\s*none/g)] + .map(m => m[1].trim()); + assert.ok(painted.length > 0, "nothing is painted, so this test is measuring nothing"); + painted.forEach(selector => { + assert.ok(forced.includes(selector), + `\`${selector}\` drops the platform's control but has no forced-colors answer`); + }); + }); + + // A tick drawn as a background is gone in forced-colors mode; a system keyword is + // the only colour guaranteed to survive, because it *is* the palette. + test("the tick that is drawn rather than typed survives the OS repainting it", () => { + const forced = atRule("(forced-colors: active)"); + assert.match(forced, /\.potWizardChoice input::before\s*\{[^}]*background:\s*CanvasText/); + }); + + test("and so does the row's own chosen state, which is a gradient", () => { + const forced = atRule("(forced-colors: active)"); + assert.match(forced, /\.potWizardChoice\.chosen\s*\{[^}]*outline:\s*2px solid Highlight/); + }); +}); + +describe("the other page of the same tool", () => { + const QUICKSPLIT = fs.readFileSync( + path.join(__dirname, "..", "..", "JoshHeaps.Net", "wwwroot", "css", "casino", "quicksplit.css"), "utf8"); + + // It is the darker of the two pages and is opened from the felt mid-hand. It has no + // checkboxes to go white, but scrollbars, caret and selection were still drawn for + // a light page. + test("Quick Split says what colour it is too", () => { + assert.match(QUICKSPLIT, /:root\s*\{[^}]*color-scheme:\s*dark/); + }); +});