From 3eb576c3130476e4d816124fe2da21dca03391ef Mon Sep 17 00:00:00 2001 From: Jim Bethancourt Date: Sun, 11 Oct 2026 18:50:28 -0500 Subject: [PATCH] Improve mobile hamburger menu color --- app/globals.css | 14 ++++++++++- tests/unit/theme-css.test.js | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/app/globals.css b/app/globals.css index 1e66f24..49b1578 100644 --- a/app/globals.css +++ b/app/globals.css @@ -28,6 +28,10 @@ --card-bg: #ffffff; --border-color: #dde4ea; --input-border: #c6d2dc; + /* Hamburger glyph + 1px border on the menu surface: mvp.css paints every + button in --color-bg (the page background), which is invisible here, so + the toggle re-drives from this accent (7.8:1 on --surface-color). */ + --menu-toggle-color: #1f5273; /* vizdom WASM graph edges bake black stroke/fill attributes into the SVG; palette-driven so the dark theme can swap them to a readable tint. */ --graph-line: #000000; @@ -94,6 +98,8 @@ html:root { --card-bg: #1a2330; --border-color: #2c3a4d; --input-border: #5b7396; + /* Hamburger glyph + 1px border on the dark menu surface (6.8:1). */ + --menu-toggle-color: #6fb1d9; --graph-line: #9fb0c0; --error-color: #f0928c; --success-color: #5bbd8b; @@ -136,6 +142,8 @@ html:root { --card-bg: #1a2330; --border-color: #2c3a4d; --input-border: #5b7396; + /* Hamburger glyph + 1px border on the dark menu surface (6.8:1). */ + --menu-toggle-color: #6fb1d9; --graph-line: #9fb0c0; --error-color: #f0928c; --success-color: #5bbd8b; @@ -326,7 +334,11 @@ pre { .menu-toggle { display: none; background: none; - border: 1px solid var(--input-border); + /* mvp.css paints every button in var(--color-bg) — the page background — + which is invisible on the menu surface; re-drive glyph and border from + the palette so the control stays perceivable in both themes. */ + color: var(--menu-toggle-color); + border: 1px solid var(--menu-toggle-color); border-radius: var(--radius); font-size: 1.1rem; padding: 0.25rem 0.6rem; diff --git a/tests/unit/theme-css.test.js b/tests/unit/theme-css.test.js index 9d0cdca..c18efb1 100644 --- a/tests/unit/theme-css.test.js +++ b/tests/unit/theme-css.test.js @@ -408,6 +408,53 @@ describe('table filter accessibility', () => { } }); +// Hamburger toggle (mobile view): mvp.css paints every button's text in +// var(--color-bg), and .menu-toggle only overrode background/border, so the +// ☰ glyph rendered in the page background color and the 1px --input-border +// edge fell below 3:1 on the menu surface. Both must be re-driven from a +// per-palette variable. +describe('menu toggle contrast', () => { + /** + * Concatenates every declaration block for a selector: the rules map keeps + * only the last occurrence (the responsive block) for repeated selectors, + * so assertions must run against all of them together. + * + * @param {string} selector - CSS selector to collect. + * @returns {string} Combined declarations. + */ + function combinedRule(selector) { + const bodies = []; + const ruleRe = /([^{}]+)\{([^{}]*)\}/g; + let match; + while ((match = ruleRe.exec(noComments)) !== null) { + if (match[1].trim() === selector) bodies.push(match[2]); + } + return bodies.join(';'); + } + + it('re-drives the glyph and border from the palette', () => { + const toggle = combinedRule('.menu-toggle'); + expect(toggle).toMatch(/(?:^|;)\s*color:\s*var\(--menu-toggle-color\)/); + expect(toggle).toMatch(/border:\s*1px solid var\(--menu-toggle-color\)/); + }); + + for (const [name, palette] of [['light', lightPalette], ['dark', darkPalette]]) { + it(`declares a ${name} palette color for the toggle`, () => { + expect(palette.get('--menu-toggle-color')).toBeTruthy(); + }); + + it(`the glyph keeps AA text contrast on the menu surface (${name}, SC 1.4.3)`, () => { + expect(contrastOf(palette, '--surface-color', '--menu-toggle-color')) + .toBeGreaterThanOrEqual(4.5); + }); + + it(`the border is perceivable on the menu surface (${name}, SC 1.4.11)`, () => { + expect(contrastOf(palette, '--surface-color', '--menu-toggle-color')) + .toBeGreaterThanOrEqual(3); + }); + } +}); + describe('report CSS selector boundaries', () => { it('themes only graph edges and arrowheads, preserving red cycles and node glyphs', () => { const fixture = document.createElement('div');