// メインアプリ — 3エリア構成 (黒板・ノート・先生)
const { useState, useEffect, useRef, useCallback: useCB } = React;

const SUBJECTS = [
  { id: 'math', label: '算数・数学', sample: '算数・基本的な数学' },
  { id: 'eng',  label: '英語',       sample: '英語の語彙・文法・読解' },
  { id: 'jp',   label: '国語',       sample: '国語・漢字・読解' },
  { id: 'gk',   label: '一般教養',   sample: '歴史・地理・雑学など一般教養' },
  { id: 'code', label: 'プログラミング', sample: 'プログラミングの基礎（擬似コードOK）' },
];

// --- 吹き出し ---
function SpeechBubble({ text, tone = 'normal' }) {
  const shown = useTypewriter(text, 28);
  if (!text) return null;
  const bg = tone === 'praise' ? '#fff2d4' : tone === 'hint' ? '#fde9e3' : '#fffef5';
  return (
    <div style={{
      position: 'relative',
      background: bg,
      border: '2px solid #2d2418',
      padding: '12px 16px',
      maxWidth: 280,
      minHeight: 44,
      borderRadius: '18px 22px 16px 24px/20px 18px 24px 16px',
      fontSize: 15, lineHeight: 1.55,
      color: '#2d2418',
      boxShadow: '3px 3px 0 rgba(45,36,24,0.15)',
    }}>
      <svg style={{ position: 'absolute', bottom: -16, left: 40, width: 28, height: 20 }} viewBox="0 0 28 20">
        <path d="M 2 0 Q 14 14 26 0 L 20 18 Z" fill={bg} stroke="#2d2418" strokeWidth="2" strokeLinejoin="round"/>
        <path d="M 2 0 Q 14 14 26 0" stroke={bg} strokeWidth="3" fill="none"/>
      </svg>
      {shown}<span style={{ opacity: shown.length < (text?.length||0) ? 1 : 0 }}>▍</span>
    </div>
  );
}

// --- 黒板コンテンツの描画（手書き風・チョーク演出） ---
function renderBoardContent(data) {
  return (palette) => {
    if (!data) {
      return (
        <g>
          <ChalkText x={400} y={200} size={28} text="出題ボタンを押して始めよう" delay={0} color={palette.chalk}/>
          <ChalkStroke d="M 260 220 Q 400 232 560 218" delay={0.5} duration={0.9} color={palette.chalkAccent} width={2} opacity={0.85}/>
        </g>
      );
    }
    const { title, lines = [] } = data;
    return (
      <g>
        {/* タイトル */}
        <ChalkText x={40} y={54} size={30} text={title || ''} delay={0.1} color={palette.chalkAccent}/>
        <ChalkStroke d="M 38 64 Q 160 70 300 60" delay={0.5} duration={0.6} color={palette.chalkAccent} width={2} opacity={0.85}/>

        {/* 本文 */}
        {lines.map((line, i) => (
          <ChalkText key={i} x={60} y={120 + i * 56} size={28} text={line} delay={0.7 + i * 0.45} color={palette.chalk}/>
        ))}

        {/* 装飾：右下に小さな星 */}
        <g style={{ transformOrigin: '700px 330px' }}>
          <ChalkStroke d="M 700 320 L 705 335 L 720 335 L 708 343 L 713 358 L 700 350 L 687 358 L 692 343 L 680 335 L 695 335 Z" delay={0.8 + lines.length * 0.45} duration={0.6} color={palette.chalkAccent} width={2}/>
        </g>

        {/* 左上矢印 */}
        <ChalkStroke d="M 600 100 Q 650 130 700 110" delay={1.2 + lines.length * 0.4} duration={0.5} color={palette.chalkRed} width={2.5} opacity={0.9}/>
        <ChalkStroke d="M 692 105 L 702 110 L 696 118" delay={1.5 + lines.length * 0.4} duration={0.3} color={palette.chalkRed} width={2.5}/>
      </g>
    );
  };
}

function TweaksPanel({ state, setState, visible }) {
  const [collapsed, setCollapsed] = useState(false);
  if (!visible) return null;
  const set = (k, v) => {
    const next = { ...state, [k]: v };
    setState(next);
    try {
      window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*');
    } catch (e) {}
  };

  if (collapsed) {
    return (
      <div className="tweaks-panel collapsed">
        <button onClick={() => setCollapsed(false)} style={{ background: 'transparent', border: 'none', cursor: 'pointer', fontSize: 13, color: '#2d2418', fontFamily: 'inherit' }}>Tweaks</button>
      </div>
    );
  }

  return (
    <div className="tweaks-panel">
      <button className="tweaks-toggle" onClick={() => setCollapsed(true)} title="閉じる">✕</button>
      <h4>Tweaks</h4>
      <div className="row">
        <label>スタイル案</label>
        <div className="seg">
          {[
            { v: 'paper', l: '紙&木目' },
            { v: 'classroom', l: '黒板教室' },
            { v: 'minimal', l: 'ミニマル' },
          ].map(o => (
            <button key={o.v} className={state.theme === o.v ? 'active' : ''} onClick={() => set('theme', o.v)}>{o.l}</button>
          ))}
        </div>
      </div>
      <div className="row">
        <label>先生のキャラ</label>
        <div className="seg">
          {[
            { v: 'round', l: '丸顔' },
            { v: 'owl',   l: 'フクロウ' },
            { v: 'blob',  l: 'ブロブ' },
          ].map(o => (
            <button key={o.v} className={state.teacher === o.v ? 'active' : ''} onClick={() => set('teacher', o.v)}>{o.l}</button>
          ))}
        </div>
      </div>
      <div className="row">
        <label>音声で話す</label>
        <div className="seg">
          <button className={state.voice ? 'active' : ''} onClick={() => set('voice', true)}>ON</button>
          <button className={!state.voice ? 'active' : ''} onClick={() => set('voice', false)}>OFF</button>
        </div>
      </div>
      <div style={{ fontSize: 11, color: '#8a6237', marginTop: 8, lineHeight: 1.5 }}>
        ※ AI機能はClaude Haikuで動作。<br/>
        回答後の添削・出題も自動生成します。
      </div>
    </div>
  );
}

function LessonTabs({ options, activeTopic, onPick, onClose }) {
  const { subject, connections = [] } = options;
  if (connections.length === 0) return null;
  return (
    <div style={{
      gridColumn: '1 / -1',
      display: 'flex', alignItems: 'center', gap: 8,
      padding: '8px 12px',
      background: 'rgba(255,248,234,0.9)',
      border: '1px solid rgba(138,98,55,0.4)',
      borderRadius: 10,
      overflowX: 'auto', whiteSpace: 'nowrap',
      zIndex: 3, position: 'relative',
    }}>
      <span style={{
        fontSize: 11, color: '#8a6237', letterSpacing: '0.1em',
        flexShrink: 0, fontWeight: 600,
      }}>
        「{subject || '—'}」の授業：
      </span>
      {connections.map((c, i) => {
        const active = activeTopic && c.topic === activeTopic;
        return (
          <button key={i} onClick={() => onPick(c)} style={{
            flexShrink: 0,
            background: active ? '#2d2418' : '#fff',
            color: active ? '#f6eed8' : '#2d2418',
            border: active ? '1.5px solid #2d2418' : '1px solid #8a6237',
            padding: '5px 11px', fontSize: 12,
            borderRadius: 999, cursor: 'pointer',
            fontFamily: 'inherit',
            display: 'inline-flex', alignItems: 'center', gap: 6,
          }}>
            <span style={{
              fontSize: 10, color: active ? '#f2c94c' : '#c84a3b', fontWeight: 700,
            }}>{c.subject}</span>
            <span style={{ fontSize: 10, opacity: 0.7 }}>{c.grade}</span>
            <span style={{ fontWeight: 600 }}>{c.topic}</span>
          </button>
        );
      })}
      <button onClick={onClose} title="タブを閉じる" style={{
        marginLeft: 'auto', flexShrink: 0,
        background: 'transparent', border: 'none', cursor: 'pointer',
        fontSize: 16, color: '#8a6237', padding: '0 6px', lineHeight: 1,
      }}>×</button>
    </div>
  );
}

function App() {
  // ---- Tweaks state ----
  const [tweaks, setTweaks] = useState(window.TWEAK_DEFAULTS);
  const [tweaksVisible, setTweaksVisible] = useState(true);

  useEffect(() => {
    const handler = (e) => {
      if (!e.data) return;
      if (e.data.type === '__activate_edit_mode') setTweaksVisible(true);
      if (e.data.type === '__deactivate_edit_mode') setTweaksVisible(false);
    };
    window.addEventListener('message', handler);
    try { window.parent.postMessage({ type: '__edit_mode_available' }, '*'); } catch (e) {}
    return () => window.removeEventListener('message', handler);
  }, []);

  // ---- Lesson state ----
  const todayKey = new Date().toISOString().slice(0, 10);
  const [subject, setSubject] = useState(SUBJECTS[0]);
  const [difficulty, setDifficulty] = useState(2);
  const [history, setHistory] = useState([]);
  const [current, setCurrent] = useState(null); // {question, hint, answer, draw}
  const [busy, setBusy] = useState(false);
  const [emotion, setEmotion] = useState('idle');
  const [talking, setTalking] = useState(false);
  const [bubble, setBubble] = useState('こんにちは！好きな科目を選んで、「出題」ボタンを押してくださいね。');
  const [bubbleTone, setBubbleTone] = useState('normal');
  const [boardKey, setBoardKey] = useState(0);
  const [showHint, setShowHint] = useState(false);
  const [cameraOpen, setCameraOpen] = useState(false);
  const [photoThumb, setPhotoThumb] = useState(null);
  const [streak, setStreak] = useState(0);
  const [bestStreak, setBestStreak] = useState(0);
  const [todayStats, setTodayStats] = useState({ date: todayKey, correct: 0, total: 0 });
  const hydrated = useRef(false);

  // 授業モード state
  const [lesson, setLesson] = useState(null);           // { intro, steps:[{title,body,board}], question, hint, answer, board_question }
  const [lessonPhase, setLessonPhase] = useState(null); // null | 'intro' | 'step' | 'question'
  const [lessonStepIdx, setLessonStepIdx] = useState(0);
  const [lessonMeta, setLessonMeta] = useState(null);   // { subject, grade, topic, context }
  const [boardOverride, setBoardOverride] = useState(null); // {title, lines} — 授業中の板書
  const [lessonOptions, setLessonOptions] = useState(null); // { subject, context, connections: [{subject,grade,topic,note}] }

  // ---- 永続化: 起動時に読み込み ----
  useEffect(() => {
    try {
      const raw = localStorage.getItem('manabiya_state_v1');
      if (raw) {
        const s = JSON.parse(raw);
        if (Array.isArray(s.history)) setHistory(s.history.slice(-60));
        if (typeof s.difficulty === 'number') setDifficulty(s.difficulty);
        if (typeof s.streak === 'number') setStreak(s.streak);
        if (typeof s.bestStreak === 'number') setBestStreak(s.bestStreak);
        if (s.todayStats && s.todayStats.date === todayKey) {
          setTodayStats(s.todayStats);
        }
        if (s.subjectId) {
          const sub = SUBJECTS.find(x => x.id === s.subjectId);
          if (sub) setSubject(sub);
        }
      }
    } catch (e) { /* ignore */ }
    hydrated.current = true;
  }, []);

  // ---- 永続化: 変更時に保存 ----
  useEffect(() => {
    if (!hydrated.current) return;
    try {
      localStorage.setItem('manabiya_state_v1', JSON.stringify({
        history: history.slice(-60),
        difficulty,
        streak,
        bestStreak,
        todayStats,
        subjectId: subject.id,
      }));
    } catch (e) { /* ignore */ }
  }, [history, difficulty, streak, bestStreak, todayStats, subject]);

  // 吹き出しのテキストが流れる時間分 talking を維持
  const talkTimer = useRef(null);
  const say = useCB((text, tone = 'normal', emo = 'happy') => {
    setBubble(text);
    setBubbleTone(tone);
    setEmotion(emo);
    setTalking(true);
    speak(text, tweaks.voice);
    if (talkTimer.current) clearTimeout(talkTimer.current);
    const ms = Math.max(1800, Math.min(6000, text.length * 110));
    talkTimer.current = setTimeout(() => {
      setTalking(false);
      setEmotion(prev => prev === 'praise' ? 'happy' : 'idle');
    }, ms);
  }, [tweaks.voice]);

  const askNext = useCB(async () => {
    setBusy(true);
    setShowHint(false);
    setEmotion('think');
    setTalking(false);
    setBubble('うーん、次はどんな問題にしようかな…');
    setBubbleTone('normal');
    try {
      const q = await generateQuestion(subject.sample, difficulty, history);
      setCurrent(q);
      setBoardKey(k => k + 1);
      say(`${q.question}  じっくり考えてみましょう。`, 'normal', 'happy');
    } catch (err) {
      console.error('askNext error', err);
      say('問題生成に失敗。もう一度「出題」を押してみて。', 'hint', 'hint');
    } finally {
      setBusy(false);
    }
  }, [subject, difficulty, history, say]);

  const submitAnswer = useCB(async (userAnswer) => {
    setBusy(true);
    setEmotion('think');
    setTalking(false);
    setBubble('採点中…どれどれ。');

    // 問題がない状態での自由質問モード
    if (!current) {
      const prompt = `家庭教師として、学習者の質問・発言に短く温かく応答してください。必要なら問題を1問出してもOK。学習者: ${userAnswer}\n\n以下のJSONのみで返答:\n{"feedback":"1-2文の返答","speak":"話し言葉の返答(1-2文)","emotion":"happy|hint|think"}`;
      try {
        const resp = await window.claude.complete(prompt);
        const m = resp.match(/\{[\s\S]*\}/);
        const r = m ? JSON.parse(m[0]) : { feedback: 'なるほど！', speak: 'なるほど、そうですね。', emotion: 'happy' };
        setHistory(h => [...h, { question: '(自由質問)', answer: userAnswer, correct: null, feedback: r.feedback }]);
        say(r.speak || r.feedback, 'normal', r.emotion || 'happy');
      } catch (e) {
        setHistory(h => [...h, { question: '(自由質問)', answer: userAnswer, correct: null, feedback: 'なるほど、メモしておきました。' }]);
        say('なるほど、メモしておきました。', 'normal', 'happy');
      }
      setBusy(false);
      return;
    }

    const result = await evaluateAnswer(current.question, current.answer, userAnswer);
    const nextStreak = result.correct ? streak + 1 : 0;
    const item = {
      question: current.question,
      hint: current.hint,
      answer: userAnswer,
      correctAnswer: current.answer,
      correct: result.correct,
      feedback: result.feedback,
      streakAtTime: nextStreak,
      ts: Date.now(),
    };
    setHistory(h => [...h, item]);
    setStreak(nextStreak);
    setBestStreak(b => Math.max(b, nextStreak));
    setTodayStats(s => {
      const base = s.date === todayKey ? s : { date: todayKey, correct: 0, total: 0 };
      return { ...base, correct: base.correct + (result.correct ? 1 : 0), total: base.total + 1 };
    });
    say(result.speak || result.feedback, result.correct ? 'praise' : 'hint', result.emotion || (result.correct ? 'praise' : 'hint'));
    if (result.correct) {
      setDifficulty(d => Math.min(5, d + 1));
      setCurrent(null);
      // 授業モードの練習問題を正解したら授業終了、それ以外は次の問題へ
      if (lessonPhase === 'question') {
        setLessonPhase(null);
        setLesson(null);
        setLessonStepIdx(0);
        setTimeout(() => {
          if (lessonOptions && lessonOptions.connections?.length > 1) {
            say(`授業おわり！他にも学べる単元があるよ。選んでね。`, 'praise', 'praise');
          } else {
            say(`授業おわり！「${lessonMeta?.topic || ''}」、身についたね。`, 'praise', 'praise');
          }
        }, 2600);
      } else {
        setTimeout(() => { askNext(); }, 2600);
      }
    } else {
      setDifficulty(d => Math.max(1, d - 1));
    }
    setBusy(false);
  }, [current, streak, todayKey, lessonPhase, lessonMeta, lessonOptions, say, askNext]);

  // 解説の深掘り
  const explainItem = useCB(async (index) => {
    const item = history[index];
    if (!item || item.explanation || item.explaining) return;
    setHistory(h => h.map((x, i) => i === index ? { ...x, explaining: true } : x));
    setEmotion('think');
    const r = await explainAnswer(item.question, item.correctAnswer, item.answer, !!item.correct);
    setHistory(h => h.map((x, i) => i === index ? { ...x, explanation: r.explanation, tip: r.tip, explaining: false } : x));
    say(r.explanation, 'normal', 'happy');
  }, [history, say]);

  // 不正解問題の再挑戦 — 履歴の問題を current に戻す
  const retryItem = useCB((index) => {
    const item = history[index];
    if (!item || busy) return;
    setCurrent({
      question: item.question,
      hint: item.hint || '前回のヒントをもう一度思い出して。',
      answer: item.correctAnswer,
      draw: { title: 'もう一度', lines: [item.question.slice(0, 22)] },
    });
    setBoardKey(k => k + 1);
    setShowHint(false);
    say('もう一度トライしてみましょう！', 'hint', 'happy');
  }, [history, busy, say]);

  const revealHint = useCB(() => {
    if (!current) return;
    setShowHint(true);
    say(`ヒント: ${current.hint}`, 'hint', 'hint');
  }, [current, say]);

  const askFromPhoto = useCB(async ({ image, caption }) => {
    setBusy(true);
    setShowHint(false);
    setPhotoThumb(image);
    setEmotion('think');
    setTalking(false);
    setBubble(`「${caption}」の写真、見せてくれてありがとう！いま問題を考えるね…`);
    try {
      const q = await generateQuestionFromPhoto(caption, subject.sample);
      setCurrent(q);
      setBoardKey(k => k + 1);
      say(q.intro || q.question, 'normal', 'happy');
    } catch (err) {
      console.error('askFromPhoto error', err);
      say('あれ、問題を考えるのに失敗しちゃった。もう一度試してみて。', 'hint', 'hint');
    } finally {
      setBusy(false);
    }
  }, [subject, say]);

  // --- 授業モード: connection から渡された単元で授業展開 ---
  const startLesson = useCB(async (meta) => {
    setBusy(true);
    setCurrent(null);
    setShowHint(false);
    setLessonMeta(meta);
    setLessonPhase('intro');
    setLessonStepIdx(0);
    setBoardOverride({ title: '授業', lines: [`${meta.subject || ''} ${meta.grade || ''}`.trim(), meta.topic || '—'] });
    setBoardKey(k => k + 1);
    setBubble(`「${meta.topic}」の授業、用意するね…`);
    setBubbleTone('normal');
    setEmotion('think');
    try {
      const l = await generateLesson(meta);
      setLesson(l);
      say(l.intro, 'normal', 'happy');
    } catch (err) {
      console.error('startLesson error', err);
      say('授業の準備に失敗しちゃった。もう一度試してみて。', 'hint', 'hint');
      setLessonPhase(null);
    } finally {
      setBusy(false);
    }
  }, [say]);

  const advanceLesson = useCB(() => {
    if (!lesson) return;
    // intro → step 0
    if (lessonPhase === 'intro') {
      const s = lesson.steps?.[0];
      if (!s) { // ステップ無しで直接問題へ
        setLessonPhase('question');
        setBoardOverride(null);
        setCurrent({ question: lesson.question, hint: lesson.hint, answer: lesson.answer, draw: lesson.board_question });
        setBoardKey(k => k + 1);
        say(lesson.question, 'normal', 'happy');
        return;
      }
      setLessonPhase('step');
      setLessonStepIdx(0);
      setBoardOverride(s.board);
      setBoardKey(k => k + 1);
      say(`${s.title} — ${s.body}`, 'normal', 'happy');
      return;
    }
    // step i → step i+1 or question
    if (lessonPhase === 'step') {
      const nextIdx = lessonStepIdx + 1;
      const total = lesson.steps?.length || 0;
      if (nextIdx < total) {
        const s = lesson.steps[nextIdx];
        setLessonStepIdx(nextIdx);
        setBoardOverride(s.board);
        setBoardKey(k => k + 1);
        say(`${s.title} — ${s.body}`, 'normal', 'happy');
      } else {
        // 問題フェーズへ
        setLessonPhase('question');
        setBoardOverride(null);
        setCurrent({ question: lesson.question, hint: lesson.hint, answer: lesson.answer, draw: lesson.board_question });
        setBoardKey(k => k + 1);
        say(`それじゃあ練習問題。${lesson.question}`, 'normal', 'happy');
      }
    }
  }, [lesson, lessonPhase, lessonStepIdx, say]);

  // URLパラメータ経由の写真連携 (?photo=<base64 or url>&caption=...) / 授業連携 (?lesson=1&sub=...)
  // または postMessage で { type: 'share_photo', image, caption }
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    // 授業連携(複数単元) — なぜなにカメラの「まなびやで授業を受ける」
    if (params.get('lessons') === '1') {
      const subj = params.get('subj') || '';
      const ctx = params.get('ctx') || '';
      let conns = [];
      try { conns = JSON.parse(params.get('conns') || '[]'); } catch {}
      const url = new URL(window.location.href);
      ['lessons','subj','ctx','conns'].forEach(k => url.searchParams.delete(k));
      window.history.replaceState({}, '', url.toString());
      setLessonOptions({ subject: subj, context: ctx, connections: conns });
      say(`「${subj}」から学べる単元があるよ。選んでね。`, 'normal', 'happy');
      return;
    }
    // 単一単元授業（後方互換）
    if (params.get('lesson') === '1') {
      const meta = {
        subject: params.get('sub') || '',
        grade: params.get('grade') || '',
        topic: params.get('topic') || '',
        context: params.get('ctx') || '',
      };
      // URL掃除
      const url = new URL(window.location.href);
      ['lesson','sub','grade','topic','ctx'].forEach(k => url.searchParams.delete(k));
      window.history.replaceState({}, '', url.toString());
      startLesson(meta);
      return;
    }
    const photo = params.get('photo');
    const caption = params.get('caption') || '写真';
    if (photo) {
      // URLが長すぎる場合はsessionStorageからも読む
      askFromPhoto({ image: photo, caption });
      // 2度実行されないようURL掃除
      const url = new URL(window.location.href);
      url.searchParams.delete('photo');
      url.searchParams.delete('caption');
      window.history.replaceState({}, '', url.toString());
    } else {
      // sessionStorage経由（大容量画像用）
      try {
        const shared = sessionStorage.getItem('shared_photo');
        if (shared) {
          const { image, caption: c } = JSON.parse(shared);
          sessionStorage.removeItem('shared_photo');
          if (image) askFromPhoto({ image, caption: c || '写真' });
        }
      } catch {}
    }

    const handler = (e) => {
      if (!e.data) return;
      if (e.data.type === 'share_photo' && e.data.image) {
        askFromPhoto({ image: e.data.image, caption: e.data.caption || '写真' });
      }
    };
    window.addEventListener('message', handler);

    // 他アプリ（例: なぜなにカメラ）から window.open された場合、準備OK信号を返す
    // 呼び出し側はこれを受けてから share_photo をpostする
    try {
      if (window.opener && !window.opener.closed) {
        window.opener.postMessage({ type: 'manabiya_ready' }, '*');
      }
    } catch (err) { /* ignore */ }

    return () => window.removeEventListener('message', handler);
  }, [askFromPhoto, startLesson]);

  // テーマ別スタイル
  const themeBg = {
    paper:     { bg: '#f6eed8', bgImg: 'radial-gradient(circle at 20% 10%, #faf2dc 0%, #eadfb8 100%)' },
    classroom: { bg: '#f0e6ce', bgImg: 'linear-gradient(180deg, #efe3c0 0%, #d9c7a0 100%)' },
    minimal:   { bg: '#f8f5ec', bgImg: 'linear-gradient(180deg, #fbf8ee 0%, #ede7d8 100%)' },
  }[tweaks.theme] || { bg: '#f6eed8', bgImg: 'radial-gradient(circle at 20% 10%, #faf2dc 0%, #eadfb8 100%)' };

  const boardTheme = { paper: 'green', classroom: 'green', minimal: 'white' }[tweaks.theme] || 'green';

  return (
    <div className="app-grid" style={{
      width: '100%',
      background: themeBg.bgImg,
      position: 'relative',
    }}>
      {/* 紙の繊維テクスチャ */}
      <svg width="100%" height="100%" style={{ position: 'absolute', inset: 0, opacity: 0.15, pointerEvents: 'none', mixBlendMode: 'multiply' }}>
        <defs>
          <filter id="grain">
            <feTurbulence baseFrequency="0.85" numOctaves="2"/>
            <feColorMatrix values="0 0 0 0 0.4  0 0 0 0 0.3  0 0 0 0 0.15  0 0 0 0.6 0"/>
          </filter>
        </defs>
        <rect width="100%" height="100%" filter="url(#grain)"/>
      </svg>

      {/* ヘッダー */}
      <header className="mobile-header" style={{ gridArea: 'header', display: 'flex', alignItems: 'center', gap: 10, zIndex: 2, flexWrap: 'nowrap', overflow: 'visible' }}>
        <div style={{
          fontFamily: "'Kaisei Decol', 'Klee One', serif", fontWeight: 700,
          fontSize: 20, color: '#2d2418', letterSpacing: '0.04em',
          whiteSpace: 'nowrap',
        }}>
          まなびや家庭教師
        </div>

        <div style={{ marginLeft: 'auto', display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'nowrap' }}>
          <span style={{ fontSize: 11, color: '#8a6237', letterSpacing: '0.1em' }}>SUBJECT</span>
          <div className="mobile-subjects" style={{ display: 'flex', gap: 2, background: 'rgba(255,255,255,0.4)', padding: 3, borderRadius: 10, border: '1px solid rgba(138,98,55,0.3)', flexWrap: 'nowrap' }}>
            {SUBJECTS.map(s => (
              <button key={s.id} onClick={() => setSubject(s)} style={{
                border: 'none',
                background: subject.id === s.id ? '#2d2418' : 'transparent',
                color: subject.id === s.id ? '#f6eed8' : '#2d2418',
                padding: '5px 9px',
                fontSize: 12, cursor: 'pointer',
                borderRadius: 6,
                fontWeight: subject.id === s.id ? 600 : 400,
                whiteSpace: 'nowrap',
                flexShrink: 0,
              }}>{s.label}</button>
            ))}
          </div>

          <div style={{ marginLeft: 6, display: 'flex', alignItems: 'center', gap: 4 }}>
            <span style={{ fontSize: 11, color: '#8a6237', letterSpacing: '0.1em' }}>LV</span>
            {[1,2,3,4,5].map(n => (
              <span key={n} style={{
                display: 'inline-block', width: 9, height: 9, borderRadius: '50%',
                background: n <= difficulty ? '#c84a3b' : 'rgba(138,98,55,0.25)',
                border: '1px solid rgba(138,98,55,0.5)',
              }}/>
            ))}
          </div>

          {/* 今日の学習バッジ */}
          <div title={`今日の正解 ${todayStats.correct}/${todayStats.total}・連続正解 ${streak}（最高 ${bestStreak}）`} style={{
            display: 'flex', alignItems: 'center', gap: 6,
            background: 'rgba(255,255,255,0.55)',
            border: '1px solid rgba(138,98,55,0.35)',
            borderRadius: 999, padding: '4px 10px',
            fontSize: 11, color: '#2d2418', whiteSpace: 'nowrap',
          }}>
            <span style={{ color: '#6b8e5a', fontWeight: 700 }}>◎ {todayStats.correct}/{todayStats.total}</span>
            <span style={{ color: '#c84a3b', fontWeight: 700 }}>連続 {streak}</span>
          </div>

          <button onClick={() => setCameraOpen(true)} disabled={busy} style={{
            background: '#6b8e5a', color: '#fff8ea',
            border: 'none', padding: '8px 14px',
            fontSize: 13, fontWeight: 600, letterSpacing: '0.08em',
            cursor: busy ? 'default' : 'pointer',
            borderRadius: '12px 18px 12px 18px/18px 12px 18px 12px',
            boxShadow: '2px 3px 0 rgba(45,36,24,0.2)',
            opacity: busy ? 0.55 : 1,
            whiteSpace: 'nowrap',
          }}>写真から</button>

          {lessonPhase && lessonPhase !== 'question' ? (
            <button onClick={advanceLesson} disabled={busy} style={{
              marginLeft: 8,
              background: '#6b8e5a', color: '#fff8ea',
              border: 'none', padding: '8px 16px',
              fontSize: 13, fontWeight: 600, letterSpacing: '0.1em',
              cursor: busy ? 'default' : 'pointer',
              borderRadius: '12px 18px 12px 18px/18px 12px 18px 12px',
              boxShadow: '2px 3px 0 rgba(45,36,24,0.2)',
              opacity: busy ? 0.55 : 1,
              whiteSpace: 'nowrap',
            }}>
              {busy ? '…' : (
                lessonPhase === 'intro' ? 'はじめる ▶' :
                (lessonStepIdx < (lesson?.steps?.length || 0) - 1 ? '次へ ▶' : '問題へ ▶')
              )}
            </button>
          ) : (
            <button onClick={askNext} disabled={busy} style={{
              marginLeft: 8,
              background: '#2d2418', color: '#f6eed8',
              border: 'none', padding: '8px 16px',
              fontSize: 13, fontWeight: 600, letterSpacing: '0.1em',
              cursor: busy ? 'default' : 'pointer',
              borderRadius: '12px 18px 12px 18px/18px 12px 18px 12px',
              boxShadow: '2px 3px 0 rgba(45,36,24,0.2)',
              opacity: busy ? 0.55 : 1,
              whiteSpace: 'nowrap',
            }}>
              {busy ? '…' : (current ? '次の問題' : '出題する')}
            </button>
          )}
        </div>
      </header>

      {lessonOptions && (
        <div style={{ gridArea: 'tabs' }}>
          <LessonTabs
            options={lessonOptions}
            activeTopic={lessonMeta?.topic}
            onPick={(c) => startLesson({
              subject: c.subject,
              grade: c.grade,
              topic: c.topic,
              context: `${lessonOptions.subject}：${c.note || lessonOptions.context || ''}`.slice(0, 200),
            })}
            onClose={() => setLessonOptions(null)}
          />
        </div>
      )}

      {/* 黒板 */}
      <div className="board-area" style={{ gridArea: 'board', position: 'relative', zIndex: 1 }}>
        <Blackboard theme={boardTheme} content={renderBoardContent(boardOverride || current?.draw)} boardKey={boardKey}/>

        {current && (
          <div style={{
            position: 'absolute', top: 22, right: 28,
            display: 'flex', gap: 8, zIndex: 3,
          }}>
            <button onClick={revealHint} disabled={busy || showHint} style={{
              background: '#f2c94c', color: '#2d2418',
              border: '1.5px solid #2d2418', padding: '6px 14px',
              fontSize: 12, fontWeight: 600, letterSpacing: '0.1em',
              cursor: busy || showHint ? 'default' : 'pointer',
              borderRadius: 8,
              opacity: showHint ? 0.4 : 1,
            }}>ヒント</button>
          </div>
        )}

        {/* 先生（黒板の中） */}
        <div style={{
          position: 'absolute', left: 24, bottom: 20,
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          gap: 4, zIndex: 2, pointerEvents: 'none',
        }}>
          <Teacher variant={tweaks.teacher} emotion={emotion} talking={talking} size={110}/>
          <div style={{
            background: '#fff8ea', border: '1px solid #2d2418',
            padding: '2px 10px', fontSize: 11, fontWeight: 600,
            letterSpacing: '0.08em',
            borderRadius: 6,
            boxShadow: '1.5px 2px 0 rgba(45,36,24,0.3)',
            color: '#2d2418',
          }}>
            {tweaks.teacher === 'owl' ? 'フクロウ博士' : tweaks.teacher === 'blob' ? 'もちせんせい' : 'まなび先生'}
          </div>
        </div>

        {/* 吹き出し（先生の横上） */}
        {bubble && (
          <div style={{
            position: 'absolute', left: 145, bottom: 110,
            maxWidth: 'calc(100% - 180px)',
            zIndex: 2, pointerEvents: 'none',
          }}>
            <SpeechBubble text={bubble} tone={bubbleTone}/>
          </div>
        )}
      </div>

      {/* ノート */}
      <div className="note-area" style={{ gridArea: 'note', zIndex: 1, minHeight: 0 }}>
        <Notebook history={history} onSubmit={submitAnswer} busy={busy} currentQuestion={current?.question} onExplain={explainItem} onRetry={retryItem}/>
      </div>

      <TweaksPanel state={tweaks} setState={setTweaks} visible={tweaksVisible}/>
      <CameraModal open={cameraOpen} onClose={() => setCameraOpen(false)} onCapture={askFromPhoto}/>


      {photoThumb && (
        <div style={{
          position: 'absolute', top: 70, left: 22,
          width: 80, height: 80, borderRadius: 8,
          border: '2px solid #fff', boxShadow: '2px 3px 0 rgba(0,0,0,0.3)',
          overflow: 'hidden', zIndex: 3,
          transform: 'rotate(-3deg)',
        }} title="今日の写真">
          <img src={photoThumb} style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
        </div>
      )}
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
