start-vibing 4.1.2 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,237 @@
1
+ ---
2
+ name: mobile-app-patterns
3
+ description: >
4
+ Best-in-class mobile UI/UX patterns inspired by Duolingo, Linear, Arc, Raycast,
5
+ Notion Mobile, Superhuman. MUST BE USED when designing, auditing, or fixing
6
+ any mobile viewport (≤768px) — especially dashboards, lists, forms, modals,
7
+ nav. Replaces "responsive-web-on-a-phone" thinking with genuine mobile-native
8
+ patterns. Referenced by sd-audit (design-intelligence rubric), sd-fix
9
+ (M-template fixes), and sd-research (component extraction from competitors).
10
+ version: 1.0.0
11
+ ---
12
+
13
+ # mobile-app-patterns
14
+
15
+ ## Philosophy
16
+
17
+ A mobile screen is **not** a shrunken desktop. It is a **thumb-reach device** used in 2–10 second sessions with one hand, often while walking/waiting/scrolling. Every pattern here is derived from apps people actually keep on their home screen.
18
+
19
+ ## Reference apps (study these before designing)
20
+
21
+ | App | Why | Patterns to extract |
22
+ |---|---|---|
23
+ | **Duolingo** | Highest D7 retention in learning category | Compact metric rows, streak flames, XP hero, bottom nav with tab bubbles, full-screen lesson flow, celebration animations |
24
+ | **Linear Mobile** | Fastest feedback SaaS on mobile | Minimal chrome, swipe-to-action on list rows, bottom sheet for create, command-K style quick switcher |
25
+ | **Arc Mobile / Search** | Search-first nav | No bottom tabs — single tap to search/command, gesture stack for back |
26
+ | **Raycast iOS** | Power-user density | Compact list rows with inline metadata, command palette, no decorative chrome |
27
+ | **Notion Mobile** | Heavy content on small screen | Block-based editor, swipe to nest/unnest, floating action button for quick capture |
28
+ | **Superhuman** | Speed as the aesthetic | No loading states visible — optimistic everything, keyboard shortcuts respected on iPad, split-swipe archive/snooze |
29
+ | **Cash App** | Financial density without tables | Big number hero, compact transaction rows (avatar + name + amount + relative time), bottom-sheet send/receive |
30
+ | **Spotify** | Media density | Horizontal scroll rails (not cards in column), sticky now-playing bar, bottom tab nav |
31
+
32
+ ## Core mobile patterns
33
+
34
+ ### 1. Lists over cards (CRITICAL)
35
+
36
+ **Rule:** On mobile dashboards, `role=listitem` rows beat `role=region` cards for metrics, entities, and history. Cards waste 40–60% of viewport height on padding+radius+shadow for a single data point.
37
+
38
+ ```tsx
39
+ // ANTI-PATTERN (what the beats-market admin dashboard did wrong)
40
+ <div className="flex flex-col gap-3">
41
+ <Card><CardHeader>Total Users</CardHeader><CardContent>16</CardContent></Card>
42
+ <Card><CardHeader>Producers</CardHeader><CardContent>5</CardContent></Card>
43
+ <Card><CardHeader>Orders</CardHeader><CardContent>18</CardContent></Card>
44
+ {/* 10+ cards = endless scroll, no density */}
45
+ </div>
46
+
47
+ // GOOD (Duolingo/Linear/Cash App style)
48
+ <ul className="divide-y divide-border">
49
+ {metrics.map(m => (
50
+ <li key={m.id} className="flex items-center justify-between py-3 px-4">
51
+ <div className="flex items-center gap-3">
52
+ <Icon name={m.icon} className="size-5 text-muted-foreground" />
53
+ <span className="text-sm text-muted-foreground">{m.label}</span>
54
+ </div>
55
+ <span className="text-base font-semibold tabular-nums">{m.value}</span>
56
+ </li>
57
+ ))}
58
+ </ul>
59
+
60
+ // EVEN BETTER for a hero metric on mobile (Cash App style)
61
+ <section className="px-4 pt-6 pb-4">
62
+ <p className="text-sm text-muted-foreground">Total revenue</p>
63
+ <h1 className="text-4xl font-bold tabular-nums">R$1.389</h1>
64
+ <p className="text-xs text-muted-foreground mt-1">+12% vs last month</p>
65
+ </section>
66
+ <ul className="divide-y">{/* supporting metrics as compact rows */}</ul>
67
+ ```
68
+
69
+ **Density target:** A mobile viewport (390×844) should fit **at least 6–8 metrics above the fold**, not 2–3.
70
+
71
+ ### 2. Hero + compact list (dashboard pattern)
72
+
73
+ ```
74
+ ┌─────────────────────────┐
75
+ │ ☰ Dashboard 👤 │ Header (56px fixed)
76
+ ├─────────────────────────┤
77
+ │ │
78
+ │ Total Revenue │ HERO: 1 big number
79
+ │ R$ 1,389.00 │ that matters most
80
+ │ +12% this month ↗ │
81
+ │ │
82
+ ├─────────────────────────┤
83
+ │ 👥 Users 16 │ Compact metric rows
84
+ │ 🎵 Producers 5 │ (44px each)
85
+ │ 📦 Active Packs 18 │
86
+ │ 🛒 Orders 18 │
87
+ │ 🔄 Refunds 0 │
88
+ │ 📊 Refund Rate 0.0% │
89
+ │ 🛡️ DMCA Claims 0 │
90
+ │ 💬 Open Tickets 1 │
91
+ ├─────────────────────────┤
92
+ │ [Home][Metrics][Orders] │ Bottom tab nav (56px)
93
+ └─────────────────────────┘
94
+ ```
95
+
96
+ ### 3. Bottom nav (NOT hamburger) for top-level nav
97
+
98
+ - 3–5 tabs max. More → move to secondary screen via "More" tab.
99
+ - Each tab = a destination, not an action.
100
+ - Fixed position, 56–64px tall, with safe-area inset.
101
+ - Active state: fill icon + label always visible (not hidden).
102
+
103
+ ```tsx
104
+ <nav className="fixed inset-x-0 bottom-0 z-40 border-t bg-background pb-[env(safe-area-inset-bottom)]">
105
+ <ul className="flex h-14">
106
+ {tabs.map(t => (
107
+ <li key={t.id} className="flex-1">
108
+ <Link
109
+ href={t.href}
110
+ aria-current={active === t.id ? 'page' : undefined}
111
+ className="flex h-full flex-col items-center justify-center gap-1 text-xs"
112
+ >
113
+ <t.Icon className={cn('size-5', active === t.id ? 'fill-current' : '')} />
114
+ <span className={active === t.id ? 'font-semibold' : 'text-muted-foreground'}>{t.label}</span>
115
+ </Link>
116
+ </li>
117
+ ))}
118
+ </ul>
119
+ </nav>
120
+ ```
121
+
122
+ ### 4. Bottom sheets (NOT centered modals) for actions
123
+
124
+ - Centered dialog on mobile = thumb cannot reach top-right close button.
125
+ - Bottom sheet slides up from the bottom, close via drag-down or button at top.
126
+ - Use `<dialog>` or Vaul/Radix + `vaul-drawer` libs.
127
+
128
+ ### 5. Full-screen flows (NOT multi-step modals)
129
+
130
+ Onboarding, lesson completion, checkout, create-entity — all should be **full-screen pages** that replace the current view, with a close/back in the top-left, not modal overlays.
131
+
132
+ Duolingo lesson = full-screen. Cash App send = full-screen. Linear create-issue = bottom sheet → expand to full. Never a centered modal trying to cram a form.
133
+
134
+ ### 6. Swipe actions on list rows
135
+
136
+ Archive / Delete / Snooze / Complete = left or right swipe on the row. Exposes discoverability via slight peek on first render.
137
+
138
+ Lib: `react-swipeable-list` / custom pointer-events handler. Always provide a long-press or trailing `[…]` button as a11y fallback.
139
+
140
+ ### 7. Pull-to-refresh on scrollable lists
141
+
142
+ Native iOS/Android pattern. Every list that fetches server data should implement it. Lib: `react-pull-to-refresh` or Framer Motion gestures.
143
+
144
+ ### 8. Typography scale for mobile
145
+
146
+ - Body: **16px** (never smaller — iOS triggers zoom on focus for <16px inputs)
147
+ - Meta / captions: 14px minimum, 13px absolute floor for tabular dense lists
148
+ - Headings: 20/24/32/40 — large hero numbers allowed (44–56px)
149
+ - Line-height: 1.4 body, 1.2 headings, 1.5 long-form reading
150
+
151
+ ### 9. Touch targets
152
+
153
+ - **44×44 px minimum** (Apple HIG) or 48dp (Material) — NOT the WCAG 24px floor
154
+ - 8px gap between adjacent targets
155
+ - Full-width list rows: the whole row is the target, not just the text
156
+
157
+ ### 10. Data tables → convert on mobile
158
+
159
+ Tables with >3 columns CANNOT fit at 375px. Transform:
160
+
161
+ | Original desktop | Mobile replacement |
162
+ |---|---|
163
+ | Users table (name, email, role, status, date, actions) | List of rows with avatar + primary text + compact metadata stack + trailing `[⋯]` menu |
164
+ | Orders table (id, buyer, items, total, payment, refund, downloads, actions) | Card per order: buyer + total prominent, metadata as chips, CTA row at bottom |
165
+ | Data grid | Virtualized list OR horizontal scroll with sticky first column (only if truly needed) |
166
+
167
+ ## Mobile anti-patterns (auto-flag in audits)
168
+
169
+ | Anti-pattern | Why bad | Fix |
170
+ |---|---|---|
171
+ | Cards in `flex-col` for metrics | Wastes 40–60% vertical space | Compact list rows with divider |
172
+ | Desktop table <768px | Unreadable microtext or horizontal scroll hell | Card-per-row OR list with primary+meta |
173
+ | Hamburger menu as only nav | Hides primary destinations behind 1+ tap | Bottom tab bar (3–5 tabs) |
174
+ | Centered modal with close in top-right | Unreachable by thumb | Bottom sheet with drag handle |
175
+ | Input `font-size < 16px` | iOS Safari zooms in on focus | Use 16px or `font-size: max(16px, 1rem)` |
176
+ | Fixed header + fixed footer > 25% height | Leaves <75% for content | Collapse header on scroll (framer shrink) |
177
+ | Multi-column layout <600px | Nothing fits | Single column or horizontal rail |
178
+ | Hover-only affordances | Touch has no hover | Gate `@media (hover: hover)` + tap equivalent |
179
+ | Tiny close buttons (<24×24) | Missed taps | 44×44 hit area even if icon is smaller |
180
+ | Toast in top-right | Thumb can't dismiss | Bottom-center toast with swipe-down |
181
+ | 100vh anywhere | iOS Safari URL bar breaks it | `100svh` / `100dvh` with `-webkit-fill-available` fallback |
182
+ | Pull-to-refresh inside inner scroll | Conflicts with browser pull | `overscroll-behavior: contain` |
183
+
184
+ ## Competitor reference for mobile patterns by domain
185
+
186
+ | Your app type | Study these on mobile |
187
+ |---|---|
188
+ | Admin / SaaS dashboard | Linear, Height, Plane, Vercel dashboard |
189
+ | Marketplace (buyer) | Instagram Shop, Depop, Vinted, Mercari |
190
+ | Marketplace (seller) | Shopify Mobile, Etsy Seller, Depop |
191
+ | E-commerce checkout | Shop App, Amazon, Stripe Checkout (in a WebView) |
192
+ | Social / community | Discord, Slack, Twitter (X), BlueSky |
193
+ | Learning / habit | Duolingo, Brilliant, Finch, Streaks |
194
+ | Finance / fintech | Cash App, Revolut, Mercury, Ramp |
195
+ | Productivity | Notion, Linear, Raycast, Things 3 |
196
+ | Media | Spotify, Apple Music, YouTube |
197
+
198
+ ## How to use this skill
199
+
200
+ - **sd-audit** references these anti-patterns as M-category findings (M1–M12).
201
+ - **sd-fix** applies M-templates with code snippets directly from this skill.
202
+ - **sd-research** studies competitors' mobile viewports against this pattern library, not just home pages.
203
+ - **frontend-design** plugin cross-references this skill when generating mobile UI.
204
+
205
+ ## Mandatory mobile audit checklist (≤375px viewport)
206
+
207
+ ```
208
+ □ Primary nav is bottom tabs (3-5), not hamburger-only
209
+ □ Dashboards use hero + compact list, not card stack
210
+ □ Tables transformed to card-per-row or compact list
211
+ □ No input has font-size < 16px
212
+ □ Every interactive target ≥ 44×44 px
213
+ □ Modals are bottom sheets or full-screen, not centered
214
+ □ No hover-only state; every hover has a tap equivalent
215
+ □ Loading states exist for async flows
216
+ □ Empty states exist for zero-data cases
217
+ □ Error states exist for server failures
218
+ □ Safe-area insets respected (iOS notch, home indicator)
219
+ □ Text uses 100svh / 100dvh (not 100vh) for full-height
220
+ □ Scroll containers use overscroll-behavior: contain
221
+ □ Pull-to-refresh implemented on primary list views
222
+ □ Swipe actions discoverable (peek on first render)
223
+ □ Back gesture (iOS) works via browser history
224
+ □ Keyboard does not overlap input (visualViewport API)
225
+ □ Touch targets 8px+ apart
226
+ □ Long-press fallback for swipe actions
227
+ □ Bottom sheet CTAs sticky above safe area
228
+ ```
229
+
230
+ ## References
231
+
232
+ - Linear Method — https://linear.app/method
233
+ - Vercel Design Engineering — https://vercel.com/blog/design-engineering-at-vercel
234
+ - iOS HIG Touch Targets — https://developer.apple.com/design/human-interface-guidelines/layout
235
+ - Material 3 Bottom App Bar — https://m3.material.io/components/bottom-app-bar/overview
236
+ - NN/g Mobile UX — https://www.nngroup.com/topic/mobile-and-tablet-design/
237
+ - Baymard Mobile Checkout — https://baymard.com/checkout-usability
@@ -8,7 +8,7 @@ description: >
8
8
  UX audit (WCAG 2.2 AA, Nielsen heuristics, Baymard, CWV), and synthesized
9
9
  overview. Re-audits only what changed since last run. On explicit user request,
10
10
  applies surgical fixes with full rollback.
11
- version: 0.4.0
11
+ version: 0.6.0
12
12
  ---
13
13
 
14
14
  # super-design
@@ -18,14 +18,36 @@ version: 0.4.0
18
18
  Four-phase pipeline with 6 specialist agents:
19
19
 
20
20
  1. **Market research** (sd-research) — auto-detects niche from repo, finds 5–10
21
- competitors, extracts design language, produces market-analysis.md.
22
- 2. **UI/UX audit** (sd-audit)drives browser via Playwright MCP directly,
23
- applies Nielsen's 10 heuristics, WCAG 2.2 AA, Baymard (if e-commerce), and
24
- Core Web Vitals. Produces findings.json with SHOT+QUOTE+SEL+VAL evidence.
25
- 3. **Synthesis** (sd-synthesis) — unifies research + audit into overview.md.
21
+ competitors, extracts design language AND component vocabulary (buttons,
22
+ nav, cards, modals, forms, tokens per competitor × mobile+desktop),
23
+ produces market-analysis.md + component-comparison.md.
24
+ 2. **UI/UX audit** (sd-audit) drives browser via Playwright MCP directly.
25
+ Five layers:
26
+ - Route discovery + static snap (Nielsen + WCAG 2.2 AA + Baymard + CWV)
27
+ - **Step 2.5 component/modal/flow discovery** (Phase A inventory, B modal
28
+ enumeration, C flow exercising, D state matrix, E form coverage) — this
29
+ is where modal contents, empty/loading/error states, and flow errors
30
+ get real evidence instead of "checklist hypothetical".
31
+ - **Step 3g design-intelligence scoring** (17-category rubric → DIS 0–100)
32
+ catches implicit best practices checklists miss (cards-in-flex-col,
33
+ low density, weak CTA hierarchy, vibecode smell).
34
+ - **Step 3h mobile-native audit** (21-item Duolingo/Linear/Arc/Cash-App
35
+ checklist) — replaces "responsive-web-on-a-phone" thinking.
36
+ - C16 ≤ 4 → design-skill advisory finding citing typeui-* selection matrix.
37
+ Produces findings.json + design-intelligence.json with SHOT+QUOTE+SEL+VAL.
38
+ 3. **Synthesis** (sd-synthesis) — unifies research + audit + design-intelligence
39
+ into overview.md (per-page DIS table + executive summary).
26
40
  4. **Fix** (sd-fix + two-stage verify) — optional. Applies safe fixes with
27
41
  technical gates (types/lint/tests) AND semantic verification ("does this
28
- fix actually resolve the finding, or just mask it?").
42
+ fix actually resolve the finding, or just mask it?"). Template families:
43
+ A1-A15 a11y · V1-V8 design · U1-U10 ux · P1-P10 perf · **M1-M15 mobile**
44
+ (cards-in-flex-col → compact list, table-on-mobile → card-per-row,
45
+ centered-modal → bottom-sheet, etc.) · **DSC-1 design-skill advisory**
46
+ (proposes typeui-* direction, never auto-applies — HIGH risk). After each
47
+ successful fix, re-drives Playwright to capture an after-screenshot (full
48
+ page + element crop) and emits `docs/super-design/sessions/<id>/fix-report.md`:
49
+ a self-contained visual diff with before/after images, file diffs,
50
+ verification status, and commit SHA per finding.
29
51
 
30
52
  ## Entry flow
31
53
 
@@ -0,0 +1,258 @@
1
+ # Component, Modal & Flow Discovery Playbook
2
+
3
+ > How sd-audit systematically exercises EVERY interactive element before
4
+ > running heuristics. Without this, the audit only sees static page snaps
5
+ > and misses modal contents, flow state, hover/focus/active variants, and
6
+ > loading/empty/error states.
7
+ >
8
+ > This playbook runs as **Step 2.5** in sd-audit, after route discovery
9
+ > and before per-viewport heuristic passes.
10
+
11
+ ## Why this matters
12
+
13
+ Static screenshots of pages show ~30% of what users interact with. The other 70%
14
+ lives inside modals, drawers, dropdowns, command palettes, error flows, empty
15
+ states, loading states, hover menus, focus rings. A page can score 95/100 on
16
+ Lighthouse and be unusable because its "Create" modal is broken — and the
17
+ auditor never opened it.
18
+
19
+ ## Discovery phases
20
+
21
+ ### Phase A — Interactive inventory (per page × viewport)
22
+
23
+ After navigating and dismissing banners:
24
+
25
+ ```js
26
+ // browser_evaluate
27
+ (() => {
28
+ const roots = [
29
+ '[role="button"]',
30
+ 'button',
31
+ 'a[href]',
32
+ '[role="link"]',
33
+ '[role="menuitem"]',
34
+ '[role="tab"]',
35
+ '[role="switch"]',
36
+ '[role="checkbox"]',
37
+ '[role="radio"]',
38
+ '[aria-haspopup]',
39
+ '[aria-expanded]',
40
+ '[data-trigger]',
41
+ '[data-state]',
42
+ 'input',
43
+ 'select',
44
+ 'textarea',
45
+ 'summary',
46
+ ];
47
+ const items = [];
48
+ roots.forEach(sel => {
49
+ document.querySelectorAll(sel).forEach(el => {
50
+ if (!el.offsetParent && getComputedStyle(el).position !== 'fixed') return;
51
+ const r = el.getBoundingClientRect();
52
+ if (r.width === 0 || r.height === 0) return;
53
+ items.push({
54
+ selector: sel,
55
+ tag: el.tagName,
56
+ role: el.getAttribute('role'),
57
+ name: el.getAttribute('aria-label') || el.textContent?.trim().slice(0, 60) || '',
58
+ type: el.getAttribute('type'),
59
+ haspopup: el.getAttribute('aria-haspopup'),
60
+ expanded: el.getAttribute('aria-expanded'),
61
+ disabled: el.disabled || el.getAttribute('aria-disabled') === 'true',
62
+ rect: { x: r.x, y: r.y, w: r.width, h: r.height },
63
+ });
64
+ });
65
+ });
66
+ return items;
67
+ })()
68
+ ```
69
+
70
+ Save to `.super-design/sessions/<id>/interactive/<slug>_<vp>.json`.
71
+
72
+ Classify each:
73
+ - **navigation** — links, tabs, back buttons
74
+ - **action** — primary CTAs, submit, delete, save
75
+ - **trigger** — opens modal/drawer/dropdown (`aria-haspopup`, `data-trigger`)
76
+ - **input** — form fields
77
+ - **state-toggle** — switches, checkboxes, expanders
78
+
79
+ ### Phase B — Modal & overlay discovery
80
+
81
+ For each trigger from Phase A:
82
+
83
+ ```
84
+ 1. Pre-click snapshot (already have from Phase 1)
85
+ 2. browser_click({ ref }) # click the trigger
86
+ 3. browser_wait_for(text="<expected modal content>") or 500ms
87
+ 4. browser_snapshot → save as snapshots/<slug>_<vp>_<triggerName>_open.yaml
88
+ 5. browser_take_screenshot fullPage + element-scoped → screens/components/
89
+ 6. browser_console_messages(level="error") → record
90
+ 7. Inside open modal, run Phase A again (nested inventory)
91
+ 8. Look for [role="dialog"] or [data-state="open"] to confirm it opened
92
+ 9. Exercise modal internals:
93
+ - Tab through to find focus trap
94
+ - Press Escape to confirm dismiss
95
+ - Resize to mobile — check if it becomes bottom-sheet
96
+ 10. Close modal (button or Escape)
97
+ 11. Re-snapshot → confirm background restored, focus returned to trigger
98
+ ```
99
+
100
+ **Modals a junior agent misses:**
101
+ - Confirmation dialogs (delete confirm, logout confirm)
102
+ - Date pickers (calendar popover)
103
+ - Color pickers
104
+ - Combobox dropdowns (autocomplete search)
105
+ - Popover menus (dropdown with options)
106
+ - Sheet / drawer (slide-in from right or bottom)
107
+ - Command palette (Cmd+K)
108
+ - Tooltips (hover-triggered on desktop)
109
+ - Toast notifications (programmatic — trigger an action that causes one)
110
+ - Error modals (submit invalid form)
111
+ - Share sheets
112
+ - File upload dialogs (click input[type=file])
113
+
114
+ ### Phase C — Flow exercising
115
+
116
+ A **flow** is a multi-step user journey. Every app has 3–10 critical flows.
117
+ sd-audit must auto-discover and exercise them.
118
+
119
+ **Auto-discover flows from routes + component names:**
120
+
121
+ | Route / name hint | Flow |
122
+ |---|---|
123
+ | `/login`, `/signin`, `/auth` | Login flow (happy + wrong password + locked account) |
124
+ | `/register`, `/signup` | Registration flow |
125
+ | `/forgot`, `/reset` | Password reset flow |
126
+ | `/onboarding`, `/welcome` | First-run flow |
127
+ | `/checkout`, `/cart` | Checkout flow (incl. errors: declined card, validation) |
128
+ | `/dashboard`, `/home` (authed) | Post-auth landing → primary CTA flow |
129
+ | List route (`/users`, `/orders`) | CRUD — create, edit, view, delete, filter, search, paginate |
130
+ | Detail route (`/users/:id`) | Edit flow, delete flow, related actions |
131
+ | `/settings`, `/profile` | Profile edit, preference toggles, account delete |
132
+ | `/support`, `/help`, `/chat` | Messaging flow |
133
+
134
+ **Per flow:**
135
+
136
+ ```
137
+ 1. Plan steps (list of expected screens + actions)
138
+ 2. Execute step-by-step:
139
+ - Navigate / click to advance
140
+ - Per step: snapshot + screenshot + console
141
+ - Test error path (invalid input, network error via DevTools)
142
+ - Test back button preserves state
143
+ 3. Capture final success state (confirmation page, toast, redirect)
144
+ 4. If flow depends on creating test data, use burner account
145
+ ```
146
+
147
+ Save per-flow artifacts under `.super-design/sessions/<id>/flows/<flow_name>/step_NN_<action>.png`.
148
+
149
+ ### Phase D — State matrix per component
150
+
151
+ For each UI component class (Button, Input, Card, ListRow, Modal, NavItem…),
152
+ capture:
153
+
154
+ | State | How to trigger |
155
+ |---|---|
156
+ | default | Initial render |
157
+ | hover | `browser_hover` (desktop only, gate `@media hover`) |
158
+ | focus | Tab to element via `browser_press_key(Tab)` until focused |
159
+ | focus-visible | Same as focus (most systems collapse them now) |
160
+ | active | `browser_press_key` Enter/Space while focused |
161
+ | disabled | Find a disabled example (e.g., form before valid) |
162
+ | loading | Submit form → catch transient state; OR throttle network via DevTools |
163
+ | error | Invalid input + submit |
164
+ | empty | Navigate to route with no data (burner account OR delete all) |
165
+ | success | Complete a flow successfully |
166
+ | selected | Click tab / radio / checkbox that shows selected variant |
167
+
168
+ Save per component class:
169
+ ```
170
+ .super-design/sessions/<id>/components/
171
+ Button/
172
+ default.png
173
+ hover.png
174
+ focus.png
175
+ active.png
176
+ disabled.png
177
+ loading.png
178
+ Input/...
179
+ Modal/...
180
+ ```
181
+
182
+ Output `.super-design/sessions/<id>/component-state-matrix.json`:
183
+
184
+ ```json
185
+ {
186
+ "Button": {
187
+ "states_captured": ["default", "hover", "focus", "active", "disabled", "loading"],
188
+ "states_missing": ["error"],
189
+ "evidence": { "default": "components/Button/default.png", "..." }
190
+ },
191
+ "...": {}
192
+ }
193
+ ```
194
+
195
+ **Missing states → finding.**
196
+
197
+ ### Phase E — Form state coverage
198
+
199
+ Per form discovered, test:
200
+ 1. Empty submit → validation messages
201
+ 2. Each field invalid individually → per-field error
202
+ 3. All valid → success state
203
+ 4. Server error (simulate 500) → error recovery
204
+ 5. Network offline → offline handling
205
+ 6. Paste into password field → paste NOT blocked
206
+ 7. Autocomplete tokens on login fields (`username`, `current-password`, `one-time-code`)
207
+ 8. Tab order matches visual order
208
+ 9. Submit via Enter key works
209
+ 10. Mobile viewport — input zoom behavior (iOS Safari `font-size < 16px`?)
210
+
211
+ Save: `.super-design/sessions/<id>/forms/<formId>_<scenario>.png`
212
+
213
+ ## Orchestration summary
214
+
215
+ sd-audit adds this between Step 2 and Step 3:
216
+
217
+ ```
218
+ Step 2.5 — Discovery
219
+ For each (page, viewport):
220
+ A. Interactive inventory
221
+ B. Modal/overlay enumeration (click every trigger)
222
+ C. Flow exercising (login, CRUD, checkout if applicable)
223
+ D. Component state matrix
224
+ E. Form state coverage
225
+ ```
226
+
227
+ This takes 3–5× longer than static-only audit but produces ~3× the findings,
228
+ each with real evidence of failure conditions (not just hypothetical WCAG
229
+ violations on static markup).
230
+
231
+ ## Budget & skipping
232
+
233
+ For very large apps, scope Phase B/C/D to:
234
+ - Top 5 most-clicked triggers per page (ranked by proximity to primary CTA)
235
+ - Critical flows only (login + checkout + 1 CRUD)
236
+ - 3 component classes minimum (Button, Input, Modal) — rest deferred to full-mode audit
237
+
238
+ Record what was skipped in `.super-design/sessions/<id>/scope.json` so later
239
+ runs can close the gap.
240
+
241
+ ## Error handling
242
+
243
+ - **Triggered modal doesn't appear within 2s** — record "trigger broken" finding, move on
244
+ - **Console error after click** — record verbatim, still capture whatever rendered
245
+ - **Focus not trapped** — record a11y violation
246
+ - **Modal close fails** — force navigate away, record "close broken" finding
247
+
248
+ Never let a broken trigger abort the full audit — isolate and continue.
249
+
250
+ ## Hard rules
251
+
252
+ 1. Every Phase A inventory item must be considered for exercising; skips recorded.
253
+ 2. Every modal opened must be screenshotted OPEN + CLOSED.
254
+ 3. Every flow must capture at least one error path, not just happy path.
255
+ 4. Component state matrix must declare which states are MISSING (not just captured).
256
+ 5. Form state coverage — 10 scenarios per form; partial completion records which.
257
+ 6. Use ONE Playwright session; reuse across phases; `browser_close` only at end.
258
+ 7. Sequential, not parallel. Never spawn parallel tabs.