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)
duration
completed_date
tasks_completed
tasks_total
files_changed
3m 23s
2026-06-18
2
2
1
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.
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
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).