# QA Punchlist — VOTD

One rolling doc. New build sections are prepended at the top. Carry-forward items stay in prior build sections until explicitly closed out.

---

## Build 103 (continued) — 2026-04-04 (feature/centralized-gates)

### Profile preview isolation (fix for good)
- [ ] **Pre-baked identity card** — preview uses `PREVIEW_PROFILE` constant (Jamie Rivera, JR initials, Sacramento address) — zero references to real user data
- [ ] **Pre-baked stats** — Civic Snapshot, How You Align, Drawn To all use `VERIFIED_STATS` when previewing regardless of real verification level
- [ ] **Pre-baked Votes tab** — full mock vote portfolio shown when previewing; tally visible, no "Sign up for tally" gate
- [ ] **Pre-baked Follows tab** — user votes visible when previewing; interactions (star, press, vote) disabled
- [ ] **Real profile card** — no `previewVerified` conditionals in real branch — clean separation
- [ ] **Header title** — shows "Verified Profile" when previewing, "My Profile" otherwise
- [ ] **Phone-only user** — still sees phone number + generic icon, never name/avatar/address
- [ ] **Preview toggle** — "Preview verified profile →" link only shown for humble (non-verified) users
- [ ] **Back link** — "← back" in preview card returns to real profile view

---

## Build 103 — 2026-04-03 (feature/centralized-gates)

### Registration complete ("You're all set") screen
- [ ] **Back chevron removed** — screen no longer shows a back arrow (end of flow, no valid back destination)
- [ ] **Brand title centered** — "Vote of the Day" brand title properly centered at top, matching profile-setup / photo-setup layout
- [ ] **Continue button** — routes to returnTo destination or VOTD tab if none

### VOTD overlay — Source / Research cards
- [ ] **Source card with OG image** — when source has preview image in meta, card shows image above title/domain/description
- [ ] **Source card without image** — displays as before: icon + title + domain row with external link arrow
- [ ] **Pending source with image** — newly added research with OG image shows image + "Pending approval" badge
- [ ] **Multiple sources stack** — existing sources + newly added pending sources render stacked (not carousel on overlay)
- [ ] **Mock data image** — first VOTD item (mock-001 LED streetlights) now has preview image in source for testing

### Share vote panel redesign
- [ ] **Panel height** — share panel is 63% of screen height (fixed, no content-sized)
- [ ] **No notch, no swipe** — top notch bar and swipe-to-dismiss gesture removed
- [ ] **"Select platform" label** — replaces old "Tap to share" label above platform row
- [ ] **Single-select checkmark** — tapping a platform shows a white checkmark in place of its icon; tapping again deselects; only one platform selectable at a time
- [ ] **Selected platform name** — label turns white when selected
- [ ] **"Share Now" button** — full-width frosted button below platform row; dimmed (35% opacity) when no platform selected; fires share action on tap
- [ ] **"Tap to Close" button** — small, diminutive, pinned at bottom of sheet; same font/color as old "Swipe down to close" hint (Roboto 400, 11pt, white 50%); tight trace outline box around copy
- [ ] **VOTD conf close** — "Tap to Close" dismisses entire VOTD overlay (same as X button)
- [ ] **vote-item conf close** — "Tap to Close" exits entire vote-item screen (same as X button)
- [ ] **Feed share close** — "Tap to Close" slides down share panel only (feed stays visible)

### Carry-forward from Build 102
- [ ] All Build 102 checklist items still apply (voted items display, skip overlay sequencing, gate table accuracy)

---

## Build 102 — 2026-04-03 (feature/centralized-gates)

### Voted items in Votes — Open list
- [ ] **Verified user voted on open item** — card shows tally with user's vote highlighted (showUserVote)
- [ ] **Phone-auth user voted on open item** — card shows faded "Sign up for tally" CTA (orange text at 55% opacity on Vote Now tint background)
- [ ] **"Sign up for tally" tap** — routes to profile-setup with "Finish signing up" heading (D sequence), no skip overlay
- [ ] **Unvoted open items** — still show normal Vote Now button (no change)

### Voted items on My Profile — Votes tab
- [ ] **Verified user** — open voted items show tally with vote highlighted; closed voted items show tally normally
- [ ] **Phone-auth user** — open voted items show faded "Sign up for tally" CTA; closed voted items show tally normally
- [ ] **"Sign up for tally" tap** — routes to profile-setup with "Finish signing up" (D sequence)

### My Profile — Follows tab
- [ ] **Followed items** — no tally gate; open items show Vote Now, closed items show tally; no blurTally

### Skip overlay — C sequence only
- [ ] **Guest taps Vote Now (VOTE_GUEST)** — gate overlay → Add My Number → signup → OTP → profile-setup: skip overlay shows ON ARRIVAL with "One more step" heading
- [ ] **Guest taps Follow (FOLLOW_GUEST)** — same: skip overlay on arrival at profile-setup
- [ ] **Guest taps Save (SAVE_GUEST)** — same: skip overlay on arrival
- [ ] **Guest taps Share (SHARE_GUEST)** — same: skip overlay on arrival
- [ ] **Skip overlay "Complete Sign Up"** — dismisses overlay, user continues profile setup (A3 → A4 → A5 → A6)
- [ ] **Skip overlay "Skip for now"** — returns to returnTo screen (not VOTD unless that was the origin)
- [ ] **Guest taps Propose (PROPOSE_GUEST)** — full A sequence, profile-setup shows "One more step" with NO skip overlay
- [ ] **Guest taps Add Research (RESEARCH_GUEST)** — full A sequence, NO skip overlay
- [ ] **Onboarding sign up** — full A sequence, NO skip overlay
- [ ] **Phone-auth taps Propose (PROPOSE_PHONE)** — D sequence, profile-setup shows "Finish signing up" with NO skip overlay
- [ ] **Phone-auth taps Add Research (RESEARCH_PHONE)** — D sequence, "Finish signing up", NO skip overlay
- [ ] **Profile "Finish Sign Up" button** — D sequence, "Finish signing up", NO skip overlay
- [ ] **Profile edit pen (phone-auth)** — D sequence, "Finish signing up", NO skip overlay

### Gate table + docs updates
- [ ] **"Index — Open Votes" renamed to "Votes — Open"** in all-comps.html gate table and all 5 audit docs
- [ ] **"Sign up for tally — phone" row added** to Votes — Open section and My Profile section in gate table
- [ ] **Routing rules updated** — sequence-based logic (A/C/D) replaces returnTo-based logic
- [ ] **Feed Card Types table** added to terminology.md — all 14 canonical component names

---

## Build 101 — 2026-04-03 (feature/centralized-gates)

### Share poster question size + layout
- [ ] SharePoster rewritten — headline "What's your take?" (voted/promo) or "I voted yes/no on..." (position)
- [ ] Question text at 42pt (was 60pt in old layout) with adjustsFontSizeToFit for long questions
- [ ] Gradient updated: #E8873A → #C85014 → #A5411E at 160deg
- [ ] Rank pill, days left badge, brand lockup (★ VOTD + tagline) all render

### Vote-item exit routing
- [ ] Votes tab > open item > vote > close confirmation → returns to Votes tab (was landing on Feed)
- [ ] VOTD/feed > open item > vote > close → returns to Feed (unchanged)
- [ ] All Votes tab VoteCard presses pass `from: 'votes'` param

### Gate skip overlay cleanup
- [ ] RESEARCH_PHONE gate: `showSkipOnEntry` set to false — no skip overlay on profile-setup from research gate
- [ ] Profile "Finish Sign Up" button: no longer passes `showSkipOnEntry` — passes `returnTo: '/(tabs)/profile'` instead
- [ ] Skip overlay only appears during original phone auth sequence (verify-otp → profile-setup with returnTo)

### Skip "for now" routing fix
- [ ] Skip on profile-setup returns to `returnTo` destination (not always VOTD)
- [ ] address-setup skip forwards `returnTo` through to photo-setup
- [ ] Full chain (profile-setup → address → photo → registration-complete) preserves returnTo

### Verify-signin "We found you" chevron
- [ ] B3a screen now has back chevron (was missing)

### Feedback widget on signup screens
- [ ] Feedback flag visible on ALL screens during preview (FEEDBACK_HIDDEN_ROUTES emptied)
- [ ] "Get support" button on verify-signin B3c now works (widget is mounted)
- [ ] Screen labels updated per flow: Flow: Sign Up, Flow: Phone, Flow: Phone Finish, Flow: Have Account
- [ ] Non-signup labels: Votes, Vote of the Day, Vote of the Day: Detail, Profile, Onboarding

### Profile shows real votes
- [ ] VOTDContext `voted` map exposed via provider
- [ ] vote-item StickyVoteBar calls `recordVote()` on vote
- [ ] votes.tsx `handleVote` calls `recordVote()` on inline vote
- [ ] Pending vote replay also records vote
- [ ] Profile Votes tab shows real voted items for phone-auth users (was empty)
- [ ] Profile stats `votesCast` reflects real vote count for humble users

### VOTD overlay — Add Research
- [ ] Add Research CTA added to VOTDOverlayCard (below sources section)
- [ ] Frosted white styling (rgba(255,255,255,0.12) bg, dashed white border) works on orange background
- [ ] Gate fires for guests (signup) and phone-auth (finish signup)
- [ ] AddResearchSheet opens on successful gate pass

---

## Build 100 — 2026-04-03 (feature/centralized-gates)

### ShareSheet content-sizing
- [ ] Share panel on feed no longer has large empty orange gap at bottom
- [ ] Share panel on vote-item same height as feed — both content-sized
- [ ] Share panel on VOTD overlay card same behavior
- [ ] `topRatio` prop removed — no per-caller configuration needed

### Gate action replay after signup
- [ ] Votes tab: tap Save as guest → complete signup → returns to votes → save auto-completes
- [ ] Feed tab: tap Propose as guest → complete signup → returns to feed → propose modal auto-opens
- [ ] Feed tab: tap Add Research as guest → complete signup → returns to feed → research sheet auto-opens
- [ ] Vote-item: pendingSave/pendingVote via query params still works
- [ ] Module-level pending actions survive component remounts during navigation

### Profile cleanup — no mock data for humble users
- [ ] Phone-verified user with no name set: profile shows formatted phone number as display name
- [ ] Phone-verified user with no name set: avatar shows generic user icon (not initials)
- [ ] Phone-verified user: no mock voted items shown (votes tab empty)
- [ ] Phone-verified user: no mock address shown
- [ ] `ME` / `MOCK_USERS` / "John Doe" completely removed from profile.tsx
- [ ] `PHONE_VERIFIED_STATS.votesCast` = 0 (was 1)
- [ ] Verified users: profile still shows real context data (name, address, avatar)

### Phone stored in ProfileContext
- [ ] `phone` field added to ProfileContext with AsyncStorage persistence
- [ ] verify-otp stores phone number on successful verification
- [ ] Phone number hydrates on app restart

### VoteCard save UX
- [ ] Authenticated user: tapping Save illuminates star orange for 400ms, then flyout closes
- [ ] Guest user: tapping Save closes flyout immediately (no animation), gate fires
- [ ] Save flyout icon is star (not bookmark), toggles to "Saved" when already followed
- [ ] `onStar` returns `false` when gated, VoteCard skips animation

### Signup flow fixes
- [ ] signup.tsx always shows X (not back chevron) — it's always first screen in flow
- [ ] verify-otp passes `showSkipOnEntry: 'true'` when `returnTo` present (gate flow)
- [ ] verify-otp passes no skip overlay for organic signup (no returnTo)
- [ ] Profile-setup skip overlay auto-shows when arriving through gate

### Hero share on vote-item
- [ ] Share button in vote-item hero opens custom ShareSheet (not native iOS share)
- [ ] Share variant defaults to anonymous

### Swipe hint text
- [ ] VOTDOverlayCard swipe hint reads "Swipe up for feed" (was "Swipe up for open votes")

### Breaker animation durations doubled
- [ ] BreakerChart: line draw 2400ms, area fade 2800ms, dot stagger 2000ms/500ms, labels 800ms/2800ms
- [ ] BreakerDistViz: curve 1600ms, marker delay 1800ms / duration 1400ms, dot 600ms
- [ ] BreakerRaceViz: bars 2200ms, delay 400ms
- [ ] BreakerBarsViz: stagger 240ms, duration 1800ms, delay 400ms

### wrapPending crash fix
- [ ] `wrapPending()` calls removed from SourceCard in vote-item.tsx (function was never defined)
- [ ] Pending sources still handled by early return at line ~1846

### Votes tab share
- [ ] Tapping Share in VoteCard flyout on Votes tab opens native iOS share (not custom panel)
- [ ] No `handleShare` ReferenceError

---

## Gate system refinements — 2026-04-02 (feature/centralized-gates, batch 2)

### StickyVoteBar centralized (#2)
- [ ] StickyVoteBar vote gate now uses `useGate()` + `GateOverlay` instead of manual `isGuest` / `nudgeVisible` / `SkipOverlay`
- [ ] Guest tapping Yes/No on vote-item fires VOTE_GUEST gate overlay
- [ ] SkipOverlay import removed from vote-item.tsx (no longer used)

### Save return state (#3)
- [ ] `pendingSave=1` appended to returnTo when save gate fires on vote-item
- [ ] On return from signup, vote-item auto-triggers `toggleFollow(id)` so star is visually selected

### Finish nudge copy centralized (#7/#8/#9)
- [ ] VOTDOverlayCard locked card text now reads from `GATES.FINISH_NUDGE.message` and `.completeLabel`
- [ ] vote-item locked card (phone_verified tally) same centralized copy
- [ ] Profile "Finish Sign Up" button reads from `GATES.FINISH_NUDGE.completeLabel`
- [ ] Changing text in gateConfig.ts cascades to all three screens

### Onboarding returnTo (#14)
- [ ] "Sign Up" on onboarding now passes `returnTo: '/(tabs)/index'` so flow lands on Vote of the Day after registration-complete

### StickyVoteBar return to confirmation (#18)
- [ ] `pendingVote=yes|no` appended to returnTo when StickyVoteBar vote gate fires
- [ ] On return, StickyVoteBar initializes in `voted` state with tally + share animations

### Vote Now gating — pending UX decision (#1/#5)
- Index and Feed card-level vote gating NOT implemented — awaiting decision on whether to gate before or after vote-item detail screen
- Vote gate on index.tsx `handleVote` reverted (was added, now removed)
- StickyVoteBar on vote-item IS gated (guest taps Yes/No → gate fires)
- VOTD overlay IS gated (guest taps Yes/No → gate fires, `_pendingCardState` preserves state)

---

## Centralized gate system — 2026-04-02 (feature/centralized-gates)

### New files
- `lib/gateConfig.ts` — Central config for all 9 gate types (VOTE_GUEST, FOLLOW_GUEST, SAVE_GUEST, SHARE_GUEST, PROPOSE_GUEST, PROPOSE_PHONE, RESEARCH_GUEST, RESEARCH_PHONE, FINISH_NUDGE) with helper functions per action
- `lib/useGate.ts` — Hook managing visibility, dismiss-count escalation (orange on 2nd tap), and routing to correct signup sequence
- `components/GateOverlay.tsx` — Thin wrapper connecting useGate() state to SkipOverlay

### Refactored screens (replaced inline SkipOverlay + local gate state with centralized system)
- [ ] **vote-item.tsx** — Save, propose, and add-research gates now use `gate.show()` + single `<GateOverlay>`; StickyVoteBar inline nudge preserved (unique dismiss-clears-vote behavior)
- [ ] **votd.tsx** — Propose and add-research gates centralized; 2 SkipOverlays → 1 GateOverlay
- [ ] **index.tsx** — Save and propose gates centralized; 2 SkipOverlays → 1 GateOverlay
- [ ] **VOTDOverlayCard.tsx** — Vote, follow, and propose gates centralized; guest nudge + propose overlay → 1 GateOverlay; `_pendingCardState` preserved by setting before `gate.show()`
- [ ] **profile.tsx** — Propose gate centralized; uses `effectiveLevel` (accounts for VP preview toggle)

### "Vote of the Day" brand title added to all signup flow screens
- [ ] **signup.tsx** — centered brand title above back chevron
- [ ] **verify-otp.tsx** — centered brand title above back chevron
- [ ] **profile-setup.tsx** — centered brand title above form
- [ ] **address-setup.tsx** — centered brand title above back chevron
- [ ] **photo-setup.tsx** — centered brand title above back chevron
- [ ] **registration-complete.tsx** — centered brand title above emoji/heading
- [ ] Style matches signin.tsx pattern: `Roboto_700Bold`, `r(22)`, `#201F1E`, `center`, `marginTop: 16`

### Behavioral checks
- [ ] Guest tapping Vote/Save/Follow shows "Confirm your mobile number to continue" overlay with "Add My Number" CTA
- [ ] 2nd dismiss of vote/save/follow gate shows message in orange (#C85014)
- [ ] Guest tapping Propose shows "Proposing votes requires voter verification" with "Sign Up" CTA
- [ ] Phone-verified tapping Propose shows same message with "Finish Sign Up" CTA, routes to /profile-setup
- [ ] Guest tapping Add Research shows "Adding research requires voter verification" with "Sign Up" CTA
- [ ] Phone-verified tapping Add Research shows same message with "Finish Sign Up" CTA, routes to /profile-setup with showSkipOnEntry
- [ ] Dismissing propose gate on VOTD/index/VOTDOverlayCard opens ProposeVoteModal
- [ ] VOTDOverlayCard: card state preserved through gate → signup → return flow
- [ ] All returnTo params route back to correct screen after signup

---

## Session fixes — 2026-04-02

### AddResearchSheet rewrite (dark panel, swipe dismiss)
- [ ] Sheet opens at 65% height (`top: screenHeight * 0.35`) with dark grey transparent background `rgba(58,53,49,0.92)`
- [ ] "Swipe down to dismiss" text sits ABOVE the notch bar
- [ ] Swipe-down on notch dismisses the sheet (PanResponder, same pattern as feed share overlay)
- [ ] Picker icons use FontAwesome6 (`link` / `file-arrow-up`) in WHITE — no emoji
- [ ] No "Preview" button — link fetch fires on keyboard submit ("go" key)
- [ ] Link preview shows: domain (orange, uppercase) → title → description → OG image (aspectRatio 1.91)
- [ ] "Add This" button: `rgba(255,255,255,0.85)` bg, orange text; goes full white on press
- [ ] "Source (required)" label is WHITE
- [ ] File upload picker: "Add This" button styled same as link version once file selected

### AR8 pending state (stripped-down link row)
- [ ] Pending sources render as dead link (View, not TouchableOpacity — not tappable)
- [ ] Domain and title text dimmed to opacity 0.40
- [ ] "Pending approval" badge at full opacity, inline below title (`alignSelf: 'flex-start'`)
- [ ] Approved sources render full preview card with working link (no badge)

### ProposeVoteModal picker icons
- [ ] Link and file picker icons use FontAwesome6 (`link` / `file-arrow-up`) in NEAR_BLACK
- [ ] No emoji text for picker icons (avoids Roboto `?` rendering bug)

### Verification fix — registration-complete
- [ ] Completing signup (registration-complete screen) sets `verificationLevel` to `'verified'`
- [ ] No double-gating after signup completion — user can immediately access Add Research

### Share position gating
- [ ] Only `verified` users can share position (not `phone_verified`)
- [ ] `phone_verified` users see "Share the vote" (anonymous) only

### Expo template stubs
- [ ] `parallax-scroll-view.tsx` stubbed (simple ScrollView) — removes react-native-reanimated dependency
- [ ] `hello-wave.tsx` stubbed (simple Text) — removes react-native-reanimated dependency
- [ ] App builds without react-native-reanimated installed

### Silhouette emoji asset
- [ ] Profile-setup screens show bust silhouette emoji (not blank/missing)
- [ ] `assets/emoji/silhouette.png` is a proper 144x144 RGBA PNG

### DESIGN_DECISIONS.md updates
- [ ] Verification tiers table added (guest → phone_verified → verified pending → verified fully)
- [ ] "Release Approved Hold" concept documented
- [ ] Share vote permission table updated (phone_verified loses Share Position)

---

## Add Research Flow (AR1–AR8) — 2026-04-02

### AR1 — CTA row on vote-item
- [ ] "Add Research" CTA row appears below sources on open vote items
- [ ] CTA does NOT appear on closed vote items
- [ ] CTA row shows orange ＋ icon, "Add Research" title, "Share a link about this vote" subtitle
- [ ] Even when item has no sources, CTA still appears on open items

### Verification gates (F5a / F5b)
- [ ] Guest tapping "Add Research" → SkipOverlay: "Adding research requires voter verification" + "Sign Up" / "Skip for now"
- [ ] Phone-verified tapping "Add Research" → SkipOverlay: same message + "Finish Sign Up" / "Skip for now"
- [ ] Verified user tapping "Add Research" → bottom sheet opens (no gate)
- [ ] "Sign Up" routes to /signup, "Finish Sign Up" routes to /profile-setup

### AR2 — Picker bottom sheet
- [ ] Sheet opens with notch, "Add Research" header, subtitle
- [ ] Two-column picker: "Paste a link" (link icon) / "Upload a file" (file icon)
- [ ] Tapping backdrop dismisses sheet
- [ ] ✕ close button dismisses sheet

### AR3 — Link input + fetching
- [ ] URL text input appears with placeholder "Paste URL here"
- [ ] Keyboard opens automatically
- [ ] "Preview" button dimmed until text entered
- [ ] Tapping Preview or keyboard "Go" starts fetch
- [ ] "Fetching preview…" loading state with spinner

### AR4 — Link preview
- [ ] OG preview card shows domain, title, description
- [ ] "Revise" link clears URL and returns to input
- [ ] Root domain (e.g. sacbee.com with no path) shows nudge: "Please paste a link to a specific article…"
- [ ] "Add This" button dimmed when root domain detected
- [ ] "Add This" submits and dismisses sheet

### AR5/AR6 — File upload
- [ ] iOS: tapping "Upload a file" shows native ActionSheet (Take Photo / Photo Library / Browse Files / Cancel)
- [ ] Android: shows dashed upload card with ＋ icon

### AR7 — File preview + source field
- [ ] File preview shows icon + filename
- [ ] "Revise" returns to picker
- [ ] "Source (required)" label + text input
- [ ] "Add This" dimmed until source field filled

### AR8 — Pending approval
- [ ] After submission, new source card appears at 45% opacity
- [ ] "Pending approval" badge visible on the card
- [ ] Only visible to the contributor (mock: always visible)

### Data model
- [ ] VoteSource type now includes optional `status` field: 'pending' | 'approved' | 'rejected'

### Brand title (B sequence fix)
- [ ] "Vote of the Day" on signin.tsx matches onboarding title: r(22), Roboto_700Bold, #201F1E
- [ ] "Vote of the Day" on verify-signin.tsx (all 3 states) matches same style
- [ ] B3c: spacing between "Sign up" button and "Need help?" label increased

---

## Aggregated QA Pass — Builds 88–93 (2026-04-02)

Consolidated checklist. Builds 88–90 items carried from prior QA list; builds 91–93 items added. Test on Build 93 (current).

### Vote of the Day (VOTD Overlay Card)

- [ ] Reading state — notch bar visible, no "Tap to dismiss"
- [ ] Choosing state (Yes/No) — notch bar visible, no "Tap to dismiss"
- [ ] Voted state — "Tap to dismiss" visible, no notch bar; tally and share panel appear immediately
- [ ] Card body is scrollable without tapping "Read more" first
- [ ] Active VOTD shows 29–30 days remaining
- [ ] Verified user sees live animated tally (no locked state)
- [ ] phone_verified user sees locked card — no tally bar, "Finish Sign Up" CTA, nudge pushed down
- [ ] "Finish Sign Up" from VOTD goes to profile setup screen (name/address) — not phone screen
- [ ] Returning from profile setup restores voted confirmation with tally and share panel visible

### Guest Flow

- [ ] Guest taps Yes/No → phone gate appears → completes phone step → returns to Yes/No buttons (not Vote Now)
- [ ] Guest taps Yes/No → phone gate → skips → still on Yes/No, can tap again (no double-vote block)
- [ ] Guest votes → skips gate → tries to vote again → gate reappears (not silently blocked)

### Vote Confirmation Screen

- [ ] "Change my vote" is the only path back to Yes/No after voting — no other button re-enters choosing state
- [ ] "Finish Sign Up" from locked tally → completes signup → returns to voted/tally state (not Vote Now)
- [ ] "+ Propose a Vote" button present in confirmation header, fires correct gate/modal
- [ ] Stance text renders correctly — full proper noun kept (e.g. "Sacramento County should not require…")
- [ ] phone_verified locked card — no ghost bar, just message + CTA

### Navigation

- [ ] X on vote-item opened from Index → lands on Index, no VOTD overlay surfaces
- [ ] X on vote-item opened from Feed → lands on Feed tab
- [ ] X on vote-item opened from VOTD → lands on Index (not VOTD)
- [ ] Back arrow from a vote item cannot navigate back to VOTD card
- [ ] No "page not found" error on any X / exit / back action
- [ ] Phone auth → complete OTP → skip name/photo → lands on originating screen (not VOTD overlay) *(Build 91+)*
- [ ] VOTD overlay → open vote item → X → overlay does NOT re-surface *(Build 91)*
- [ ] Dismiss VOTD overlay → open vote item → X → overlay does NOT re-surface *(Build 91)*
- [ ] Complete a vote from Index → X → overlay does NOT appear *(Build 91)*
- [ ] Completing signup flow (phone → name → address) → lands in app → VOTD overlay DOES appear (first-time load path still works) *(Build 91)*

### Share Panel — General

- [ ] "Share This Vote" heading centered with space below in all three destinations (VOTD, vote-item, feed)
- [ ] "Share the vote" toggle label used everywhere (not "Share this vote")
- [ ] Poll question shown and centered only in the Feed share modal (showQuestion prop)
- [ ] "Preview Poster" link present and centered in all destinations
- [ ] Share panel height feels proportional at 0.56 across VOTD, vote-item, and feed
- [ ] Open vote item → tap share icon (arrow-up-from-bracket) in hero image → system share sheet opens *(Build 93)*
- [ ] Vote on any item → share panel appears → tap any platform → share fires without crash *(Build 93)*
- [ ] Tap "More" → system share sheet opens without crash *(Build 93)*

### Share Panel — Platform Carousel

- [ ] Tapping any platform fires share immediately — no multi-select, no Share Now button
- [ ] "More" opens native iOS share sheet immediately — no checkmark
- [ ] iMessage present in carousel — tapping opens native Messages compose sheet with pre-filled text, no crash
- [ ] Truth Social "T" is visually centered in its bubble
- [ ] Platform icons are visibly larger than Build 88 size
- [ ] Last platform icon in carousel is visibly clipped — confirms horizontal scroll
- [ ] Snapping in carousel aligns cleanly to icon boundaries

### Share Panel — Feed

- [ ] Feed share panel: notch at top reads "Swipe down to close" — swipe down closes panel
- [ ] Feed share panel: tapping backdrop closes panel

### Poster Preview

- [ ] "Share the vote" toggle → shows VOTD_Vote.png
- [ ] "Share how I voted" + YES vote → shows VOTD_Share_Vote_Yes.png
- [ ] "Share how I voted" + NO vote → shows VOTD_Share_Vote_NO.png
- [ ] Preview image updates live when toggle is flipped

### Feed *(Build 92+)*

- [ ] Feed tab renders without crash or red error overlay
- [ ] Swipe down on share panel (after tapping Share on any feed card) → panel dismisses smoothly
- [ ] Fling share panel downward fast → dismisses without freezing
- [ ] Slow-drag share panel partway down, release → springs back up
- [ ] Navigate Index → Feed → Index → Feed — no crash on repeated tab switches
- [ ] Scroll feed past breaker cards → breaker graphic animates in on scroll *(Build 93)*

### Propose a Vote *(Build 93)*

- [ ] Intro card → swipe up → advances to step 1
- [ ] Intro card → tap X → closes modal entirely (not step 1)
- [ ] Submit → confirmation card shows Done button only (no "Go to feed" link)
- [ ] Index bottom bar caption: "What's an issue that deserves consideration?"
- [ ] Feed bottom bar caption: "What's an issue that deserves consideration?"

### Sign Up & Account Recovery *(Build 93)*

- [ ] Onboarding "Already have an account?" → lands on sign-in screen (B1)
- [ ] Sign-in B1 → enter phone → B2 OTP → correct code → B3a "We found you!" → Get started → /(tabs)
- [ ] Sign-in B2 → enter wrong code → inline error "That code doesn't match. Try again." — stays on OTP
- [ ] Photo setup "Remind me later" → A6 Registration Complete → Continue → /(tabs)
- [ ] Photo setup "Continue" (with photo) → A6 Registration Complete → Continue → /(tabs)

### Profile

- [ ] Navigating away from Profile and back always opens on About tab (not last visited tab)
- [ ] Starring a vote from the index dot-stack menu shows it in Profile → Follows tab
- [ ] Starred items appear in Follows regardless of whether the item has been voted on
- [ ] Saved votes section is empty on fresh session (no pre-seeded items)

### Propose a Vote — Modal *(Builds 88–90)*

- [ ] ProposeVoteModal X button same icon weight and position on both intro and form steps
- [ ] ProposeVoteModal submitted state shows "Done" button

### Feedback / Analytics

- [ ] Feedback submissions from each screen log correct label: Vote Index, Feed, Vote Item, Onboarding, Account, Profile, Propose

### Stability

- [ ] App launches cleanly — no crash on startup
- [ ] No crash when idle on Index or during normal navigation

### Visual / Design

- [ ] Vote index closed view: area icons visibly smaller (size 24)
- [ ] All X buttons use consistent icon weight (FontAwesome6 xmark, r(22)) across VOTD, vote-item, and ProposeVoteModal

---

## Build 93 (2026-04-01)

### Bug fixes: share crashes, breaker animation, routing, propose copy, sign-up Section B, A6

#### Changes

**Share panel — all platforms crashing (vote-item + feed)**
- Root cause: `getPosterUri()` returns Metro bundled asset URIs (`bundled-asset://`). RNShare ObjC code cannot open these, throws NSException → TurboModule bridge crashes in `JSObject::addOwnProperty`.
- Fix in `shareUtils.ts`: removed `imageUri` from every `shareSingle` call across all platforms. `'more'` (system sheet) now uses `Share.share()` instead of `native.open()`. Email uses `url: appUrl` instead of `imageUrl`. iMessage Linking body now includes `appUrl`. All social platforms use `url: appUrl` only. Poster image sharing marked TODO until assets are written to `file://` temp path.

**Hero share button on vote-item did nothing**
- Root cause: `TouchableOpacity` wrapping `arrow-up-from-bracket` icon had no `onPress` handler.
- Fix: added `handleHeroShare()` in `VoteItemScreen` — calls `shareToApp('more', ...)` with an anonymous share message. Added `shareToApp` to shareUtils import.

**Vote-item X button wrong destination**
- Root cause: `handleBack()` mapped `from === 'feed'` → `/(tabs)/votd`, but no callers outside `votd.tsx` passed `from`, so all closed vote items returned to Index overlay instead of back to the originating tab.
- Fix: rewritten to `if (from === 'votd') replace('/(tabs)')` else `router.canGoBack() ? back() : replace('/(tabs)')`.

**VOTD feed breaker graphics never animated**
- Root cause: FlatList cached item renders — `visibleBreakers` Set changed externally but FlatList never re-rendered breaker rows.
- Fix: added `extraData={visibleBreakers}` to FlatList in `votd.tsx`.

**Propose a vote intro card — swipe up didn't work**
- Root cause: no PanResponder attached to the intro card.
- Fix: created `introPan` PanResponder in `ProposeVoteModal.tsx`; attached `panHandlers` to `introTopBar` View. Threshold: dy < −8 to start, dy < −40 or vy < −0.4 to dismiss.

**Propose a vote intro card — X button advanced to step 1 instead of closing modal**
- Fix: changed `onPress={dismissIntro}` to `onPress={onClose}` on the intro X button.

**Propose a vote confirmation card — "Go to feed" link removed**
- The redundant link below the Done button has been removed. Done is the single exit.

**Phone auth → skip → landed on VOTD overlay instead of origin**
- Root cause: `profile-setup.tsx` `onDismiss` on SkipOverlay hard-coded `router.replace('/(tabs)')`, ignoring `returnTo`.
- Fix: changed to `router.replace((returnTo as any) ?? '/(tabs)')`.

**Index + Feed — Propose a Vote caption updated**
- New copy: "What's an issue that deserves consideration?"

**Section B — Account Recovery screens (B1, B2, B3a/b/c)**
- New files: `app/signin.tsx` (B1 phone entry), `app/verify-signin.tsx` (B2 OTP + B3 outcomes).
- B3a "We found you! 👋" → `router.replace('/(tabs)')`. B3b wrong code → inline error stays on OTP. B3c "Hmm… that didn't work" → sign-up link + support TODO.
- Onboarding "Already have an account?" now routes to `/signin` (was `/signup`).
- All new screens added to `_layout.tsx` Stack with `headerShown: false, gestureEnabled: false` and to `OVERLAY_HIDDEN_ROUTES` + `FEEDBACK_HIDDEN_ROUTES`.

**A6 — Registration Complete screen**
- New file: `app/registration-complete.tsx`. BEIGE background, 🎉 emoji, "You're all set" heading, body explaining 24–48 hr verification, single "Continue" → `returnTo` or `/(tabs)`.
- `photo-setup.tsx`: both "Continue" (with photo) and "Remind me later" now route to `/registration-complete` instead of directly to tabs.

**Comp library — User Accounts removed from nav**
- Removed nav `<li>` for User Accounts from `docs/all-comps.html`. Stale Copy Inventory table replaced with forwarding note.

#### QA Checklist

- [ ] Open any vote item → tap share icon (arrow-up-from-bracket) in hero image → system share sheet opens
- [ ] Vote on any item → share panel appears → tap any platform → share fires without crash
- [ ] Vote on any item → tap "More" share option → system sheet opens without crash
- [ ] Open a vote item from Feed tab → tap X → lands back on Feed
- [ ] Open a vote item from Index → tap X → lands on Index
- [ ] VOTD overlay → open a vote item → tap X → lands on Index, overlay does NOT re-appear
- [ ] Scroll VOTD feed past breaker cards — breaker graphic animates in on scroll
- [ ] Propose a vote → intro card → swipe up → advances to step 1
- [ ] Propose a vote → intro card → tap X → closes modal entirely (not step 1)
- [ ] Propose a vote → submit → confirmation card shows Done button only (no "Go to feed" link)
- [ ] Phone auth → complete OTP → skip name/photo steps → lands on originating screen (not VOTD overlay)
- [ ] Index bottom bar caption: "What's an issue that deserves consideration?"
- [ ] Feed bottom bar caption: "What's an issue that deserves consideration?"
- [ ] Onboarding "Already have an account?" → lands on sign-in screen (B1)
- [ ] Sign-in B1 → enter phone → B2 OTP → correct code → B3a "We found you!" → Get started → `/(tabs)`
- [ ] Sign-in B2 → enter wrong code → inline error "That code doesn't match. Try again." — stays on OTP
- [ ] Photo setup "Remind me later" → lands on A6 Registration Complete → Continue → `/(tabs)`
- [ ] Photo setup "Continue" (with photo) → lands on A6 Registration Complete → Continue → `/(tabs)`

---

## Build 92 (2026-04-01)

### Feed screen crash fix — `PanResponder` missing import

**Change:** Added `PanResponder` to the `react-native` named imports in `votd.tsx`. It was referenced at line 3204 (`feedSharePan = useRef(PanResponder.create(...))`) but not imported, causing an immediate `ReferenceError: Property 'PanResponder' doesn't exist` render error any time the Feed tab was mounted.

**File changed:** `apps/mobile/app/(tabs)/votd.tsx`

### QA checklist

- [ ] Tap Feed tab — screen renders without crash or red error overlay
- [ ] Swipe down on the share panel (after tapping Share on any feed card) — panel dismisses smoothly
- [ ] Fling the share panel downward fast — dismisses without freezing
- [ ] Slow-drag share panel partway down, release — springs back up
- [ ] Navigate Index → Feed → Index → Feed — no crash on repeated tab switches
- [ ] Tap X on a vote item opened from Feed — returns to Feed (not VOTD overlay)
- [ ] Confirm VOTD overlay still appears correctly on cold launch

---

## Build 91 (2026-04-01)

### VOTD overlay re-surfacing fix + comp library User Accounts restore

#### Changes

**VOTD overlay re-surfaces after vote-item X**
- Root cause: `useEffect` in `_layout.tsx` called `resetOverlay()` every time `currentRoute` became `'(tabs)'`, including on return from `/vote-item`. This reset `overlayDismissed` to `false` and re-showed the card.
- Fix: added `prevRouteRef` — `resetOverlay()` now only fires when arriving at `(tabs)` from the initial render (`prev === ''`) or from a signup/hidden flow (`OVERLAY_HIDDEN_ROUTES.has(prev)`). Returning from `vote-item` no longer triggers it.

**Comp library — User Accounts section (`docs/all-comps.html`)**
- Root cause of missing designs: all phone UI CSS classes (`.signup-screen`, `.btn-primary`, `.so`, `.tab-bar`, `.vc`, etc.) were scoped to `#design-comps` and `#insights` only. `#comp-4` had no matching rules so all phone interiors rendered invisible.
- Fix: added complete `#comp-4`-scoped CSS block covering frames, phone chrome, vote card, skip overlay, signup screens, OTP, USPS suggestion, avatar, profile card, and tables.
- Tab bars updated: all 10 phone mockups in the section replaced old 4-tab structure (🗳 VOTD / 📋 Feed / ⭐ My Votes / 👤 Profile) with current 3-tab structure (🗳 Index / 📋 Feed / 👤 Profile).
- QA Flow Map table added at bottom of User Accounts section: 12 rows covering every testable account flow (guest prompts, full sign-up, phone-verified vote nudge, all four Profile states, About tab reset, Follows starring).

#### QA Checklist

- [ ] Index → Open Votes → open a vote item → X → lands on Index, VOTD overlay does NOT appear
- [ ] Index → dismiss VOTD overlay → open a vote item → X → lands on Index, VOTD overlay does NOT re-surface
- [ ] Index → open vote item → complete a vote → X → lands on Index, VOTD overlay does NOT appear
- [ ] Completing signup flow (phone → name → address) → lands in app → VOTD overlay DOES appear (first-time load path still works)
- [ ] Comp library User Accounts section: all phone mockups render with visible designs (no blank white boxes)
- [ ] Comp library User Accounts section: tab bars show 3 tabs (Index, Feed, Profile) — no "My Votes" tab
- [ ] Comp library User Accounts section: QA Flow Map table visible at bottom of section

---

## Build 90 (2026-04-01)

### Navigation hardening, share panel polish, feedback screen labels, terminology doc

#### Changes

**Feedback screen labels**
- `useSegments()` replaced with `usePathname()` — was logging `"(tabs)"` for all tab screens
- Full lookup map added: `/` → `Vote Index`, `/votd` → `Feed`, `/vote-item` → `Vote Item`, `/onboarding` → `Onboarding`, `/signup` + all sub-screens → `Account`, `/propose` → `Propose` etc.
- `FeedScreen` function in `votd.tsx` renamed `VoteOfTheDayScreen` then corrected to `FeedScreen` (file is the Feed tab, not VOTD)
- `IndexScreen` in `index.tsx` renamed `VoteIndexScreen`

**Terminology doc (`docs/terminology.md`)**
- New section: Screen Names — canonical labels for all routes matching the feedback lookup table
- New section: Nav Tabs — three tabs documented with icon, screen name, code name, and description
- New section: Component & Panel Names — canonical names for VOTDOverlayCard, VoteCard, SharePanel, SharePosterPreview, GlobalFeedbackFlag, SkipOverlay, ProposeVoteModal, VoteTally, StickyVoteBar
- Feed tab description added: "App activity updates relevant to the user"
- VOTDOverlayCard relationship to Index tab documented

**Dismiss pill — VOTDOverlayCard**
- Reverted to pre-Build-89 notch bar + swipe gesture for reading and choosing states
- "Tap to dismiss" pill added back but gated to `voted` state only
- `tallyRollUp` and `shareRollUp` now initialise at 1 when remounting in `voted` state — previously tally/share layers were invisible on return from signup flow

**Navigation routing**
- "Finish Sign Up" in VOTDOverlayCard and vote-item now routes to `/profile-setup` not `/signup` (phone step already done for `phone_verified` users)
- `_pendingCardState` correctly set before navigating to `/profile-setup` from propose gate
- X button in vote-item always uses `router.replace` — `router.back()` was surfacing the VOTD overlay unexpectedly. Routes: `from=feed` → Feed tab, all others → Index tab
- `/(tabs)/index` corrected to `/(tabs)` throughout — the former was resolving as "page not found"

**Share panel**
- Platform icons enlarged: wrap `r(44)→r(54)`, icon size `r(22)→r(26)`, btn width `r(52)→r(64)`
- Truth Social "T" centering fixed: `lineHeight`, `includeFontPadding: false`, `textAlignVertical: center` added
- iMessage crash fixed: replaced `shareSingle({ social: 'sms' })` with `Linking.openURL('sms:&body=...')` — the RNShare call was throwing a native ObjC exception causing SIGABRT on `turbomodulemanager.queue`
- Platform carousel constrained to `r(324)` (4.5 item widths) — ensures last visible item is always clipped for scroll affordance
- `snapToInterval` corrected to `r(72)` (actual item width) with `snapToAlignment: 'start'`
- Share panel top position adjusted: `0.50 → 0.56` across all three locations (VOTDOverlayCard, vote-item, feed)

**Profile screen**
- `useFocusEffect` added — profile tab resets to About on every focus, not where user left off
- Follows tab filter: removed `!votedIds.has(i.id)` exclusion — starred items now appear in Follows regardless of voted status

**CLAUDE.md**
- Rule #4 updated: sandbox must never run `git commit` or `git push` — always hand off to user terminal with explicit command block

#### QA Checklist

- [ ] Feedback submissions from each screen log correct label (Vote Index, Feed, Vote Item, Onboarding, Account, Profile)
- [ ] Vote of the Day — reading state shows notch bar, no "Tap to dismiss"
- [ ] Vote of the Day — choosing state (Yes/No) shows notch bar, no "Tap to dismiss"
- [ ] Vote of the Day — voted state shows "Tap to dismiss", no notch bar; tally and share panel visible immediately
- [ ] "Finish Sign Up" from VOTD voted state goes to profile setup screen (name/address), not phone screen
- [ ] Returning from profile-setup after "Finish Sign Up" restores voted confirmation with tally and share panel visible
- [ ] X on vote-item opened from Index → lands on Index, no VOTD overlay
- [ ] X on vote-item opened from Feed → lands on Feed tab
- [ ] No "page not found" on any X / exit action
- [ ] Platform icons visibly larger in share panel
- [ ] Truth Social "T" visually centered in its bubble
- [ ] iMessage tap opens native Messages compose sheet with pre-filled text — no crash
- [ ] Last platform icon in carousel is visibly clipped (scroll affordance)
- [ ] Snapping in platform carousel aligns cleanly to item boundaries
- [ ] Share panel height feels right at 0.56 across VOTD, vote-item, and feed
- [ ] Profile — navigating away and back always opens on About tab
- [ ] Starring a vote from index dot-stack menu shows it in Profile → Follows tab, including items already voted on
- [ ] No crash when idle on Index

---

## Build 89 (2026-04-01)

### Share panel overhaul, navigation hardening, and poster asset wiring

#### Changes

**Navigation**
- VOTD card body now always scrollable — was locked behind "Read more" tap (`scrollEnabled={expanded}` → `scrollEnabled`)
- Vote confirmation X button exits to origin (index / feed / profile) — old back chevron reset to idle state allowing re-vote, which is now only possible via "Change my vote" link
- "Change my vote" is the only path back to choosing state after a vote is cast — signup flows preserve actual card state, not always 'choosing'
- After phone confirmation from VOTD guest gate, card returns to 'choosing' (Yes/No visible) not 'reading' (Vote Now)
- "Finish Sign Up" from locked tally preserves 'voted' state on return

**Vote confirmation screen**
- "+ Propose a Vote" button added to confirmation header (right side), matching main vote-item header
- `rewriteAsStance` regex fixed — captures full proper noun sequence as subject (e.g. "Sacramento County should not require…" not "Sacramento should not County…")

**VOTD mock data**
- Rooftop solar and surrounding VOTD items re-dated so active VOTD shows 29–30 days remaining (was 23)

**Share panel — dismiss UX**
- VOTD card + vote-item confirmation: notch/swipe replaced with outlined "Tap to dismiss" pill — exits to origin, no swipe gesture
- Feed share panel: notch moved to top, labeled "Swipe down to close", pan responder fires `dismissShare` on downward fling or 60pt drag

**Share panel — platform row**
- Switched from multi-select + "Share Now" queue to single-tap model — each platform fires immediately on tap
- "Pick your platforms" label updated to "Tap to share"
- "Share Now" button and all selection state (checkmarks, selectedPlatforms, togglePlatform) removed across all three locations
- "More" button fires native iOS share sheet immediately — never showed a checkmark
- Truth Social "T" mark centered (`textAlign: 'center'`)
- iMessage added to platform list (com.apple.MobileSMS, FontAwesome6 `message` icon)

**Share panel — poster assets**
- Real PNG poster assets now used in preview and sharing (replacing programmatically rendered SharePoster component)
- Toggle "Share the vote" → `VOTD_Vote.png`; "Share how I voted" + YES → `VOTD_Share_Vote_Yes.png`; + NO → `VOTD_Share_Vote_NO.png`
- Preview updates live as toggle changes
- `shareToApp` now accepts `imageUri` and passes it to RNShare.shareSingle as `imageUrl`
- `VOTD_Brand.png` available via `POSTER_BRAND` export for generic sharing (not yet wired to a surface)
- `posterAssets.ts` created as single source of truth for asset resolution

**Share panel — uniformity**
- `shareLayer.top`, `shareScrollContent` padding, and `notchBar` spacing synced across all three locations (VOTDOverlayCard canonical values)

#### QA checklist
- [ ] VOTD card: can scroll down without tapping "Read more" first
- [ ] VOTD card: rooftop solar (or current VOTD) shows 29–30 days remaining
- [ ] VOTD card: guest taps Yes/No → phone gate → completes signup → returns to Yes/No buttons, not Vote Now
- [ ] VOTD card: guest taps Yes/No → phone gate → skips → still on Yes/No, can tap again
- [ ] VOTD card: after voting, "Finish Sign Up" → completes signup → returns to voted/tally state, not Vote Now
- [ ] Vote confirmation: X button exits to correct origin (index from VOTD, back from feed/profile)
- [ ] Vote confirmation: "Change my vote" is only path back to Yes/No after voting
- [ ] Vote confirmation: "+ Propose a Vote" button present in header, fires correct gate/modal
- [ ] Vote confirmation: "Sacramento County should not require…" reads correctly (full proper noun)
- [ ] Share panel: tapping any platform fires immediately — no multi-select, no Share Now button
- [ ] Share panel: "More" opens native iOS share sheet, no checkmark
- [ ] Share panel: iMessage present in carousel, fires Messages app
- [ ] Share panel: Truth Social "T" is centered in its icon box
- [ ] Share panel: "Tap to dismiss" pill visible on VOTD card and vote-item confirmation, exits correctly
- [ ] Feed share panel: notch at top reads "Swipe down to close", swipe down closes panel
- [ ] Feed share panel: tapping backdrop still closes panel
- [ ] Preview Poster: "Share the vote" toggle shows VOTD_Vote.png
- [ ] Preview Poster: "Share how I voted" + YES vote shows VOTD_Share_Vote_Yes.png
- [ ] Preview Poster: "Share how I voted" + NO vote shows VOTD_Share_Vote_NO.png
- [ ] Preview Poster: image updates live when toggle flips
- [ ] Share panel height, notch spacing visually consistent across VOTD card, vote-item, and feed

---

## Build 88 (2026-04-01)

### Share panel, navigation, QA fixes, and consistency pass

#### Changes

**SharePanel — single source of truth**
- Extracted `SharePanel.tsx` component — heading, toggle, preview link, platform carousel, Share Now button all live in one file; used by VOTDOverlayCard, vote-item, and votd feed modal
- "Share This Vote" heading now centered everywhere with increased space below (`marginBottom: r(18)`)
- Poll question shown only in feed modal (`showQuestion` prop, default false) — centered with extra space below when shown
- Toggle label corrected: "Share this vote" → "Share the vote" across all destinations

**Navigation fixes**
- Closing a vote item opened from Vote of the Day now lands on vote index (`/(tabs)/index`) instead of returning to votd
- Back arrow on votd is blocked — `from: 'votd'` param passed via `router.replace` so history entry is replaced not pushed
- `handleBack` in vote-item reads `from` param and routes to `/(tabs)/index` when `from === 'votd'`

**Vote of the Day share panel**
- Share layer top raised from `height * 0.54` → `height * 0.48` — panel taller to fit all content, shorter than previous session fix
- Scroll `paddingBottom` tightened to `r(48)`, notch bar `paddingTop` reduced to 4, Share Now `marginTop` reduced to `r(6)`
- Share layer synced to canonical design: "Share This Vote", dark-track toggle, "Preview Poster" link, "Pick your platforms" label

**X close button standardization**
- All X buttons now use `FontAwesome6 name="xmark" size={r(22)}` — replaced text `✕` character in VOTDOverlayCard and both ProposeVoteModal screens (intro + form steps)
- All X button containers standardized to `width: r(44), height: r(44), alignItems: 'center', justifyContent: 'center'`

**Locked tally (phone_verified)**
- VOTDOverlayCard now gates live tally behind `needsRegistration` check — phone_verified users see locked state matching vote-item
- Ghost bar removed from locked tally in both VOTDOverlayCard and vote-item — just message + "Finish Sign Up" CTA
- Locked card nudge pushed down with `marginTop: r(24)`

**Bug fixes**
- Pre-seeded follows removed — saved votes now start empty (was pre-following first 3 mock items)
- Double-vote after skipping guest gate fixed — `voted` reset to `null` on SkipOverlay dismiss
- Vote index area icons size reduced to 24 (was 32)
- ProposeVoteModal submitted state gets "Done" button

#### QA checklist
- [ ] Vote of the Day: vote YES/NO → share panel rolls up, fits without clipping, Share Now not obscured by notch
- [ ] Vote of the Day: phone_verified user sees locked card (no bar), "Finish Sign Up" CTA, nudge pushed down
- [ ] Vote of the Day: verified user sees live animated tally
- [ ] Vote of the Day: X button matches weight of vote-item X button
- [ ] Vote item: close (X) when opened from votd → lands on vote index, not votd
- [ ] Vote item: back arrow from another vote item cannot return to votd
- [ ] Vote item: phone_verified locked card shows no ghost bar
- [ ] Share panel: "Share This Vote" centered with space below in all three destinations
- [ ] Share panel: question text shown and centered only in feed modal
- [ ] Share panel: "Share the vote" label (not "Share this vote") in all destinations
- [ ] Feed modal: "Preview Poster" link present and centered
- [ ] ProposeVoteModal: X button same weight/position on intro and form steps
- [ ] ProposeVoteModal: submitted state shows "Done" button
- [ ] My Profile: saved votes section empty on fresh session (no pre-seeded items)
- [ ] Guest: vote YES → phone gate appears → skip → vote YES again → gate reappears (no double-vote block)
- [ ] Vote index closed view: area icons visibly smaller than before

---

## Session — 2026-03-31

### docs/all-comps.html — multi-session restructure

#### Changes
- Replaced static screenshot `feed-screen.html` with fully live-coded HTML version inside phone frame (scrollable, live countdown timer, live vote trickle)
- Feed screen cards implemented: ENDING SOON countdown (JS live clock + urgency coloring), Top Votes pair (USA Final with tally bars + CA Open with Vote Now), urgency/share nudge, Neighbor Proposal, VOTD Insights breaker (purple, sparkline), feature card with topic ghost image, Just Closed (3-row YES/NO verdict list), Your Backlog (horizontal scroll with topic poster images), Top Issues by Topic list, Milestones card, Stand and Be Counted (3-column stat), Propose a Vote (dashed border), end state (🎉 You're up to date)
- Color token pass applied: all colors pulled from official theme (ORANGE #C85014, NEAR_BLACK #231D1A, GRAY #6A5B53, WARM_MID_GREY #9F8475, TALLY_NO #D3C4BB, PURPLE_DARK #5C415D, etc.)
- `docs/skill-embed-existing.md` created — project rule enforcing use-existing-content-first discipline
- `docs/color-style-guide.html` — Topic Category Colors fixed from single column to flex-wrap rows (class swap swatch-row → swatches)
- `docs/all-comps.html` — nav order: Color Guide → Insights → Feed Cards → Feed Screen → Guest Prompt & Verify → Vote Card → Splash → Share; CSS scoping fixes for comp-2 aside/main layout; sections anchored inside `<main class="main">` to prevent drift

#### QA checklist
- [ ] feed-screen.html: opens in browser, phone frame visible on dark background
- [ ] Countdown timer ticks down correctly (seconds decrement, urgency orange fires at <48h)
- [ ] Live vote count increments every 4–8s
- [ ] Topic poster images load (housing, environment, education, public health, infrastructure)
- [ ] Backlog horizontal scroll works
- [ ] Tab bar shows Feed tab active (orange), other tabs muted
- [ ] all-comps.html: all 8 nav items click to correct sections
- [ ] Feed Screen section shows iframe with scrollable phone frame (no blank space above)
- [ ] Color guide topic category colors display in rows (not single column)
- [ ] comp-2 (Feed Cards) layout renders with left sidebar + main content correctly

---

## Build 84 (2026-03-30)

### Color token pass — error reds + rogue neutral cleanup

#### Changes
- Added 5 new error tokens to theme.ts: `ERROR_RED`, `ERROR_RED_DARK`, `ERROR_RED_TINT`, `ERROR_RED_MID`, `ERROR_RED_STRONG`
- Replaced all hardcoded error reds (`#C0392B`, `#D93B3B`, `rgba(200,30,30,…)`) across 8 files: ProposeVoteModal, VoteCard, VOTDOverlayCard, vote-item, profile, verify-otp, address-setup, my-votes
- Rogue neutral sweep: `#9A908A` → `WARM_MID_GREY` (profile, votd, index), `#7A7370` → `WARM_MID_GREY` (votd), `#F7D0B4` → `PEACH_LIGHT` (votd), `#888` → `GRAY`/`WARM_MID_GREY` (vote-item, FeedbackWidget)
- Color style guide updated: error token family documented, audit row marked done
- Commit: `63d18f4`

#### QA checklist
- [ ] App launches cleanly — no crash, no token import error
- [ ] VoteCard urgent countdown: red tint background + red countdown text
- [ ] VOTD overlay urgent badge: semi-transparent red background
- [ ] vote-item sticky bar urgent state: ERROR_RED_STRONG applied correctly
- [ ] Profile nav flyout: disabled items render in muted warm grey (not missing/white)
- [ ] verify-otp: error text renders in red on bad code entry
- [ ] address-setup: error underline + text renders red on invalid address
- [ ] ProposeVoteModal: "required field" label renders red
- [ ] FeedbackWidget: X close button visible (warm grey icon)
- [ ] No visual regressions on non-error UI (tally bars, topic badges, feed)

---

## Branch merge: ios-debug-isolation → ios-debug (2026-03-30)

### Full sync — isolation branch (builds 65–81) merged into ios-debug

- [x] **Merge commit** — `de499c1` on `ios-debug`; all 15 conflicts resolved by taking isolation version
- [x] **RGB app icon** — App-Icon-1024x1024@1x.png confirmed color type 2 (RGB, no alpha) in merged ios-debug
- [ ] **ios-debug push** — run `git push origin ios-debug` from terminal to publish merge
- [ ] **Smoke test ios-debug** — confirm build 81 artifact matches ios-debug-isolation tip after push
- [ ] **Retire ios-debug-isolation** — once ios-debug confirmed stable, isolation branch can be archived

---

## Build 78 (2026-03-30)

### Branch sync complete — isolation branch now current

#### Changes
- No new features — this build confirms isolation branch is fully caught up with ios-debug
- All token imports verified clean across all files
- ios-debug bugs caught and kept out: `color="MID_GREY"` string literals in profile.tsx (would render as literal string, not color value)
- Overlay flash fix and `overlayDismissed` init confirmed present (ios-debug does not have these)

#### QA checklist
- [ ] Clean launch — no crash, no vote card flash before splash
- [ ] Feed renders — topic badge colors, tally bars, breaker cards all correct
- [ ] Share layer opens from feed and vote-item
- [ ] Profile — nav flyout menu items render with correct icon colors (not literal "MID_GREY" string)
- [ ] Feedback panel — fixed height, blue sky option blue
- [ ] Full vote flow works for guest, phone_verified, verified

---

## Build 76 (2026-03-30)

### Color system + feedback fixes (cherry-picked from ios-debug)

#### Changes
- Complete color token consolidation — rogue sweep, hue realignment, breaker palette
- MID_GREY token added (#BEACA2 — fills gap between WARM_MID_GREY and TALLY_NO)
- 16 TOPIC_ tokens replacing hardcoded topic badge colors
- ORANGE_LIGHT correction, orange spectrum style guide
- Feedback panel: fixed height — no more resize between intro and comment steps
- Feedback: blue sky urgency option corrected from green to blue

#### QA checklist
- [ ] App launches cleanly — no crash
- [ ] Splash fix still present — no vote card flash before splash animation
- [ ] Feed topic badge colors render correctly (housing, environment, education etc. each have distinct color)
- [ ] Breaker cards (Insights) render correctly — purple tints, no color regression
- [ ] Tally bars: correct warm colors, MID_GREY visible where used
- [ ] Feedback panel: open sheet — height stays fixed when switching from intro to comment step
- [ ] Feedback: blue sky option shows blue pill, not green

---

## Build 74 (2026-03-30)

### Theme token import sweep — aliased-import crash fix (Bug #4)

#### Root cause
The color token sweep (build 71) replaced inline hex strings with named theme tokens. In several files the auto-fix script introduced aliased imports (`BEIGE as BORDER`, `DARK_GREY as LIGHT`, etc.) while the file body continued to reference the raw token name. On New Architecture, passing `undefined` to a native color prop throws an Objective-C exception in `ObjCTurboModule::performVoidMethodInvocation` → SIGABRT. Confirmed via Xcode exception breakpoint + Metro/LogBox showing exact file:line references.

#### Files fixed this build
- `components/ProposeVoteModal.tsx` — `BEIGE` used at lines 278/331 but only `BEIGE as BORDER` imported
- `app/(tabs)/votd.legacy.tsx` — `DARK_GREY` used at lines 2956/3019/3438 but only `DARK_GREY as LIGHT` imported
- `app/(tabs)/profile.tsx` — `WARM_MID_GREY` used at line 851 but only `WARM_MID_GREY as GRAY` imported
- `app/(tabs)/votd.tsx` — `BEIGE` used raw but only `BEIGE as BORDER` imported
- `app/vote-item.tsx` — `STONE` used raw but only `STONE as DIVIDER` imported

Fix: add the raw token name alongside each alias so both identifiers resolve correctly.

#### QA checklist
- [ ] App launches on simulator without any LogBox "Property '...' doesn't exist" errors
- [ ] App launches on device (TestFlight build 74) without SIGABRT crash
- [ ] Feed tab renders correctly — BEIGE dividers, DARK_GREY muted text visible
- [ ] Vote-item detail page renders correctly — step indicator BEIGE bubbles, STONE dividers
- [ ] Profile tab renders correctly — WARM_MID_GREY labels visible
- [ ] ProposeVoteModal opens without crash — step indicator renders with correct BEIGE/orange colors
- [ ] Propose Vote flow completes end-to-end without crash

---

## Build 51 (2026-03-27)

### Feed share modal; profile follows logic; locked tally CTA; source card cleanup

#### Changes
- **Feed: Share This Vote inline modal** — tapping Share on any feed card (Your Side Is Losing / Winning) rolls the orange gradient share sheet up over the feed as a transparent Modal; user stays on feed. Card knows which vote it is sharing via `shareSheetItem`.
- **Profile Follows: remove phantom saves** — removed `previewFollowedItems` baked slice that was injecting 4 hardcoded items when `previewVerified` was true.
- **Profile Follows: voted items graduate to Votes** — Follows tab now filters out any item the user has voted on (`votedIds` set). Once you vote, the card moves to the Votes tab automatically.
- **Vote-item locked tally CTA** — replaced semi-transparent absolute overlay with a solid warm-grey card (`#F0EDEA`), rounded corners, subtle shadow. Updated copy: "Want your votes to help make a difference?" / "Finish Sign Up".
- **Source cards: no generated artwork** — removed placeholder illustration (government building icon etc.) from source cards with no OG image. No-image cards now render as a clean text row: domain · title · description · external link arrow · optional type tag (Gov / PDF).

#### QA checklist
- [ ] Feed — tap "Share This Vote" on Your Side Is Losing card: orange sheet rolls up, feed visible behind, backdrop tap dismisses
- [ ] Feed — share sheet shows correct vote question in share message
- [ ] Feed — "Share how I voted" pill is dimmed for phone_verified user; "Share this vote" is always active
- [ ] Profile Follows tab — no phantom saves appear without user having starred anything
- [ ] Profile Follows — after voting on a followed item, it disappears from Follows and appears in Votes
- [ ] Vote-item — phone_verified user on open voted item: grey card shows "Want your votes to help make a difference?" with orange "Finish Sign Up" button
- [ ] Vote-item — "Finish Sign Up" routes to profile-setup with `showSkipOnEntry: 'true'`
- [ ] Source card with no OG image: no icon illustration, clean text layout with arrow
- [ ] Source card with real OG image: image renders above text as before

---

## Build 50 (2026-03-27)

### VP preview; phone_verified vote flow; splash star animation; Feed share fix

- [ ] **Splash star — drop animation** — star shrinks from ~5x into place with fade, quick elastic bounce on landing
- [ ] **Splash star — size and position** — star is 24px, centered above the V glyph
- [ ] **Verified Profile (VP) — header title** — header reads "Verified Profile" when previewing, "My Profile" otherwise
- [ ] **VP — back link in name row** — "← back" link appears inline to the right of the name; tapping exits preview
- [ ] **VP — edit pen hidden** — no edit button visible while in VP preview mode
- [ ] **VP — badge shows Voter Verified** — orange badge in VP mode, not Phone Confirmed
- [ ] **VP — Votes tab static** — vote cards non-interactive in preview
- [ ] **VP — Follows tab static** — follow cards non-interactive, no star/tap handlers in preview
- [ ] **phone_verified vote flow — no tally** — after voting, phone_verified users see locked ghost bar (greyed 50/50) not live results
- [ ] **phone_verified vote flow — locked tally CTA** — "Finish Signing Up" button overlaid on ghost bar
- [ ] **phone_verified vote flow — share enabled** — "Share how I voted" pill is active (not greyed out) for phone_verified
- [ ] **phone_verified — Votes tab humble** — only 3 voted items shown (not full mock slate)
- [ ] **phone_verified — Follows tab empty** — empty state shown, no mock follows
- [ ] **Feed Share This — opens share sheet** — tapping Share This on urgency cards opens share sheet directly, no blank screen
- [ ] **US flag and silhouette PNGs** — pending replacement of broken 1-bit white PNGs with proper color emoji files

---

## Build 49 (2026-03-27)

### Feedback sheet; new app icon; splash star position; emoji PNGs; closed vote cards

- [ ] **Feedback sheet extends to bottom** — sheet fills down to the true bottom edge, no gap below the submit button
- [ ] **Feedback keyboard — Done key dismisses** — tapping Done on the keyboard while typing in the comment field dismisses the keyboard and reveals the Submit button
- [ ] **Feedback keyboard — sheet stays visible** — when keyboard is open the sheet remains visible above it; not pushed off screen
- [ ] **Feedback — no stuck Sending…** — opening feedback a second time shows a fresh empty form, not the Sending… state
- [ ] **New app icon appears on home screen** — diagonal brighterplus sat plus plate icon showing (not the previous border variant)
- [ ] **Splash star — centered above V** — star appears centered above the V, matches icon layout (device only — not testable in simulator)
- [ ] **Signup — US flag shows in country code field** — flag PNG renders next to +1 (no ? box)
- [ ] **Profile setup — silhouette shows in heading** — person silhouette PNG renders next to "Set up your profile" (no ? box)
- [ ] **Closed vote cards show tally** — closed votes in any list show the final Yes/No tally bar, not a Vote Now button

---

## Build 48 (2026-03-27)

### phone_verified profile card; vote gate; tiered mock stats; splash star fix

- [ ] **Splash star is orange** — star that pops in after VOTD types out is orange (#C85014), not white/invisible
- [ ] **Splash star position — left of V at mid-height** — star sits to the left of the V letterform at roughly mid-height, mirroring the app icon layout (not floating above)
- [ ] **Profile — phone_verified badge reads "Phone Confirmed"** — badge label is "Phone Confirmed" (not "Phone Verified")
- [ ] **Profile — phone_verified hides address** — no address line shown when user is phone_verified
- [ ] **Profile — phone_verified button reads "Finish Signing Up"** — CTA button on card is "Finish Signing Up"
- [ ] **Profile — "Remind me later" is gone** — no secondary link below the CTA button for phone_verified state
- [ ] **Profile — tester shortcut "Preview verified profile →"** — small link below "Finish Signing Up" button that flips to verified mock profile when tapped
- [ ] **Profile — phone_verified shows humble stats** — votesCast: 3, streak: 1, no alignment section, no topics drawn to, no civic rank
- [ ] **Profile — verified shows rich stats** — after tapping preview shortcut, votesCast: 184, streak: 47, How You Align section shows, Drawn To section shows with topic badges
- [ ] **Vote — phone_verified can vote and see results** — tapping Yes/No as phone_verified records vote and tally animates in; no hard block
- [ ] **Vote — phone_verified soft nudge after tally** — ~2200ms after tally animates in, "Your vote is recorded. Finish signing up for it to count toward the results." nudge appears
- [ ] **Vote — phone_verified nudge button reads "Finish Signing Up"** — primary CTA in post-vote nudge is "Finish Signing Up"
- [ ] **Vote — guest still gets hard block** — tapping Yes/No as guest still shows "Verify your number" gate immediately (no vote recorded)

---

## Build 47 (2026-03-27)

### Emoji PNGs, OTP gate, share flow, C3B overlay, crash fixes

- [ ] **Signup — US flag shows in country code** — flag PNG renders next to +1 in phone entry field (no ? box)
- [ ] **Profile-setup — silhouette shows in heading** — person silhouette PNG renders next to "Set up your profile" heading
- [ ] **Profile-setup — C3B overlay copy** — overlay after OTP shows "Make your vote count. See live results. Propose your own votes." with "Complete Sign Up" primary button
- [ ] **C3B overlay shows immediately after OTP** — completing OTP verification navigates to profile-setup and the skip overlay appears on entry (showSkipOnEntry param wired correctly)
- [ ] **Vote card press in vote index no longer crashes** — tapping any vote card in the vote index opens vote-item screen without JS error
- [ ] **Second-tap red message on vote gate** — as guest: tap Yes/No → Skip for now → tap again → overlay message turns red (#C85014)
- [ ] **Second-tap red message on save gate** — same behavior for star/save gate
- [ ] **Feed "Share This Vote" opens share layer** — tapping share icon on a feed vote card navigates to vote-item and immediately opens share layer
- [ ] **Share position variant locked to verified users** — phone_verified and guest users cannot select "Share with name/position" variant; toggle is hidden/disabled
- [ ] **OTP accepts any 6-digit code** — entering any 6 digits (e.g. 123456) in verify-otp passes validation for tester builds
- [ ] **Splash star animation** — after VOTD text types out, a star pops in above the V with a pulse bounce, then Sacramento subtitle fades in 300ms later
- [ ] **Guest profile — ballot box image shows** — ballot box PNG renders at full size on the guest profile screen (no ? box)

---

## Build 45 (2026-03-27)

### Guest/save gate second-tap red message; days countdown fix; Yes/No button alignment

- [ ] **Vote gate turns red on second tap** — as guest, tap Vote Yes/No → Skip for now → tap again → message appears in orange-red (#C85014)
- [ ] **Save gate turns red on second tap** — same behavior on the Save (star) gate
- [ ] **VOTD days remaining shows ~29** — Vote of the Day shows ~29 days left (not 12–18); based on daysAgo(1) release date
- [ ] **Feed countdown spread looks natural** — other open items show 27, 23, 20, 16 days remaining in plausible spread
- [ ] **Yes/No buttons align with Vote Now** — after tapping Vote Now, Yes and No pills appear at same vertical position; no jump
- [ ] **Yes/No buttons not too wide** — pills are capped at 160pt wide, centered, with gap between them
- [ ] **Vote Now position unchanged** — Vote Now button sits in same position as before this session

---

## Build 44 (2026-03-26)

### VOTDContext refactor — root-level overlay, guest gate navigation

- [ ] **VOTDOverlayCard displays on app launch** — orange VOTD card appears above tabs on first launch; swipe left reveals vote index behind it
- [ ] **Swipe gesture still works** — card can be swiped horizontally to dismiss / reveal index
- [ ] **Vote (Yes/No) as guest shows gate** — tapping Yes or No shows "Verify your number to continue" overlay with Verify / Skip for now buttons
- [ ] **Verify button opens phone auth** — tapping Verify navigates to /signup screen above the card (no longer renders behind it)
- [ ] **Full registration flow completes** — after phone auth, user proceeds through name → address → photo; not dropped back early
- [ ] **Save (star) as guest shows gate** — tapping the star shows the verify nudge overlay
- [ ] **Propose (+) as guest shows gate** — tapping + shows the verification gate; verified users see ProposeVoteModal
- [ ] **After vote, card advances to next item** — voting Yes or No dismisses the current item and surfaces the next unvoted open item
- [ ] **Card hidden on signup/onboarding routes** — VOTD card does not appear on signup, verify-otp, profile-setup, address-setup, photo-setup screens
- [ ] **ProposeVoteModal opens from card** — verified users tapping + see the propose modal rendered above the card

### Vote index — all users can navigate to vote-item

- [ ] **Vote Now button works for guests** — tapping Vote Now on any open vote card navigates to vote-item screen (not blocked at index)
- [ ] **Vote title tap works for guests** — tapping the vote title on a card navigates to vote-item
- [ ] **Gate lives inside vote-item** — on vote-item screen, guests attempting to vote see "Verify your number to continue" overlay; save and propose gates also present

### App icon

- [ ] **New icon displays correctly** — diagonal brighter/saturated icon with border appears on home screen and in Settings

#### Session notes

- `lib/VOTDContext.tsx` (new): lifts VOTD overlay state (votdItem, votdRank, overlayDismissed, voted, proposeVisible) to root level; `recordVote()` advances to next unvoted item
- `app/_layout.tsx`: `VOTDProvider` wraps full app; `VOTDRootOverlay` renders card as absolute View with `zIndex: 100` above entire navigation stack; hidden on signup flow routes
- `app/(tabs)/index.tsx`: `VOTDOverlayCard` and its Modal wrapper removed; `goToVoteItem()` guest check removed — all users navigate to vote-item; save gate still present for save/bookmark action
- `components/VOTDOverlayCard.tsx`: `onNavigate` prop removed; `onVoted` prop added — calls `recordVote` in context; guest gate `router.push` now fires reliably since card is no longer inside a parent Modal
- `app.json`: icon updated to `2603261533_diagonal_brighter_sat_plus_border_180px.png`

---

## Build 43 (2026-03-26)

### Guest gating — VOTD orange overlay (SkipOverlay Modal fix)

- [ ] **Vote (Yes/No) shows nudge** — tapping Yes or No as a guest shows the "Sign up for your vote to count" overlay; iOS Modal stacking issue resolved by `useModal` prop
- [ ] **Star (save) shows nudge** — tapping the star as a guest shows the same sign-up overlay
- [ ] **+ (Propose) button shows gate** — tapping + as a guest shows the "Proposing a vote requires full voter verification" overlay; no longer unresponsive

### Feedback widget

- [ ] **Feedback flag present on onboarding slides** — the GlobalFeedbackFlag tab is visible while swiping through onboarding slides; it was accidentally hidden in build 42 and is now restored
- [ ] **Feedback panel does not cover full screen** — sheet slides up from bottom with dark backdrop; top portion of the screen behind it remains visible (`maxHeight: 90%`)
- [ ] **Feedback closes immediately on submit** — pressing Submit closes the sheet instantly; submission is fire-and-forget in background

#### Session notes

- `SkipOverlay.tsx`: added `useModal?: boolean` prop — when true, wraps the overlay card in its own transparent `Modal` with a dim backdrop. Required because iOS cannot render `position: absolute` children above a parent `Modal`; both guest-nudge and propose-gate overlays in `VOTDOverlayCard` now use `useModal`.
- `VOTDOverlayCard.tsx`: both `SkipOverlay` instances now pass `useModal` so they render above the card's own Modal layer.
- `_layout.tsx`: `onboarding` removed from `FEEDBACK_HIDDEN_ROUTES` — feedback flag should appear on intro slides.
- `FeedbackWidget.tsx`: `handleSubmit` calls `closeSheet()` immediately before awaiting network; `maxHeight: '90%'` prevents sheet from covering entire screen.

---

## Build 41 (2026-03-26)

### Intro sequence — UIWindow background grey flash

- [ ] **No grey between launch screen and app** — transition from Apple launch screen to VOTD splash is pure white throughout; no grey or off-white flash visible in app switcher or during launch

### Guest gating — VOTD orange overlay

- [ ] **Vote (Yes/No) shows nudge** — tapping Yes or No as a guest shows the "Sign up for your vote to count" overlay; vote is not recorded
- [ ] **+ (Propose) button shows gate** — tapping + as a guest shows the "Proposing a vote requires full voter verification" overlay; not unresponsive

### Guest gating — Votes index

- [ ] **VoteCard tap gates guests** — tapping an open VoteCard as a guest triggers the sign-up overlay rather than navigating to vote-item

#### Session notes

- `AppDelegate.swift`: set `window?.backgroundColor = .white` immediately after `UIWindow` is created — fixes the system default grey/dark background that peeks through during app launch transitions and in the app switcher
- `VOTDOverlayCard.tsx`: `handleVote` now gates guests before recording a vote; `+` button checks `canPropose` internally and shows `SkipOverlay` inside the same Modal layer (fixes unresponsive tap — iOS can't stack Modals so the gate in `index.tsx` was invisible)
- `index.tsx`: VoteCard `onPress`/`onShare` now route through `goToVoteItem()` which blocks guests

---

## Build 40 (2026-03-26)

### Intro sequence — native posterboard color

- [ ] **iOS posterboard is white** — during app-switcher and app launch transitions the background is pure white, not grey or off-white; fixed by setting `UIUserInterfaceStyle = Light` in `Info.plist`

### Intro sequence — first slide entry

- [ ] **No jerk on first slide** — the transition from the VOTD typewriter splash to the first onboarding slide is smooth and seamless; no white flash or mount-jank visible
- [ ] **Slides fully painted before splash clears** — the FlatList and images are already rendered underneath the splash overlay before the splash begins fading; no re-mount on transition
- [ ] **Slide fade completes before splash clears** — slides reach full opacity while splash is still partially visible, so there is no bare white background between them

#### Session notes

- `Info.plist`: `UIUserInterfaceStyle` changed from `Automatic` → `Light` — forces white posterboard/background on all iOS transitions regardless of device dark-mode setting
- `onboarding.tsx`: Refactored from two-tree pattern (early `if (showSplash) return ...`) to single unified tree — slides always mounted underneath an absolute-positioned splash overlay with `pointerEvents="none"`. This prevents FlatList re-mount jank when the splash fades.
- Slide fade-in now starts 1800ms after typewriter completes (400ms before splash begins fading at 2200ms), giving slides a head-start so they are fully visible before the splash overlay clears.
- `slidesReady` state and its associated `useEffect` removed — no longer needed since slides are always mounted.

---

## Build 38 (2026-03-26)

### Intro sequence — Apple launch screen

- [ ] **Plain white launch screen** — Apple's system launch screen is a clean white background with no image; no orange-box-with-logo artifact visible
- [ ] **Seamless handoff to RN splash** — as the launch screen fades, the React Native splash (white bg, VOTD typed in orange) appears without any color flash or jump

### Intro sequence — VOTD wordmark

- [ ] **™ sits snug against D** — the ™ superscript is visually close to the D, not floating far to the right

### Feedback tab — floating, surface level

- [ ] **Visible on every screen** — white pill tab with orange bubble icon drops from the top frame; present on Daily Feed, Votes, My Profile, Vote Item, onboarding slides, and all other screens
- [ ] **Never inline** — tab is not embedded in any header row; does not affect header layout or title centering
- [ ] **Position consistent** — tab appears at the same horizontal and vertical position on every screen
- [ ] **Tap opens feedback sheet** — tapping the tab slides up the feedback bottom sheet
- [ ] **Urgency options** — Urgent (red), Worth a look (amber), Blue sky (green)
- [ ] **Intro and comment panels same height** — sheet does not jump in size when transitioning from name/email step to comment step

### Icons

- [ ] **Phone app icon** — home screen shows `2603261223_diagonal_brighter_sat_plus` variant
- [ ] **Watch app icon** — Apple Watch shows `2603261223_watch_brighter_sat_plus` variant

#### Session notes

- `SplashScreen.storyboard`: `UIImageView` removed, `backgroundColor` set to plain white — eliminates the pinkish logo-box artifact on Apple launch screen
- `onboarding.tsx`: ™ `right` offset tightened from `-28` → `-18`
- `InlineFeedbackButton` added to header row in `votd.tsx`, `index.tsx`, `profile.tsx` (guest + auth); `GlobalFeedbackFlag` removed from `_layout.tsx`
- Phone icon: `2603261223_diagonal_brighter_sat_plus.png` → `App-Icon-1024x1024@1x.png`; `app.json` path updated
- Watch icon: `2603261223_watch_brighter_sat_plus.png` → Watch `AppIcon.png` (1024×1024, single universal slot)

---

## Build 37 (2026-03-26)

### Feed slot sequence

- [ ] **Closing Soon always present** — slot 1 of the Daily Feed always shows a "Closing Soon" card regardless of how many days remain on the soonest-closing vote; no minimum threshold applied
- [ ] **mock-001 countdown reads ~2 days** — the Closing Soon card shows a 2-day countdown badge (e.g. "2d left"); exact value depends on when the daily date-roll script last ran
- [ ] **Urgent styling at ≤ 3 days** — countdown badge turns red when daysLeft ≤ 3; confirm the 2-day mock triggers this

### Feed card — Vote Now button

- [ ] **Vote Now height correct** — Vote Now button in all feed cards is the correct height; not oversized as seen in build 30

### Vote Now navigation behavior

- [ ] **Feed / Votes index / Follows — Vote Now → vote-item** — tapping Vote Now on any standard VoteCard navigates to the vote-item detail screen; card does NOT split inline into Yes / No
- [ ] **VOTD orange overlay — Vote Now → inline split** — tapping Vote Now on the orange Vote of the Day overlay card triggers the animated inline Yes / No split; does NOT navigate away

### Closed tab — tappable vote titles

- [ ] **Closed tab drill-down cards are tappable** — in Votes tab → Closed, tapping a VoteCard title or card body navigates to the vote-item detail screen
- [ ] **No three-dot menu on closed cards** — dots menu is hidden on all closed-tab VoteCards
- [ ] **"Final" pill present** — closed-tab VoteCards show a dark "Final" pill badge

### Add Research — phone verification gate

- [ ] **Guest taps Add Research → gate sheet** — SkipOverlay appears
- [ ] **Phone-verified user can Add Research** — passes through without gate
- [ ] **No false positives for verified users** — verified users pass straight through

### Share how I voted — toggle gating

- [ ] **Guest — "Share how I voted" toggle disabled** — shown in greyed-out / disabled state
- [ ] **Phone-verified — "Share how I voted" toggle disabled**
- [ ] **Verified — "Share how I voted" toggle enabled**
- [ ] **Toggle labels correct everywhere** — first toggle: "Share this vote"; second toggle: "Share how I voted"

### Share This Vote

- [ ] **"Share This Vote" opens share UI** — navigates to / opens the vote-item share layer
- [ ] **Native share sheet available** — share layer includes an option that opens the iOS native share sheet

### Post-vote nudge (vote-item)

- [ ] **Guest post-vote → verification nudge** — SkipOverlay appears after voting
- [ ] **Phone-verified post-vote → nudge** — SkipOverlay appears after voting
- [ ] **Verified post-vote → no nudge**

### Guest profile screen states

- [ ] **Guest — full-screen prompt** — unauthenticated users see a full-screen guest profile state
- [ ] **Phone-verified — card CTAs visible**
- [ ] **"Verifying" state shown** while verification is in progress
- [ ] **Verified — clean profile** — no gate CTAs

### Save and Propose — guest gates

- [ ] **Guest taps Save (VOTD) → gate**
- [ ] **Guest taps Propose (VOTD) → gate**
- [ ] **Guest taps Save (Votes / Daily Feed) → gate**
- [ ] **Authenticated user — Save and Propose work normally**

### Registration return routing

- [ ] **Registration chain returns to origin tab** — after completing registration from a gate on a specific tab, user lands back on that tab

### Breaker chart animations

- [ ] **Charts animate on scroll-into-view** — animation triggers when chart scrolls into viewport; not stuck unanimated on first load
- [ ] **Charts animate on page/tab change** — switching away and back re-triggers animation

### Feedback comment icon — header

- [ ] **Bubble icon visible in header** — speech-bubble icon appears in every screen header (Daily Feed, Votes, My Votes, My Profile, Vote Item, Votes Detail)
- [ ] **Tap opens feedback sheet** — see Build 28 feedback widget checklist for full sheet QA

### Watch icon

- [ ] **Watch app icon updated** — shows 2603262A variant (brighter, higher saturation); no color-cast artifacts
- [ ] **Icon is RGB, no alpha channel**

### Archive (Build 37)

- [ ] **Phone archive succeeds** — Xcode archive for `votd` target completes without errors
- [ ] **Watch archive succeeds** — includes `votd Watch` and `votd Watch Complication` without "multiple commands produce Info.plist", "bundle ID null", or `TARGETED_DEVICE_FAMILY` errors
- [ ] **CocoaPods installs cleanly** — `pod install` runs without "unable to find compatibility version string for object version" errors
- [ ] **TestFlight upload accepted** — build passes App Store validation and appears in TestFlight

#### Session notes

- `inlineSplit` prop added to `VoteCard` (default `false`) — all standard usages navigate to vote-item; only VOTD overlay passes `inlineSplit={true}`
- Closed-tab VoteCards get `hideDots` + `isClosed` props — removes nested `TouchableOpacity` that was swallowing taps on iOS
- Add Research gated behind `verificationLevel === 'phone_verified' || 'verified'`
- "Share how I voted" toggle disabled below verified; post-vote nudge shown for guest + phone_verified
- Closing Soon: engine `ending_soon` slot has no `filterFn` threshold; mock-001 pinned to 28 days before today via daily scheduled task (`votd-reset-mock-dates`, 3am) — task commits locally, push must be done manually from `~/votd`
- Watch icon: 2603262A variant, sRGB stamped, 1024×1024 RGB
- Xcode archive fixes (builds 35–37): Info.plist moved out of synchronized folder; `GENERATE_INFOPLIST_FILE` removed from Complication; `CFBundle*` keys added with `$(VARIABLE)` substitution; `INFOPLIST_PREPROCESS = YES`; `TARGETED_DEVICE_FAMILY` → `"4"` for all watchOS configs; `CURRENT_PROJECT_VERSION` added to Watch app; `objectVersion` restored to 54; Podfile target name corrected to `votd`

---

## Build 28 (2026-03-25)

### Feedback widget — all screens

- [ ] **Icon visible in header** — small speech-bubble icon appears between the dots menu and the screen title on: Daily Feed, Votes, My Votes, My Profile, Vote Item, Votes Detail
- [ ] **Tap opens sheet** — tapping the icon slides up the feedback bottom sheet
- [ ] **Backdrop tap closes sheet** — tapping outside the sheet dismisses it without submitting
- [ ] **X button closes sheet** — tapping the X in the top-right corner closes the sheet
- [ ] **Name field is optional** — sheet submits successfully with name left blank
- [ ] **Comment field required** — Submit button is disabled (greyed out) when comment is empty; enables once text is entered
- [ ] **RAG urgency selector** — three options: Urgent (red dot), Worth a look (amber dot), When you can (green dot); selected option highlights with matching border color
- [ ] **Screen label** — small muted label at the bottom of the form reads the correct screen name for whichever screen you opened it from
- [ ] **Submit → thank you** — tapping Submit shows 🙏 emoji, "Thank you for the note." headline, and the "From your humble friends at VOTD" body copy
- [ ] **Auto-closes after thank you** — sheet automatically closes ~2.4s after thank-you message appears
- [ ] **Submit sends to Supabase** — once env vars are configured, row appears in `feedback` table with: `install_id`, `screen`, `comment`, `urgency`, `build`, `created_at`, and `name` if provided
- [ ] **Stable install ID** — close and reopen the app; the same `install_id` is used on the next submission (persisted via AsyncStorage)
- [ ] **Dev fallback** — without Supabase env vars set, submission logs the payload to the Xcode / Metro console (`[Feedback] { ... }`) and shows the thank-you message normally

#### Supabase setup (one-time, by developer)

```sql
create table feedback (
  id          uuid primary key default gen_random_uuid(),
  install_id  text not null,
  screen      text not null,
  comment     text not null,
  urgency     text not null check (urgency in ('red', 'amber', 'green')),
  build       text not null,
  name        text,
  created_at  timestamptz default now()
);
```

Add to `apps/mobile/.env` (create if absent):

```
EXPO_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
EXPO_PUBLIC_SUPABASE_ANON=your-anon-key
```

Run `expo prebuild` and re-archive before distributing the build that should write to Supabase.

#### Session notes

- New `FeedbackWidget` component; speech-bubble icon (`comment` from FontAwesome6) in every screen header
- `apps/mobile/lib/feedbackService.ts` — pure `fetch` POST to Supabase; degrades to `console.log` when env vars absent
- Stable install ID: UUID persisted in AsyncStorage under `votd_install_id`
- Build number read dynamically from `Constants.expoConfig.ios.buildNumber`

---

## Build 27 (2026-03-25)

### Watch sizing — Series 10 (45mm)

- [ ] **VOTD card** — poll question at 17pt semibold, readable at a glance; eyebrow at 10pt; "VOTE OF THE DAY" label at 11pt; horizontal padding comfortable (8pt each side)
- [ ] **Vote Now button** — 14pt bold, height 32, capsule shape; sits at bottom without overlap
- [ ] **Yes / No buttons** — 14pt bold, height 32, both fit side by side with 8pt horizontal padding
- [ ] **TallyView** — percentages at 16pt, vote counts at 12pt; both rows visible without scrolling
- [ ] **Share / More Votes / Done buttons** — 14pt bold, height 32; Share sits above More Votes/Done with 8pt gap
- [ ] **CatchUp cards** — same sizing as VOTD card; carousel dots visible above button row
- [ ] **FireworksView** — 🎉 emoji large (42pt), "All caught up!" at 17pt, subtext at 13pt
- [ ] **AllCaughtUpView** — 🎉 at 36pt, "All voted up!" at 18pt, subtext at 13pt
- [ ] **LoadingView** — 🗳️ at 40pt, "VOTD" wordmark at 19pt bold

### Watch complication

- [ ] **Complication appears in picker** — long press watch face → Edit → tap slot → VOTD appears in list
- [ ] **Rectangular (large slot)** — orange V badge left, "VOTD" eyebrow orange, "Your voice is needed" white, "N open votes" orange; all text readable
- [ ] **Circular (small/corner slot)** — solid orange circle, white V, vote count below V
- [ ] **Count reflects open votes** — on first launch, count matches actual open vote queue
- [ ] **Count decrements mid-session** — vote one card, navigate away, complication shows N-1
- [ ] **Switches to "All caught up!"** after voting all cards — complication shows "All caught up! / Check back tomorrow"
- [ ] **Cold start resets** — fully close and reopen app; complication reverts to open vote count (not "All caught up!")
- [ ] **Tap complication → opens app** — tapping the complication on the watch face launches VOTD directly

### Watch UX fixes

- [ ] **Swipe right skips** — on CatchUp cards, swiping right (as well as left) dismisses the current card
- [ ] **Skip → EndView (no pill)** — skipping the last card goes straight to EndView; "All caught up!" pill is absent; streak + rank stats and "View Profile on iPhone" button still present
- [ ] **Vote all → Confetti → EndView (with pill)** — voting the last card triggers FireworksView, auto-advances to EndView; "All caught up!" pill present

### Phone ↔ watch bridge

- [ ] **Cold launch — data loads** — open phone app first, then open watch app; watch loads real vote data (not Sacramento County mock); Xcode console shows `[WatchBridge] Replied to todayVote request`
- [ ] **Reachability push** — with watch app already open, foreground the phone app; watch refreshes data
- [ ] **Vote registered on phone** — cast a vote on the watch; phone console shows `[WatchBridge] Vote received: { itemId, choice }`
- [ ] **Long press → open on phone** — long press question on watch → "Open on Phone" → phone navigates to correct vote-item detail screen
- [ ] **Share from watch** — tap Share on TallyView → phone navigates to vote-item and opens post-vote share layer
- [ ] **View Profile on iPhone** — tap "View Profile on iPhone" button on EndView → phone navigates directly to My Profile tab
- [ ] **Cold start clears voted state** — fully close watch app, reopen; app starts at VOTD card regardless of prior session state

### Carried forward from Build 26 — still to confirm

- [ ] **VOTD card** — Vote Now button pinned at bottom; header pinned at top; neither shifts with question length
- [ ] **More Votes / Done** — correct label shown based on backlog state; both route correctly
- [ ] **41mm layout** — all key screens on smaller face; no clipping or overflow
- [ ] **App icon** — home screen shows `diagonal_brighter_sat_plus`; watch shows `watch_brighter_sat_plus`

#### Session notes

- All watch font sizes and button heights bumped for 45mm canvas — see table below
- New `votd Watch Complication` WidgetKit extension added; rectangular + circular families
- `WatchSessionManager.updateComplicationData()` writes to UserDefaults + calls `WidgetCenter.shared.reloadTimelines` on each vote/skip/data receive
- `react-native-watch-connectivity` v2 payload mismatches fixed: `votdPayload` key, reply handler for `request: 'todayVote'`, string→JSON parsing
- Swipe both directions skips; skip path routes to `done(showCaughtUp: false)`; EndView "View Profile on iPhone" fires `sendOpenProfileRequest()`

| Element | Before | After |
|---|---|---|
| Poll question | 15pt semibold | 17pt semibold |
| Jurisdiction eyebrow | 8pt | 10pt |
| Screen header label | 13pt | 11pt |
| Vote Now / Share / More Votes | 13pt bold, h28 | 14pt bold, h32 |
| Yes / No buttons | 13pt bold, h28 | 14pt bold, h32 |
| Tally percentages | 14pt | 16pt |
| Vote counts | 11pt | 12pt |
| FireworksView emoji | 36pt | 42pt |
| FireworksView headline | 15pt | 17pt |
| Celebration subtext | 11pt | 13pt |
| AllCaughtUpView emoji | 28pt | 36pt |
| AllCaughtUpView headline | 16pt | 18pt |
| Loading 🗳️ emoji | 32pt | 40pt |
| Loading "VOTD" wordmark | 16pt | 19pt |
| Horizontal padding | 4pt | 8pt throughout |

---

## Build 26 (2026-03-24)

### Watch — test on physical device (45mm + 41mm)

- [ ] **VOTD card** — "VOTE OF THE DAY" header pinned at top, Vote Now button pinned at bottom; neither moves when question length varies
- [ ] **Vote Now → Yes/No** — tap Vote Now reveals thumb buttons; tap Yes or No advances to TallyView
- [ ] **TallyView** — "YOU VOTED YES/NO" header correct, tally bar animates left to right, pct row (14pt) and counts row (11pt) visible; tally content not clipped
- [ ] **Share button** — tap Share on TallyView: phone app navigates to vote-item and opens post-vote share layer (requires phone running simultaneously)
- [ ] **More Votes / Done** — shows "More Votes →" when backlog exists; shows "Done" when it doesn't; both route correctly
- [ ] **Open Votes / CatchUp** — header reads "OPEN VOTES", carousel dots show correct count and advance with each vote, swipe left skips current card
- [ ] **Long press on question** — overlay appears: "See full vote details" / "Open on Phone" / "Cancel"; tapping "Open on Phone" sends message to phone and dismisses overlay
- [ ] **Skip → EndView** — skipping the last open vote routes directly to EndView with no confetti
- [ ] **Vote all → Confetti → EndView** — voting on the last open vote triggers FireworksView confetti, auto-advances to EndView after ~2s
- [ ] **EndView (full completion)** — streak + civic rank stats visible, all text white, "All caught up!" badge present
- [ ] **EndView (skip path)** — streak + civic rank stats visible, "All caught up!" badge absent
- [ ] **41mm layout** — repeat key screens above on smaller watch face; no clipping

### Phone — test with watch connected and both apps running

- [ ] **Open on Phone (openItem)** — long press question → tap "Open on Phone": phone navigates to the correct vote-item detail screen
- [ ] **Share from watch (openShare)** — tap Share on TallyView: phone opens vote-item and drops directly into the post-vote share layer
- [ ] **Cold launch** — no crash; Xcode console shows `[WatchBridge] Initialised`

### Carried forward from Build 24

- [ ] **App icon** — home screen shows `fixed_diagonal_border_brighterplus_sat_plus` (diagonal orange, brighter + saturated, with border)
- [ ] **No white card flash on open** — background stays orange through splash fade
- [ ] **First slide eases in smoothly** — subtle upward translate + fade, not a hard pop
- [ ] **Slide captions top-aligned** — not vertically centered
- [ ] **Caption crossfade** — fades out and back in smoothly when swiping between slides
- [ ] **Dots and buttons visible** — Sign Up / Explore / Already have an account below captions
- [ ] **Propose Step 3 — root domain nudge** — paste root domain URL → "Please use a specific article or research link, not a root domain." — Propose button suppressed
- [ ] **Propose Step 3 — valid URL preview** — orange domain label, title (no line clamp), description (no line clamp), large OG image at 1.91 ratio
- [ ] **Propose Step 3 — link list** — up to 5 links; ✕ remove button; input hides at cap; only "Propose Your Vote" CTA (no "Next")
- [ ] **Propose confirmation** — no "Congrats!" block; 🗳️ emoji large; "Most votes receive feedback within 48 hours."; no divider line
- [ ] **Daily Feed backlog cards** — no 📍 pin emoji; meta row truncates with … on one line

---

## Build 24 (2026-03-23)

### App icon

- [ ] **Home screen icon** — shows `fixed_diagonal_border_brighterplus_sat_plus` (diagonal orange design, brighter + saturated, with border)

### Launch / Onboarding

- [ ] **No white card flash** — background stays orange through the splash fade
- [ ] **First slide ease-in** — subtle upward translate + fade, not a hard pop
- [ ] **Captions top-aligned** — not vertically centered
- [ ] **Caption crossfade** — fades out and back in smoothly when swiping between slides
- [ ] **Dots and buttons visible** — Sign Up / Explore / Already have an account buttons visible below captions

### Propose a Vote — Step 3

- [ ] **Root domain nudge** — paste root domain URL (e.g. `https://washingtonpost.com`) → "Please use a specific article or research link, not a root domain." — Propose button suppressed
- [ ] **Valid URL preview** — full-width card: orange domain label, title (no line clamp), description (no line clamp), large OG image at 1.91 ratio
- [ ] **Add Link** — link confirmed into list, input clears, ready for next URL
- [ ] **Cap at 5 links** — input hides once cap reached; each link shows ✕ remove button
- [ ] **No "Next" button** — only "Propose Your Vote" CTA on Step 3
- [ ] **Required source field** — only appears after a file is picked

### Propose a Vote — Confirmation screen

- [ ] **No "Congrats!"** — "Congrats! We appreciate you." block absent
- [ ] **🗳️ emoji large** — matches megaphone size on intro screen
- [ ] **Copy correct** — "Most votes receive feedback within 48 hours."
- [ ] **No divider** — no divider line between dots and body

### Daily Feed — Backlog cards

- [ ] **No 📍 emoji** — pin emoji absent from meta row
- [ ] **Meta row truncates** — jurisdiction · vote count truncates with … on one line; does not wrap and push title down

### Apple Watch (mock data only at this build)

- [ ] **Watch app appears** — visible on Apple Watch after installing build 24 on phone
- [ ] **Card renders** — VOTE OF THE DAY eyebrow, jurisdiction + vote count meta, question text, Vote Now button
- [ ] **Vote Now → Yes/No** — tapping Vote Now reveals Yes / No buttons
- [ ] **Vote → tally** — voting leads to tally screen with animated split bar
- [ ] **Note** — watch shows Sacramento streetlights mock data at this build; live bridge not yet wired

---

## Known gaps — do not flag as regressions

- Watch bridge requires phone app to be open / recently backgrounded — votes sent when phone is fully closed are silently dropped (future: `transferUserInfo` fallback queue)
- `votd_hasVotedToday` resets on every cold start — intentional for prototype, date-stamp logic deferred
- Watch UI not yet QA'd on 41mm
- Complication background `.black.opacity(0.55)` — may need tuning against different watch face backgrounds
- Feedback widget Supabase writes require env vars + prebuild; until then, submissions log to console only
- `GlobalFeedbackFlag` in `_layout.tsx` is a temporary parking spot — floating placement above Stack nav unresolved (user decision: wait)
- Daily mock date-roll scheduled task commits locally at 3am but cannot push (VM has no network) — run `git push origin ios-debug` from `~/votd` manually after each overnight run
- Feed slot canonical names: `your_side_losing` = "It's Not Over Yet"; `your_side_winning` = "Push to the Finish"; `neighbor_proposal` = "Just Approved" — not yet surfaced in UI
