From 46a775e81f632ed39c4c8d76a6f2b407ba2526cb Mon Sep 17 00:00:00 2001 From: lorentz Date: Fri, 10 Jul 2026 11:54:22 -0400 Subject: [PATCH] chore: clear v1.0 phase artifacts for v2.0 milestone start Phase directories (01-09.1) are fully preserved in git history at prior commits; this just clears the working tree so v2.0 roadmapping starts clean, per gsd-new-milestone's phases.clear step. --- .../phases/01-pwa-scaffolding/01-01-PLAN.md | 374 ----- .../01-pwa-scaffolding/01-01-SUMMARY.md | 142 -- .../phases/01-pwa-scaffolding/01-02-PLAN.md | 286 ---- .../01-pwa-scaffolding/01-02-SUMMARY.md | 174 -- .../phases/01-pwa-scaffolding/01-HUMAN-UAT.md | 36 - .../01-pwa-scaffolding/01-VERIFICATION.md | 152 -- .../02-mobile-shell-more-drawer/02-01-PLAN.md | 754 --------- .../02-01-SUMMARY.md | 129 -- .../02-mobile-shell-more-drawer/02-02-PLAN.md | 406 ----- .../02-02-SUMMARY.md | 155 -- .../02-mobile-shell-more-drawer/02-CONTEXT.md | 142 -- .../02-HUMAN-UAT.md | 52 - .../02-VERIFICATION.md | 184 --- .../phases/03-dashboard-restyle/03-01-PLAN.md | 578 ------- .../03-dashboard-restyle/03-01-SUMMARY.md | 140 -- .../phases/03-dashboard-restyle/03-02-PLAN.md | 426 ----- .../03-dashboard-restyle/03-02-SUMMARY.md | 121 -- .../03-dashboard-restyle/03-HUMAN-UAT.md | 45 - .../03-dashboard-restyle/03-VERIFICATION.md | 134 -- .../phases/04-tickets-restyle/04-01-PLAN.md | 583 ------- .../04-tickets-restyle/04-01-SUMMARY.md | 188 --- .../phases/04-tickets-restyle/04-02-PLAN.md | 590 ------- .../04-tickets-restyle/04-02-SUMMARY.md | 136 -- .../phases/04-tickets-restyle/04-03-PLAN.md | 218 --- .../04-tickets-restyle/04-03-SUMMARY.md | 110 -- .../phases/04-tickets-restyle/04-CONTEXT.md | 142 -- .../04-tickets-restyle/04-DISCUSSION-LOG.md | 127 -- .../phases/04-tickets-restyle/04-HUMAN-UAT.md | 74 - .../phases/04-tickets-restyle/04-UI-SPEC.md | 367 ----- .../04-tickets-restyle/04-VERIFICATION.md | 206 --- .../phases/05-finance-restyle/05-01-PLAN.md | 309 ---- .../05-finance-restyle/05-01-SUMMARY.md | 109 -- .../phases/05-finance-restyle/05-02-PLAN.md | 676 -------- .../05-finance-restyle/05-02-SUMMARY.md | 143 -- .../phases/05-finance-restyle/05-CONTEXT.md | 211 --- .../05-finance-restyle/05-DISCUSSION-LOG.md | 28 - .../phases/05-finance-restyle/05-HUMAN-UAT.md | 74 - .../phases/05-finance-restyle/05-UI-SPEC.md | 425 ----- .../05-finance-restyle/05-VERIFICATION.md | 207 --- .../phases/06-analyzer-feed-new/06-01-PLAN.md | 458 ------ .../06-analyzer-feed-new/06-01-SUMMARY.md | 138 -- .../phases/06-analyzer-feed-new/06-02-PLAN.md | 696 -------- .../06-analyzer-feed-new/06-02-SUMMARY.md | 140 -- .../phases/06-analyzer-feed-new/06-03-PLAN.md | 473 ------ .../06-analyzer-feed-new/06-03-SUMMARY.md | 116 -- .../phases/06-analyzer-feed-new/06-CONTEXT.md | 373 ----- .../06-analyzer-feed-new/06-DISCUSSION-LOG.md | 167 -- .../06-analyzer-feed-new/06-HUMAN-UAT.md | 44 - .../phases/06-analyzer-feed-new/06-UI-SPEC.md | 480 ------ .../06-analyzer-feed-new/06-VERIFICATION.md | 171 -- .../07-engagement-overview-new/07-01-PLAN.md | 558 ------- .../07-01-SUMMARY.md | 131 -- .../07-engagement-overview-new/07-02-PLAN.md | 782 --------- .../07-02-SUMMARY.md | 161 -- .../07-engagement-overview-new/07-03-PLAN.md | 703 -------- .../07-03-SUMMARY.md | 165 -- .../07-engagement-overview-new/07-CONTEXT.md | 430 ----- .../07-DISCUSSION-LOG.md | 152 -- .../07-HUMAN-UAT.md | 52 - .../07-engagement-overview-new/07-UI-SPEC.md | 613 ------- .../07-VERIFICATION.md | 202 --- .../07.1-01-PLAN.md | 296 ---- .../07.1-01-SUMMARY.md | 130 -- .../07.1-02-PLAN.md | 342 ---- .../07.1-02-SUMMARY.md | 162 -- .../07.1-03-PLAN.md | 669 -------- .../07.1-03-SUMMARY.md | 305 ---- .../07.1-04-AUDIT.md | 183 --- .../07.1-04-PLAN.md | 531 ------ .../07.1-04-SUMMARY.md | 230 --- .../07.1-05-MANIFEST.md | 550 ------- .../07.1-05-PLAN.md | 424 ----- .../07.1-05-SUMMARY.md | 270 --- .../07.1-HUMAN-UAT.md | 102 -- .../07.1-VERIFICATION.md | 162 -- .../08-01-PLAN.md | 412 ----- .../08-01-SUMMARY.md | 99 -- .../08-02-PLAN.md | 1446 ----------------- .../08-02-SUMMARY.md | 99 -- .../08-CONTEXT.md | 167 -- .../08-DISCUSSION-LOG.md | 152 -- .../08-HUMAN-UAT.md | 29 - .../08-UI-SPEC.md | 286 ---- .../08-VERIFICATION.md | 113 -- .../09-01-PLAN.md | 421 ----- .../09-01-SUMMARY.md | 126 -- .../09-02-PLAN.md | 617 ------- .../09-02-SUMMARY.md | 144 -- .../09-03-PLAN.md | 709 -------- .../09-03-SUMMARY.md | 186 --- .../09-04-PLAN.md | 466 ------ .../09-04-SUMMARY.md | 172 -- .../09-05-PLAN.md | 436 ----- .../09-05-SUMMARY.md | 143 -- .../09-06-PLAN.md | 523 ------ .../09-06-SUMMARY.md | 177 -- .../09-CONTEXT.md | 459 ------ .../09-DISCUSSION-LOG.md | 188 --- .../09-HUMAN-UAT.md | 93 -- .../09-UI-SPEC.md | 386 ----- .../09-VERIFICATION.md | 257 --- .../09.1-ntfy-backend-fix/09.1-01-PLAN.md | 437 ----- .../09.1-ntfy-backend-fix/09.1-01-SUMMARY.md | 139 -- .../09.1-ntfy-backend-fix/09.1-HUMAN-UAT.md | 32 - .../09.1-VERIFICATION.md | 117 -- 105 files changed, 29945 deletions(-) delete mode 100644 .planning/phases/01-pwa-scaffolding/01-01-PLAN.md delete mode 100644 .planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md delete mode 100644 .planning/phases/01-pwa-scaffolding/01-02-PLAN.md delete mode 100644 .planning/phases/01-pwa-scaffolding/01-02-SUMMARY.md delete mode 100644 .planning/phases/01-pwa-scaffolding/01-HUMAN-UAT.md delete mode 100644 .planning/phases/01-pwa-scaffolding/01-VERIFICATION.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-01-PLAN.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-01-SUMMARY.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-02-PLAN.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-02-SUMMARY.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-CONTEXT.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-HUMAN-UAT.md delete mode 100644 .planning/phases/02-mobile-shell-more-drawer/02-VERIFICATION.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-01-PLAN.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-01-SUMMARY.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-02-PLAN.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-02-SUMMARY.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-HUMAN-UAT.md delete mode 100644 .planning/phases/03-dashboard-restyle/03-VERIFICATION.md delete mode 100644 .planning/phases/04-tickets-restyle/04-01-PLAN.md delete mode 100644 .planning/phases/04-tickets-restyle/04-01-SUMMARY.md delete mode 100644 .planning/phases/04-tickets-restyle/04-02-PLAN.md delete mode 100644 .planning/phases/04-tickets-restyle/04-02-SUMMARY.md delete mode 100644 .planning/phases/04-tickets-restyle/04-03-PLAN.md delete mode 100644 .planning/phases/04-tickets-restyle/04-03-SUMMARY.md delete mode 100644 .planning/phases/04-tickets-restyle/04-CONTEXT.md delete mode 100644 .planning/phases/04-tickets-restyle/04-DISCUSSION-LOG.md delete mode 100644 .planning/phases/04-tickets-restyle/04-HUMAN-UAT.md delete mode 100644 .planning/phases/04-tickets-restyle/04-UI-SPEC.md delete mode 100644 .planning/phases/04-tickets-restyle/04-VERIFICATION.md delete mode 100644 .planning/phases/05-finance-restyle/05-01-PLAN.md delete mode 100644 .planning/phases/05-finance-restyle/05-01-SUMMARY.md delete mode 100644 .planning/phases/05-finance-restyle/05-02-PLAN.md delete mode 100644 .planning/phases/05-finance-restyle/05-02-SUMMARY.md delete mode 100644 .planning/phases/05-finance-restyle/05-CONTEXT.md delete mode 100644 .planning/phases/05-finance-restyle/05-DISCUSSION-LOG.md delete mode 100644 .planning/phases/05-finance-restyle/05-HUMAN-UAT.md delete mode 100644 .planning/phases/05-finance-restyle/05-UI-SPEC.md delete mode 100644 .planning/phases/05-finance-restyle/05-VERIFICATION.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-01-PLAN.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-01-SUMMARY.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-02-PLAN.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-02-SUMMARY.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-03-PLAN.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-03-SUMMARY.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-CONTEXT.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-DISCUSSION-LOG.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-HUMAN-UAT.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-UI-SPEC.md delete mode 100644 .planning/phases/06-analyzer-feed-new/06-VERIFICATION.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-01-PLAN.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-01-SUMMARY.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-02-PLAN.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-02-SUMMARY.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-03-PLAN.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-03-SUMMARY.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-CONTEXT.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-DISCUSSION-LOG.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-HUMAN-UAT.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-UI-SPEC.md delete mode 100644 .planning/phases/07-engagement-overview-new/07-VERIFICATION.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-01-PLAN.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-01-SUMMARY.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-02-PLAN.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-02-SUMMARY.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-03-PLAN.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-03-SUMMARY.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-AUDIT.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-PLAN.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-04-SUMMARY.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-MANIFEST.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-PLAN.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-05-SUMMARY.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-HUMAN-UAT.md delete mode 100644 .planning/phases/07.1-user-timezone-fix-inserted-urgent/07.1-VERIFICATION.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-01-PLAN.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-01-SUMMARY.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-02-PLAN.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-02-SUMMARY.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-CONTEXT.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-DISCUSSION-LOG.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-HUMAN-UAT.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-UI-SPEC.md delete mode 100644 .planning/phases/08-engagement-user-profile-new/08-VERIFICATION.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-01-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-01-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-02-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-02-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-03-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-03-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-04-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-04-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-05-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-05-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-06-PLAN.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-06-SUMMARY.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-CONTEXT.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-DISCUSSION-LOG.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-HUMAN-UAT.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-UI-SPEC.md delete mode 100644 .planning/phases/09-user-profile-preferences-new/09-VERIFICATION.md delete mode 100644 .planning/phases/09.1-ntfy-backend-fix/09.1-01-PLAN.md delete mode 100644 .planning/phases/09.1-ntfy-backend-fix/09.1-01-SUMMARY.md delete mode 100644 .planning/phases/09.1-ntfy-backend-fix/09.1-HUMAN-UAT.md delete mode 100644 .planning/phases/09.1-ntfy-backend-fix/09.1-VERIFICATION.md diff --git a/.planning/phases/01-pwa-scaffolding/01-01-PLAN.md b/.planning/phases/01-pwa-scaffolding/01-01-PLAN.md deleted file mode 100644 index 6a48d35..0000000 --- a/.planning/phases/01-pwa-scaffolding/01-01-PLAN.md +++ /dev/null @@ -1,374 +0,0 @@ ---- -phase: 01-pwa-scaffolding -plan: 01 -type: execute -wave: 1 -depends_on: [] -files_modified: - - public/manifest.json - - app/layout.tsx -autonomous: true -requirements: - - PWA-01 - - PWA-02 - - PWA-03 - -must_haves: - truths: - - "Visiting /manifest.json returns valid JSON with name 'Pulse', short_name 'Pulse', display 'standalone', start_url '/mobile'" - - "The manifest theme_color matches the Wulf brand blue (#0075AD) and background_color matches the light shell" - - "app/layout.tsx references the manifest so Chrome/Safari pick it up automatically (via metadata.manifest or )" - - "app/layout.tsx exports a viewport object whose viewportFit is 'cover' so the rendered contains 'viewport-fit=cover'" - - "Installing Pulse to a phone home screen launches a chromeless app that opens to /mobile" - artifacts: - - path: "public/manifest.json" - provides: "Web App Manifest — name, short_name, display, start_url, theme/background, icons" - contains: '"display": "standalone"' - - path: "app/layout.tsx" - provides: "Root layout exporting metadata (with manifest) and viewport (with viewportFit:'cover')" - contains: "viewportFit" - key_links: - - from: "app/layout.tsx" - to: "public/manifest.json" - via: "metadata.manifest or " - pattern: "manifest" - - from: "public/manifest.json" - to: "/mobile" - via: "start_url field" - pattern: '"start_url"\s*:\s*"/mobile"' - - from: "app/layout.tsx (viewport export)" - to: "rendered " - via: "Next.js viewport export → viewport-fit=cover in DOM" - pattern: "viewportFit" ---- - - -Add the PWA install surface: a valid Web App Manifest at `/manifest.json`, a manifest reference from the root layout, and a viewport export with `viewportFit: 'cover'` so future shell phases can paint behind the device home indicator. - -Purpose: PWA-01, PWA-02, PWA-03 — make Pulse installable to a phone home screen and have the install land on `/mobile` in standalone (chromeless) mode. No service worker, no offline. - -Output: `public/manifest.json` (new file) and an updated `app/layout.tsx` that adds the manifest reference and a Next 16 viewport export. Verifiable by `curl http://localhost:3100/manifest.json` and grep on `app/layout.tsx`. - - - -@$HOME/.claude/get-shit-done/workflows/execute-plan.md -@$HOME/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/STATE.md -@.planning/REQUIREMENTS.md -@docs/superpowers/specs/2026-05-03-mobile-shell-design.md -@CLAUDE.md -@app/layout.tsx -@app/globals.css -@app/styles/brand.css - - - - -**Existing `app/layout.tsx` shape (what is currently there):** -- Imports `Metadata` from `next` (already imported). -- Exports `const metadata: Metadata = { title, description, icons: { icon: [...], shortcut: '/favicon.png', apple: '/wulff-logo.png' } }`. -- Does NOT currently export `viewport`. Next 16 expects a separate `viewport` export of type `Viewport` from `next`. -- The metadata object already has an `icons` field. Do NOT remove it; the PWA `manifest` field is added alongside `icons`. - -**Brand colors (already defined in `app/styles/brand.css`):** -- Wulf primary blue: `#0075AD` (oklch `0.540 0.136 233.3`). This is the `theme_color`. -- Light shell background: white (`#FFFFFF`). This is the `background_color` (the manifest only allows one; the light shell is the standard splash background). - -**Existing icon assets (in `/public`):** -- `/public/wulff-logo.png` — square PNG, used today as `metadata.icons.apple` (apple-touch-icon). -- `/public/favicon.png` — square PNG. -- `/public/branding/wulf-mark.png` — Wulf "W" mark, square PNG. -- `/public/branding/wulf-wordmark.png` — Wulf "Pulse" wordmark. -None of these have explicit pixel sizes verified, but they're used today and PWA install tools accept them with `"sizes": "any"`. - -**Next.js 16 metadata API for manifest:** -- The recommended way to reference a manifest is `metadata.manifest = '/manifest.json'` in the metadata export. Next emits `` automatically. This satisfies the spec wording (``) without hand-rolling the link tag. -- Alternative: hand-roll `` inside ``. Either approach is acceptable per the spec; prefer `metadata.manifest` because the file already uses the metadata API. - -**Next.js 16 viewport API:** -- Import: `import type { Viewport } from 'next'`. -- Export: `export const viewport: Viewport = { ... }` (separate from `metadata`; Next 16 deprecated `metadata.viewport`). -- The `viewportFit` field is camelCase in TS; Next emits `viewport-fit=cover` in the rendered `` tag. -- Reasonable default fields: `width: 'device-width'`, `initialScale: 1`, `viewportFit: 'cover'`. Do NOT add `maximumScale` or `userScalable: false` (accessibility). - -**Theme color / dark mode caveat:** -- The manifest only allows one `theme_color`. Use the Wulf blue `#0075AD` so the system UI tint matches the brand in both light and dark modes. -- Optionally also add a viewport `themeColor` array with `media: '(prefers-color-scheme: dark)'` variants in the viewport export. This is a Next.js helper that emits `` per-scheme. NOT required for PWA-01..03; only add if it falls out naturally. - -**Verification commands the executor will use:** -- `curl -sf http://localhost:3100/manifest.json | jq .` (dev server must be running) -- `grep -E "viewportFit|viewport-fit" app/layout.tsx` -- `grep -E 'manifest:|rel="manifest"' app/layout.tsx` -- `npx tsc --noEmit --pretty` (must pass) - - - - - - - Task 1: Create public/manifest.json - public/manifest.json - - - docs/superpowers/specs/2026-05-03-mobile-shell-design.md (§4 — exact field requirements) - - .planning/REQUIREMENTS.md (PWA-01) - - app/styles/brand.css (line 28: `--wulf-blue` is `#0075AD` — this is theme_color) - - app/globals.css (lines 47-48: light theme `--background` is white; lines 82-83: dark theme background) - - public/ directory listing — confirm `wulff-logo.png`, `favicon.png`, `branding/wulf-mark.png` exist - - -Create `public/manifest.json` (new file) with exactly this JSON shape. Hand-write the file; do not use a generator. - -```json -{ - "name": "Pulse", - "short_name": "Pulse", - "description": "Wulf Consulting operations console — tickets, RMM, backups, and analytics on the go.", - "start_url": "/mobile", - "scope": "/", - "display": "standalone", - "orientation": "portrait", - "theme_color": "#0075AD", - "background_color": "#FFFFFF", - "icons": [ - { - "src": "/wulff-logo.png", - "sizes": "any", - "type": "image/png", - "purpose": "any" - }, - { - "src": "/branding/wulf-mark.png", - "sizes": "any", - "type": "image/png", - "purpose": "any" - }, - { - "src": "/favicon.png", - "sizes": "any", - "type": "image/png", - "purpose": "any" - } - ] -} -``` - -Notes on the choices (so a reviewer doesn't have to ask): -- `name` and `short_name` both "Pulse" — matches spec §4 verbatim. -- `start_url: "/mobile"` — spec §4 verbatim. The phone install lands on the mobile shell, not the desktop dashboard. -- `scope: "/"` — allow the standalone window to navigate anywhere in the app without falling out to the browser. (Spec doesn't specify; root scope is the safe default for an installed PSA console.) -- `display: "standalone"` — spec §4 verbatim. Chromeless app surface. -- `orientation: "portrait"` — phone-first per the spec's overall framing (§1, §2). Tablet landscape is explicit out-of-scope (§7). -- `theme_color: "#0075AD"` — Wulf brand blue from `app/styles/brand.css` line 28 (`--wulf-blue`). Matches the `--primary` token in both light and dark modes (oklch values resolve to this brand blue, slightly lifted for dark). -- `background_color: "#FFFFFF"` — light shell background. Manifest only allows one value; the iOS/Android splash uses this. White matches Pulse's default theme on light devices and is acceptable on dark devices (brief flash, not a regression). -- `icons` — three entries reusing existing assets in `/public`. Using `"sizes": "any"` because the assets are not explicitly sized — install tools accept this for PNGs and pick the largest. Do NOT generate new icon PNGs in this task; reuse what's there. (A future polish phase can add density-specific 192/512 icons if install warns.) - -Do NOT: -- Add a `serviceworker` field (no SW in v1, spec §4 explicit). -- Add `display_override` or `prefer_related_applications` (not needed; not in spec). -- Add `categories` or `lang` (cosmetic; not in spec scope). -- Reference `next-pwa` or any plugin (forbidden by spec §4 and CLAUDE.md). -- Edit any existing migration, lib/, or component file. - -The file must be served directly by Next.js as a static asset — placing it at `public/manifest.json` makes it available at `http://localhost:3100/manifest.json`. - - - test -f public/manifest.json && jq -e '.name == "Pulse" and .short_name == "Pulse" and .display == "standalone" and .start_url == "/mobile" and .theme_color == "#0075AD" and .background_color == "#FFFFFF" and (.icons | length) >= 1' public/manifest.json - - - - File `public/manifest.json` exists. - - `jq -r .name public/manifest.json` outputs `Pulse`. - - `jq -r .short_name public/manifest.json` outputs `Pulse`. - - `jq -r .display public/manifest.json` outputs `standalone`. - - `jq -r .start_url public/manifest.json` outputs `/mobile`. - - `jq -r .theme_color public/manifest.json` outputs `#0075AD`. - - `jq -r .background_color public/manifest.json` outputs `#FFFFFF`. - - `jq -e '.icons | length >= 1' public/manifest.json` exits 0. - - `jq -e '.icons[0].src' public/manifest.json` outputs a path beginning with `/` (e.g., `/wulff-logo.png`). - - File is valid JSON: `jq empty public/manifest.json` exits 0. - - No `serviceworker` field present: `jq -e '.serviceworker == null' public/manifest.json` exits 0. - - When dev server is running on port 3100: `curl -sf http://localhost:3100/manifest.json` exits 0 and the body equals the file contents. - - - `public/manifest.json` exists, is valid JSON, contains the spec-mandated fields with the values above, references at least one icon from `/public`, and is reachable at `http://localhost:3100/manifest.json` when the dev server is running. - - - - - Task 2: Add manifest reference and viewport export to app/layout.tsx - app/layout.tsx - - - app/layout.tsx (current file — already exports `metadata: Metadata`, no `viewport` export yet) - - docs/superpowers/specs/2026-05-03-mobile-shell-design.md (§4 — viewport-fit=cover wording) - - .planning/REQUIREMENTS.md (PWA-02, PWA-03) - - public/manifest.json (created in Task 1 — must exist before this task ships) - - -Edit `app/layout.tsx` (do NOT create a new file). Two changes, both at the top of the file alongside the existing `metadata` export. The body of `RootLayout` is unchanged. - -**Change 1 — add `manifest: '/manifest.json'` to the existing `metadata` object.** - -The current export looks like: - -```ts -export const metadata: Metadata = { - title: "Pulse · Operations console", - description: "Wulf Consulting operations console — tickets, RMM, IT Glue, backups, and analytics in one place.", - icons: { - icon: [ - { url: "/favicon.png", sizes: "any" }, - { url: "/wulff-logo.png", sizes: "32x32", type: "image/png" }, - ], - shortcut: "/favicon.png", - apple: "/wulff-logo.png", - }, -}; -``` - -Add a `manifest` field alongside `icons`. The result should be: - -```ts -export const metadata: Metadata = { - title: "Pulse · Operations console", - description: "Wulf Consulting operations console — tickets, RMM, IT Glue, backups, and analytics in one place.", - manifest: "/manifest.json", - icons: { - icon: [ - { url: "/favicon.png", sizes: "any" }, - { url: "/wulff-logo.png", sizes: "32x32", type: "image/png" }, - ], - shortcut: "/favicon.png", - apple: "/wulff-logo.png", - }, -}; -``` - -Next.js 16 emits `` automatically from this field — this satisfies the spec wording (`` from §4) without hand-rolling the tag. - -**Change 2 — add a `Viewport` import and a separate `viewport` export.** - -Update the `next` type import on line 1. The current import is: - -```ts -import type { Metadata } from "next"; -``` - -Change it to: - -```ts -import type { Metadata, Viewport } from "next"; -``` - -Then, immediately after the `metadata` export (and before `export default function RootLayout(...)`), add: - -```ts -export const viewport: Viewport = { - width: "device-width", - initialScale: 1, - viewportFit: "cover", - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "#FFFFFF" }, - { media: "(prefers-color-scheme: dark)", color: "#0A0A0A" }, - ], -}; -``` - -Notes on the choices: -- `viewportFit: 'cover'` — the only field PWA-03 strictly requires. Emits `viewport-fit=cover` in the rendered `` tag. With this set, Phase 2's safe-area-inset utilities can paint behind the home indicator. -- `width: 'device-width'` and `initialScale: 1` — standard mobile viewport defaults; they were absent before and Next 16 would warn without them. Adding them here removes the warning and makes the viewport explicit. -- `themeColor` — paired light/dark values for the system browser chrome (status bar tint). Light = white (matches manifest `background_color`); dark = `#0A0A0A` (close to the existing `--background` oklch `0.145 0 0` in `app/globals.css` line 83). This is OPTIONAL for PWA-03 (the manifest's `theme_color` already covers the install chrome), but it's a one-line improvement that ships better dark-mode rendering and costs nothing. Keep it; remove if it ever conflicts with a future per-page override. -- Do NOT add `maximumScale`, `userScalable: false`, or `minimumScale` — accessibility regression. - -Do NOT: -- Touch the `RootLayout` function body. -- Touch the `ThemeProvider`, `AppNavigation`, `CommandPalette`, `TaglineFooter`, `Toaster`, or `AuthProvider` imports. -- Add any `` JSX (no hand-rolled `` tag — let Next emit it from `metadata.manifest`). -- Touch the `IBM_Plex_Sans` / `IBM_Plex_Mono` font setup. -- Add `'use client'` — root layout is a server component. - - - grep -q 'manifest: "/manifest.json"' app/layout.tsx && grep -q 'viewportFit: "cover"' app/layout.tsx && grep -q 'import type { Metadata, Viewport } from "next"' app/layout.tsx && grep -q 'export const viewport: Viewport' app/layout.tsx && npx tsc --noEmit --pretty 2>&1 | tee /tmp/tsc-out && ! grep -E "app/layout\\.tsx.*error" /tmp/tsc-out - - - - `grep -E '^import type \{ Metadata, Viewport \} from "next"' app/layout.tsx` matches one line (or `Metadata` and `Viewport` both appear in a single named-import line from `next`). - - `grep -E 'manifest:\s*"/manifest\.json"' app/layout.tsx` matches one line inside the `metadata` object. - - `grep -E '^export const viewport: Viewport = \{' app/layout.tsx` matches exactly one line. - - `grep -E 'viewportFit:\s*"cover"' app/layout.tsx` matches one line inside the `viewport` export. - - `grep -E 'width:\s*"device-width"' app/layout.tsx` matches one line. - - `grep -E 'initialScale:\s*1' app/layout.tsx` matches one line. - - The `metadata.icons` object is unchanged (still contains `apple: "/wulff-logo.png"`): `grep -E 'apple:\s*"/wulff-logo\.png"' app/layout.tsx` matches. - - The `RootLayout` default export is unchanged: `grep -E 'export default function RootLayout' app/layout.tsx` matches. - - No `'use client'` pragma added: `! grep -E "^'use client'" app/layout.tsx`. - - Type check passes: `npx tsc --noEmit --pretty` exits 0 (or, if other files have unrelated pre-existing errors, no error rows mention `app/layout.tsx`). - - When dev server is running: viewing http://localhost:3100/ source contains `viewport-fit=cover` (e.g. `curl -s http://localhost:3100/ | grep -E 'viewport-fit=cover'` exits 0). Optional manual check; not strictly required for the automated gate. - - - `app/layout.tsx` exports both `metadata` (now with `manifest: "/manifest.json"`) and `viewport` (with `viewportFit: "cover"`, `width: "device-width"`, `initialScale: 1`, and themeColor light/dark pair). Type check passes. The `RootLayout` body is unchanged. PWA-02 (manifest reference) and PWA-03 (viewport-fit=cover) are satisfied. - - - - - - -## Trust Boundaries - -| Boundary | Description | -|----------|-------------| -| Browser ↔ static asset (/manifest.json) | Public client read of a manifest. No auth, no input. | -| Browser ↔ rendered HTML head | Public client read of `` and ``. | - -## STRIDE Threat Register - -| Threat ID | Category | Component | Disposition | Mitigation Plan | -|-----------|----------|-----------|-------------|-----------------| -| T-01-01 | Information Disclosure | public/manifest.json | accept | Manifest is intended to be world-readable per W3C Web App Manifest spec. Contains only public app branding (name, theme color, icon paths) — no secrets, no user data, no endpoints. | -| T-01-02 | Tampering | app/layout.tsx viewport export | accept | Server-rendered; no user input flows into the viewport meta. No injection vector. | -| T-01-03 | Denial of Service | manifest fetch | accept | Static file served by Next.js; same risk profile as `/favicon.png`. No new attack surface. | - -**Summary:** No new threat surface introduced. `manifest.json` is public per W3C spec; viewport meta is a public client hint; no auth, data, or endpoints are introduced. ASVS-L1 baseline preserved. - - - -With dev server running (`npm run dev` → port 3100), all of the following must pass: - -```bash -# Manifest is reachable and well-formed -curl -sf http://localhost:3100/manifest.json | jq -e '.name == "Pulse" and .display == "standalone" and .start_url == "/mobile"' - -# Manifest is referenced from root layout (Next emits the link tag automatically) -curl -s http://localhost:3100/ | grep -E 'rel="manifest"' - -# Viewport meta includes viewport-fit=cover -curl -s http://localhost:3100/ | grep -E 'viewport-fit=cover' - -# Type check passes -npx tsc --noEmit --pretty - -# No service worker file shipped (negative check — must be absent) -test ! -f public/sw.js && test ! -f public/service-worker.js - -# next-pwa is not in dependencies -! grep -E '"next-pwa"' package.json -``` - - - -- `public/manifest.json` exists with name "Pulse", short_name "Pulse", display "standalone", start_url "/mobile", theme_color "#0075AD", background_color "#FFFFFF", and at least one icon (PWA-01). -- `app/layout.tsx` references the manifest via `metadata.manifest = "/manifest.json"`, which makes Next.js emit `` in the rendered HTML head (PWA-02). -- `app/layout.tsx` exports `viewport: Viewport` with `viewportFit: "cover"` so the rendered `` tag contains `viewport-fit=cover` (PWA-03). -- `npx tsc --noEmit --pretty` passes. -- No service worker file or `next-pwa` dependency introduced. - - - -After completion, create `.planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md` documenting: -- Files created/modified (paths and one-line descriptions) -- The exact `theme_color` and `background_color` values chosen (and why — Wulf brand blue + light shell background) -- The viewport export shape (so Phase 2 knows it can rely on `viewport-fit=cover` being present) -- Verification results (manifest curl, viewport grep, tsc result) -- Any deviations from the plan and rationale - diff --git a/.planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md b/.planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md deleted file mode 100644 index b652ff6..0000000 --- a/.planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md +++ /dev/null @@ -1,142 +0,0 @@ ---- -phase: 01-pwa-scaffolding -plan: 01 -subsystem: pwa-shell -tags: [pwa, manifest, viewport, mobile] -requires: - - app/layout.tsx (existing root layout with metadata export) - - public/wulff-logo.png, public/favicon.png, public/branding/wulf-mark.png (existing icon assets) -provides: - - public/manifest.json (Web App Manifest at /manifest.json) - - app/layout.tsx exports `viewport: Viewport` with viewportFit: "cover" - - app/layout.tsx exports `metadata.manifest = "/manifest.json"` (Next.js emits automatically) -affects: - - Phase 02 mobile shell (can rely on viewport-fit=cover for safe-area insets) - - All routes (root layout viewport applies app-wide) -tech-stack: - added: [] - patterns: - - Next.js 16 separate `viewport` export (replaces deprecated metadata.viewport) - - Next.js 16 metadata.manifest field (auto-emits ) -key-files: - created: - - public/manifest.json - modified: - - app/layout.tsx -decisions: - - theme_color #0075AD chosen as Wulf primary brand blue (sourced from app/styles/brand.css line 28, --wulf-blue) — gives consistent system UI tint in light and dark mode since manifest only allows one value - - background_color #FFFFFF chosen as the light shell background — manifest only allows one splash background, white matches Pulse's default light theme and is acceptable on dark devices (brief flash, not a regression) - - Used metadata.manifest field over hand-rolled — Next.js 16 emits the link tag automatically, satisfies spec wording, and keeps with the existing metadata API pattern - - Reused existing icon assets with `"sizes": "any"` (wulff-logo.png, branding/wulf-mark.png, favicon.png) instead of generating sized 192/512 variants — install tools accept this for PNGs; sized icons can be added in a future polish phase if install warns - - Added themeColor light/dark pair in viewport (one-line improvement) — paired with Next.js helper, emits per-scheme tags. Optional per the plan; kept since it costs nothing and improves dark-mode rendering - - orientation set to "portrait" — phone-first per spec §1/§2; tablet landscape is explicit out-of-scope per spec §7 - - scope set to "/" — allow standalone window to navigate anywhere in the app without falling out to browser -metrics: - duration: ~1m - tasks_completed: 2 - files_created: 1 - files_modified: 1 - completed: 2026-05-03T17:38:55Z ---- - -# Phase 01 Plan 01: PWA Scaffolding Summary - -PWA install surface added: a Web App Manifest at `/manifest.json` plus a Next.js 16 viewport export with `viewport-fit=cover` so the mobile shell can paint behind the device home indicator in future phases. - -## What Shipped - -### Task 1: `public/manifest.json` (NEW) - -Hand-written 31-line JSON manifest with all spec-mandated fields: - -| Field | Value | Why | -|-------|-------|-----| -| `name`, `short_name` | "Pulse" | Spec §4 verbatim | -| `description` | Wulf operations console blurb | Install dialog readability | -| `start_url` | `/mobile` | Spec §4 — phone install lands on mobile shell, not desktop dashboard | -| `scope` | `/` | Allow standalone window to navigate the whole app | -| `display` | `standalone` | Spec §4 — chromeless app surface | -| `orientation` | `portrait` | Phone-first (spec §1, §2); tablet landscape is OOS (§7) | -| `theme_color` | `#0075AD` | Wulf primary blue from `app/styles/brand.css` line 28 | -| `background_color` | `#FFFFFF` | Light shell background (manifest allows only one) | -| `icons` | 3 entries with `sizes: "any"` | Reuses `/wulff-logo.png`, `/branding/wulf-mark.png`, `/favicon.png` | - -No `serviceworker`, no `display_override`, no `prefer_related_applications`, no `next-pwa` — per spec §4 and CLAUDE.md. - -**Commit:** `3e3df24` - -### Task 2: `app/layout.tsx` (MODIFIED) - -Three minimal additions to the existing root layout, body unchanged: - -1. Import upgraded: `import type { Metadata, Viewport } from "next";` -2. `metadata.manifest = "/manifest.json"` added alongside the existing `icons` field — Next.js 16 emits `` in the rendered HTML head automatically (satisfies PWA-02 spec wording). -3. New `viewport` export: - - ```ts - export const viewport: Viewport = { - width: "device-width", - initialScale: 1, - viewportFit: "cover", - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "#FFFFFF" }, - { media: "(prefers-color-scheme: dark)", color: "#0A0A0A" }, - ], - }; - ``` - - `viewportFit: "cover"` is the load-bearing field for PWA-03 — Next.js renders `viewport-fit=cover` in the `` tag so future phases can use safe-area-inset utilities to paint behind the home indicator. `width`, `initialScale`, and `themeColor` are baseline mobile defaults that prevent Next.js viewport warnings. - -**Commit:** `d196d22` - -## Verification Results - -| Gate | Result | -|------|--------| -| `test -f public/manifest.json` | PASS | -| `jq -e '.name == "Pulse" and .display == "standalone" and .start_url == "/mobile"' public/manifest.json` | PASS (true) | -| `jq -e '.theme_color == "#0075AD" and .background_color == "#FFFFFF"' public/manifest.json` | PASS | -| `jq -e '.icons \| length >= 1' public/manifest.json` | PASS (3 icons) | -| `jq -e '.serviceworker == null' public/manifest.json` | PASS | -| `jq empty public/manifest.json` | PASS (valid JSON) | -| `grep -E '^import type \{ Metadata, Viewport \} from "next"' app/layout.tsx` | PASS | -| `grep -E 'manifest:\s*"/manifest\.json"' app/layout.tsx` | PASS | -| `grep -E '^export const viewport: Viewport = \{' app/layout.tsx` | PASS | -| `grep -E 'viewportFit:\s*"cover"' app/layout.tsx` | PASS | -| `grep -E 'width:\s*"device-width"' app/layout.tsx` | PASS | -| `grep -E 'initialScale:\s*1' app/layout.tsx` | PASS | -| `grep -E 'apple:\s*"/wulff-logo\.png"' app/layout.tsx` (icons preserved) | PASS | -| `grep -E 'export default function RootLayout' app/layout.tsx` (body intact) | PASS | -| `! grep -E "^'use client'" app/layout.tsx` | PASS | -| `npx tsc --noEmit --pretty` | exit 0 | -| `test ! -f public/sw.js && test ! -f public/service-worker.js` | PASS | -| `! grep '"next-pwa"' package.json` | PASS | - -**Dev-server-only checks** (`curl http://localhost:3100/manifest.json`, `curl http://localhost:3100/ \| grep viewport-fit=cover`) were not run — this executor runs in a worktree without a dev server. The offline equivalents above are equivalent: the file is a static asset served verbatim by Next.js from `public/`, and `viewportFit: "cover"` is type-checked to render `viewport-fit=cover` per Next.js 16's documented metadata API. - -## Requirements Satisfied - -- **PWA-01:** `public/manifest.json` exists with name "Pulse", short_name "Pulse", display "standalone", start_url "/mobile", theme_color "#0075AD", background_color "#FFFFFF", and 3 icons. -- **PWA-02:** `app/layout.tsx` references the manifest via `metadata.manifest = "/manifest.json"` — Next.js 16 emits the `` tag automatically. -- **PWA-03:** `app/layout.tsx` exports `viewport: Viewport` with `viewportFit: "cover"` — Next.js renders `viewport-fit=cover` in the `` tag, unblocking safe-area painting in Phase 2. - -## Deviations from Plan - -None - plan executed exactly as written. - -No bugs encountered, no missing critical functionality, no blocking issues, no architectural decisions needed. - -## Threat Surface Scan - -No new threat surface introduced beyond the plan's ``. The manifest is world-readable per W3C Web App Manifest spec and contains only public branding (no secrets, no user data, no endpoints). The viewport export is server-rendered with no user input flow. ASVS-L1 baseline preserved. - -## Known Stubs - -None. All values are real (brand colors sourced from `app/styles/brand.css`, icons reference real public assets, start_url matches the existing `/mobile` route). - -## Self-Check: PASSED - -- `[ -f public/manifest.json ]` → FOUND -- `[ -f app/layout.tsx ]` → FOUND -- `git log --oneline | grep 3e3df24` → FOUND (Task 1 commit) -- `git log --oneline | grep d196d22` → FOUND (Task 2 commit) diff --git a/.planning/phases/01-pwa-scaffolding/01-02-PLAN.md b/.planning/phases/01-pwa-scaffolding/01-02-PLAN.md deleted file mode 100644 index 7c2dab8..0000000 --- a/.planning/phases/01-pwa-scaffolding/01-02-PLAN.md +++ /dev/null @@ -1,286 +0,0 @@ ---- -phase: 01-pwa-scaffolding -plan: 02 -type: execute -wave: 1 -depends_on: [] -gap_closure: true -files_modified: - - app/styles/brand.css -autonomous: true -requirements: - - PWA-04 - -must_haves: - truths: - - "A shared @utility named pt-safe is defined in app/styles/brand.css that applies padding-top: env(safe-area-inset-top)" - - "A shared @utility named pb-safe is defined in app/styles/brand.css that applies padding-bottom: env(safe-area-inset-bottom)" - - "Phase 2's sticky header can opt into safe-area-inset-top padding by adding the pt-safe class" - - "Phase 2's fixed bottom nav can opt into safe-area-inset-bottom padding by adding the pb-safe class" - - "The Tailwind 4 build accepts the new @utility blocks (no CSS syntax errors, npm run build succeeds)" - artifacts: - - path: "app/styles/brand.css" - provides: "Two new @utility blocks (pt-safe, pb-safe) sitting alongside the existing num/metric/surface/rule/chrome/tagline utilities" - contains: "@utility pt-safe" - key_links: - - from: "app/styles/brand.css (@utility pt-safe)" - to: "rendered CSS class .pt-safe" - via: "Tailwind 4 @utility block — Tailwind compiles @utility name { ... } into a class .name { ... }" - pattern: "@utility pt-safe" - - from: "app/styles/brand.css (@utility pb-safe)" - to: "rendered CSS class .pb-safe" - via: "Tailwind 4 @utility block" - pattern: "@utility pb-safe" - - from: "app/globals.css" - to: "app/styles/brand.css" - via: "@import './styles/brand.css' on line 125 (already wired — no change required)" - pattern: '@import "./styles/brand.css"' ---- - - -Close the PWA-04 gap from Phase 01 verification by adding shared safe-area `@utility` blocks to `app/styles/brand.css`. Phase 2's sticky header and fixed bottom nav need to opt into `env(safe-area-inset-top)` / `env(safe-area-inset-bottom)` padding so content paints correctly under the iOS home indicator and Android gesture bar when `viewport-fit=cover` is in effect (already shipped by 01-01). - -Purpose: PWA-04 — make a safe-area utility available so any sticky top/bottom bar can opt in. ROADMAP Phase 1 SC #3 requires the utility to be **available in Phase 1**; Phase 2's contract (SHELL-05, SHELL-06) only mandates **consumption**. This plan restores the broken phase boundary identified by `01-VERIFICATION.md`. - -Output: `app/styles/brand.css` updated with two new `@utility` blocks (`pt-safe`, `pb-safe`) appended to the existing utility section. No other files touched. Verifiable by `grep -E '@utility (pt-safe|pb-safe)' app/styles/brand.css` and `npm run build`. - -Why `app/styles/brand.css` (not `app/globals.css`): -- All named project utilities (`num`, `num-lg`, `num-xl`, `metric-label`, `surface-brand`, `surface-brand-ink`, `rule-brand`, `text-chrome`, `border-chrome`, `tagline`, `has-mark-watermark`) already live there. -- `brand.css` is already imported into `globals.css` (line 125) — no extra wiring needed. -- Keeps utilities co-located so Phase 2 has a single file to scan when looking for project helpers. -- `globals.css` is reserved for Tailwind imports, `@theme inline` token mapping, and `:root` / `.dark` variable definitions — adding utility classes there would muddy that separation. - -Note on traceability: this plan claims `PWA-04` in its `requirements` frontmatter, restoring the orphaned-requirement state flagged by `01-VERIFICATION.md`. The executor's SUMMARY (`01-02-SUMMARY.md`) should explicitly call out that PWA-04 is now satisfied, closing the requirements traceability table. - - - -@$HOME/.claude/get-shit-done/workflows/execute-plan.md -@$HOME/.claude/get-shit-done/templates/summary.md - - - -@.planning/PROJECT.md -@.planning/ROADMAP.md -@.planning/REQUIREMENTS.md -@.planning/phases/01-pwa-scaffolding/01-VERIFICATION.md -@.planning/phases/01-pwa-scaffolding/01-01-SUMMARY.md -@docs/superpowers/specs/2026-05-03-mobile-shell-design.md -@CLAUDE.md -@app/styles/brand.css -@app/globals.css - - - - -**Tailwind 4 `@utility` syntax (already in use in this project):** -- This project is Tailwind 4 with NO `tailwind.config.*` file. Custom utilities are declared inline in CSS using the `@utility` at-rule. -- Pattern: `@utility name { /* CSS declarations */ }` — Tailwind compiles this to a class `.name { ... }` that participates in the variant system (`hover:name`, `md:name`, etc.). -- See existing examples in `app/styles/brand.css` lines 70-140 (e.g., `@utility num { ... }`, `@utility metric-label { ... }`, `@utility surface-brand { ... }`). -- Each `@utility` block holds plain CSS property declarations. No `@apply` is required for simple `padding-*` cases. - -**`env()` CSS environment variables for safe areas:** -- `env(safe-area-inset-top)` — top safe-area inset (e.g., iPhone notch / Dynamic Island area). -- `env(safe-area-inset-bottom)` — bottom safe-area inset (e.g., iPhone home indicator area). -- Browser-side CSS feature; no JavaScript involvement. Falls back to `0` on browsers/devices without safe-area insets. -- Requires `` to take non-zero values. **This is already shipped by 01-01** (`viewportFit: "cover"` in `app/layout.tsx`). - -**Existing `app/styles/brand.css` structure (line numbers from current file):** -- Lines 1-21: file header / brand documentation comment. -- Lines 23-52: `:root` overrides (`--wulf-blue`, etc.) for the light theme. -- Lines 54-62: `.dark` overrides. -- Lines 64-68: `/* === Utility classes === */` section header comment. -- Lines 70-140: existing `@utility` blocks — `num`, `num-lg`, `num-xl`, `metric-label`, `surface-brand`, `surface-brand-ink`, `rule-brand`, `text-chrome`, `border-chrome`, `tagline`. -- Lines 142-147: `/* === Wolf-mark watermark === */` section header comment. -- Lines 149-152: `@utility has-mark-watermark`. -- Lines 154-170: `.mark-watermark` plain rule + `.dark .mark-watermark` override. -- **Insertion point for new utilities:** after the `tagline` utility (line 140) and **before** the watermark section header (line 142). This keeps utilities grouped before the watermark block, which has its own thematic header. - -**`app/globals.css` import wiring (already in place — DO NOT change):** -- Line 125: `@import "./styles/brand.css";` — pulls `brand.css` into the global stylesheet at the end. Anything added to `brand.css` is automatically available app-wide. No additional wiring needed. - -**Spec wording (`docs/superpowers/specs/2026-05-03-mobile-shell-design.md` §5/§6):** -- The mobile shell's sticky top header must respect `env(safe-area-inset-top)`. -- The fixed bottom nav must respect `env(safe-area-inset-bottom)` (often combined with the bottom-nav height). -- The spec accepts either a named utility or Tailwind 4 arbitrary values (`pt-[env(safe-area-inset-top)]`). - -**Why ship a named utility (not arbitrary values):** -- Phase 2 will use these classes in 2+ places (header, bottom nav, drawer footer, possibly modals). A named utility is one source of truth — if the iOS rules ever change (e.g., add `max(env(safe-area-inset-top), 0.5rem)`), it's a one-line edit instead of a multi-file find-and-replace. -- `pt-safe` / `pb-safe` reads more clearly in JSX class lists than `pt-[env(safe-area-inset-top)]`. -- ROADMAP Phase 1 SC #3 explicitly mentions "shared utility class" as one acceptable form — picking that form removes ambiguity for Phase 2. - -**Verification commands the executor will use:** -- `grep -E '@utility pt-safe' app/styles/brand.css` -- `grep -E '@utility pb-safe' app/styles/brand.css` -- `grep -E 'env\(safe-area-inset-top\)' app/styles/brand.css` -- `grep -E 'env\(safe-area-inset-bottom\)' app/styles/brand.css` -- `npm run build` (CSS @utility blocks must parse — broken syntax fails the Tailwind compile step in Next.js) -- `npx tsc --noEmit --pretty` (sanity check; CSS doesn't affect TS but pre-existing baseline must hold) - - - - - - - Task 1: Append pt-safe and pb-safe @utility blocks to app/styles/brand.css - app/styles/brand.css - - - app/styles/brand.css (the entire file — confirm line numbers above match current state; the exact insertion point is between the existing `tagline` utility and the watermark section header) - - app/globals.css lines 1-5 and 125 (confirm `brand.css` is still imported; no change needed) - - .planning/phases/01-pwa-scaffolding/01-VERIFICATION.md (the gap source — frontmatter `gaps[0].missing`) - - .planning/REQUIREMENTS.md line 16 (PWA-04 wording) - - -Edit `app/styles/brand.css`. Append two new `@utility` blocks **after** the existing `@utility tagline { ... }` block (which ends around line 140) and **before** the `/* === Wolf-mark watermark === */` section header comment (around line 142). Do NOT touch any other part of the file. - -Insert exactly this block (including the leading section comment and the two `@utility` definitions): - -```css -/* === Safe-area insets ================================================= - * - * Opt-in padding helpers for sticky top / fixed bottom bars on devices - * with notches, dynamic islands, or gesture home indicators. Pair with - * the viewport-fit=cover viewport meta (set in app/layout.tsx) — without - * that, env(safe-area-inset-*) resolves to 0 and these utilities are - * no-ops, which is the desired fallback on non-PWA / non-mobile contexts. - * - * Usage: - *
// header clears notch - *