From ce95aa3e6bc73c472e633a7397ec538c3d4e357d Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Thu, 18 Jun 2026 12:48:55 -0400 Subject: [PATCH 1/3] feat(17-04): wire logo img into BrandSlot, set --brand-logo-border-radius 0 - Replace placeholder FS div with decorative - Apply Surface B-1 style (width/height brand-logo-size, borderRadius token, contain/block) - Update --brand-logo-border-radius from 50% to 0 (SVG draws its own rx=104 shape) - h1 FamilySync and tagline p unchanged; LoginPage.tsx untouched (seam contract honored) - No dangerouslySetInnerHTML (T-05-24 invariant maintained) --- apps/pwa/src/components/BrandSlot.tsx | 44 +++++++++++---------------- apps/pwa/src/styles/tokens.css | 2 +- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/apps/pwa/src/components/BrandSlot.tsx b/apps/pwa/src/components/BrandSlot.tsx index 5ee2090..2214335 100644 --- a/apps/pwa/src/components/BrandSlot.tsx +++ b/apps/pwa/src/components/BrandSlot.tsx @@ -1,24 +1,20 @@ /** * BrandSlot — Phase 17 seam component for the login page brand area. * - * Phase 19 ships a minimal shippable placeholder: a 48px circle with "FS" + * Phase 19 shipped a minimal shippable placeholder: a 48px circle with "FS" * initials, the app name "FamilySync", and the tagline "Family calendar & lists". * - * Phase 17 replaces the internals of this component (swap the placeholder div for - * an with a real logo) without touching LoginPage's layout. This isolates - * the branding seam — see 19-UI-SPEC.md §Brand Slot section. + * Phase 17 replaces the placeholder div with a decorative logo — the approved + * FamilySync family-house SVG. LoginPage layout is untouched (seam contract honored; + * see 19-UI-SPEC.md §Brand Slot section). * - * CSS custom properties used (all set in tokens.css with placeholder defaults; - * Phase 17 overrides these values): - * --brand-logo-bg — logo circle background (default: var(--color-member-0)) - * --brand-logo-text — initials color (default: #ffffff) - * --brand-logo-size — circle diameter (default: 48px) - * --brand-logo-border-radius — circle shape (default: 50%) + * CSS custom properties used (all set in tokens.css): + * --brand-logo-size — image size (default: 48px) + * --brand-logo-border-radius — image border-radius (0 — SVG draws its own shape) * * Accessibility: *

contains the app name — screen readers read "FamilySync" as the page title. - * The logo circle is aria-hidden (the text is the accessible label). - * No today → no broken image ref → no layout shift when Phase 17 replaces it. + * The logo image is decorative (alt="", aria-hidden="true"). * * Security: all copy is plain-text JSX children — no dangerouslySetInnerHTML (T-05-24). */ @@ -26,28 +22,22 @@ export function BrandSlot() { return (
- {/* Phase 17 replaces this div with */} - + /> {/* App name —

so screen readers identify the page (UI-SPEC §Accessibility) */}

Date: Thu, 18 Jun 2026 12:50:50 -0400 Subject: [PATCH 2/3] feat(17-04): wire favicons + theme-color in index.html, fix maskable icon + accent in manifest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.html: add favicon.svg (SVG, modern browsers first) + favicon.ico (legacy) links - index.html: update theme-color from #4A90D9 to approved #e8915a (warm amber) - vite.config.ts: fix maskable icon — reference /icon-maskable-512.png (separate file) not /icon-512.png - vite.config.ts: update manifest theme_color to #e8915a to match index.html - tokens.css: update --color-member-0 to #e8915a (warm amber, Variant B, operator-approved 17-02) - --sx-color-primary follows automatically via var(--color-member-0) --- apps/pwa/index.html | 4 +++- apps/pwa/src/styles/tokens.css | 2 +- apps/pwa/vite.config.ts | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/pwa/index.html b/apps/pwa/index.html index 5eca05e..dfd1854 100644 --- a/apps/pwa/index.html +++ b/apps/pwa/index.html @@ -3,8 +3,10 @@ - + + + diff --git a/apps/pwa/src/styles/tokens.css b/apps/pwa/src/styles/tokens.css index 38927ba..8f5a53c 100644 --- a/apps/pwa/src/styles/tokens.css +++ b/apps/pwa/src/styles/tokens.css @@ -38,7 +38,7 @@ * 10% accent band — ONLY for event chip fills and color legend swatches. * ───────────────────────────────────────────────────────────────────────── */ - --color-member-0: #4a90d9; + --color-member-0: #e8915a; /* brand accent — warm amber (approved 17-02 checkpoint) */ --color-member-1: #50c878; --color-member-2: #f5a623; --color-member-3: #9b59b6; diff --git a/apps/pwa/vite.config.ts b/apps/pwa/vite.config.ts index ede94d0..6e2081f 100644 --- a/apps/pwa/vite.config.ts +++ b/apps/pwa/vite.config.ts @@ -30,7 +30,7 @@ export default defineConfig({ name: 'FamilySync', short_name: 'FamilySync', description: 'Family calendar and lists', - theme_color: '#4A90D9', + theme_color: '#e8915a', background_color: '#ffffff', display: 'standalone', scope: '/', @@ -38,7 +38,7 @@ export default defineConfig({ icons: [ { src: '/icon-192.png', sizes: '192x192', type: 'image/png' }, { src: '/icon-512.png', sizes: '512x512', type: 'image/png' }, - { src: '/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, + { src: '/icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, ], }, }), From 4cb16f82716757bfd16f45f641b1a579f8d0703e Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Thu, 18 Jun 2026 12:51:58 -0400 Subject: [PATCH 3/3] =?UTF-8?q?docs(17-04):=20complete=20brand=20wiring=20?= =?UTF-8?q?plan=20=E2=80=94=20BrandSlot=20logo,=20favicons,=20maskable=20i?= =?UTF-8?q?con=20fix,=20accent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- .../17-04-SUMMARY.md | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 .planning/phases/17-ui-optimization-polish/17-04-SUMMARY.md diff --git a/.planning/phases/17-ui-optimization-polish/17-04-SUMMARY.md b/.planning/phases/17-ui-optimization-polish/17-04-SUMMARY.md new file mode 100644 index 0000000..37a53de --- /dev/null +++ b/.planning/phases/17-ui-optimization-polish/17-04-SUMMARY.md @@ -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 — 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 `
FS
` with a decorative `` element: + +```tsx + +``` + +- `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 `` (SVG first, modern browsers) +- Added `` (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 `` 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*