diff --git a/docs/NEXT.md b/docs/NEXT.md index 94d697d..f0f46c4 100644 --- a/docs/NEXT.md +++ b/docs/NEXT.md @@ -2,7 +2,7 @@ The flight plan. Each item carries enough context to start cold; update this file whenever an item lands (move it to "Done") or a new one is queued. Decisions made while working an item still go through `decisions/` as usual. -_Last updated: 2026-08-27 (**PD-11 recorded: the site-metrics offering** — free real-7d / paid-30d on Analytics Engine, design fully settled in `research/2026-08-26-analytics-offering.md`, queued as item 2 below. Also: **PRs #27, #28 and #31 are all merged and deployed.** mooring.page now serves the demo-first landing page (PD-10) — verified live: the apex carries the Open Graph card, `/s/jzweifel.dev` renders with the claim banner and `noindex`, and the domain lock, sign-off band and republished `signOff` lexicon from the earlier PRs are all in place. **PR #33 is merged and deployed too** — the postmark cut-off fix and the landing footer's attribution row (both below), smoke-tested live. **PR #35 is merged and deployed** — the admin and login pages wear the site letterhead (details below). **PR #37 is merged and deployed too** — it fixes the white frame #35 shipped with (the `body { margin: 0 }` reset lived only in SiteLayout's `:global` styles, so routes that never bundle SiteLayout kept the default body margin; `letterhead.css` now resets body margin and paints `html` with background + `color-scheme` via `:has(.letterhead)`, mirroring SiteLayout's own root treatment) — verified live: the served letterhead stylesheet on mooring.page/login carries the reset in both schemes. **Nothing is in flight; the queue below is current.** The queue below is otherwise current. Critique trends, two separate targets: the rendered **theme** ran 25 → 31 → 29 → 32, and the **landing page** has one run at 21/40 — snapshots in `.impeccable/critique/`)._ +_Last updated: 2026-08-27 (**PD-11 recorded: the site-metrics offering** — free real-7d / paid-30d on Analytics Engine, design fully settled in `research/2026-08-26-analytics-offering.md`, queued as item 2 below. Also: **PRs #27, #28 and #31 are all merged and deployed.** mooring.page now serves the demo-first landing page (PD-10) — verified live: the apex carries the Open Graph card, `/s/jzweifel.dev` renders with the claim banner and `noindex`, and the domain lock, sign-off band and republished `signOff` lexicon from the earlier PRs are all in place. **PR #33 is merged and deployed too** — the postmark cut-off fix and the landing footer's attribution row (both below), smoke-tested live. **PR #35 is merged and deployed** — the admin and login pages wear the site letterhead (details below). **PR #37 is merged and deployed too** — it fixes the white frame #35 shipped with (the `body { margin: 0 }` reset lived only in SiteLayout's `:global` styles, so routes that never bundle SiteLayout kept the default body margin; `letterhead.css` now resets body margin and paints `html` with background + `color-scheme` via `:has(.letterhead)`, mirroring SiteLayout's own root treatment) — verified live: the served letterhead stylesheet on mooring.page/login carries the reset in both schemes. **PR #39 is merged and deployed too** — the theme's contrast guards for user color overrides (details below); verified live in both schemes. **Nothing is in flight; the queue below is current.** The queue below is otherwise current. Critique trends, two separate targets: the rendered **theme** ran 25 → 31 → 29 → 32, and the **landing page** has one run at 21/40 — snapshots in `.impeccable/critique/`)._ ## Where things stand @@ -37,7 +37,7 @@ The whole design is settled and recorded — `research/2026-08-26-analytics-offe ## Done -- 2026-08-27 — **User color overrides can no longer render a site unreadable** (PR #39, open as a draft; not merged, not deployed). `theme.colors` set `--paper`/`--ink`/`--accent`/`--accent-ink` through the `style` attribute on `.site`, and inline custom properties outrank every stylesheet rule — so the theme's own `@media (prefers-color-scheme: dark)` block could never fire for an overridden token. A site that declared only a background got that background pinned in dark mode while `--ink` still flipped to `#e9e3d6`: near-white text on near-white paper, ~1.06:1, with a near-black `--paper-sunk` panel sitting in the middle of it. Reproduced in a browser before the fix. The record carries one `colors` object and no scheme variants, so the fix takes that at its word: **any color override declares a single palette and pins the site to one scheme**, chosen by the background's luminance (or, with only a foreground declared, its inverse — dark text means light paper). A new `apps/web/src/lib/server/render/palette.ts` builds the whole eight-token palette server-side from whatever subset was declared — the derived roles (`--muted`, `--rule`, `--paper-sunk`) are mixed from the *declared* paper and ink instead of stranding at the other scheme's values — and holds every text-bearing pairing (ink/muted/accent on paper, accent-ink on accent) to WCAG AA 4.5:1. **Failing colors are darkened or lightened toward black or white until they clear, rather than dropped** (Jacob's call): most plausible brand colors fail AA on the near-white paper — Bluesky blue is 3.26:1, a mid teal 2.89:1 — so dropping them would have made "I set my accent and nothing happened" the common case. Hue is preserved; the teal renders 24% darker and still unmistakably teal. The walk always terminates: whichever of black and white is further from the background reaches at least 4.58:1. `color-scheme` is pinned alongside the palette (via `html:has(.site.pinned)`, whose specificity beats the theme's own `html` rule regardless of load order) so scrollbars and form controls stop following the OS against a pinned page. Sites with no override emit no tokens at all and keep both schemes — verified unchanged in both directions. 15 new tests including nine hostile palettes (identical fg/bg, mid-grey, white-on-white); verified in a browser through a temporary preview route, deleted before commit. **Known ceiling:** an accent-only override now also pins the scheme, so a user who only wanted a brand color loses dark mode. The honest upgrade is a `colorsDark` sibling in the `page.mooring.site` lexicon rather than more CSS — the lexicon simply cannot express two schemes today. Its `colors` description was left alone to avoid a republish for prose; fold the pinning semantics in next time that record is republished. +- 2026-08-27 — **User color overrides can no longer render a site unreadable** (PR #39, **merged and deployed 2026-08-27**, Worker version `ea42ea99`). `theme.colors` set `--paper`/`--ink`/`--accent`/`--accent-ink` through the `style` attribute on `.site`, and inline custom properties outrank every stylesheet rule — so the theme's own `@media (prefers-color-scheme: dark)` block could never fire for an overridden token. A site that declared only a background got that background pinned in dark mode while `--ink` still flipped to `#e9e3d6`: near-white text on near-white paper, ~1.06:1, with a near-black `--paper-sunk` panel sitting in the middle of it. Reproduced in a browser before the fix. The record carries one `colors` object and no scheme variants, so the fix takes that at its word: **any color override declares a single palette and pins the site to one scheme**, chosen by the background's luminance (or, with only a foreground declared, its inverse — dark text means light paper). A new `apps/web/src/lib/server/render/palette.ts` builds the whole eight-token palette server-side from whatever subset was declared — the derived roles (`--muted`, `--rule`, `--paper-sunk`) are mixed from the *declared* paper and ink instead of stranding at the other scheme's values — and holds every text-bearing pairing (ink/muted/accent on paper, accent-ink on accent) to WCAG AA 4.5:1. **Failing colors are darkened or lightened toward black or white until they clear, rather than dropped** (Jacob's call): most plausible brand colors fail AA on the near-white paper — Bluesky blue is 3.26:1, a mid teal 2.89:1 — so dropping them would have made "I set my accent and nothing happened" the common case. Hue is preserved; the teal renders 24% darker and still unmistakably teal. The walk always terminates: whichever of black and white is further from the background reaches at least 4.58:1. `color-scheme` is pinned alongside the palette (via `html:has(.site.pinned)`, whose specificity beats the theme's own `html` rule regardless of load order) so scrollbars and form controls stop following the OS against a pinned page. Sites with no override emit no tokens at all and keep both schemes — verified unchanged in both directions. 15 new tests including nine hostile palettes (identical fg/bg, mid-grey, white-on-white); verified in a browser through a temporary preview route, deleted before commit. **Known ceiling:** an accent-only override now also pins the scheme, so a user who only wanted a brand color loses dark mode. The honest upgrade is a `colorsDark` sibling in the `page.mooring.site` lexicon rather than more CSS — the lexicon simply cannot express two schemes today. Its `colors` description was left alone to avoid a republish for prose; fold the pinning semantics in next time that record is republished. Smoke-tested against the deployed origin: `mooring.page/s/jzweifel.dev` renders correctly in both schemes (`--paper` `#101520`/`#f7f3ea` following the reader, empty inline style, no `pinned` class, `color-scheme: light dark`) with no console errors, and the served stylesheet carries the compiled `.site.svelte-8htptl:not(.pinned)` — note Svelte places the scope class *before* the `:not()`, so grep for `pinned` rather than the authored selector. **One gap:** no deployed site declares `theme.colors` yet, so the pinned path itself is covered by the tests and the dev preview, not by a live record — exercise it the first time a real site sets colors. - 2026-08-27 — **The admin and login pages wear the site letterhead** (PR #35, merged and deployed 2026-08-27). The /admin routes and the sign-in page were bare system-ui defaults next to a landing page with a committed identity. The palette and control skin now live once in `apps/web/src/lib/styles/letterhead.css`, class-scoped under `.letterhead` (airmail stripe, paper/ink/terracotta tokens in both color schemes, serif body with the mono-uppercase system voice, one skin for inputs/buttons/links/notices/`code`), imported by a new `admin/+layout.svelte` — masthead nav (Overview / Pages / Hosting, current section marked), container sizing, valediction footer — and by the login page. The admin pages shed their ad-hoc styles and hardcoded colors; per-page "← Admin" back-links gave way to the persistent nav; destructive actions (Delete, Remove, Release, Sign out) wear a quiet outline that warms to `--warn` on hover; the hosting page's paused notice traded its side-stripe for a sunk paper panel. Verified in-browser (login at the real route, admin via a temporary unauthenticated preview route, deleted before commit) in both schemes at desktop and 375px. Shipped with one bug — the white body-margin frame — fixed in the follow-up noted above. - 2026-08-26 — **The landing footer names a human and points at the source** (PR #33, **merged and deployed 2026-08-26**; verified live on mooring.page — both links present and resolving). Jacob's call: the page asked visitors to trust it with their handle while offering no way to find out who wrote it or read the code. The footer row now reads "Made for the Atmosphere by **Jacob Zweifel**" (→ `jzweifel.dev`, itself a Mooring site, so the byline doubles as a second example) and "**Source on Tangled (AGPL-3.0)**" (→ `tangled.org/jzweifel.dev/fahrenheit`, the canonical URL for the `sh.tangled.repo` record in Jacob's PDS; the GitHub mirror is deliberately not linked — the Atmosphere-native forge is the one that fits the pitch). Link styling and the negative-margin tap padding are lifted from the site theme's own footer, and the connecting rule now hides below 40rem the way the theme's does, so the wrapped three-line stack on a phone has no squeezed rule in it. No new colors: the links inherit `--muted`, which clears 4.5:1 on paper in both schemes (5.05 light, 5.41 dark) and stays underlined. **This closes the "substantiate the ownership claim" clause of the queued landing-critique item** ("you've built a rendering engine and put a text ad in front of it" and the rest still stand). Verified at desktop and 375px.