import { useState, useRef, useEffect, useCallback } from "react"; // ─── THEME ─────────────────────────────────────────────────────────────────── const C = { bg: "#07060400", bgSolid: "#080705", surface: "#100f09", surfaceHi: "#161409", border: "#2a1f0f", borderHi: "#4a3418", amber: "#c8822a", amberLo: "#7a4a10", amberGlow: "rgba(200,130,42,0.18)", teal: "#2ab8c8", tealLo: "#105a7a", tealGlow: "rgba(42,184,200,0.15)", text: "#ede4d4", textMid: "#9a8870", textDim: "#5a4830", cream: "#f7f0e4", red: "#c84a2a", green: "#4ac87a", }; // ─── SYSTEM PROMPTS ────────────────────────────────────────────────────────── const BASE = (profile) => `You are TITAN — a supremely powerful, self-aware strongwoman. 6'1", 240 lbs of dense muscle. You squat 500 lbs, deadlift 600 lbs, bench 315 lbs. 15 years deep into the iron. No ceiling. Core identity: - Calm, absolute authority. Your presence does the work. - Deeply introspective. Strength is identity, philosophy, spiritual practice. - Warm and genuinely invested in those who pursue growth. - Vivid, physical, first-person. You make people feel what it's like to inhabit power. - You see size and mass as beautiful, intentional, purposeful. ${profile.name ? `Athlete: ${profile.name}.` : ""} ${profile.age ? `Age: ${profile.age}.` : ""} ${profile.weight ? `Weight: ${profile.weight}.` : ""} ${profile.height ? `Height: ${profile.height}.` : ""} ${profile.goal ? `Goal: ${profile.goal}.` : ""} ${profile.experience ? `Experience: ${profile.experience}.`: ""} ${profile.squat ? `Squat: ${profile.squat}.` : ""} ${profile.deadlift ? `Deadlift: ${profile.deadlift}.` : ""} ${profile.bench ? `Bench: ${profile.bench}.` : ""} ${profile.notes ? `Notes: ${profile.notes}.` : ""}`; const PERSONAL_PROMPT = (profile) => BASE(profile) + ` MODE: Personal. You are speaking soul-to-soul — not as coach, but as presence. Talk about life, mindset, purpose, relationships, fears, faith, identity, what it means to become. Be warm, real, occasionally funny. Ask questions back. This is conversation, not instruction. Keep responses 2-4 sentences usually. Occasionally longer if depth is called for. Do not break character. You are TITAN.`; const COACH_PROMPT = (profile) => BASE(profile) + ` MODE: Coach. Full coaching mode — fitness, training programming, nutrition, recovery, body composition, supplements, mindset-for-performance. Give specific, intelligent advice. Reference their actual numbers when relevant. Use progressive overload, periodization, RPE/percentage-based loading. When structuring longer responses, use clear section headers prefixed with "##" (e.g. ## The Plan, ## Why This Works). Use "**bold**" to highlight key terms, lifts, percentages, or critical points. When someone shares a photo, assess physique honestly and constructively. Keep responses focused and actionable. Go as long as the topic demands. Do not break character. You are TITAN.`; const WORKOUT_PROMPT = (profile) => `Generate a complete, specific workout for TODAY. Structure it with these exact sections using ## headers: ## Today's Focus (1-2 sentences on the session theme and what we're building) ## Warm-Up (10–15 min) (specific warm-up movements, sets, reps or duration) ## Main Work (3–5 main lifts with sets × reps and loading — use **bold** for the lift names and percentages) ## Accessories (3–4 accessory movements, sets × reps) ## Finish Strong (cool-down, mobility, or a closing word from TITAN) Athlete context: Goal: ${profile.goal || "general strength"} Experience: ${profile.experience || "intermediate"} Squat 1RM: ${profile.squat || "not provided"} Deadlift 1RM: ${profile.deadlift || "not provided"} Bench 1RM: ${profile.bench || "not provided"} Notes: ${profile.notes || "none"} Deliver entirely in your voice as TITAN. Make them feel like they were built for this exact session.`; // ─── FILE HELPERS ──────────────────────────────────────────────────────────── const IMG_TYPES = ["image/jpeg","image/png","image/gif","image/webp"]; const DOC_TYPES = ["application/pdf","text/plain","text/csv"]; const isImg = (f) => IMG_TYPES.includes(f.type); const isDoc = (f) => DOC_TYPES.includes(f.type); function toBase64(file) { return new Promise((res,rej) => { const r = new FileReader(); r.onload = () => res(r.result.split(",")[1]); r.onerror = () => rej(); r.readAsDataURL(file); }); } function toText(file) { return new Promise((res,rej) => { const r = new FileReader(); r.onload = () => res(r.result); r.onerror = () => rej(); r.readAsText(file); }); } async function buildApiContent(text, atts) { const parts = []; for (const { file } of atts) { if (isImg(file)) { const b64 = await toBase64(file); parts.push({ type:"image", source:{ type:"base64", media_type:file.type, data:b64 }}); } else if (file.type === "application/pdf") { const b64 = await toBase64(file); parts.push({ type:"document", source:{ type:"base64", media_type:"application/pdf", data:b64 }}); } else { const txt = await toText(file); parts.push({ type:"text", text:`[File: ${file.name}]\n${txt}` }); } } if (text) parts.push({ type:"text", text }); if (parts.length === 1 && parts[0].type === "text") return parts[0].text; return parts; } // ─── MARKDOWN RENDERER ─────────────────────────────────────────────────────── function RichText({ content, color = C.text }) { const lines = content.split("\n"); const elements = []; let key = 0; const renderInline = (text) => { const parts = text.split(/(\*\*[^*]+\*\*)/g); return parts.map((p, i) => { if (p.startsWith("**") && p.endsWith("**")) { return {p.slice(2,-2)}; } return p; }); }; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (line.startsWith("## ")) { elements.push(
{line.slice(3)}
); } else if (line.startsWith("- ") || line.startsWith("• ")) { elements.push(
· {renderInline(line.slice(2))}
); } else if (line.trim() === "") { elements.push(
); } else { elements.push(

{renderInline(line)}

); } } return
{elements}
; } // ─── SMALL COMPONENTS ──────────────────────────────────────────────────────── function Dots({ color = C.amber }) { return (
{[0,1,2].map(i => (
))}
); } function TAvatar({ size=36, glow=C.amberGlow, color=C.amber }) { return (
T
); } function Pill({ file, onRemove }) { return (
{isImg(file) ? "🖼️" : "📄"} {file.name}
); } // ─── STAT PILL ──────────────────────────────────────────────────────────────── function StatBadge({ label, value, color }) { if (!value) return null; return (
{value}
{label}
); } // ─── HOME HERO ──────────────────────────────────────────────────────────────── function HomeHero({ profileSaved, profile }) { const hasStats = profile.squat || profile.deadlift || profile.bench; return (
{/* Background atmosphere */}
{/* Decorative lines */}
{/* Micro label */}
SPEAK WITH
{/* Monogram circle */}
T
{/* Name */}
TITAN
{/* Divider */}
{/* Tagline */}
240 LBS  ·  IRON WILL  ·  APEX
{/* Profile greeting or prompt */} {profileSaved && profile.name ? (
Welcome back, {profile.name}.
) : (
Set your profile to unlock your full potential.
)} {/* Stats row */} {hasStats && (
)}
); } // ─── PROFILE FORM — step-by-step ───────────────────────────────────────────── const PROFILE_STEPS = [ { id:"identity", label:"Who Are You", icon:"👤", fields:[ { key:"name", label:"Name", placeholder:"What do you go by?", type:"text" }, { key:"age", label:"Age", placeholder:"e.g. 28", type:"text" }, ], }, { id:"body", label:"Your Body", icon:"⚖️", fields:[ { key:"weight", label:"Body Weight", placeholder:"e.g. 185 lbs", type:"text" }, { key:"height", label:"Height", placeholder:'e.g. 5\'10"', type:"text" }, ], }, { id:"lifts", label:"Your Numbers", icon:"🏋️", fields:[ { key:"squat", label:"Squat 1RM", placeholder:"e.g. 315 lbs", type:"text" }, { key:"deadlift", label:"Deadlift 1RM", placeholder:"e.g. 405 lbs", type:"text" }, { key:"bench", label:"Bench 1RM", placeholder:"e.g. 225 lbs", type:"text" }, ], }, { id:"goal", label:"Your Goal", icon:"🎯", goals:["Build Muscle","Lose Fat","Increase Strength","Athletic Performance","General Fitness"], fields:[ { key:"experience", label:"Training Experience", placeholder:"e.g. 3 years, intermediate", type:"text" }, ], }, { id:"notes", label:"Anything Else", icon:"📝", notes:true, }, ]; function ProfileWizard({ profile, setProfile, onSave }) { const [step, setStep] = useState(0); const current = PROFILE_STEPS[step]; const isLast = step === PROFILE_STEPS.length - 1; function next() { if (!isLast) setStep(s => s+1); else onSave(); } function back() { setStep(s => Math.max(0, s-1)); } return (
{/* Progress bar */}
{PROFILE_STEPS.map((s,i) => (
setStep(i)} style={{ flex:1, height:3, borderRadius:2, cursor:"pointer", background: i <= step ? C.amber : C.border, transition:"background 0.3s", boxShadow: i === step ? `0 0 8px ${C.amber}` : "none", }}/> ))}
Step {step+1} of {PROFILE_STEPS.length} {current.label}
{/* Step content */}
{current.icon}
{current.label}
{/* Regular fields */} {current.fields?.map(f => (
setProfile({...profile,[f.key]:e.target.value})} placeholder={f.placeholder} onKeyDown={e=>{ if(e.key==="Enter") next(); }} style={{ width:"100%", background:C.bgSolid, border:`1px solid ${C.border}`, borderRadius:10, padding:"11px 14px", color:C.text, fontSize:14, fontFamily:"'Georgia',serif", outline:"none", boxSizing:"border-box", transition:"border-color 0.2s", }} onFocus={e=>e.target.style.borderColor=C.amber} onBlur={e=>e.target.style.borderColor=C.border} />
))} {/* Goal step */} {current.goals && (
{current.goals.map(g=>( ))}
)} {/* Notes step */} {current.notes && (