--- phase: "17" plan: "01" subsystem: pwa/styles tags: [css-tokens, theme-groundwork, workstream-c, d-06] dependency_graph: requires: [] provides: - apps/pwa/src/styles/tokens.css — combined :root,[data-theme="light"] selector - --bottom-chrome-h token (consumed by Workstreams A and D plans) affects: - apps/pwa/src/styles/tokens.css (selector restructure, new token) tech_stack: added: [] patterns: - "CSS combined selector :root,[data-theme=light] for future dark-theme override" - "--bottom-chrome-h: calc(56px + env(safe-area-inset-bottom, 0px)) layout-chrome token" key_files: created: [] modified: - apps/pwa/src/styles/tokens.css decisions: - "D-06: combined :root,[data-theme=light] selector is purely structural — all token values unchanged; enables future data-theme=dark override without any component-file changes" - "Dark-theme stub is a comment-only block — no live [data-theme=dark] rule; Phase 999.20 owns that work" - "--bottom-chrome-h placed in spacing-scale section (alongside --space-* tokens) as its conceptual peer" - "All --sx-color-* overrides remain inside the combined rule block (do not split); prevents Schedule-X cascade break (Pitfall 3)" metrics: duration: "3m 23s" completed_date: "2026-06-18" tasks_completed: 2 tasks_total: 2 files_changed: 1 status: complete --- # Phase 17 Plan 01: Token Groundwork — Summary Restructured `apps/pwa/src/styles/tokens.css` from a single `:root {}` block to a combined `:root, [data-theme="light"]` selector (D-06 theme-token groundwork), and added the `--bottom-chrome-h` layout-chrome token as the single source of truth for BottomTabBar effective height. ## What Was Built **One-liner:** CSS selector restructure to `[data-theme="light"]-capable pattern + `--bottom-chrome-h` token for BottomTabBar height, zero value changes. ### tokens.css structural change - The opening `:root {` selector changed to `:root,\n[data-theme="light"] {` - All 12 `--sx-color-*` Schedule-X overrides remain inside the same combined rule block (cascade order unchanged) - All `--brand-logo-*` tokens remain inside the combined rule block (verbatim) - New token added to spacing scale: `--bottom-chrome-h: calc(56px + env(safe-area-inset-bottom, 0px))` - Dark theme stub added as `/* ... */` comment below the closing brace (no live rule) ### No component/route file changes This plan is groundwork only. No component, route, or App file was touched. Workstream A (Plan 17-02) and Workstream D (Plans 17-04, 17-05) consume `--bottom-chrome-h` from this foundation. ## Verification Results ### Task 1 acceptance criteria | Criterion | Result | |-----------|--------| | `[data-theme="light"]` selector present | PASS | | `--bottom-chrome-h` present with exact value `calc(56px + env(safe-area-inset-bottom, 0px))` | PASS | | `--sx-color-*` count still 12 (unchanged) | PASS (12 occurrences) | | No live `[data-theme="dark"]` rule (commented stub only) | PASS — line is inside `/* ... */` block comment | | `pnpm --filter @familysync/pwa build` exits 0 | PASS | ### Task 2 verification | Check | Result | |-------|--------| | Grep invariant — no NEW hard-coded hex/px in component/route files | PASS — zero literals introduced by this plan (selector-only change, no component files touched) | | playwright-cli `/calendar` Schedule-X color sweep | PASS — calendar renders with FamilySync custom colors (member-0 blue #4a90d9 for today-circle + nav active state; shared-family rose #f25c7a for seeded event chip). Not reverting to Schedule-X default blue/green. Screenshot captured. | | `layout.spec.ts` pixel profile | PASS — 15 passed, 1 skipped (desktop-only, expected); 0 failures | ## Deviations from Plan None. Plan executed exactly as written. The single selector change in tokens.css was the only modification; all values are verbatim from the original file. ## Known Stubs None introduced by this plan. ## Noted Observations (Task 2 — Out of Scope) The grep invariant sweep of `apps/pwa/src/components/` and `apps/pwa/src/routes/` found pre-existing hard-coded literals in multiple files (not introduced by this plan): - `SyncStateToast.tsx` — hardcoded `#50C878` color (line 105) and `rgba(0,0,0,0.12)` box shadow - `ListCard.tsx` — hardcoded `56px` min-height (line 68), `4px` border-radius (line 127), `44px`/`44px` touch targets (lines 166–167) - `EmptyState.tsx` — hardcoded `280px` max-width - Other component files — similar pre-existing literals These are pre-existing at commit eb0db8b and are explicitly out of scope for Plan 17-01 (selector-only change). They do not affect the plan's deliverable. Noted here per Task 2 instructions. ## Threat Surface Scan No new trust boundaries, network endpoints, auth paths, or schema changes. This is a static CSS file selector change — no runtime data flow, no new dependencies. Threat model confirmed: T-17-01-01 accepted (CSS custom properties carry no executable content; no new threat above LOW). ## Self-Check: PASSED | Item | Status | |------|--------| | `apps/pwa/src/styles/tokens.css` exists | FOUND | | `17-01-SUMMARY.md` exists | FOUND | | Task 1 commit `c2f89bd` in git log | FOUND |