The white surfaces were reading as a milky white panel (a card top was
~71% white). The frosted recipes now use a 14% base veil plus the gloss
over the pre-blurred wallpaper, small chrome (rows, chips, segments,
buttons) keeps a touch more veil, and nothing nested inside a sheet or
dialog uses the viewport-aligned layer (it showed the raw dark water
under the settings theme labels at 1.5:1 — nested chrome falls back to
the flat fills over the genuinely blurred sheet).
The first-load text bug was the boot script: its dark test was
`s && !a ? s === 'dark' : matchMedia(...)`, which for a stored aero fell
through to the OS preference, so a dark-preferring machine loaded with
both `dark` and `aero` classes and every `.dark` rule painted over the
wallpaper until a theme toggle re-applied the classes. The stored value
now decides alone; a dark-colorScheme check pins it in the mobile suite
(123 checks).
Background: the user's latest Gemini scene (1280x714) re-encoded to
public/aero/background.webp (206 kB) with a fresh pre-blurred sibling.
Contrast: 0 below-minimum findings, 0 axe violations, all three themes.
Version 0.3.1, SW -> freezmo-v62.
Frutiger Aero (Settings -> Theme): a third theme, not a dark/light variant.
A sky gradient with a strip of grass, the glacier blobs become clouds, the
orbs soap bubbles, glass gets the classic horizon gloss and the buttons a
glossy aqua. The light/dark toggles (header, rail, chat header) hide while it
is on and the picker says why; the pre-paint script applies the class before
first paint and the PWA status bar follows (#3fa3e0). Its muted/frost text is
darker than Light's because those labels sit directly on the sky.
Contrast, measured on real pixels (tests/contrast.mjs, now covering aero):
- The light settings sheet was translucent over a dark scrim, so its muted
text measured ~2.8:1. Sheets and dialogs now use --glass-sheet-bg (a more
opaque surface), and Light's --text-muted is a touch darker.
- Result: 0 below-minimum findings and 0 axe violations across every screen,
all three themes, phone and desktop.
Also: the suites now seed the cookie notice as already dismissed (they run as
a returning user); the regression suite opts out to test the notice itself —
the previous deploy failed its gate because the notice blocked a chat chip
click. The notice also hides during immersive sessions (overlay-open), so it
can never cover a study feed.
Version 0.1.8, SW -> freezmo-v54.
- Production now runs from ~/freezmo-prod/current (release symlink) as a
standalone server on :3207; releases are exported by scripts/deploy.sh,
built and e2e-verified on a temp port, switched atomically, health-
checked via the new /api/healthz (commit + build time) and rolled back
automatically on failure. Last 5 releases kept; scripts/rollback.sh for
manual rollback. Shared env + data live in ~/freezmo-prod/shared/ and
are symlinked into every release (existing sync/push data migrated and
verified identical).
- Dev runs from ~/freezmo via freezmo-dev.service: next dev on :3217
(LAN only), its own build folder (.next-dev via NEXT_DIST_DIR), its own
data (~/freezmo/.freezmo-dev), DEV badge, dev favicon/theme colour,
"Freezmo Dev" PWA identity and never the production service worker.
- /api/healthz + the Settings Details version row (short commit + build
time). output: standalone in next.config (next start still works).
- AGENTS.md documents the workflow rules: only dev updates during a task,
temporary dirs/ports for test builds, and deploy-at-the-end as the only
production path. README gains an Environments and deploy section.
- Fix found by the rehearsal: lib/dev-mode.ts must not be a client module
(a server component importing a constant from a "use client" module
gets a truthy proxy, which baked dev metadata into production builds).
- SW -> freezmo-v34.
The browser harness lived in /tmp/opencode and an overnight reboot
wiped it. It now lives in tests/ and survives reboots, is versioned
and runs with one command.
- tests/lib.mjs: shared helpers (Chromium auto-detect, seeding,
IndexedDB fixtures, stub/extra instance spawn with process-group
cleanup, check/finish).
- tests/run-all.mjs + npm run test:e2e [filter]: runs the ten suites
in order with a summary; suites that need a stub Ollama or VAPID
keys start their own next start instance on 3208/3209, verify the
port is free and kill the group on exit. Test scratch in
tests/.tmp/ (gitignored).
- Suites rebuilt and green against the current build: regression 38,
mobile 94 (tab matrix, ... sheet, settings sheet, axe), wizard 83,
native 31 (PWA/offline/share/back/undo/haptics/draft), i18n 13,
freeze-loading 6, review 15, phase1 36 (backup/sync/usage limits),
phase2 42 (learning engine/reminders), phase3 21 (homework check).
379 checks, 10/10 suites in one full run.
- playwright-core + axe-core added as devDependencies; CHROME env or
the newest ~/.cache/ms-playwright chromium is used.
- README: new decision 45 documenting the harness; decision 44's
verification note updated.
The older suites' exact sources were lost with the wipe, so the
rebuilt versions reconstruct the same feature areas rather than
being byte-identical.