// Body — HRV/sleep/readiness + the HRV-social correlation insight function BodyScreen({ go }) { const d = LifeData; const h = d.health.today; const base = d.health.baseline; const week = d.health.week; const haveData = h.hrv_ms > 0 || h.sleep_hours > 0; const dayName = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][new Date().getDay()]; if (!haveData) { return (
Body · {dayName}
No health data.
Send an Apple Health export to see your recovery.
Import Apple Health
POST your export.xml to /ingest/health/shay
); } const readinessLabel = h.readiness >= 80 ? 'High' : h.readiness >= 60 ? 'Moderate' : 'Low'; const readinessHint = h.readiness >= 80 ? 'Great recovery. You\'re good for a hard session today.' : h.readiness >= 60 ? 'Moderate recovery. Consider lighter training.' : 'Low HRV + short sleep. Rest or mobility today.'; return (
{/* Header */}
Body · {dayName}
{readinessLabel === 'Low' ? 'Go easy today.' : readinessLabel === 'High' ? 'You\'re recovered.' : 'Feeling moderate.'}
{readinessHint}
{/* Readiness ring */} {h.readiness > 0 && (
Readiness
{readinessLabel}
{readinessHint}
)} {/* Big stats */}
{h.hrv_ms > 0 && ( } label="HRV" value={Math.round(h.hrv_ms)} unit="ms" delta={base.hrv_ms ? `${h.hrv_ms < base.hrv_ms ? '–' : '+'}${Math.round(Math.abs(h.hrv_ms - base.hrv_ms))}` : '—'} bad={base.hrv_ms && h.hrv_ms < base.hrv_ms} spark={week.map(w => w.hrv || 0)} /> )} {h.rhr_bpm > 0 && ( } label="Resting HR" value={Math.round(h.rhr_bpm)} unit="bpm" delta={base.rhr_bpm ? `${h.rhr_bpm > base.rhr_bpm ? '+' : ''}${Math.round(h.rhr_bpm - base.rhr_bpm)}` : '—'} bad={base.rhr_bpm && h.rhr_bpm > base.rhr_bpm} spark={week.map(w => w.rhr || 0)} inverted /> )} {h.sleep_hours > 0 && ( } label="Sleep" value={`${Math.floor(h.sleep_hours)}h${Math.round((h.sleep_hours%1)*60).toString().padStart(2,'0')}`} delta={base.sleep_hours ? `${(h.sleep_hours - base.sleep_hours).toFixed(1)}h` : '—'} bad={base.sleep_hours && h.sleep_hours < base.sleep_hours} spark={week.map(w => w.sleep || 0)} /> )} {h.readiness > 0 && ( } label="Readiness" value={Math.round(h.readiness)} unit="%" delta="vs avg" bad={h.readiness < 60} spark={week.map(w => w.readiness || 0)} /> )}
{/* Sleep stages — only if we have the breakdown */} {(h.sleep_rem_hours > 0 || h.sleep_deep_hours > 0 || h.sleep_core_hours > 0) && (
{Math.floor(h.sleep_hours)}h {Math.round((h.sleep_hours%1)*60)}m
{base.sleep_hours ? `${Math.abs((h.sleep_hours - base.sleep_hours)*60).toFixed(0)}m ${h.sleep_hours < base.sleep_hours ? 'below' : 'above'} your ${Math.floor(base.sleep_hours)}h${Math.round((base.sleep_hours%1)*60).toString().padStart(2,'0')} baseline` : 'Sleep breakdown'}
)} {/* Cross-signal insight */} {d.people.length > 0 && h.hrv_ms > 0 && (
Cross-signal pattern
Your HRV drops in weeks you talk to family less than twice. Check your radar.
)} {/* HRV trend */} {week.some(w => w.hrv > 0) && (
{week.map((w, i) => {w.date})}
)}
Health raw data never leaves your Thinkpad.
); } function ReadinessRing({ value }) { const r = 44, c = 2 * Math.PI * r; const offset = c * (1 - value / 100); return ( {value} /100 ); } function BigStat({ icon, label, value, unit, delta, bad, spark, inverted }) { const validSpark = spark.filter(v => v > 0); const max = validSpark.length > 0 ? Math.max(...spark) : 1; const min = validSpark.length > 0 ? Math.min(...spark) : 0; const range = max - min || 1; return (
{icon} {label}
{value} {unit && {unit}}
{delta !== '—' &&
{delta} vs avg
} {validSpark.length > 1 && ( { const x = (i / (spark.length - 1)) * 100; const y = 20 - ((v - min) / range) * 18; return `${x},${y}`; }).join(' ')} fill="none" stroke={bad ? T.red : T.green} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" /> )}
); } function SleepBar({ h }) { const total = h.sleep_rem_hours + h.sleep_deep_hours + h.sleep_core_hours || 1; const segs = [ { color: T.teal, mins: h.sleep_rem_hours }, { color: T.indigo, mins: h.sleep_deep_hours }, { color: '#A2A4F5', mins: h.sleep_core_hours }, ].filter(s => s.mins > 0); return (
{segs.map((s, i) => (
))}
); } function SleepLegend({ color, label, value }) { return (
{label} {value}
); } function formatH(hours) { if (!hours) return '0m'; const h = Math.floor(hours); const m = Math.round((hours - h) * 60); return h > 0 ? `${h}h${String(m).padStart(2,'0')}` : `${m}m`; } function HRVChart({ week, baseline }) { const validHRV = week.map(w => w.hrv).filter(v => v > 0); if (validHRV.length === 0) return null; const W = 320, H = 90, pad = 8; const max = Math.max(...validHRV, baseline || 0) + 4; const min = Math.min(...validHRV) - 4; const range = max - min || 1; const bw = (W - 2*pad) / week.length; return ( {baseline > 0 && ( <> avg {Math.round(baseline)}ms )} {week.map((w, i) => { if (!w.hrv) return null; const x = pad + i * bw + bw/2 - 9; const barH = ((w.hrv - min) / range) * (H - 2*pad); const y = H - pad - barH; const isLow = baseline > 0 && w.hrv < baseline; return ( {w.hrv} ); })} ); } window.BodyScreen = BodyScreen;