Spec: docs/superpowers/specs/2026-08-23-web-ui-rewrite-design.md § Client.
Depends on #534 (API) and #535 (static serving). Depends on #532 for the palette it renders with.
The first JavaScript keel ships. It sets the pattern every later view follows, so the constraints matter more here than anywhere.
Constraints
Plain ES modules, served exactly as authored. No framework, no bundler, no transpile, no minification, and no source maps — the code running must be byte-identical to the code a user reads in devtools. gzip only.
Zero third-party JavaScript. js/external/ exists and is empty, and that is the intended end state rather than a stage. keel clears this bar where youperiod could not, structurally: its cryptography lives in Python and the OS keychain rather than the browser, and the client performs no arithmetic (#533), so no decimal library is required.
| need |
answer |
| routing |
History API |
| dates |
Intl.DateTimeFormat |
| money formatting |
none — server-side (#533) |
Type checking without a build step: // @ts-check with JSDoc and tsc --noEmit in CI. Types are checked; nothing is transpiled and nothing shipped is altered.
File structure
- main — entry point; event listeners, the router, mounts views.
- api — the single
fetch wrapper. Adds X-Keel-Client; turns a failed request into the explicit "keel isn't running" state rather than an empty view.
- render — builds DOM from payloads. Places
display strings; contains no arithmetic and no money formatting, deliberately, so a reviewer can confirm the absence by reading one file.
- format —
Intl.DateTimeFormat wrappers. Dates only.
Responsive
Today's stylesheet is max-width: 62rem with one auto-fit grid and no @media query beyond prefers-color-scheme. Phones are out of scope (there is no keel on iOS), but desktop windows get dragged narrow and touch devices running a full OS exist, so the layout is built responsive from the start rather than retrofitted.
Accessibility baseline
Semantic HTML, native form elements, aria-live/aria-atomic on status regions that change underneath a reader, full keyboard paths, visible focus. For a dashboard whose numbers move on their own, aria-live is a feature, not compliance.
Acceptance
Spec:
docs/superpowers/specs/2026-08-23-web-ui-rewrite-design.md§ Client.Depends on #534 (API) and #535 (static serving). Depends on #532 for the palette it renders with.
The first JavaScript keel ships. It sets the pattern every later view follows, so the constraints matter more here than anywhere.
Constraints
Plain ES modules, served exactly as authored. No framework, no bundler, no transpile, no minification, and no source maps — the code running must be byte-identical to the code a user reads in devtools. gzip only.
Zero third-party JavaScript.
js/external/exists and is empty, and that is the intended end state rather than a stage. keel clears this bar where youperiod could not, structurally: its cryptography lives in Python and the OS keychain rather than the browser, and the client performs no arithmetic (#533), so no decimal library is required.Intl.DateTimeFormatType checking without a build step:
// @ts-checkwith JSDoc andtsc --noEmitin CI. Types are checked; nothing is transpiled and nothing shipped is altered.File structure
fetchwrapper. AddsX-Keel-Client; turns a failed request into the explicit "keel isn't running" state rather than an empty view.displaystrings; contains no arithmetic and no money formatting, deliberately, so a reviewer can confirm the absence by reading one file.Intl.DateTimeFormatwrappers. Dates only.Responsive
Today's stylesheet is
max-width: 62remwith one auto-fit grid and no@mediaquery beyondprefers-color-scheme. Phones are out of scope (there is no keel on iOS), but desktop windows get dragged narrow and touch devices running a full OS exist, so the layout is built responsive from the start rather than retrofitted.Accessibility baseline
Semantic HTML, native form elements,
aria-live/aria-atomicon status regions that change underneath a reader, full keyboard paths, visible focus. For a dashboard whose numbers move on their own,aria-liveis a feature, not compliance.Acceptance
/renders today.js/external/is empty and a test asserts the client ships no third-party code.tsc --noEmitruns in CI and passes.grep-able proof thatrendercontains no arithmetic on monetary values.