No files under frontend/ (HTML/CSS/JS) were modified. Black is a Python
formatter, so this feature only touches the backend and dev workflow.
- Added
blackas a dev dependency (uv add --dev black) and a[tool.black]section inpyproject.toml(line length 88, py313, excludeschroma_db). - Added
scripts/format.sh(auto-formatbackend/andmain.py) andscripts/check.sh(black --checkplus the pytest suite). - Reformatted all Python files with black (16 files; formatting only).
- All 61 tests pass after reformatting.
./scripts/format.sh: format the code./scripts/check.sh: verify formatting and run the tests
Frontend formatting (e.g. Prettier for JS/CSS) was not added, since it wasn't requested.
- Added a
#themeTogglebutton (fixed, top-right) with inline sun and moon SVG icons. It hasaria-labelandaria-pressed, and is a native<button>, so Tab/Enter/Space work. - Added a small inline script in
<head>that applies the saved theme (localStorage) to<html data-theme>before first paint, which avoids a flash of the wrong theme. - Bumped the CSS and JS cache-busting versions.
- Added a
:root[data-theme="light"]block that overrides the CSS variables: light backgrounds and surfaces, dark text, a darker teal primary (white text on it passes WCAG AA), and adjusted borders and focus ring. - Replaced hardcoded colors with new variables so both themes work:
--on-primary,--on-user-message,--link-hover,--link-underline,--user-link-underline,--code-bg,--welcome-shadow,--error-*,--success-*,--button-glow. Dark values equal the previous hardcoded ones, so the dark theme looks unchanged. - Fixed the blockquote border, which referenced the undefined
--primary. - Added
.theme-togglestyles: a circular button with hover and:focus-visiblering. The sun and moon icons cross-fade and rotate. - Added an
html.theme-transitionrule that animates background, text and border colors for 0.35s.
- Added
setupThemeToggle(), called on load. A click flipsdata-themeon<html>betweenlightanddark, saves it tolocalStorage, updates the button's aria attributes, and applies the temporarytheme-transitionclass so the change is smooth. The class is removed afterwards so normal interactions aren't slowed.
- Toggled by click and by keyboard (Enter), checked persistence across reloads, and checked desktop and 390px mobile layouts in both themes.
- Measured WCAG contrast for 20+ text/background pairs in both themes (messages, links, code, blockquote, sources, error/success, sidebar, buttons, input). All are at least 4.5:1 after these fixes:
bodybackground had been accidentally set to--on-primaryand is now--background.- Links in user messages now use
--on-user-message(was 3.18:1 in light). - Light
--success-textdarkened to#166534(was 4.2:1).