// academy.jsx — Motion Academy Lite (multi-step flow + edge states)
const { useState: useStateA, useEffect: useEffectA, useRef: useRefA } = React;

function Academy({ exit, initial, data, spendEnergy, onReward }) {
  const [step, setStep] = useStateA(initial || 'home');
  const [wk, setWk] = useStateA(null);
  const [lensReport, setLensReport] = useStateA(null);
  const go = (s, payload) => { if (payload !== undefined) setLensReport(payload); setStep(s); };
  const openWorkout = (w) => { setWk(w); go('wkIntro'); };

  const map = {
    home: <AcademyHome go={go} exit={exit} openWorkout={openWorkout}/>,
    tutorial: <AvatarTutorial go={go}/>,
    permission: <CameraPermission go={go}/>,
    denied: <CameraDenied go={go}/>,
    setup: <CameraSetup go={go}/>,
    lens: <MotionLens go={go}/>,
    failed: <LensFailed go={go}/>,
    feedback: <LensFeedback go={go} report={lensReport}/>,
    unlock: <SkillUnlock go={go} exit={exit} report={lensReport}/>,
    wkIntro: <WorkoutIntro go={go} exit={exit} wk={wk} data={data} spendEnergy={spendEnergy}/>,
    wkPlay: <WorkoutPlayer go={go} wk={wk}/>,
    wkDone: <WorkoutDone go={go} exit={exit} wk={wk} onReward={onReward}/>,
  };
  return map[step];
}

// learned exercises you can train as sets (with camera form-check)
const WORKOUTS = [
  { id: 'squat', name: '스쿼트', cat: 'strength', icon: 'dumbbell', reps: 10, sets: 3, sec: 4, xp: 30, cue: '무릎은 발끝 방향으로', steps: ['발은 어깨너비', '천천히 앉기', '일어나며 숨 내쉬기'] },
  { id: 'shoulder', name: '어깨 리셋', cat: 'mobility', icon: 'wind', reps: 8, sets: 2, sec: 3, xp: 20, cue: '어깨를 크게 돌려요', steps: ['어깨를 귀 쪽으로', '뒤로 크게 돌리기', '숨 길게 내쉬기'] },
  { id: 'hinge', name: '힙 힌지', cat: 'strength', icon: 'dumbbell', reps: 10, sets: 3, sec: 4, xp: 30, cue: '엉덩이를 뒤로', steps: ['무릎 살짝 굽히기', '엉덩이 뒤로 밀기', '등은 곧게'] },
  { id: 'breath', name: '회복 호흡', cat: 'recovery', icon: 'leaf', reps: 6, sets: 1, sec: 6, xp: 14, cue: '4초 들이마시고 6초 내쉬기', steps: ['편하게 앉기', '4초 들이마시기', '6초 내쉬기'] },
];

// Real browser camera preview + lightweight on-device frame metrics.
// No image leaves the browser; only brightness/contrast/motion numbers are exposed.
function ensureCameraRuntime() {
  if (window.FitbodyCamera) return window.FitbodyCamera;
  const runtime = {
    current: null,
    last: null,
    tracking: { start: null, peakMotion: 0, frames: 0, bestBox: null },
    attach(session) { this.current = session; },
    detach(session) { if (this.current === session) this.current = null; },
    latest() { return this.last; },
    captureFrame(kind) {
      if (!this.current || !this.current.capture) return { ok: false, kind, status: 'no_camera', capturedAt: new Date().toISOString() };
      return this.current.capture(kind);
    },
    startTracking() { this.tracking = { start: Date.now(), peakMotion: 0, frames: 0, bestBox: null }; },
    updateTracking(frame) {
      if (!frame || !frame.ok || !this.tracking.start) return;
      this.tracking.frames += 1;
      this.tracking.peakMotion = Math.max(this.tracking.peakMotion, frame.motion || 0);
      if (frame.movementBox && (!this.tracking.bestBox || frame.movementBox.active > this.tracking.bestBox.active)) this.tracking.bestBox = frame.movementBox;
    },
    finishTracking() {
      const t = this.tracking;
      const report = { durationMs: t.start ? Date.now() - t.start : 0, peakMotion: t.peakMotion, frames: t.frames, movementBox: t.bestBox, ok: t.frames > 0 };
      this.tracking = { start: null, peakMotion: 0, frames: 0, bestBox: null };
      return report;
    },
    motionScore() { return this.last && typeof this.last.motion === 'number' ? this.last.motion : 0; },
  };
  window.FitbodyCamera = runtime;
  return runtime;
}

function hasMeaningfulCameraMovement(report) {
  if (!report || !report.ok) return false;
  const box = report.movementBox;
  return report.peakMotion > 2 || !!(box && box.active > 8);
}

function cameraBrightnessLabel(frame) {
  if (!frame || !frame.ok) return '확인 필요';
  if (frame.brightness < 45) return '조금 어두움';
  if (frame.brightness > 215) return '너무 밝음';
  return '좋음';
}

function cameraStabilityLabel(frame) {
  if (!frame || !frame.ok) return '확인 필요';
  if (frame.motion > 18) return '움직임 많음';
  if (frame.motion > 6) return '움직임 감지';
  return '안정적';
}

function cameraContrastLabel(frame) {
  if (!frame || !frame.ok) return '확인 필요';
  if (frame.contrast < 18) return '배경과 구분 낮음';
  return '구분 가능';
}

function CameraView({ label = 'CAMERA PREVIEW', guide = true, tint, mirror = true, onFrame }) {
  const videoRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  const prevGray = React.useRef(null);
  const sessionRef = React.useRef(null);
  const [status, setStatus] = React.useState('starting');
  const [metrics, setMetrics] = React.useState(null);
  const [error, setError] = React.useState('');

  React.useEffect(() => {
    const runtime = ensureCameraRuntime();
    let alive = true;
    let stream = null;
    let timer = null;

    function stopStream(s) {
      if (!s) return;
      s.getTracks().forEach(track => track.stop());
    }

    function analyze(kind) {
      const video = videoRef.current;
      const canvas = canvasRef.current;
      if (!video || !canvas || video.readyState < 2 || !video.videoWidth || !video.videoHeight) {
        return { ok: false, kind, status, capturedAt: new Date().toISOString() };
      }
      const w = 64, h = 64;
      canvas.width = w;
      canvas.height = h;
      const ctx = canvas.getContext('2d', { willReadFrequently: true });
      if (!ctx) return { ok: false, kind, status: 'no_canvas', capturedAt: new Date().toISOString() };
      ctx.drawImage(video, 0, 0, w, h);
      const data = ctx.getImageData(0, 0, w, h).data;
      let sum = 0, sumSq = 0, motion = 0;
      let minX = w, minY = h, maxX = 0, maxY = 0, active = 0;
      const gray = new Uint8Array(w * h);
      for (let i = 0, p = 0; i < data.length; i += 4, p++) {
        const y = Math.round(data[i] * 0.2126 + data[i + 1] * 0.7152 + data[i + 2] * 0.0722);
        gray[p] = y;
        sum += y;
        sumSq += y * y;
        if (prevGray.current) {
          const diff = Math.abs(y - prevGray.current[p]);
          motion += diff;
          if (diff > 22) {
            const x = p % w, yy = Math.floor(p / w);
            minX = Math.min(minX, x); maxX = Math.max(maxX, x);
            minY = Math.min(minY, yy); maxY = Math.max(maxY, yy);
            active++;
          }
        }
      }
      const count = gray.length;
      const brightness = sum / count;
      const variance = Math.max(0, (sumSq / count) - brightness * brightness);
      const contrast = Math.sqrt(variance);
      const motionScore = prevGray.current ? motion / count : 0;
      prevGray.current = gray;
      const movementBox = active > 8 ? {
        x: Math.round((minX / w) * 100),
        y: Math.round((minY / h) * 100),
        width: Math.round(((maxX - minX + 1) / w) * 100),
        height: Math.round(((maxY - minY + 1) / h) * 100),
        active,
      } : null;
      const frame = {
        ok: true,
        kind,
        status: 'live',
        brightness: Math.round(brightness),
        contrast: Math.round(contrast),
        motion: Math.round(motionScore),
        movementBox,
        width: video.videoWidth,
        height: video.videoHeight,
        capturedAt: new Date().toISOString(),
      };
      runtime.last = frame;
      return frame;
    }

    const session = { capture: (kind = 'capture') => analyze(kind) };
    sessionRef.current = session;
    runtime.attach(session);

    async function startCamera() {
      if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
        setStatus('unsupported');
        setError('camera API unsupported');
        return;
      }
      try {
        stream = await navigator.mediaDevices.getUserMedia({
          video: { facingMode: 'user', width: { ideal: 720 }, height: { ideal: 1280 } },
          audio: false,
        });
        if (!alive) {
          stopStream(stream);
          return;
        }
        const video = videoRef.current;
        if (video) {
          video.srcObject = stream;
          await video.play().catch(() => {});
        }
        setStatus('live');
        timer = setInterval(() => {
          const frame = analyze('preview');
          if (frame.ok) {
            setMetrics(frame);
            runtime.updateTracking(frame);
            if (onFrame) onFrame(frame);
          }
        }, 500);
      } catch (err) {
        setStatus('blocked');
        setError(err && (err.name || err.message) ? (err.name || err.message) : 'camera unavailable');
      }
    }

    startCamera();
    return () => {
      alive = false;
      if (timer) clearInterval(timer);
      runtime.detach(session);
      stopStream(stream);
    };
  }, []);

  const live = status === 'live';
  const dot = live ? T.good : status === 'starting' ? T.amber : '#FF4D4D';
  const statusText = live ? (metrics ? `${cameraBrightnessLabel(metrics)} · ${cameraStabilityLabel(metrics)}` : 'LIVE') : status === 'starting' ? '카메라 시작 중' : status === 'unsupported' ? '카메라 미지원' : '카메라 권한 필요';
  return (
    <div style={{
      position: 'relative', width: '100%', flex: 1, borderRadius: 24, overflow: 'hidden',
      background: `repeating-linear-gradient(135deg, #2A2926 0 14px, #232220 14px 28px)`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <video ref={videoRef} muted playsInline autoPlay style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', transform: mirror ? 'scaleX(-1)' : 'none', opacity: live ? 1 : 0 }}/>
      <canvas ref={canvasRef} style={{ display: 'none' }}/>
      {!live && (
        <div style={{ textAlign: 'center', color: 'rgba(255,255,255,0.84)', padding: 20, maxWidth: 250 }}>
          <Icon name={status === 'blocked' ? 'camera_off' : 'cameraline'} size={38} color="rgba(255,255,255,0.84)" sw={1.8}/>
          <div style={{ fontSize: 15, fontWeight: 800, marginTop: 12 }}>{statusText}</div>
          <div style={{ fontSize: 12.5, fontWeight: 600, opacity: 0.72, marginTop: 6 }}>{error || '브라우저 권한 창에서 카메라를 허용하세요'}</div>
        </div>
      )}
      {guide && (
        <svg width="120" height="220" viewBox="0 0 120 220" style={{ position: 'relative', opacity: live ? 0.62 : 0.5, filter: live ? 'drop-shadow(0 2px 8px rgba(0,0,0,0.35))' : 'none' }}>
          <circle cx="60" cy="34" r="20" fill="none" stroke={tint || T.coral} strokeWidth="3"/>
          <path d="M60 54v70M60 70l-34 22M60 70l34 22M60 124l-22 78M60 124l22 78" fill="none" stroke={tint || T.coral} strokeWidth="3" strokeLinecap="round"/>
        </svg>
      )}
      <div style={{ position: 'absolute', top: 14, left: 14, display: 'flex', alignItems: 'center', gap: 6, padding: '5px 10px', borderRadius: 8, background: 'rgba(0,0,0,0.48)' }}>
        <span style={{ width: 7, height: 7, borderRadius: 999, background: dot }}/>
        <span style={{ fontFamily: 'ui-monospace, Menlo, monospace', fontSize: 10.5, color: 'rgba(255,255,255,0.86)', letterSpacing: 0.5 }}>{live ? label : statusText.toUpperCase()}</span>
      </div>
      {live && metrics && (
        <div style={{ position: 'absolute', left: 14, bottom: 14, padding: '6px 10px', borderRadius: 9, background: 'rgba(0,0,0,0.48)', color: '#fff', fontSize: 11.5, fontWeight: 800 }}>
          밝기 {metrics.brightness} · 움직임 {metrics.motion}
        </div>
      )}
      {[[14,14,'tl'],[14,14,'tr'],[14,14,'bl'],[14,14,'br']].map((_,i)=>{
        const pos = ['tl','tr','bl','br'][i];
        const s = { position:'absolute', width:26, height:26, borderColor:'rgba(255,255,255,0.5)', borderStyle:'solid', borderWidth:0 };
        if(pos[0]==='t'){s.top=14;s.borderTopWidth=3;}else{s.bottom=14;s.borderBottomWidth=3;}
        if(pos[1]==='l'){s.left=14;s.borderLeftWidth=3;}else{s.right=14;s.borderRightWidth=3;}
        return <div key={i} style={s}/>;
      })}
    </div>
  );
}

function AcademyHome({ go, exit, openWorkout }) {
  const path = [
    { g: 'Mobility', items: [{ t: 'Neck Reset', done: true }, { t: 'Shoulder Reset', cur: true }, { t: 'Hip Opener' }] },
    { g: 'Strength Basics', items: [{ t: 'Squat Setup 1', cur: true }, { t: 'Hip Hinge 1' }, { t: 'Push-up Setup 1' }] },
    { g: 'Recovery', items: [{ t: 'Breath Reset', done: true }, { t: 'Sleep Prep' }, { t: 'Body Scan' }] },
  ];
  return (
    <Screen bg={T.surface} nav="academy">
      <TopBar title="Motion Academy"/>
      <AvaSays size={42} style={{ marginBottom: 18 }}>움직임을 잘하는 법을 하나씩 배워볼게요. 오늘은 무릎 방향만 봐요.</AvaSays>

      <Card pad={22} style={{ marginBottom: 18, background: `linear-gradient(150deg, ${T.calmSoft}, ${T.bg})` }}>
        <div style={{ fontSize: 12, fontWeight: 800, color: T.calm, letterSpacing: 1 }}>TODAY'S SKILL</div>
        <div style={{ fontSize: 26, fontWeight: 800, color: T.ink, letterSpacing: -0.6, margin: '6px 0 14px' }}>Squat Setup 1</div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 18 }}>
          {['아바타 튜토리얼', '카메라 체크 (선택)', 'Skill Unlock'].map((s, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{ width: 24, height: 24, borderRadius: 999, background: T.bg, boxShadow: `inset 0 0 0 1.5px ${T.calm}`, color: T.calm, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, fontWeight: 800 }}>{i + 1}</div>
              <span style={{ fontSize: 15, fontWeight: 600, color: T.ink }}>{s}</span>
            </div>
          ))}
        </div>
        <Btn variant="calm" onClick={() => go('tutorial')} icon={<Icon name="play" size={19} color="#fff"/>}>아바타 튜토리얼 시작</Btn>
        <Btn variant="soft" size="md" style={{ marginTop: 10 }} onClick={() => go('permission')} icon={<Icon name="cameraline" size={19} color={T.ink}/>}>카메라로 자세 체크</Btn>
        <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginTop: 12, padding: '10px 12px', borderRadius: 12, background: T.calmSoft }}>
          <Icon name="sparkle" size={16} color={T.calm}/>
          <span style={{ fontSize: 12.5, fontWeight: 700, color: T.calmDark, lineHeight: 1.4 }}>카메라 움직임이 감지되면 <b>보너스 XP</b>와 League 점수가 더 들어가요</span>
        </div>
      </Card>

      <div style={{ fontSize: 13, fontWeight: 800, color: T.ink3, letterSpacing: 0.6, margin: '4px 2px 12px' }}>배운 운동 하기</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 20 }}>
        {WORKOUTS.map(w => {
          const c = catColor(w.cat);
          return (
            <button key={w.id} onClick={() => openWorkout(w)} style={{ display: 'flex', alignItems: 'center', gap: 13, width: '100%', textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit', background: T.bg, border: 'none', borderRadius: 18, padding: 14, boxShadow: '0 1px 3px rgba(0,0,0,0.05)' }}>
              <div style={{ width: 46, height: 46, borderRadius: 13, background: c.s, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                <Icon name={w.icon} size={23} color={c.c} fill={w.icon === 'leaf' ? 'none' : 'none'} sw={2}/>
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 16, fontWeight: 700, color: T.ink, letterSpacing: -0.3 }}>{w.name}</div>
                <div style={{ fontSize: 13, color: T.ink3, fontWeight: 600, marginTop: 1 }}>{w.sets}세트 · {w.reps}회 · 카메라 자세 체크</div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0, padding: '6px 9px', borderRadius: 9, background: T.tealSoft }}>
                <Icon name="bolt" size={13} color={T.tealDark} fill={T.tealDark} sw={0}/>
                <span style={{ fontSize: 12.5, fontWeight: 800, color: T.tealDark }}>1</span>
              </div>
            </button>
          );
        })}
      </div>

      <div style={{ fontSize: 13, fontWeight: 800, color: T.ink3, letterSpacing: 0.6, margin: '4px 2px 12px' }}>Skill Path</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
        {path.map(p => (
          <Card key={p.g} pad={16}>
            <div style={{ fontSize: 14, fontWeight: 800, color: T.ink, marginBottom: 12 }}>{p.g}</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
              {p.items.map(it => (
                <div key={it.t} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <div style={{ width: 22, height: 22, borderRadius: 999, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center',
                    background: it.done ? T.calm : it.cur ? T.coralTint : T.surface2 }}>
                    {it.done ? <Icon name="check" size={13} color="#fff" sw={2.8}/> : it.cur ? <span style={{ width: 7, height: 7, borderRadius: 999, background: T.coral }}/> : <Icon name="lock" size={11} color={T.ink3} sw={2}/>}
                  </div>
                  <span style={{ fontSize: 14.5, fontWeight: it.cur ? 700 : 600, color: it.done ? T.ink2 : it.cur ? T.ink : T.ink3 }}>{it.t}</span>
                  {it.cur && <span style={{ fontSize: 11, fontWeight: 800, color: T.coral, letterSpacing: 0.4 }}>오늘</span>}
                </div>
              ))}
            </div>
          </Card>
        ))}
      </div>
      <div style={{ height: 12 }}/>
    </Screen>
  );
}

function AvatarTutorial({ go }) {
  return (
    <div style={{ position: 'absolute', inset: 0, background: T.surface, display: 'flex', flexDirection: 'column' }}>
      <StatusBar/>
      <div style={{ padding: '54px 22px 0' }}><TopBar title="Squat Setup 1" onBack={() => go('home')}/></div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '0 22px', gap: 16 }}>
        {/* avatar loop */}
        <div style={{ flex: 1, borderRadius: 24, background: `radial-gradient(120% 90% at 50% 20%, ${T.calmSoft}, ${T.bg})`, display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', overflow: 'hidden' }}>
          <div style={{ position: 'absolute', bottom: 0, width: '70%', height: 8, borderRadius: '50%', background: 'rgba(28,27,25,0.06)', filter: 'blur(4px)' }}/>
          <svg width="150" height="240" viewBox="0 0 150 240" style={{ animation: 'avatarBob 2.6s ease-in-out infinite' }}>
            <circle cx="75" cy="40" r="24" fill={T.calm}/>
            <rect x="58" y="66" width="34" height="74" rx="17" fill={T.calm}/>
            <path d="M58 96l-26 26M92 96l26 26" stroke={T.calm} strokeWidth="15" strokeLinecap="round"/>
            <path d="M64 138l-14 64M86 138l14 64" stroke={T.calm} strokeWidth="16" strokeLinecap="round"/>
            <path d="M50 206h22M78 206h22" stroke={T.coral} strokeWidth="4" strokeLinecap="round" opacity="0.8"/>
          </svg>
          <div style={{ position: 'absolute', top: 16, left: 16, fontFamily: 'ui-monospace, monospace', fontSize: 11, color: T.calm, fontWeight: 700, letterSpacing: 0.5 }}>AVATAR LOOP</div>
        </div>
        <Card pad={18} style={{ background: T.bg }}>
          <div style={{ fontSize: 12, fontWeight: 800, color: T.coral, letterSpacing: 0.8, marginBottom: 4 }}>오늘의 포인트</div>
          <div style={{ fontSize: 18, fontWeight: 800, color: T.ink, letterSpacing: -0.3, marginBottom: 8 }}>무릎은 발끝 방향으로</div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <AvaOrb size={30} speaking/>
            <div style={{ fontSize: 14.5, color: T.ink2, fontWeight: 500 }}>“발은 어깨너비, 깊이보다 방향만 신경 써요.”</div>
          </div>
        </Card>
      </div>
      <div style={{ padding: '14px 22px 32px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <Btn variant="soft" size="md" onClick={() => go('permission')} icon={<Icon name="cameraline" size={19} color={T.ink}/>}>카메라로 체크하기 (+15 보너스)</Btn>
        <Btn variant="calm" onClick={() => go('feedback')}>따라 해봤어요 · 완료</Btn>
      </div>
    </div>
  );
}

function CameraPermission({ go }) {
  return (
    <Screen bg={T.bg}>
      <div style={{ paddingTop: 8 }}><TopBar title="" onBack={() => go('home')}/></div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', paddingTop: 20 }}>
        <div style={{ width: 88, height: 88, borderRadius: 26, background: T.calmSoft, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 24 }}>
          <Icon name="cameraline" size={42} color={T.calm} sw={1.8}/>
        </div>
        <h1 style={{ fontSize: 24, fontWeight: 800, color: T.ink, letterSpacing: -0.5, lineHeight: 1.3, margin: '0 0 10px' }}>카메라로 자세를<br/>확인할까요?</h1>
        <p style={{ fontSize: 15.5, color: T.ink2, lineHeight: 1.5, maxWidth: 290, margin: '0 0 16px' }}>무릎과 상체 각도를 더 정확히 볼 수 있어요. 카메라는 <b style={{ color: T.ink }}>자세 분석에만</b> 사용되고 저장되지 않아요.</p>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '8px 14px', borderRadius: 999, background: T.surface, fontSize: 13, fontWeight: 600, color: T.ink2 }}>
          <Icon name="lock" size={15} color={T.good} sw={2}/>영상은 기기를 벗어나지 않아요
        </div>
      </div>
      <FloatCTA>
        <Btn variant="calm" onClick={() => go('setup')} icon={<Icon name="cameraline" size={19} color="#fff"/>}>카메라 허용하고 체크</Btn>
        <Btn variant="ghost" size="md" style={{ marginTop: 6 }} onClick={() => go('denied')}>지금은 허용 안 함</Btn>
      </FloatCTA>
    </Screen>
  );
}

function CameraDenied({ go }) {
  return (
    <Screen bg={T.bg}>
      <div style={{ paddingTop: 8 }}><TopBar title="" onBack={() => go('permission')}/></div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', paddingTop: 20 }}>
        <div style={{ width: 88, height: 88, borderRadius: 26, background: T.surface2, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 24 }}>
          <Icon name="camera_off" size={42} color={T.ink3} sw={1.8}/>
        </div>
        <h1 style={{ fontSize: 23, fontWeight: 800, color: T.ink, letterSpacing: -0.5, lineHeight: 1.3, margin: '0 0 10px' }}>카메라 없이도<br/>레슨을 계속할 수 있어요</h1>
        <p style={{ fontSize: 15.5, color: T.ink2, lineHeight: 1.5, maxWidth: 290, margin: 0 }}>Ava 아바타가 먼저 자세를 보여드릴게요. 카메라는 언제든 나중에 켤 수 있어요.</p>
      </div>
      <FloatCTA>
        <Btn variant="calm" onClick={() => go('tutorial')}>아바타 튜토리얼 계속</Btn>
        <Btn variant="ghost" size="md" style={{ marginTop: 6 }} onClick={() => go('permission')}>설정에서 카메라 켜기</Btn>
      </FloatCTA>
    </Screen>
  );
}

function CameraSetup({ go }) {
  const checks = ['전신이 화면에 들어오나요?', '바닥이 보이나요?', '팔을 벌릴 공간이 있나요?', '조명이 너무 어둡지 않나요?'];
  return (
    <div style={{ position: 'absolute', inset: 0, background: T.ink, display: 'flex', flexDirection: 'column' }}>
      <StatusBar light/>
      <div style={{ padding: '54px 22px 0' }}><TopBar title="카메라 세팅" light onBack={() => go('permission')} transparent/></div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '8px 22px 0' }}>
        <CameraView label="SETUP CHECK" tint={T.calm}/>
        <div style={{ padding: '18px 2px 0', display: 'flex', flexDirection: 'column', gap: 10 }}>
          {checks.map((c, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
              <div style={{ width: 24, height: 24, borderRadius: 999, background: T.calm, display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="check" size={14} color="#fff" sw={2.8}/></div>
              <span style={{ fontSize: 15, color: '#fff', fontWeight: 500 }}>{c}</span>
            </div>
          ))}
        </div>
      </div>
      <div style={{ padding: '16px 22px 32px' }}>
        <Btn variant="calm" onClick={() => go('lens')}>체크 시작</Btn>
      </div>
    </div>
  );
}

function MotionLens({ go }) {
  const [count, setCount] = useStateA(3);
  const [running, setRunning] = useStateA(false);
  useEffectA(() => {
    const camera = ensureCameraRuntime();
    if (count === 0) {
      setRunning(true);
      camera.startTracking();
      const t = setTimeout(() => {
        const report = camera.finishTracking();
        if (window.FitbodyBackend && window.FitbodyBackend.recordMotionLens) {
          window.FitbodyBackend.recordMotionLens(report).catch(() => {});
        }
        go('feedback', report);
      }, 3200);
      return () => clearTimeout(t);
    }
    const t = setTimeout(() => setCount(c => c - 1), 800);
    return () => clearTimeout(t);
  }, [count]);
  return (
    <div style={{ position: 'absolute', inset: 0, background: T.ink, display: 'flex', flexDirection: 'column' }}>
      <StatusBar light/>
      <div style={{ padding: '54px 22px 0' }}><TopBar title="Motion Lens" light transparent right={
        <button onClick={() => go('failed', null)} style={{ background: 'rgba(255,255,255,0.12)', border: 'none', borderRadius: 999, color: 'rgba(255,255,255,0.8)', fontSize: 12.5, fontWeight: 700, padding: '8px 12px', cursor: 'pointer', fontFamily: 'inherit' }}>인식이 안 돼요</button>
      }/></div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '8px 22px 0' }}>
        <div style={{ position: 'relative', flex: 1, display: 'flex' }}>
          <CameraView label={running ? 'TRACKING' : 'READY'} tint={running ? T.good : T.calm}/>
          {!running && count > 0 && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <div key={count} style={{ fontSize: 110, fontWeight: 800, color: '#fff', animation: 'popNum .6s ease' }}>{count}</div>
            </div>
          )}
        </div>
      </div>
      <div style={{ padding: '20px 22px 36px', textAlign: 'center' }}>
        {running ? (
          <>
            <div style={{ fontSize: 22, fontWeight: 800, color: '#fff', marginBottom: 6 }}>천천히 내려가요</div>
            <div style={{ fontSize: 15, color: 'rgba(255,255,255,0.65)', fontWeight: 600 }}>무릎은 발끝 방향으로</div>
          </>
        ) : (
          <div style={{ fontSize: 16, color: 'rgba(255,255,255,0.7)', fontWeight: 600 }}>준비되면 1회만 천천히 앉았다 일어나세요</div>
        )}
      </div>
    </div>
  );
}

function LensFailed({ go }) {
  return (
    <Screen bg={T.bg}>
      <div style={{ paddingTop: 8 }}><TopBar title="" onBack={() => go('home')}/></div>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', paddingTop: 16 }}>
        <div style={{ width: 84, height: 84, borderRadius: 24, background: T.surface2, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 22 }}>
          <Icon name="cameraline" size={40} color={T.ink3} sw={1.8}/>
        </div>
        <h1 style={{ fontSize: 22, fontWeight: 800, color: T.ink, letterSpacing: -0.4, lineHeight: 1.3, margin: '0 0 14px' }}>자세를 충분히<br/>읽지 못했어요</h1>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 11, textAlign: 'left', background: T.surface, padding: 16, borderRadius: 20, maxWidth: 320 }}>
          <AvaOrb size={34} speaking/>
          <div style={{ fontSize: 14.5, lineHeight: 1.5, color: T.ink, fontWeight: 500 }}>“문제 없어요. 오늘은 아바타 기준으로 연습하고 Skill XP를 일부 받을 수 있어요.”</div>
        </div>
        <div style={{ marginTop: 16, padding: '12px 16px', borderRadius: 14, background: T.amberSoft, fontSize: 13.5, color: T.amberDark, fontWeight: 600, maxWidth: 320 }}>
          전신이 화면에 들어오도록 폰을 조금 더 멀리 두면 도움이 돼요.
        </div>
      </div>
      <FloatCTA>
        <Btn variant="soft" size="md" style={{ marginBottom: 8 }} onClick={() => go('unlock')}>아바타로 완료 (+10 XP)</Btn>
        <Btn variant="calm" onClick={() => go('setup')}>다시 체크하기</Btn>
      </FloatCTA>
    </Screen>
  );
}

function LensFeedback({ go, report }) {
  const movementSeen = hasMeaningfulCameraMovement(report);
  const primaryLine = movementSeen ? '카메라가 실제 움직임을 감지했어요.' : '움직임 신호가 적어서 오늘은 참고용 기록으로 남길게요.';
  const nextLine = movementSeen ? '움직임 기록을 바탕으로 다음 연습을 이어가요.' : '조명과 거리만 맞춘 뒤 다시 체크하면 더 정확해져요.';
  return (
    <Screen bg={T.bg}>
      <div style={{ paddingTop: 8 }}><TopBar title="Motion Feedback"/></div>
      <div style={{ paddingTop: 6 }}>
        <Card pad={20} style={{ marginBottom: 12, background: movementSeen ? T.goodSoft : T.amberSoft }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
            <Icon name={movementSeen ? 'check' : 'cameraline'} size={20} color={movementSeen ? T.good : T.amber} sw={2.6}/>
            <span style={{ fontSize: 15, fontWeight: 800, color: movementSeen ? T.good : T.amberDark }}>{movementSeen ? '감지됐어요' : '참고용'}</span>
          </div>
          <div style={{ fontSize: 16, color: T.ink, fontWeight: 600, lineHeight: 1.45 }}>{primaryLine}</div>
        </Card>
        <Card pad={20} style={{ marginBottom: 18 }}>
          <div style={{ fontSize: 12, fontWeight: 800, color: T.coral, letterSpacing: 0.6, marginBottom: 6 }}>다음에 하나만 신경 쓸 것</div>
          <div style={{ fontSize: 16, color: T.ink, fontWeight: 600, lineHeight: 1.45 }}>{nextLine}</div>
        </Card>
        <div style={{ borderRadius: 18, background: T.calmSoft, padding: 16, marginBottom: 8 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 12 }}>
            <Icon name="cameraline" size={17} color={T.calmDark} sw={2}/>
            <span style={{ fontSize: 12.5, fontWeight: 800, color: T.calmDark, letterSpacing: 0.4 }}>{movementSeen ? '카메라 움직임 기록 — 보너스 적립' : '참고 기록 — 카메라 보너스 없음'}</span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
            {movementSeen ? [['Skill 기본', '+15', false], ['카메라 움직임 감지', '+10', true], ['오늘 첫 카메라 체크', '+5', true]] : [['Skill 기본', '+15', false], ['카메라 참고 기록', '+0', true], ['다시 체크 가능', '+0', true]].map((r, i) => (
              <div key={i} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
                <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 14, fontWeight: 600, color: T.ink }}>{r[2] && <Icon name="sparkle" size={14} color={T.calm}/>}{r[0]}</span>
                <span style={{ fontSize: 15, fontWeight: 800, color: r[2] ? T.calmDark : T.ink2, fontVariantNumeric: 'tabular-nums' }}>{r[1]}</span>
              </div>
            ))}
            <div style={{ height: 1, background: 'rgba(71,111,137,0.18)', margin: '2px 0' }}/>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <span style={{ fontSize: 15, fontWeight: 800, color: T.ink }}>Skill XP 합계</span>
              <span style={{ fontSize: 19, fontWeight: 800, color: T.calmDark }}>{movementSeen ? '+30 XP' : '+15 XP'}</span>
            </div>
          </div>
        </div>
      </div>
      <FloatCTA>
        <Btn variant="soft" size="md" style={{ marginBottom: 8 }} onClick={() => go('setup')}>다시 해보기</Btn>
        <Btn variant="calm" onClick={() => go('unlock')}>Skill Unlock 보기</Btn>
      </FloatCTA>
    </Screen>
  );
}

function SkillUnlock({ go, exit, report }) {
  const movementSeen = hasMeaningfulCameraMovement(report);
  return (
    <div style={{ position: 'absolute', inset: 0, background: T.bg, display: 'flex', flexDirection: 'column' }}>
      <StatusBar/>
      <Confetti/>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '54px 30px 0', textAlign: 'center' }}>
        <div style={{ animation: 'badgeFlip .7s cubic-bezier(.2,1,.3,1)', marginBottom: 24 }}>
          <div style={{ width: 110, height: 110, borderRadius: 30, background: `linear-gradient(150deg, ${T.calm}, ${T.calmDark})`, display: 'flex', alignItems: 'center', justifyContent: 'center', boxShadow: `0 18px 44px ${T.calm}55` }}>
            <Icon name="target" size={54} color="#fff" sw={2}/>
          </div>
        </div>
        <div style={{ fontSize: 12, fontWeight: 800, color: T.calm, letterSpacing: 1.4, marginBottom: 8 }}>SKILL UNLOCKED</div>
        <div style={{ fontSize: 28, fontWeight: 800, color: T.ink, letterSpacing: -0.5, marginBottom: 6 }}>Squat Setup 1</div>
        <div style={{ fontSize: 15.5, color: T.ink2, marginBottom: 20 }}>{movementSeen ? '카메라 움직임 기록으로 완료' : '아바타 기준 연습 기록으로 완료'}</div>
        <div style={{ display: 'flex', gap: 10, marginBottom: 14 }}>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '10px 16px', borderRadius: 14, background: T.calmSoft }}>
            <Icon name="sparkle" size={18} color={T.calm}/><span style={{ fontSize: 15, fontWeight: 800, color: T.calmDark }}>{movementSeen ? '+30 XP' : '+15 XP'}</span>
          </div>
          <div style={{ display: 'inline-flex', alignItems: 'center', gap: 7, padding: '10px 16px', borderRadius: 14, background: T.pinkSoft }}>
            <Icon name="medal" size={18} color={T.pink}/><span style={{ fontSize: 15, fontWeight: 800, color: T.pinkDark }}>{movementSeen ? 'League +15' : 'League +0'}</span>
          </div>
        </div>
        <div style={{ fontSize: 13.5, color: T.ink3, fontWeight: 700, display: 'flex', alignItems: 'center', gap: 6 }}><Icon name="cameraline" size={15} color={T.ink3} sw={2}/>{movementSeen ? '카메라 움직임 보너스가 포함됐어요' : '카메라 보너스 없이 참고 기록만 저장됐어요'}</div>
      </div>
      <div style={{ padding: '14px 22px 32px', display: 'flex', flexDirection: 'column', gap: 10 }}>
        <Btn variant="soft" size="md" onClick={() => go('home')}>다음 Skill 예약 · Hip Hinge</Btn>
        <Btn variant="calm" onClick={exit}>홈으로</Btn>
      </div>
    </div>
  );
}

// ── Workout (set) mode — train a learned exercise w/ camera ──
function WorkoutIntro({ go, exit, wk, data, spendEnergy }) {
  if (!wk) return null;
  const c = catColor(wk.cat);
  const noEnergy = !data.pro && data.energy <= 0;
  const start = () => {
    if (noEnergy) { exit(); window.__nav && window.__nav('home'); return; }
    if (spendEnergy) spendEnergy();
    go('wkPlay');
  };
  return (
    <Screen bg={T.surface}>
      <div style={{ paddingTop: 8 }}><TopBar title="" onBack={() => go('home')}/></div>
      <div style={{ textAlign: 'center', paddingTop: 8 }}>
        <div style={{ width: 76, height: 76, borderRadius: 22, background: c.s, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', marginBottom: 16 }}>
          <Icon name={wk.icon} size={36} color={c.c} sw={2}/>
        </div>
        <h1 style={{ fontSize: 26, fontWeight: 800, color: T.ink, letterSpacing: -0.5, margin: '0 0 6px' }}>{wk.name}</h1>
        <p style={{ fontSize: 15, color: T.ink2, margin: 0 }}>배운 자세로 세트 운동을 해볼게요.</p>
      </div>
      <div style={{ display: 'flex', gap: 10, margin: '22px 0 14px' }}>
        {[[`${wk.sets}`, '세트'], [`${wk.reps}`, '회/세트'], [`+${wk.xp}`, 'XP']].map((s, i) => (
          <div key={i} style={{ flex: 1, background: T.bg, borderRadius: 16, padding: '14px 8px', textAlign: 'center', boxShadow: '0 1px 3px rgba(0,0,0,0.05)' }}>
            <div style={{ fontSize: 22, fontWeight: 800, color: i === 2 ? c.c : T.ink, letterSpacing: -0.5 }}>{s[0]}</div>
            <div style={{ fontSize: 12, fontWeight: 700, color: T.ink3, marginTop: 2 }}>{s[1]}</div>
          </div>
        ))}
      </div>
      <Card pad={16} style={{ marginBottom: 14, display: 'flex', alignItems: 'center', gap: 11 }}>
        <Icon name="cameraline" size={22} color={c.c} sw={2}/>
        <div style={{ fontSize: 14, color: T.ink, fontWeight: 600, lineHeight: 1.4 }}>카메라가 자세를 실시간으로 봐주고, 끝나면 피드백을 줘요.</div>
      </Card>
      <FloatCTA hint={noEnergy ? '에너지가 부족해요 · 충전 후 다시 시도' : '시작하면 에너지 1개가 소모돼요'}>
        {noEnergy ? (
          <Btn variant="soft" onClick={() => { exit(); window.__nav && window.__nav('home'); }}>에너지 충전하러 가기</Btn>
        ) : (
          <Btn variant="primary" onClick={start} icon={<Icon name="bolt" size={18} color="#fff" fill="#fff" sw={0}/>}>운동 시작 · 에너지 1</Btn>
        )}
      </FloatCTA>
    </Screen>
  );
}

function WorkoutPlayer({ go, wk }) {
  const total = wk ? wk.sets : 1;
  const [phase, setPhase] = useStateA('count'); // count | active | rest
  const [count, setCount] = useStateA(3);
  const [setN, setSetN] = useStateA(1);
  const [rep, setRep] = useStateA(0);
  const [rest, setRest] = useStateA(15);
  const c = wk ? catColor(wk.cat) : { c: T.coral, d: T.coralDark };
  const lastRepAtRef = useRefA(0);

  useEffectA(() => {
    if (phase !== 'count') return;
    if (count === 0) { setPhase('active'); return; }
    const t = setTimeout(() => setCount(x => x - 1), 700); return () => clearTimeout(t);
  }, [phase, count]);

  useEffectA(() => {
    if (phase !== 'active') return;
    if (rep >= wk.reps) {
      if (setN >= total) { const t = setTimeout(() => go('wkDone'), 600); return () => clearTimeout(t); }
      setPhase('rest'); setRest(15); return;
    }
    const camera = ensureCameraRuntime();
    const t = setInterval(() => {
      const frame = camera.latest();
      const box = frame && frame.movementBox;
      const movementSeen = frame && frame.ok && (frame.motion > 2 || (box && box.active > 8));
      const now = Date.now();
      if (!movementSeen || now - lastRepAtRef.current < 1100) return;
      lastRepAtRef.current = now;
      setRep(r => Math.min(wk.reps, r + 1));
    }, 300);
    return () => clearInterval(t);
  }, [phase, rep, setN, total, wk]);

  useEffectA(() => {
    if (phase !== 'rest') return;
    if (rest <= 0) { setSetN(s => s + 1); setRep(0); setPhase('active'); return; }
    const t = setTimeout(() => setRest(x => x - 1), 1000); return () => clearTimeout(t);
  }, [phase, rest]);

  if (phase === 'count') {
    return (
      <div style={{ position: 'absolute', inset: 0, background: '#000', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <StatusBar light/>
        <div key={count} style={{ fontSize: 120, fontWeight: 800, color: '#fff', animation: 'popNum .6s ease' }}>{count === 0 ? '시작' : count}</div>
      </div>
    );
  }

  const resting = phase === 'rest';
  return (
    <div style={{ position: 'absolute', inset: 0, background: '#000', display: 'flex', flexDirection: 'column' }}>
      <StatusBar light/>
      <div style={{ padding: '54px 22px 0' }}>
        <TopBar title={wk.name} light transparent right={
          <button onClick={() => go('wkDone')} style={{ background: 'rgba(255,255,255,0.14)', border: 'none', borderRadius: 999, color: '#fff', fontSize: 12.5, fontWeight: 700, padding: '8px 12px', cursor: 'pointer', fontFamily: 'inherit' }}>끝내기</button>
        }/>
      </div>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', padding: '8px 22px 0' }}>
        <div style={{ position: 'relative', flex: 1, display: 'flex' }}>
          <CameraView label={resting ? 'REST' : 'TRACKING'} tint={resting ? T.amber : T.good}/>
          {/* live set/rep badges */}
          <div style={{ position: 'absolute', top: 14, right: 14, display: 'flex', gap: 8 }}>
            <div style={{ background: 'rgba(0,0,0,0.5)', borderRadius: 10, padding: '6px 11px', color: '#fff', fontSize: 13, fontWeight: 800 }}>SET {setN}/{total}</div>
          </div>
          {!resting && (
            <div style={{ position: 'absolute', bottom: 18, left: 0, right: 0, textAlign: 'center' }}>
              <div style={{ fontSize: 64, fontWeight: 800, color: '#fff', lineHeight: 1, textShadow: '0 2px 12px rgba(0,0,0,0.4)' }}>{rep}<span style={{ fontSize: 26, opacity: 0.7 }}>/{wk.reps}</span></div>
            </div>
          )}
          {resting && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
              <div style={{ fontSize: 15, fontWeight: 700, color: 'rgba(255,255,255,0.7)', marginBottom: 6 }}>휴식</div>
              <div style={{ fontSize: 60, fontWeight: 800, color: '#fff' }}>{rest}</div>
            </div>
          )}
        </div>
      </div>
      <div style={{ padding: '18px 22px 30px', textAlign: 'center' }}>
        <div style={{ fontSize: 17, fontWeight: 700, color: '#fff', marginBottom: 4 }}>{resting ? '다음 세트를 준비해요' : wk.cue}</div>
        <div style={{ fontSize: 14, color: 'rgba(255,255,255,0.6)', fontWeight: 600 }}>{resting ? `${setN + 1}세트까지 ${rest}초` : `${setN}세트 진행 중`}</div>
      </div>
    </div>
  );
}

function WorkoutDone({ go, exit, wk, onReward }) {
  const xp = wk ? wk.xp : 20;
  const [shown, setShown] = useStateA(false);
  useEffectA(() => { if (onReward) onReward(xp); const t = setTimeout(() => setShown(true), 40); return () => clearTimeout(t); }, []);
  const rise = (d) => ({ opacity: shown ? 1 : 0, transform: shown ? 'translateY(0) scale(1)' : 'translateY(14px) scale(0.92)', transition: `opacity .5s ${d}s, transform .55s ${d}s cubic-bezier(.2,1.3,.4,1)` });
  return (
    <div style={{ position: 'absolute', inset: 0, background: `radial-gradient(120% 80% at 50% 0%, ${T.goodSoft} 0%, ${T.surface} 55%)`, display: 'flex', flexDirection: 'column' }}>
      <StatusBar/>
      <Confetti/>
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '54px 30px 0', textAlign: 'center', position: 'relative', zIndex: 2 }}>
        <div style={{ width: 96, height: 96, borderRadius: '50%', background: T.good, display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 22, ...rise(0) }}>
          <Icon name="check" size={50} color="#fff" sw={3}/>
        </div>
        <div style={{ fontSize: 30, fontWeight: 800, color: T.good, letterSpacing: -0.6, marginBottom: 6, ...rise(0.08) }}>운동 완료!</div>
        <div style={{ fontSize: 15.5, color: T.ink2, fontWeight: 600, marginBottom: 24, ...rise(0.12) }}>{wk ? `${wk.name} · ${wk.sets}세트 완료` : '세트 완료'}</div>
        <div style={{ display: 'flex', gap: 12, marginBottom: 22 }}>
          <RewardTile icon="bolt" tone={T.coral} value={`+${xp}`} label="XP" style={rise(0.16)}/>
          <RewardTile icon="medal" tone={T.amber} value="+12" label="League" style={rise(0.26)}/>
        </div>
        <Card pad={16} style={{ display: 'flex', alignItems: 'flex-start', gap: 11, maxWidth: 330, ...rise(0.34) }}>
          <AvaOrb size={34} speaking/>
          <div style={{ fontSize: 14.5, lineHeight: 1.5, color: T.ink, fontWeight: 500 }}>“{wk ? wk.cue : '좋아요'} — 자세가 안정적이었어요. 언제든 다시 와서 운동할 수 있어요.”</div>
        </Card>
      </div>
      <div style={{ padding: '14px 22px 30px', display: 'flex', flexDirection: 'column', gap: 8, position: 'relative', zIndex: 2 }}>
        <Btn variant="soft" size="md" onClick={() => go('home')}>다른 운동 하기</Btn>
        <Btn variant="primary" onClick={exit}>완료</Btn>
      </div>
    </div>
  );
}

Object.assign(window, { Academy });
