diff --git a/app/complete/CLAUDE.md b/app/complete/CLAUDE.md
new file mode 100644
index 0000000..bee9fb7
--- /dev/null
+++ b/app/complete/CLAUDE.md
@@ -0,0 +1,14 @@
+
+# Recent Activity
+
+
+
+### Feb 20, 2026
+
+| ID | Time | T | Title | Read |
+|----|------|---|-------|------|
+| #5047 | 8:22 AM | ✅ | Completed Host wrapper removal from all screens | ~241 |
+| #5046 | " | ✅ | Removed opening Host tag from workout complete screen | ~165 |
+| #5033 | 8:20 AM | ✅ | Removed Host import from workout complete screen | ~212 |
+| #5026 | 8:18 AM | 🔵 | Workout complete screen properly wraps content with Host component | ~252 |
+
\ No newline at end of file
diff --git a/app/complete/[id].tsx b/app/complete/[id].tsx
new file mode 100644
index 0000000..9a51638
--- /dev/null
+++ b/app/complete/[id].tsx
@@ -0,0 +1,626 @@
+/**
+ * TabataFit Workout Complete Screen
+ * Celebration with real data from activity store
+ */
+
+import { useRef, useEffect } from 'react'
+import {
+ View,
+ Text as RNText,
+ StyleSheet,
+ ScrollView,
+ Pressable,
+ Animated,
+ Dimensions,
+} from 'react-native'
+import { useRouter, useLocalSearchParams } from 'expo-router'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { LinearGradient } from 'expo-linear-gradient'
+import { BlurView } from 'expo-blur'
+import Ionicons from '@expo/vector-icons/Ionicons'
+
+import * as Sharing from 'expo-sharing'
+import { useHaptics } from '@/src/shared/hooks'
+import { useActivityStore } from '@/src/shared/stores'
+import { getWorkoutById, getTrainerById, getPopularWorkouts } from '@/src/shared/data'
+
+import {
+ BRAND,
+ DARK,
+ TEXT,
+ GLASS,
+ SHADOW,
+} from '@/src/shared/constants/colors'
+import { TYPOGRAPHY } from '@/src/shared/constants/typography'
+import { SPACING, LAYOUT } from '@/src/shared/constants/spacing'
+import { RADIUS } from '@/src/shared/constants/borderRadius'
+import { SPRING, EASE } from '@/src/shared/constants/animations'
+
+const { width: SCREEN_WIDTH } = Dimensions.get('window')
+
+// ═══════════════════════════════════════════════════════════════════════════
+// BUTTON COMPONENTS
+// ═══════════════════════════════════════════════════════════════════════════
+
+function SecondaryButton({
+ onPress,
+ children,
+ icon,
+}: {
+ onPress: () => void
+ children: React.ReactNode
+ icon?: keyof typeof Ionicons.glyphMap
+}) {
+ const scaleAnim = useRef(new Animated.Value(1)).current
+
+ const handlePressIn = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 0.97,
+ useNativeDriver: true,
+ ...SPRING.SNAPPY,
+ }).start()
+ }
+
+ const handlePressOut = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 1,
+ useNativeDriver: true,
+ ...SPRING.SNAPPY,
+ }).start()
+ }
+
+ return (
+
+
+ {icon && }
+ {children}
+
+
+ )
+}
+
+function PrimaryButton({
+ onPress,
+ children,
+}: {
+ onPress: () => void
+ children: React.ReactNode
+}) {
+ const scaleAnim = useRef(new Animated.Value(1)).current
+
+ const handlePressIn = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 0.97,
+ useNativeDriver: true,
+ ...SPRING.SNAPPY,
+ }).start()
+ }
+
+ const handlePressOut = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 1,
+ useNativeDriver: true,
+ ...SPRING.SNAPPY,
+ }).start()
+ }
+
+ return (
+
+
+
+ {children}
+
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// COMPONENTS
+// ═══════════════════════════════════════════════════════════════════════════
+
+function CelebrationRings() {
+ const ring1Anim = useRef(new Animated.Value(0)).current
+ const ring2Anim = useRef(new Animated.Value(0)).current
+ const ring3Anim = useRef(new Animated.Value(0)).current
+
+ useEffect(() => {
+ Animated.stagger(200, [
+ Animated.spring(ring1Anim, {
+ toValue: 1,
+ ...SPRING.BOUNCY,
+ useNativeDriver: true,
+ }),
+ Animated.spring(ring2Anim, {
+ toValue: 1,
+ ...SPRING.BOUNCY,
+ useNativeDriver: true,
+ }),
+ Animated.spring(ring3Anim, {
+ toValue: 1,
+ ...SPRING.BOUNCY,
+ useNativeDriver: true,
+ }),
+ ]).start()
+ }, [])
+
+ return (
+
+
+ 🔥
+
+
+ 💪
+
+
+ ⚡
+
+
+ )
+}
+
+function StatCard({
+ value,
+ label,
+ icon,
+ delay = 0,
+}: {
+ value: string | number
+ label: string
+ icon: keyof typeof Ionicons.glyphMap
+ delay?: number
+}) {
+ const scaleAnim = useRef(new Animated.Value(0)).current
+
+ useEffect(() => {
+ Animated.sequence([
+ Animated.delay(delay),
+ Animated.spring(scaleAnim, {
+ toValue: 1,
+ ...SPRING.BOUNCY,
+ useNativeDriver: true,
+ }),
+ ]).start()
+ }, [delay])
+
+ return (
+
+
+
+ {value}
+ {label}
+
+ )
+}
+
+function BurnBarResult({ percentile }: { percentile: number }) {
+ const barAnim = useRef(new Animated.Value(0)).current
+
+ useEffect(() => {
+ Animated.timing(barAnim, {
+ toValue: percentile,
+ duration: 1000,
+ easing: EASE.EASE_OUT,
+ useNativeDriver: false,
+ }).start()
+ }, [percentile])
+
+ const barWidth = barAnim.interpolate({
+ inputRange: [0, 100],
+ outputRange: ['0%', '100%'],
+ })
+
+ return (
+
+ Burn Bar
+ You beat {percentile}% of users!
+
+
+
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// MAIN SCREEN
+// ═══════════════════════════════════════════════════════════════════════════
+
+export default function WorkoutCompleteScreen() {
+ const insets = useSafeAreaInsets()
+ const router = useRouter()
+ const haptics = useHaptics()
+ const { id } = useLocalSearchParams<{ id: string }>()
+
+ const workout = getWorkoutById(id ?? '1')
+ const streak = useActivityStore((s) => s.streak)
+ const history = useActivityStore((s) => s.history)
+ const recentWorkouts = history.slice(0, 1)
+
+ // Get the most recent result for this workout
+ const latestResult = recentWorkouts[0]
+ const resultCalories = latestResult?.calories ?? workout?.calories ?? 45
+ const resultMinutes = latestResult?.durationMinutes ?? workout?.duration ?? 4
+
+ // Recommended workouts (different from current)
+ const recommended = getPopularWorkouts(4).filter(w => w.id !== id).slice(0, 3)
+
+ const handleGoHome = () => {
+ haptics.buttonTap()
+ router.replace('/(tabs)')
+ }
+
+ const handleShare = async () => {
+ haptics.selection()
+ const isAvailable = await Sharing.isAvailableAsync()
+ if (isAvailable) {
+ await Sharing.shareAsync('https://tabatafit.app', {
+ dialogTitle: `I just completed ${workout?.title ?? 'a workout'}! 🔥 ${resultCalories} calories in ${resultMinutes} minutes.`,
+ })
+ }
+ }
+
+ const handleWorkoutPress = (workoutId: string) => {
+ haptics.buttonTap()
+ router.push(`/workout/${workoutId}`)
+ }
+
+ // Simulate percentile
+ const burnBarPercentile = Math.min(95, Math.max(40, Math.round((resultCalories / (workout?.calories ?? 45)) * 70)))
+
+ return (
+
+
+ {/* Celebration */}
+
+ 🎉
+ WORKOUT COMPLETE
+
+
+
+ {/* Stats Grid */}
+
+
+
+
+
+
+ {/* Burn Bar */}
+
+
+
+
+ {/* Streak */}
+
+
+
+
+
+ {streak.current} Day Streak!
+ Keep the momentum going!
+
+
+
+
+
+ {/* Share Button */}
+
+
+ Share Your Workout
+
+
+
+
+
+ {/* Recommended */}
+
+ Recommended Next
+
+ {recommended.map((w) => {
+ const trainer = getTrainerById(w.trainerId)
+ return (
+ handleWorkoutPress(w.id)}
+ style={styles.recommendedCard}
+ >
+
+
+
+ {trainer?.name[0] ?? 'T'}
+
+ {w.title}
+ {w.duration} min
+
+ )
+ })}
+
+
+
+
+ {/* Fixed Bottom Button */}
+
+
+
+
+ Back to Home
+
+
+
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// STYLES
+// ═══════════════════════════════════════════════════════════════════════════
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: DARK.BASE,
+ },
+ scrollView: {
+ flex: 1,
+ },
+ scrollContent: {
+ paddingHorizontal: LAYOUT.SCREEN_PADDING,
+ },
+
+ // Buttons
+ secondaryButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: SPACING[3],
+ paddingHorizontal: SPACING[4],
+ borderRadius: RADIUS.LG,
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.3)',
+ backgroundColor: 'transparent',
+ },
+ secondaryButtonText: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.PRIMARY,
+ fontWeight: '600',
+ },
+ primaryButton: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ paddingVertical: SPACING[4],
+ paddingHorizontal: SPACING[6],
+ borderRadius: RADIUS.LG,
+ overflow: 'hidden',
+ },
+ primaryButtonText: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ fontWeight: '700',
+ },
+ buttonIcon: {
+ marginRight: SPACING[2],
+ },
+
+ // Celebration
+ celebrationSection: {
+ alignItems: 'center',
+ paddingVertical: SPACING[8],
+ },
+ celebrationEmoji: {
+ fontSize: 64,
+ marginBottom: SPACING[4],
+ },
+ celebrationTitle: {
+ ...TYPOGRAPHY.TITLE_1,
+ color: TEXT.PRIMARY,
+ letterSpacing: 2,
+ },
+ ringsContainer: {
+ flexDirection: 'row',
+ marginTop: SPACING[6],
+ gap: SPACING[4],
+ },
+ ring: {
+ width: 64,
+ height: 64,
+ borderRadius: 32,
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderWidth: 2,
+ borderColor: 'rgba(255, 255, 255, 0.2)',
+ },
+ ring1: {
+ borderColor: BRAND.PRIMARY,
+ backgroundColor: 'rgba(255, 107, 53, 0.15)',
+ },
+ ring2: {
+ borderColor: '#30D158',
+ backgroundColor: 'rgba(48, 209, 88, 0.15)',
+ },
+ ring3: {
+ borderColor: '#5AC8FA',
+ backgroundColor: 'rgba(90, 200, 250, 0.15)',
+ },
+ ringEmoji: {
+ fontSize: 28,
+ },
+
+ // Stats Grid
+ statsGrid: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: SPACING[6],
+ },
+ statCard: {
+ width: (SCREEN_WIDTH - LAYOUT.SCREEN_PADDING * 2 - SPACING[4]) / 3,
+ padding: SPACING[3],
+ borderRadius: RADIUS.LG,
+ alignItems: 'center',
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ overflow: 'hidden',
+ },
+ statValue: {
+ ...TYPOGRAPHY.TITLE_1,
+ color: TEXT.PRIMARY,
+ marginTop: SPACING[2],
+ },
+ statLabel: {
+ ...TYPOGRAPHY.CAPTION_2,
+ color: TEXT.TERTIARY,
+ marginTop: SPACING[1],
+ },
+
+ // Burn Bar
+ burnBarContainer: {
+ marginBottom: SPACING[6],
+ },
+ burnBarTitle: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ },
+ burnBarResult: {
+ ...TYPOGRAPHY.BODY,
+ color: BRAND.PRIMARY,
+ marginTop: SPACING[1],
+ marginBottom: SPACING[3],
+ },
+ burnBarTrack: {
+ height: 8,
+ backgroundColor: DARK.SURFACE,
+ borderRadius: 4,
+ overflow: 'hidden',
+ },
+ burnBarFill: {
+ height: '100%',
+ backgroundColor: BRAND.PRIMARY,
+ borderRadius: 4,
+ },
+
+ // Divider
+ divider: {
+ height: 1,
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
+ marginVertical: SPACING[2],
+ },
+
+ // Streak
+ streakSection: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingVertical: SPACING[4],
+ gap: SPACING[4],
+ },
+ streakBadge: {
+ width: 64,
+ height: 64,
+ borderRadius: 32,
+ backgroundColor: 'rgba(255, 107, 53, 0.15)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ streakInfo: {
+ flex: 1,
+ },
+ streakTitle: {
+ ...TYPOGRAPHY.TITLE_2,
+ color: TEXT.PRIMARY,
+ },
+ streakSubtitle: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.TERTIARY,
+ marginTop: SPACING[1],
+ },
+
+ // Share
+ shareSection: {
+ paddingVertical: SPACING[4],
+ alignItems: 'center',
+ },
+
+ // Recommended
+ recommendedSection: {
+ paddingVertical: SPACING[4],
+ },
+ recommendedTitle: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ marginBottom: SPACING[4],
+ },
+ recommendedGrid: {
+ flexDirection: 'row',
+ gap: SPACING[3],
+ },
+ recommendedCard: {
+ flex: 1,
+ padding: SPACING[3],
+ borderRadius: RADIUS.LG,
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ overflow: 'hidden',
+ },
+ recommendedThumb: {
+ width: '100%',
+ aspectRatio: 1,
+ borderRadius: RADIUS.MD,
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginBottom: SPACING[2],
+ overflow: 'hidden',
+ },
+ recommendedInitial: {
+ ...TYPOGRAPHY.TITLE_1,
+ color: TEXT.PRIMARY,
+ },
+ recommendedTitleText: {
+ ...TYPOGRAPHY.CARD_TITLE,
+ color: TEXT.PRIMARY,
+ },
+ recommendedDurationText: {
+ ...TYPOGRAPHY.CARD_METADATA,
+ color: TEXT.TERTIARY,
+ },
+
+ // Bottom Bar
+ bottomBar: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ paddingHorizontal: LAYOUT.SCREEN_PADDING,
+ paddingTop: SPACING[4],
+ borderTopWidth: 1,
+ borderTopColor: 'rgba(255, 255, 255, 0.1)',
+ },
+ homeButtonContainer: {
+ height: 56,
+ justifyContent: 'center',
+ },
+})
diff --git a/app/player/CLAUDE.md b/app/player/CLAUDE.md
new file mode 100644
index 0000000..ded1bfc
--- /dev/null
+++ b/app/player/CLAUDE.md
@@ -0,0 +1,12 @@
+
+# Recent Activity
+
+
+
+### Feb 19, 2026
+
+| ID | Time | T | Title | Read |
+|----|------|---|-------|------|
+| #5000 | 9:35 AM | 🔵 | Reviewed Player Screen Implementation | ~522 |
+| #4912 | 8:16 AM | 🔵 | Found doneButton component in player screen | ~104 |
+
\ No newline at end of file
diff --git a/app/player/[id].tsx b/app/player/[id].tsx
new file mode 100644
index 0000000..998cbe4
--- /dev/null
+++ b/app/player/[id].tsx
@@ -0,0 +1,756 @@
+/**
+ * TabataFit Player Screen
+ * Full-screen workout player with timer overlay
+ * Wired to shared data + useTimer hook
+ */
+
+import React, { useRef, useEffect, useCallback, useState } from 'react'
+import {
+ View,
+ Text,
+ StyleSheet,
+ Pressable,
+ Animated,
+ Dimensions,
+ StatusBar,
+} from 'react-native'
+import { useRouter, useLocalSearchParams } from 'expo-router'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { LinearGradient } from 'expo-linear-gradient'
+import { BlurView } from 'expo-blur'
+import { useKeepAwake } from 'expo-keep-awake'
+import Ionicons from '@expo/vector-icons/Ionicons'
+
+import { useTimer } from '@/src/shared/hooks/useTimer'
+import { useHaptics } from '@/src/shared/hooks/useHaptics'
+import { useAudio } from '@/src/shared/hooks/useAudio'
+import { useActivityStore } from '@/src/shared/stores'
+import { getWorkoutById, getTrainerById } from '@/src/shared/data'
+
+import {
+ BRAND,
+ DARK,
+ TEXT,
+ GLASS,
+ SHADOW,
+ PHASE_COLORS,
+ GRADIENTS,
+} from '@/src/shared/constants/colors'
+import { TYPOGRAPHY } from '@/src/shared/constants/typography'
+import { SPACING } from '@/src/shared/constants/spacing'
+import { RADIUS } from '@/src/shared/constants/borderRadius'
+import { DURATION, EASE, SPRING } from '@/src/shared/constants/animations'
+
+const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window')
+
+// ═══════════════════════════════════════════════════════════════════════════
+// COMPONENTS
+// ═══════════════════════════════════════════════════════════════════════════
+
+type TimerPhase = 'PREP' | 'WORK' | 'REST' | 'COMPLETE'
+
+function TimerRing({
+ progress,
+ phase,
+ size = 280,
+}: {
+ progress: number
+ phase: TimerPhase
+ size?: number
+}) {
+ const strokeWidth = 12
+ const phaseColor = PHASE_COLORS[phase].fill
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+function PhaseIndicator({ phase }: { phase: TimerPhase }) {
+ const phaseColor = PHASE_COLORS[phase].fill
+ const phaseLabels: Record = {
+ PREP: 'GET READY',
+ WORK: 'WORK',
+ REST: 'REST',
+ COMPLETE: 'COMPLETE',
+ }
+
+ return (
+
+ {phaseLabels[phase]}
+
+ )
+}
+
+function ExerciseDisplay({
+ exercise,
+ nextExercise,
+}: {
+ exercise: string
+ nextExercise?: string
+}) {
+ return (
+
+ Current
+ {exercise}
+ {nextExercise && (
+
+ Next:
+ {nextExercise}
+
+ )}
+
+ )
+}
+
+function RoundIndicator({ current, total }: { current: number; total: number }) {
+ return (
+
+
+ Round {current}/{total}
+
+
+ )
+}
+
+function ControlButton({
+ icon,
+ onPress,
+ size = 64,
+ variant = 'primary',
+}: {
+ icon: keyof typeof Ionicons.glyphMap
+ onPress: () => void
+ size?: number
+ variant?: 'primary' | 'secondary' | 'danger'
+}) {
+ const scaleAnim = useRef(new Animated.Value(1)).current
+
+ const handlePressIn = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 0.9,
+ ...SPRING.SNAPPY,
+ useNativeDriver: true,
+ }).start()
+ }
+
+ const handlePressOut = () => {
+ Animated.spring(scaleAnim, {
+ toValue: 1,
+ ...SPRING.BOUNCY,
+ useNativeDriver: true,
+ }).start()
+ }
+
+ const backgroundColor =
+ variant === 'primary'
+ ? BRAND.PRIMARY
+ : variant === 'danger'
+ ? '#FF3B30'
+ : 'rgba(255, 255, 255, 0.1)'
+
+ return (
+
+
+
+
+
+
+ )
+}
+
+function BurnBar({
+ currentCalories,
+ avgCalories,
+}: {
+ currentCalories: number
+ avgCalories: number
+}) {
+ const percentage = Math.min((currentCalories / avgCalories) * 100, 100)
+
+ return (
+
+
+ Burn Bar
+ {currentCalories} cal
+
+
+
+
+
+ Community avg: {avgCalories} cal
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// MAIN SCREEN
+// ═══════════════════════════════════════════════════════════════════════════
+
+export default function PlayerScreen() {
+ useKeepAwake()
+ const router = useRouter()
+ const { id } = useLocalSearchParams<{ id: string }>()
+ const insets = useSafeAreaInsets()
+ const haptics = useHaptics()
+ const addWorkoutResult = useActivityStore((s) => s.addWorkoutResult)
+
+ const workout = getWorkoutById(id ?? '1')
+ const trainer = workout ? getTrainerById(workout.trainerId) : null
+
+ const timer = useTimer(workout ?? null)
+ const audio = useAudio()
+
+ const [showControls, setShowControls] = useState(true)
+
+ // Animation refs
+ const timerScaleAnim = useRef(new Animated.Value(0.8)).current
+ const glowAnim = useRef(new Animated.Value(0)).current
+
+ const phaseColor = PHASE_COLORS[timer.phase].fill
+
+ // Format time
+ const formatTime = (seconds: number) => {
+ const mins = Math.floor(seconds / 60)
+ const secs = seconds % 60
+ return mins > 0 ? `${mins}:${secs.toString().padStart(2, '0')}` : `${secs}`
+ }
+
+ // Start timer
+ const startTimer = useCallback(() => {
+ timer.start()
+ haptics.buttonTap()
+ }, [timer, haptics])
+
+ // Pause/Resume
+ const togglePause = useCallback(() => {
+ if (timer.isPaused) {
+ timer.resume()
+ } else {
+ timer.pause()
+ }
+ haptics.selection()
+ }, [timer, haptics])
+
+ // Stop workout
+ const stopWorkout = useCallback(() => {
+ haptics.phaseChange()
+ timer.stop()
+ router.back()
+ }, [router, timer, haptics])
+
+ // Complete workout - go to celebration screen
+ const completeWorkout = useCallback(() => {
+ haptics.workoutComplete()
+ if (workout) {
+ addWorkoutResult({
+ id: Date.now().toString(),
+ workoutId: workout.id,
+ completedAt: Date.now(),
+ calories: timer.calories,
+ durationMinutes: workout.duration,
+ rounds: workout.rounds,
+ completionRate: 1,
+ })
+ }
+ router.replace(`/complete/${workout?.id ?? '1'}`)
+ }, [router, workout, timer.calories, haptics, addWorkoutResult])
+
+ // Skip
+ const handleSkip = useCallback(() => {
+ timer.skip()
+ haptics.selection()
+ }, [timer, haptics])
+
+ // Toggle controls visibility
+ const toggleControls = useCallback(() => {
+ setShowControls(s => !s)
+ }, [])
+
+ // Entrance animation
+ useEffect(() => {
+ Animated.parallel([
+ Animated.spring(timerScaleAnim, {
+ toValue: 1,
+ friction: 6,
+ tension: 100,
+ useNativeDriver: true,
+ }),
+ Animated.loop(
+ Animated.sequence([
+ Animated.timing(glowAnim, {
+ toValue: 1,
+ duration: DURATION.BREATH,
+ easing: EASE.EASE_IN_OUT,
+ useNativeDriver: false,
+ }),
+ Animated.timing(glowAnim, {
+ toValue: 0,
+ duration: DURATION.BREATH,
+ easing: EASE.EASE_IN_OUT,
+ useNativeDriver: false,
+ }),
+ ])
+ ),
+ ]).start()
+ }, [])
+
+ // Phase change animation + audio
+ useEffect(() => {
+ timerScaleAnim.setValue(0.9)
+ Animated.spring(timerScaleAnim, {
+ toValue: 1,
+ friction: 4,
+ tension: 150,
+ useNativeDriver: true,
+ }).start()
+ haptics.phaseChange()
+ if (timer.phase === 'COMPLETE') {
+ audio.workoutComplete()
+ } else if (timer.isRunning) {
+ audio.phaseStart()
+ }
+ }, [timer.phase])
+
+ // Countdown beep for last 3 seconds
+ useEffect(() => {
+ if (timer.isRunning && timer.timeRemaining <= 3 && timer.timeRemaining > 0) {
+ audio.countdownBeep()
+ }
+ }, [timer.timeRemaining])
+
+ const glowOpacity = glowAnim.interpolate({
+ inputRange: [0, 1],
+ outputRange: [0.3, 0.6],
+ })
+
+ return (
+
+
+
+ {/* Background gradient */}
+
+
+ {/* Phase glow */}
+
+
+ {/* Main content */}
+
+ {/* Header */}
+ {showControls && (
+
+
+
+
+
+
+ {workout?.title ?? 'Workout'}
+ with {trainer?.name ?? 'Coach'}
+
+
+
+ )}
+
+ {/* Timer */}
+
+
+
+
+
+ {formatTime(timer.timeRemaining)}
+
+
+
+
+ {/* Exercise */}
+ {!timer.isComplete && (
+
+ )}
+
+ {/* Complete state */}
+ {timer.isComplete && (
+
+ Workout Complete!
+ Great job!
+
+
+ {timer.totalRounds}
+ Rounds
+
+
+ {timer.calories}
+ Calories
+
+
+ {workout?.duration ?? 4}
+ Minutes
+
+
+
+ )}
+
+ {/* Controls */}
+ {showControls && !timer.isComplete && (
+
+ {!timer.isRunning ? (
+
+ ) : (
+
+
+
+
+
+ )}
+
+ )}
+
+ {/* Complete button */}
+ {timer.isComplete && (
+
+
+
+ Done
+
+
+ )}
+
+ {/* Burn Bar */}
+ {showControls && timer.isRunning && !timer.isComplete && (
+
+
+
+
+ )}
+
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// STYLES
+// ═══════════════════════════════════════════════════════════════════════════
+
+const timerStyles = StyleSheet.create({
+ timerRingContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ timerRingBg: {
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ position: 'absolute',
+ },
+ timerRingContent: {
+ position: 'absolute',
+ },
+ timerProgressRing: {
+ position: 'absolute',
+ },
+ timerTextContainer: {
+ position: 'absolute',
+ alignItems: 'center',
+ },
+ phaseIndicator: {
+ paddingHorizontal: SPACING[4],
+ paddingVertical: SPACING[1],
+ borderRadius: RADIUS.FULL,
+ marginBottom: SPACING[2],
+ },
+ phaseText: {
+ ...TYPOGRAPHY.CALLOUT,
+ fontWeight: '700',
+ letterSpacing: 1,
+ },
+ timerTime: {
+ ...TYPOGRAPHY.TIMER_NUMBER,
+ color: TEXT.PRIMARY,
+ },
+ roundIndicator: {
+ marginTop: SPACING[2],
+ },
+ roundText: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.TERTIARY,
+ },
+ roundCurrent: {
+ color: TEXT.PRIMARY,
+ fontWeight: '700',
+ },
+
+ // Exercise
+ exerciseDisplay: {
+ alignItems: 'center',
+ marginTop: SPACING[6],
+ paddingHorizontal: SPACING[6],
+ },
+ currentExerciseLabel: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ textTransform: 'uppercase',
+ letterSpacing: 1,
+ },
+ currentExercise: {
+ ...TYPOGRAPHY.TITLE_1,
+ color: TEXT.PRIMARY,
+ textAlign: 'center',
+ marginTop: SPACING[1],
+ },
+ nextExerciseContainer: {
+ flexDirection: 'row',
+ marginTop: SPACING[2],
+ },
+ nextExerciseLabel: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.TERTIARY,
+ },
+ nextExercise: {
+ ...TYPOGRAPHY.BODY,
+ color: BRAND.PRIMARY,
+ },
+
+ // Controls
+ controlButton: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ controlButtonBg: {
+ position: 'absolute',
+ width: '100%',
+ height: '100%',
+ borderRadius: 100,
+ },
+
+ // Burn Bar
+ burnBar: {},
+ burnBarHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: SPACING[2],
+ },
+ burnBarLabel: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ },
+ burnBarValue: {
+ ...TYPOGRAPHY.CALLOUT,
+ color: BRAND.PRIMARY,
+ fontWeight: '600',
+ },
+ burnBarTrack: {
+ height: 6,
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
+ borderRadius: 3,
+ overflow: 'hidden',
+ },
+ burnBarFill: {
+ height: '100%',
+ backgroundColor: BRAND.PRIMARY,
+ borderRadius: 3,
+ },
+ burnBarAvg: {
+ position: 'absolute',
+ top: -2,
+ width: 2,
+ height: 10,
+ backgroundColor: TEXT.TERTIARY,
+ },
+ burnBarAvgLabel: {
+ ...TYPOGRAPHY.CAPTION_2,
+ color: TEXT.TERTIARY,
+ marginTop: SPACING[1],
+ textAlign: 'right',
+ },
+})
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: DARK.BASE,
+ },
+ phaseGlow: {
+ position: 'absolute',
+ top: -100,
+ left: -100,
+ right: -100,
+ bottom: -100,
+ borderRadius: 500,
+ },
+ content: {
+ flex: 1,
+ },
+
+ // Header
+ header: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingHorizontal: SPACING[4],
+ },
+ closeButton: {
+ width: 44,
+ height: 44,
+ borderRadius: 22,
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ },
+ headerCenter: {
+ alignItems: 'center',
+ },
+ workoutTitle: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ },
+ workoutTrainer: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ },
+
+ // Timer
+ timerContainer: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginTop: SPACING[8],
+ },
+
+ // Controls
+ controls: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ alignItems: 'center',
+ },
+ controlsRow: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: SPACING[6],
+ },
+
+ // Burn Bar
+ burnBarContainer: {
+ position: 'absolute',
+ left: SPACING[4],
+ right: SPACING[4],
+ height: 72,
+ borderRadius: RADIUS.LG,
+ overflow: 'hidden',
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ padding: SPACING[3],
+ },
+
+ // Complete
+ completeContainer: {
+ alignItems: 'center',
+ marginTop: SPACING[8],
+ },
+ completeTitle: {
+ ...TYPOGRAPHY.LARGE_TITLE,
+ color: TEXT.PRIMARY,
+ },
+ completeSubtitle: {
+ ...TYPOGRAPHY.TITLE_3,
+ color: BRAND.PRIMARY,
+ marginTop: SPACING[1],
+ },
+ completeStats: {
+ flexDirection: 'row',
+ marginTop: SPACING[6],
+ gap: SPACING[8],
+ },
+ completeStat: {
+ alignItems: 'center',
+ },
+ completeStatValue: {
+ ...TYPOGRAPHY.TITLE_1,
+ color: TEXT.PRIMARY,
+ },
+ completeStatLabel: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ marginTop: SPACING[1],
+ },
+ doneButton: {
+ width: 200,
+ height: 56,
+ borderRadius: RADIUS.GLASS_BUTTON,
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ ...SHADOW.BRAND_GLOW,
+ },
+ doneButtonText: {
+ ...TYPOGRAPHY.BUTTON_MEDIUM,
+ color: TEXT.PRIMARY,
+ letterSpacing: 1,
+ },
+})
diff --git a/app/workout/CLAUDE.md b/app/workout/CLAUDE.md
new file mode 100644
index 0000000..84bcc23
--- /dev/null
+++ b/app/workout/CLAUDE.md
@@ -0,0 +1,14 @@
+
+# Recent Activity
+
+
+
+### Feb 20, 2026
+
+| ID | Time | T | Title | Read |
+|----|------|---|-------|------|
+| #5045 | 8:22 AM | ✅ | Removed closing Host tag from workout detail screen | ~188 |
+| #5044 | " | ✅ | Removed opening Host tag from workout detail screen | ~158 |
+| #5032 | 8:19 AM | ✅ | Removed Host import from workout detail screen | ~194 |
+| #5025 | 8:18 AM | 🔵 | Workout detail screen properly wraps content with Host component | ~244 |
+
\ No newline at end of file
diff --git a/app/workout/[id].tsx b/app/workout/[id].tsx
new file mode 100644
index 0000000..05a4dd4
--- /dev/null
+++ b/app/workout/[id].tsx
@@ -0,0 +1,449 @@
+/**
+ * TabataFit Pre-Workout Detail Screen
+ * Dynamic data via route params
+ */
+
+import { useState } from 'react'
+import { View, Text as RNText, StyleSheet, ScrollView, Pressable } from 'react-native'
+import { useRouter, useLocalSearchParams } from 'expo-router'
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
+import { LinearGradient } from 'expo-linear-gradient'
+import { BlurView } from 'expo-blur'
+import Ionicons from '@expo/vector-icons/Ionicons'
+
+import { useHaptics } from '@/src/shared/hooks'
+import { getWorkoutById, getTrainerById } from '@/src/shared/data'
+import { VideoPlayer } from '@/src/shared/components/VideoPlayer'
+
+import {
+ BRAND,
+ DARK,
+ TEXT,
+ GLASS,
+ SHADOW,
+} from '@/src/shared/constants/colors'
+import { TYPOGRAPHY } from '@/src/shared/constants/typography'
+import { SPACING, LAYOUT } from '@/src/shared/constants/spacing'
+import { RADIUS } from '@/src/shared/constants/borderRadius'
+
+// ═══════════════════════════════════════════════════════════════════════════
+// MAIN SCREEN
+// ═══════════════════════════════════════════════════════════════════════════
+
+export default function WorkoutDetailScreen() {
+ const insets = useSafeAreaInsets()
+ const router = useRouter()
+ const haptics = useHaptics()
+ const { id } = useLocalSearchParams<{ id: string }>()
+ const [isSaved, setIsSaved] = useState(false)
+
+ const workout = getWorkoutById(id ?? '1')
+ if (!workout) {
+ return (
+
+ Workout not found
+
+ )
+ }
+
+ const trainer = getTrainerById(workout.trainerId)
+
+ const handleStartWorkout = () => {
+ haptics.phaseChange()
+ router.push(`/player/${workout.id}`)
+ }
+
+ const handleGoBack = () => {
+ haptics.selection()
+ router.back()
+ }
+
+ const toggleSave = () => {
+ haptics.selection()
+ setIsSaved(!isSaved)
+ }
+
+ const repeatCount = Math.max(1, Math.floor(workout.rounds / workout.exercises.length))
+
+ return (
+
+
+ {/* Video Preview */}
+
+
+
+
+ {/* Header overlay */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Trainer preview */}
+
+
+ {trainer?.name[0] ?? 'T'}
+
+
+
+
+ {/* Title Section */}
+
+ {workout.title}
+
+ {/* Quick stats */}
+
+
+
+ {trainer?.name ?? ''}
+
+ •
+
+
+ {workout.level}
+
+ •
+
+
+ {workout.duration} min
+
+ •
+
+
+ {workout.calories} cal
+
+
+
+
+
+
+ {/* Equipment */}
+
+ What You'll Need
+ {workout.equipment.map((item, index) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+ {/* Exercises */}
+
+ Exercises ({workout.rounds} rounds)
+
+ {workout.exercises.map((exercise, index) => (
+
+
+ {index + 1}
+
+ {exercise.name}
+ {exercise.duration}s work
+
+ ))}
+
+
+ Repeat × {repeatCount} rounds
+
+
+
+
+
+
+ {/* Music */}
+
+ Music
+
+
+
+
+
+ {workout.musicVibe.charAt(0).toUpperCase() + workout.musicVibe.slice(1)} Mix
+ Curated for your workout
+
+
+
+
+
+ {/* Fixed Start Button */}
+
+
+
+ [
+ styles.startButton,
+ pressed && styles.startButtonPressed,
+ ]}
+ onPress={handleStartWorkout}
+ >
+ START WORKOUT
+
+
+
+
+ )
+}
+
+// ═══════════════════════════════════════════════════════════════════════════
+// STYLES
+// ═══════════════════════════════════════════════════════════════════════════
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: DARK.BASE,
+ },
+ scrollView: {
+ flex: 1,
+ },
+ scrollContent: {
+ paddingHorizontal: LAYOUT.SCREEN_PADDING,
+ },
+
+ // Video Preview
+ videoPreview: {
+ height: 280,
+ marginHorizontal: -LAYOUT.SCREEN_PADDING,
+ marginBottom: SPACING[4],
+ backgroundColor: DARK.SURFACE,
+ },
+ headerOverlay: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ padding: SPACING[4],
+ },
+ headerButton: {
+ width: 44,
+ height: 44,
+ borderRadius: 22,
+ alignItems: 'center',
+ justifyContent: 'center',
+ overflow: 'hidden',
+ borderWidth: 1,
+ borderColor: 'rgba(255, 255, 255, 0.1)',
+ },
+ headerRight: {
+ flexDirection: 'row',
+ gap: SPACING[2],
+ },
+ trainerPreview: {
+ position: 'absolute',
+ bottom: SPACING[4],
+ left: 0,
+ right: 0,
+ alignItems: 'center',
+ },
+ trainerAvatarLarge: {
+ width: 80,
+ height: 80,
+ borderRadius: 40,
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderWidth: 3,
+ borderColor: TEXT.PRIMARY,
+ },
+ trainerInitial: {
+ ...TYPOGRAPHY.HERO,
+ color: TEXT.PRIMARY,
+ },
+
+ // Title Section
+ titleSection: {
+ marginBottom: SPACING[4],
+ },
+ title: {
+ ...TYPOGRAPHY.LARGE_TITLE,
+ color: TEXT.PRIMARY,
+ marginBottom: SPACING[3],
+ },
+ quickStats: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ flexWrap: 'wrap',
+ gap: SPACING[2],
+ },
+ statItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: SPACING[1],
+ },
+ statText: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.SECONDARY,
+ },
+ statDot: {
+ color: TEXT.TERTIARY,
+ },
+
+ // Divider
+ divider: {
+ height: 1,
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
+ marginVertical: SPACING[2],
+ },
+
+ // Section
+ section: {
+ paddingVertical: SPACING[4],
+ },
+ sectionTitle: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ marginBottom: SPACING[3],
+ },
+
+ // Equipment
+ equipmentItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: SPACING[3],
+ marginBottom: SPACING[2],
+ },
+ equipmentText: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.SECONDARY,
+ },
+
+ // Exercises
+ exercisesList: {
+ gap: SPACING[2],
+ },
+ exerciseRow: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingVertical: SPACING[3],
+ paddingHorizontal: SPACING[4],
+ backgroundColor: DARK.SURFACE,
+ borderRadius: RADIUS.LG,
+ gap: SPACING[3],
+ },
+ exerciseNumber: {
+ width: 28,
+ height: 28,
+ borderRadius: 14,
+ backgroundColor: 'rgba(255, 107, 53, 0.15)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ exerciseNumberText: {
+ ...TYPOGRAPHY.CALLOUT,
+ color: BRAND.PRIMARY,
+ fontWeight: '700',
+ },
+ exerciseName: {
+ ...TYPOGRAPHY.BODY,
+ color: TEXT.PRIMARY,
+ flex: 1,
+ },
+ exerciseDuration: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ },
+ repeatNote: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: SPACING[2],
+ marginTop: SPACING[2],
+ paddingHorizontal: SPACING[2],
+ },
+ repeatText: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ },
+
+ // Music
+ musicCard: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ padding: SPACING[4],
+ backgroundColor: DARK.SURFACE,
+ borderRadius: RADIUS.LG,
+ gap: SPACING[3],
+ },
+ musicIcon: {
+ width: 48,
+ height: 48,
+ borderRadius: 24,
+ backgroundColor: 'rgba(255, 107, 53, 0.15)',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ musicInfo: {
+ flex: 1,
+ },
+ musicName: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ },
+ musicDescription: {
+ ...TYPOGRAPHY.CAPTION_1,
+ color: TEXT.TERTIARY,
+ marginTop: 2,
+ },
+
+ // Bottom Bar
+ bottomBar: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ paddingHorizontal: LAYOUT.SCREEN_PADDING,
+ paddingTop: SPACING[4],
+ borderTopWidth: 1,
+ borderTopColor: 'rgba(255, 255, 255, 0.1)',
+ },
+ startButtonContainer: {
+ height: 56,
+ justifyContent: 'center',
+ },
+
+ // Start Button
+ startButton: {
+ height: 56,
+ borderRadius: RADIUS.LG,
+ backgroundColor: BRAND.PRIMARY,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ startButtonPressed: {
+ backgroundColor: BRAND.PRIMARY_DARK,
+ transform: [{ scale: 0.98 }],
+ },
+ startButtonText: {
+ ...TYPOGRAPHY.HEADLINE,
+ color: TEXT.PRIMARY,
+ letterSpacing: 1,
+ },
+})