docs(17-04): complete brand wiring plan — BrandSlot logo, favicons, maskable icon fix, accent

- BrandSlot: placeholder div replaced with decorative logo img (ce95aa3)
- tokens.css: --brand-logo-border-radius 0, --color-member-0 #e8915a (df578fd)
- index.html: favicon.svg + favicon.ico links, theme-color #e8915a (df578fd)
- vite.config.ts: maskable icon fixed to /icon-maskable-512.png, theme_color #e8915a (df578fd)
- Build: green; manifest.webmanifest verified correct
This commit is contained in:
Lucas Berger
2026-06-18 12:51:58 -04:00
parent df578fd7b7
commit 4cb16f8271
@@ -0,0 +1,164 @@
---
phase: 17-ui-optimization-polish
plan: "04"
subsystem: ui
tags: [pwa, branding, logo, favicon, tokens, manifest, brandslot]
# Dependency graph
requires: ["17-01", "17-02"]
provides:
- "BrandSlot renders the approved decorative logo img (src /logo.svg, alt empty, aria-hidden)"
- "index.html: favicon.svg + favicon.ico + apple-touch-icon with sizes, theme-color #e8915a"
- "vite.config.ts manifest: maskable icon correctly references /icon-maskable-512.png (separate file)"
- "Approved brand accent #e8915a applied to --color-member-0, index.html theme-color, manifest theme_color"
- "--brand-logo-border-radius: 0 applied (SVG draws its own rx=104 shape)"
affects: []
# Tech tracking
tech-stack:
added: []
patterns:
- "BrandSlot seam: placeholder div replaced with <img src='/logo.svg' alt='' aria-hidden> — LoginPage.tsx untouched"
- "tokens.css --color-member-0 is the single source for brand accent; --sx-color-primary follows via var()"
key-files:
created: []
modified:
- "apps/pwa/src/components/BrandSlot.tsx — placeholder FS div replaced with decorative logo img"
- "apps/pwa/src/styles/tokens.css — --brand-logo-border-radius: 0; --color-member-0: #e8915a"
- "apps/pwa/index.html — favicon.svg + favicon.ico links added; theme-color updated to #e8915a"
- "apps/pwa/vite.config.ts — maskable icon fixed to /icon-maskable-512.png; theme_color updated to #e8915a"
key-decisions:
- "Applied --brand-logo-border-radius: 0 verbatim from 17-02 checkpoint (SVG rx=104 draws its own shape)"
- "Applied brand accent #e8915a verbatim from 17-02 checkpoint across all three files (Variant B)"
- "Favicon order: favicon.svg first (modern browsers), favicon.ico second (legacy) — per UI-SPEC wiring contract"
- "--color-focus-ring left at #4a90d9 — semantic accessibility token; not in scope for brand accent update"
# Metrics
duration: 4min
completed: 2026-06-18
status: complete
---
# Phase 17 Plan 04: Brand Wiring Summary
**BrandSlot logo img wired from seam with no LoginPage change; favicon set + theme-color in index.html; manifest maskable icon fixed to /icon-maskable-512.png; brand accent #e8915a applied consistently across tokens.css, index.html, and vite.config.ts**
## Performance
- **Duration:** ~4 min
- **Started:** 2026-06-18T16:47:28Z
- **Completed:** 2026-06-18T16:51:02Z
- **Tasks:** 2/2
- **Files modified:** 4
## Accomplishments
### Task 1: BrandSlot logo img + --brand-logo-border-radius
Replaced the Phase 19 placeholder `<div aria-hidden>FS</div>` with a decorative `<img>` element:
```tsx
<img
src="/logo.svg"
alt=""
aria-hidden="true"
style={{
width: 'var(--brand-logo-size, 48px)',
height: 'var(--brand-logo-size, 48px)',
borderRadius: 'var(--brand-logo-border-radius)',
margin: '0 auto var(--space-2, 8px)',
display: 'block',
aspectRatio: '1 / 1',
objectFit: 'contain',
flexShrink: 0,
}}
/>
```
- `h1` "FamilySync" and tagline `p` unchanged
- `LoginPage.tsx` NOT in the diff (seam contract honored)
- `dangerouslySetInnerHTML` NOT used (T-05-24 invariant maintained)
- Updated `--brand-logo-border-radius: 50%``0` in tokens.css (approved 17-02: SVG draws its own rx=104 background)
### Task 2: index.html favicons + theme-color, vite.config.ts manifest fix, tokens.css accent
**index.html changes:**
- Added `<link rel="icon" href="/favicon.svg" type="image/svg+xml" />` (SVG first, modern browsers)
- Added `<link rel="icon" href="/favicon.ico" sizes="any" />` (legacy fallback)
- Updated `theme-color` from `#4A90D9``#e8915a`
- `apple-touch-icon` already had `sizes="180x180"` (was already present)
**vite.config.ts changes:**
- Fixed maskable icon: `/icon-512.png` with `purpose: 'maskable'``/icon-maskable-512.png` (the separate safe-zone file, 8627 B)
- Updated `theme_color: '#4A90D9'``'#e8915a'`
**tokens.css changes:**
- Updated `--color-member-0: #4a90d9``#e8915a` (warm amber, operator-approved Variant B)
- `--sx-color-primary: var(--color-member-0)` follows automatically (no additional edit needed)
## Task Commits
| Task | Name | Commit | Files |
|------|------|--------|-------|
| 1 | BrandSlot logo img + border-radius token | ce95aa3 | BrandSlot.tsx, tokens.css |
| 2 | Favicons + theme-color + maskable fix + accent | df578fd | index.html, tokens.css, vite.config.ts |
## Verification
### Automated checks passed
- `grep -q 'src="/logo.svg"' BrandSlot.tsx` — OK
- `grep -q 'alt=""' BrandSlot.tsx` — OK
- `grep -q 'FamilySync' BrandSlot.tsx` (h1 intact) — OK
- `dangerouslySetInnerHTML` only in security comment, not in JSX — OK
- `--brand-logo-border-radius: 0` in tokens.css — OK
- `--color-member-0: #e8915a` in tokens.css — OK
- `favicon.svg` link in index.html — OK
- `favicon.ico` link in index.html — OK
- `theme-color: #e8915a` in index.html — OK
- `icon-maskable-512.png` in vite.config.ts manifest — OK
- No `icon-512.png` with `maskable` purpose in manifest — OK
- `theme_color: '#e8915a'` in vite.config.ts — OK
- `pnpm --filter @familysync/pwa build` — exits 0
### Build output verified
- `dist/index.html` contains `favicon.svg`, `favicon.ico`, `theme-color: #e8915a`
- `dist/manifest.webmanifest` contains `icon-maskable-512.png` with `"purpose":"maskable"`, `"theme_color":"#e8915a"`
- JS bundle contains `logo.svg` with `alt:""` (decorative img confirmed in minified output)
### playwright-cli observation
The Vite dev server at :5173 is the main-repo instance (not the worktree), so the live browser showed the pre-existing placeholder. Build artifact verification was used as the authoritative check — `dist/manifest.webmanifest` and `dist/index.html` confirm all wiring is correct. The production-equivalent build passes cleanly.
## Deviations from Plan
None — plan executed exactly as written. All approved branding decisions from 17-02 applied verbatim:
- `--color-member-0: #e8915a` (Variant B warm amber)
- `--brand-logo-border-radius: 0` (SVG self-rounds)
- Favicon order per UI-SPEC wiring contract (SVG first, ICO second)
## Threat Surface Scan
No new trust boundaries introduced. All changes are static asset references and token values:
- `BrandSlot.tsx` uses `<img>` with empty alt + aria-hidden — no executable content, no user input, no dangerouslySetInnerHTML
- `index.html` favicon links and theme-color meta — committed static references
- `vite.config.ts` manifest — committed static icon references at known paths
- `tokens.css` value updates — no new surface
No new threat flags above the LOW level accepted in the plan's threat model.
## Self-Check: PASSED
- `apps/pwa/src/components/BrandSlot.tsx` — modified, committed at ce95aa3
- `apps/pwa/src/styles/tokens.css` — modified, committed at ce95aa3 (border-radius) + df578fd (color)
- `apps/pwa/index.html` — modified, committed at df578fd
- `apps/pwa/vite.config.ts` — modified, committed at df578fd
- `dist/manifest.webmanifest` — correct maskable + theme_color confirmed
- Build: exits 0
---
*Phase: 17-ui-optimization-polish*
*Completed: 2026-06-18*