Files
2026-06-18 22:21:38 -04:00

9.8 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
17-ui-optimization-polish 01 execute 1
apps/pwa/src/styles/tokens.css
true
D-06
truths artifacts key_links
Light tokens still apply with no data-theme attribute on <html> (combined :root, [data-theme="light"] selector)
Schedule-X calendar grid keeps its custom member/shared colors after the restructure
A single --bottom-chrome-h token exists for Workstreams A and D to consume
No hard-coded hex/px appears in component/route files (existing invariant unbroken)
path provides contains
apps/pwa/src/styles/tokens.css Themeable token layer (:root, [data-theme="light"]) + --bottom-chrome-h --bottom-chrome-h
from to via pattern
apps/pwa/src/styles/tokens.css @schedule-x/theme-default --sx-color-* overrides remain inside the combined rule block, after the theme-default import --sx-color-
Restructure `apps/pwa/src/styles/tokens.css` from a single light `:root {}` block into a themeable semantic-token layer using the combined selector `:root, [data-theme="light"]` (D-06), and add the shared `--bottom-chrome-h` layout-chrome token that Workstreams A and D will consume. This is GROUNDWORK ONLY — no dark palette values, no `prefers-color-scheme` wiring, no theme toggle. Light stays the sole shipped theme.

This plan OWNS tokens.css for the phase. It runs first (Wave 1) so the phone-layout plan (A) and branding plan (B) add/update their token edits into the already-restructured block without write-ordering conflicts.

Purpose: enable a future data-theme="dark" attribute (backlog 999.20) to override tokens with zero component-file changes, and establish one source of truth for the BottomTabBar height. Output: a restructured tokens.css with the combined selector, a dark-theme stub comment, the new --bottom-chrome-h token, all existing values unchanged.

<execution_context> @$HOME/.claude/gsd-core/workflows/execute-plan.md @$HOME/.claude/gsd-core/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/17-ui-optimization-polish/17-UI-SPEC.md @.planning/phases/17-ui-optimization-polish/17-PATTERNS.md @.planning/phases/17-ui-optimization-polish/17-RESEARCH.md Task 1: Restructure tokens.css to a themeable layer and add --bottom-chrome-h apps/pwa/src/styles/tokens.css - apps/pwa/src/styles/tokens.css (the entire file — single `:root {}` block; note the `--sx-color-*` overrides near the bottom and the `--brand-logo-*` defaults) - 17-UI-SPEC.md §"Workstream C — Theme-Token Groundwork" (the exact combined-selector contract + dark-theme stub comment) - 17-UI-SPEC.md §"Spacing Scale" → "New layout-chrome token" (the --bottom-chrome-h definition) - 17-PATTERNS.md §"apps/pwa/src/styles/tokens.css" (before/after selector excerpt) - 17-RESEARCH.md §"Common Pitfalls" → Pitfall 3 (Schedule-X cascade break) Change the single top-level `:root {` opening selector of `apps/pwa/src/styles/tokens.css` to the combined selector `:root, [data-theme="light"] {`. Keep every existing declaration inside that one rule block VERBATIM — no value changes. Critically, the `--sx-color-*` Schedule-X overrides and the `--brand-logo-*` tokens MUST remain inside this same combined rule block (do NOT split them into a separate selector — splitting changes specificity and breaks the override of `@schedule-x/theme-default`, per RESEARCH Pitfall 3).
Inside the same block, add the new layout-chrome token alongside the existing spacing scale: `--bottom-chrome-h: calc(56px + env(safe-area-inset-bottom, 0px));`. This is the source-of-truth for the BottomTabBar effective height; Workstreams A and D consume it.

Below the closing brace of the combined block, add a dark-theme stub as a COMMENT ONLY (no live rule), documenting that Phase 999.20 fills the values and wires prefers-color-scheme. Do NOT add a live `[data-theme="dark"]` rule, do NOT add any dark color values, do NOT add a `data-theme` attribute anywhere in the app (anti-pattern per RESEARCH — the combined selector means light applies with no attribute present).

Do not touch any component or route file in this plan.
grep -q 'bottom-chrome-h' apps/pwa/src/styles/tokens.css && grep -qE '^\s*\[data-theme="light"\]' apps/pwa/src/styles/tokens.css && test $(grep -c -- '--sx-color' apps/pwa/src/styles/tokens.css) -ge 1 && pnpm --filter @familysync/pwa build - `grep -qE '\[data-theme="light"\]' apps/pwa/src/styles/tokens.css` succeeds (combined selector present). - `grep -q 'bottom-chrome-h' apps/pwa/src/styles/tokens.css` succeeds; the value is exactly `calc(56px + env(safe-area-inset-bottom, 0px))`. - The `--sx-color-*` override lines remain inside the combined `:root, [data-theme="light"]` block (count unchanged from before: still 12 `sx-color` occurrences). - No live `[data-theme="dark"]` rule exists: `grep -nE '\[data-theme="dark"\]\s*\{' apps/pwa/src/styles/tokens.css` returns nothing (a commented stub is acceptable; a live rule is not). - `pnpm --filter @familysync/pwa build` exits 0 (TypeScript + Vite build green). tokens.css uses the combined `:root, [data-theme="light"]` selector with all values unchanged, `--bottom-chrome-h` added, `--sx-color-*` overrides intact inside the block, dark stub is a comment only, and the PWA build passes. Task 2: Verify Schedule-X colors and the no-hard-coded-values invariant survive the restructure apps/pwa/src/styles/tokens.css (verification target — read-only) - apps/pwa/src/styles/tokens.css (post-restructure) - 17-VALIDATION.md §"Per-Task Verification Map" rows for D-06 (grep invariant + Schedule-X sweep + build) - .claude/skills/playwright-cli/ (browser-verification skill for the /calendar Schedule-X sweep) Confirm the no-hard-coded-values invariant still holds: component and route files reference only `var(--token)` — no literal hex or px values leaked in during the restructure (the restructure is selector-only, but verify nothing in components changed). Run the grep invariant from 17-VALIDATION.md across `apps/pwa/src/components/` and `apps/pwa/src/routes/`.
Then verify the Schedule-X custom calendar colors are visually unchanged after the restructure using the playwright-cli skill: load `/calendar`, confirm the member/shared event chips render in the FamilySync custom colors (member-0 blue, shared rose) and have NOT reverted to the Schedule-X default theme colors. This is the regression check for RESEARCH Pitfall 3 (cascade break).

If the grep flags any pre-existing literals that are NOT introduced by this restructure, do NOT fix them in this plan (out of scope — selector-only change); record them in the SUMMARY as a noted observation instead.
! grep -rnE '#[0-9a-fA-F]{3,6}|[0-9]+px' apps/pwa/src/components apps/pwa/src/routes --include='*.tsx' --include='*.ts' | grep -v 'var(--' | grep -vE '^\s*//|^\s*\*' | grep -q . ; echo "grep invariant check exit=$?" - The grep invariant command from 17-VALIDATION.md (D-06 row) shows no NEW hard-coded hex/px literals introduced by this plan in component/route files. - playwright-cli sweep of `/calendar`: Schedule-X event chips render in FamilySync custom colors (member blue + shared rose), not Schedule-X default blue/green — visual confirmation captured (screenshot or observation noted in SUMMARY). - `pnpm --filter @familysync/pwa exec playwright test --project=pixel layout.spec.ts` still green (no structural regression from the token change). The grep invariant passes with no new literals, Schedule-X colors are confirmed unchanged via playwright-cli on /calendar, and the layout.spec.ts pixel profile is green.

<threat_model>

Trust Boundaries

Boundary Description
(none new) This plan is a CSS-only restructure of a static stylesheet. No new trust boundary is introduced.

STRIDE Threat Register

Threat ID Category Component Disposition Mitigation Plan
T-17-01-01 Tampering tokens.css restructure accept CSS custom properties carry no executable content and no user input; a selector change cannot introduce injection. No new threat above LOW for Workstream C.

No new high/medium-severity threats. This is a static stylesheet selector restructure with zero runtime data flow and no new dependencies. </threat_model>

- `grep -qE '\[data-theme="light"\]' apps/pwa/src/styles/tokens.css` — combined selector present - `grep -q 'bottom-chrome-h' apps/pwa/src/styles/tokens.css` — new token present - `pnpm --filter @familysync/pwa build` — exits 0 - playwright-cli `/calendar` sweep — Schedule-X custom colors intact - `pnpm --filter @familysync/pwa exec playwright test --project=pixel layout.spec.ts` — green

<success_criteria> tokens.css is restructured to the combined :root, [data-theme="light"] selector with all values unchanged, --bottom-chrome-h added as the single source of truth for bottom-chrome height, Schedule-X overrides confirmed working, the no-hard-coded-values invariant intact, and the build + pixel layout suite green. </success_criteria>

Create `.planning/phases/17-ui-optimization-polish/17-01-SUMMARY.md` when done.