## What changed
### Player Redesign (video-first layout)
- New compact timer ring (110pt) with phase label, replaces 240pt ring
- Auto-hide top bar with block progress dots (3s auto-dismiss)
- Expandable now-playing music pill with skip control
- Bottom control bar with heart rate, play/pause, and skip
- Exercise caption with 'Next' preview during rest phases
- Compact round counter (capsule dots)
### Dynamic Island & Live Activities
- WorkoutLiveActivity widget: expanded, compact, and minimal views
- Phase-colored timers with Text(timerInterval:) countdown
- Shows exercise name, round progress, heart rate, music track
- MusicLiveActivity: standalone music now-playing widget
- LiveActivityMusicBars animated component
- Deep link from Dynamic Island back to app
### Timer Drift Fix (critical)
- Store a stable phaseEndDate once per phase instead of
recalculating Date() + timeRemaining on every update
- Prevents dynamic island countdown from rubber-banding
due to 5-second periodic update recalculation drift
- Reset phaseEndDate on phase change and resume from pause
- Guard Live Activity updates behind vm.isRunning to prevent
premature creation when music track loads before workout start
- Fixes timer showing 0 in Dynamic Island when expanding
from home screen
### New PlayerViewModel timer engine
- Full phase support: prep, warmup, work, rest,
interBlockRest, cooldown, complete
- 1-second countdown with audio cues at 3-2-1
- Phase transitions with spring animation and haptics
- HealthKit live session integration
- Workout session recording with completion
### Music Service
- New MusicPlayerViewModel with vibe-based playlist loading
- Track info exposed for Dynamic Island display
- Skip track support from Dynamic Island notification action
- Automatic play/pause based on phase and running state
### Additional
- ZoneHighlightIcon component for HomeTab zone cards
- Updated watchOS localizations with complication strings
- Info.plist updated for widget extension
- Replace external pill badges (level + FREE) with immersive overlay card:
level tag pinned top-right with ultraThinMaterial blur, FREE shown inline
with checkmark.seal.fill icon, dark scrim for text legibility
- Remove card drop shadow
- Move Browse by Zone section above Featured in Home tab scroll order
- Add purchaseSucceeded flag to PurchaseViewModel, set on purchase success
- PaywallView observes the flag and dismisses itself automatically
- ProfileTab.syncSubscription() writes PurchaseService.currentPlan back
to UserProfile.subscriptionRaw via SwiftData on sheet dismiss
Swap the two horizontal FilterChip scroll rows with a native segmented
Picker for body zone and a toolbar Menu for difficulty level. Fix zone
values to match Supabase enum (upper-body, lower-body, full-body).
Remove unused FilterChip struct.