/* global React, ReactDOM, PHASES, CHECKLISTS, TIPS, GLOSSARY,
   RisoMachineDiagram, SeparationSim, PassAnimation, DrumSwapDiagram, TrappingDiagram,
   TweaksPanel, useTweaks, TweakSection, TweakRadio, TweakSelect */

const { useState, useEffect, useMemo } = React;

const STORAGE_KEY = 'riso_manual_state_v1';

function loadState() {
  try { return JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); } catch(e){ return {}; }
}
function saveState(s) {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(s)); } catch(e){}
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "riso",
  "lang": "ja",
  "inkCombo": "YPBK"
}/*EDITMODE-END*/;

function App() {
  const persisted = loadState();
  const [phaseIdx, setPhaseIdx] = useState(persisted.phaseIdx || 0);
  const [checks, setChecks] = useState(persisted.checks || {});
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // apply theme/lang to <html>
  useEffect(() => {
    document.documentElement.setAttribute('data-theme', tweaks.theme || 'riso');
    document.documentElement.setAttribute('data-lang', tweaks.lang || 'ja');
  }, [tweaks.theme, tweaks.lang]);

  useEffect(() => { saveState({ phaseIdx, checks }); }, [phaseIdx, checks]);

  function toggleCheck(id) {
    setChecks(c => ({...c, [id]: !c[id]}));
  }

  // Total checklist progress (includes 3 synthetic "read" acks: cover, tips, glossary)
  const READ_KEYS = ['cover_read', 'tips_read', 'glossary_read'];
  const totalChecks = Object.values(CHECKLISTS).reduce((n, arr) => n + arr.length, 0) + READ_KEYS.length;
  const checklistIds = new Set([
    ...Object.values(CHECKLISTS).flatMap(arr => arr.map(c => c.id)),
    ...READ_KEYS,
  ]);
  const doneChecks = Object.entries(checks).filter(([k,v]) => v && checklistIds.has(k)).length;
  const pct = Math.round((doneChecks / totalChecks) * 100);

  // Phase complete = all its checks done, OR cover/reference pages marked read
  const isPhaseComplete = (pid) => {
    const list = CHECKLISTS[pid];
    if (list) return list.every(c => checks[c.id]);
    // Cover, tips, glossary use a synthetic "_read" check
    return !!checks[pid + '_read'];
  };

  const phase = PHASES[phaseIdx];
  const prev = phaseIdx > 0 ? PHASES[phaseIdx-1] : null;
  const next = phaseIdx < PHASES.length-1 ? PHASES[phaseIdx+1] : null;

  return (
    <div className="app" data-screen-label={`${phase.numLabel} ${phase.titleJa}`}>
      <Sidebar phases={PHASES} idx={phaseIdx} setIdx={setPhaseIdx} pct={pct} done={doneChecks} total={totalChecks} isComplete={isPhaseComplete}/>
      <main className="main">
        <div className="topbar">
          <div className="crumb">
            <span className="crumb-num">{phase.numLabel}</span>
            <span>{tweaks.lang === 'en' ? phase.titleEn : phase.titleJa}</span>
          </div>
          <div className="topbar-right">
            <div className="lang-switch">
              <button className={tweaks.lang==='ja'?'on':''} onClick={()=>setTweak('lang','ja')}>JA</button>
              <button className={tweaks.lang==='en'?'on':''} onClick={()=>setTweak('lang','en')}>EN</button>
            </div>
          </div>
        </div>

        <div className="content-wrap" key={phase.id}>
          <PhaseRenderer phase={phase} checks={checks} toggle={toggleCheck} tweaks={tweaks}/>

          <div className="phase-footer">
            <button className="foot-btn" disabled={!prev} onClick={()=>prev && setPhaseIdx(phaseIdx-1)} style={{visibility: prev?'visible':'hidden'}}>
              <span className="small">← {tweaks.lang==='en'?'Previous':'前へ'}</span>
              {prev && <span className="big">{prev.numLabel} · {tweaks.lang==='en'?prev.titleEn:prev.titleJa}</span>}
            </button>
            {next && (
              <button className="foot-btn primary" onClick={()=>setPhaseIdx(phaseIdx+1)} style={{alignItems:'flex-end', textAlign:'right'}}>
                <span className="small">{tweaks.lang==='en'?'Next':'次へ'} →</span>
                <span className="big">{next.numLabel} · {tweaks.lang==='en'?next.titleEn:next.titleJa}</span>
              </button>
            )}
          </div>
        </div>
      </main>

      <TweaksPanelHost tweaks={tweaks} setTweak={setTweak}/>
    </div>
  );
}

function TweaksPanelHost({tweaks, setTweak}) {
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title={tweaks.lang==='en' ? 'Theme' : 'テーマ / Theme'}>
        <TweakRadio value={tweaks.theme} onChange={v => setTweak('theme', v)}
          options={[
            {value:'riso', label: tweaks.lang==='en' ? 'Riso' : 'リソ印刷'},
            {value:'light', label: tweaks.lang==='en' ? 'Light' : 'ライト'},
            {value:'dark', label: tweaks.lang==='en' ? 'Dark' : 'ダーク'},
          ]}/>
      </TweakSection>
      <TweakSection title={tweaks.lang==='en' ? 'Language / 言語' : '言語 / Language'}>
        <TweakRadio value={tweaks.lang} onChange={v => setTweak('lang', v)}
          options={[{value:'ja', label:'日本語'}, {value:'en', label:'English'}]}/>
      </TweakSection>
      <TweakSection title={tweaks.lang==='en' ? 'Sample inks' : 'サンプルインク'} subtitle={tweaks.lang==='en' ? 'Simulator combination' : 'シミュレーター内の組み合わせ'}>
        <TweakSelect value={tweaks.inkCombo} onChange={v=>setTweak('inkCombo', v)}
          options={tweaks.lang==='en' ? [
            {value:'YPBK', label:'Y + P + B + K (standard)'},
            {value:'FLOR', label:'Fl. Pink + Fl. Yellow + K + Teal'},
            {value:'DUO', label:'Fl. Orange + P + B + K'},
          ] : [
            {value:'YPBK', label:'Y + P + B + K (標準)'},
            {value:'FLOR', label:'蛍光P + 蛍光Y + K + Teal'},
            {value:'DUO', label:'蛍光Orange + P + B + K'},
          ]}/>
      </TweakSection>
    </TweaksPanel>
  );
}

// =================
// Sidebar
// =================
function Sidebar({phases, idx, setIdx, pct, done, total, isComplete}) {
  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark">
          <span className="dot-y">R</span>
          <span className="dot-p">I</span>
          <span className="dot-b">S</span>
          <span className="dot-k">O</span>
        </div>
        <div className="brand-jp">RISOGRAPH MANUAL</div>
        <div className="brand-sub">
          <span className="lang-ja">4色印刷ガイド · MZ/MD系 2-drum</span>
          <span className="lang-en">4-Color Printing · MZ/MD 2-drum</span>
        </div>
      </div>

      <div className="progress-card">
        <div className="progress-row">
          <span><span className="lang-ja">進捗</span><span className="lang-en">Progress</span></span>
          <span className="pct">{pct}%</span>
        </div>
        <div className="progress-bar"><div className="progress-bar-fill" style={{width: pct+'%'}}/></div>
        <div style={{marginTop:8, fontSize:10, color:'var(--ui-text-mut)', fontFamily:'var(--font-mono)', letterSpacing:'0.06em'}}>
          {done} / {total} CHECKED
        </div>
      </div>

      <nav className="nav">
        <div className="nav-section-title">Process</div>
        {phases.filter(p => p.kind !== 'tips' && p.kind !== 'glossary').map((p, i) => {
          const done = isComplete(p.id);
          return (
            <button key={p.id} className={`nav-item ${idx===i?'active':''}`} onClick={()=>setIdx(i)}>
              <span className="num">{p.numLabel}</span>
              <div>
                <div className="label-jp">{p.titleJa}</div>
                <div className="label-en">{p.titleEn}</div>
              </div>
              <span className={`check ${done?'done':''}`}>
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3"><polyline points="20 6 9 17 4 12"/></svg>
              </span>
            </button>
          );
        })}
        <div className="nav-section-title" style={{marginTop:14}}>Reference</div>
        {phases.filter(p => p.kind === 'tips' || p.kind === 'glossary').map(p => {
          const i = phases.indexOf(p);
          const done = isComplete(p.id);
          return (
            <button key={p.id} className={`nav-item ${idx===i?'active':''}`} onClick={()=>setIdx(i)}>
              <span className="num">{p.numLabel}</span>
              <div>
                <div className="label-jp">{p.titleJa}</div>
                <div className="label-en">{p.titleEn}</div>
              </div>
              <span className={`check ${done?'done':''}`}>
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3"><polyline points="20 6 9 17 4 12"/></svg>
              </span>
            </button>
          );
        })}
      </nav>

      <div style={{marginTop:'auto', fontSize:10, color:'var(--ui-text-mut)', lineHeight:1.6, letterSpacing:'0.04em'}}>
        工作室向けインタラクティブマニュアル<br/>
        <span style={{color:'var(--ui-text-mut)', opacity:0.7}}>v1.0 · 印刷の前に必ず通読してください</span>
      </div>
    </aside>
  );
}

// =================
// Phase renderer
// =================
function PhaseRenderer({phase, checks, toggle, tweaks}) {
  const readKey = phase.id + '_read';
  const readBlock = (
    <div className="check-list" style={{marginTop:24}}>
      <div className="check-list-title">
        <span className="lang-ja">確認</span>
        <span className="lang-en">Acknowledge</span>
      </div>
      <div className={`check-row ${checks[readKey]?'done':''}`} onClick={()=>toggle(readKey)}>
        <div className="box">
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3"><polyline points="20 6 9 17 4 12"/></svg>
        </div>
        <div className="label-text">
          <span className="lang-ja">このページを読んだ</span>
          <span className="lang-en">I have read this page</span>
        </div>
      </div>
    </div>
  );
  if (phase.kind === 'cover')    return <><Cover tweaks={tweaks}/>{readBlock}</>;
  if (phase.kind === 'tips')     return <><TipsPage tweaks={tweaks}/>{readBlock}</>;
  if (phase.kind === 'glossary') return <><GlossaryPage tweaks={tweaks}/>{readBlock}</>;

  return (
    <article>
      <header className="phase-head">
        <div className="phase-tag"><span className="swatch"/> PHASE {phase.numLabel} / 6</div>
        <h1 className="phase-title">
          <span className="layer" data-text={tweaks.lang==='en'?phase.titleEn:phase.titleJa}>
            {tweaks.lang==='en'?phase.titleEn:phase.titleJa}
          </span>
        </h1>
        <span className="phase-title-en">
          {tweaks.lang==='en' ? phase.titleJa : phase.titleEn}
        </span>
        <p className="phase-lead">{tweaks.lang==='en'?phase.leadEn:phase.leadJa}</p>
      </header>

      {phase.kind === 'phase1' && <Phase1/>}
      {phase.kind === 'phase2' && <Phase2/>}
      {phase.kind === 'phase3' && <Phase3/>}
      {phase.kind === 'phase4' && <Phase4/>}
      {phase.kind === 'phase5' && <Phase5/>}
      {phase.kind === 'phase6' && <Phase6/>}

      {CHECKLISTS[phase.id] && (
        <CheckList items={CHECKLISTS[phase.id]} checks={checks} toggle={toggle}/>
      )}
    </article>
  );
}

// =================
// Cover
// =================
function Cover({tweaks}) {
  const isEn = tweaks?.lang === 'en';
  return (
    <div className="cover">
      <h1>
        RISOGRAPH
        <span className="ja">{isEn ? '4-Color Printing Manual' : '4色印刷マニュアル'}</span>
        <span className="stamp">WORKSHOP / v1.0</span>
      </h1>
      <p style={{fontSize:17, color:'var(--ui-text-dim)', maxWidth:680, lineHeight:1.75, marginTop:12}}>
        {isEn
          ? 'Step-by-step guide for 4-color printing on a 2-drum Risograph (MZ / MD-class) — six phases from data prep to final dry, in two paper passes.'
          : '2ドラム機（MZ/MD系）を使い、2回の紙通し（2パス）で4色を印刷する手順を、データ作成から仕上げまで6つのフェーズに整理しています。'}
      </p>
      <p style={{fontSize:14, color:'var(--ui-text-mut)', marginTop:6, fontStyle:'italic', maxWidth:680}}>
        {isEn
          ? '2ドラム機（MZ/MD系）で4色を2パス印刷する実機ガイド。'
          : 'Step-by-step guide for 4-color printing on a 2-drum Risograph (MZ / MD-class), in two passes.'}
      </p>

      <div className="cover-meta">
        <div className="cell"><div className="k">{isEn ? 'Machine / 対象機' : '対象機 / Machine'}</div><div className="v">2-drum (MZ / MD)</div></div>
        <div className="cell"><div className="k">{isEn ? 'Passes / パス' : 'パス / Passes'}</div><div className="v">2 passes</div></div>
        <div className="cell"><div className="k">{isEn ? 'Colors / 色数' : '色数 / Colors'}</div><div className="v">4 colors</div></div>
        <div className="cell"><div className="k">{isEn ? 'Audience / 対象' : '対象 / Audience'}</div><div className="v">{isEn ? 'Beginners · Students' : '初心者・学生'}</div></div>
      </div>

      <div style={{marginTop:36, marginBottom:14, fontSize:11, fontWeight:700, letterSpacing:'0.18em', textTransform:'uppercase', color:'var(--ui-text-dim)'}}>
        {isEn ? 'The Process at a Glance / 全体像' : '全体像 / The Process at a Glance'}
      </div>
      <RisoMachineDiagram/>

      <div className="phase-meta-row" style={{marginTop:36}}>
        <div className="meta-card">
          <div className="k">{isEn ? 'Phases / フェーズ数' : 'フェーズ数 / Phases'}</div>
          <div className="v">6</div>
          <div className="vsub">{isEn ? 'From data prep to final dry' : 'データ作成から最終乾燥まで'}</div>
        </div>
        <div className="meta-card">
          <div className="k">{isEn ? 'Duration / 所要時間' : '所要時間 / Duration'}</div>
          <div className="v">6–10h</div>
          <div className="vsub">{isEn ? 'Includes drying / 乾燥時間を含む' : '乾燥時間を含む / Includes drying'}</div>
        </div>
        <div className="meta-card">
          <div className="k">{isEn ? 'Surplus / 推奨予備' : '推奨予備 / Surplus'}</div>
          <div className="v">+30%</div>
          <div className="vsub">{isEn ? 'Buffer for misfeeds & misregistration' : 'ロス対策で多めに刷る'}</div>
        </div>
      </div>

      <div className="callout tip" style={{marginTop:32}}>
        <div className="callout-icon">i</div>
        <div className="callout-body">
          <div className="callout-title">{isEn ? 'For Operators / 利用者の方へ' : '利用者の方へ / For Operators'}</div>
          <div className="callout-text">
            <span className="lang-ja">左のサイドバーから各フェーズに進めます。チェックボックスは自動保存されるので、印刷中にこのページを開いたまま進捗を確認できます。</span>
            <span className="lang-en">Use the sidebar to navigate phases. Checkboxes auto-save, so you can keep this page open beside the machine while you work and your progress will persist.</span>
          </div>
        </div>
      </div>
    </div>
  );
}

// =================
// Phase 1 — Data
// =================
function Phase1() {
  return (
    <>
      <Step n="1.1" titleJa="レイヤーの分割（分版）" titleEn="Split into layers · color separation">
        <p><span className="lang-ja">デザインデータを、印刷したい4色（例：Yellow, Pink, Blue, Black）ごとにレイヤー分けします。各レイヤーの色情報を<strong>グレースケール（K濃度0〜100%）</strong>に変換します。<code>K100%</code>がインク濃度100%です。</span>
        <span className="lang-en">Split your design into 4 layers — one per ink color. Convert each layer to grayscale; <code>K100%</code> = full ink coverage.</span></p>
        <SeparationSim/>
      </Step>

      <Step n="1.2" titleJa="トラッピング（隙間対策）" titleEn="Trapping · prevent white gaps">
        <p><span className="lang-ja">版ズレで生じる白抜けを防ぐため、隣接する色は<strong>0.1〜0.5mm</strong>ほどデータ同士をオーバーラップさせます。</span>
        <span className="lang-en">Overlap adjacent colors by <strong>0.1–0.5mm</strong> so misregistration doesn't reveal the paper underneath.</span></p>
        <div className="diagram diagram-bg">
          <div className="diagram-cap"><span className="ttl">FIG.01 — Trapping</span><span className="num">±0.3mm</span></div>
          <TrappingDiagram/>
        </div>
      </Step>

      <Step n="1.3" titleJa="網点・解像度の確認" titleEn="Halftone · resolution">
        <p><span className="lang-ja">写真やグラデーションの濃淡はドライバ側で網点処理されますが、データ側で先にハーフトーン処理（ディザリング等）を行うと、より意図通りのレトロな仕上がりになります。</span>
        <span className="lang-en">Halftoning is automatic in the driver, but pre-processing in your data tool gives a more controlled retro feel.</span></p>
        <ul>
          <li><span className="lang-ja">推奨解像度：<strong>300〜600 dpi</strong></span><span className="lang-en">Recommended: <strong>300–600 dpi</strong></span></li>
          <li><span className="lang-ja">写真は事前にディザリング処理を検討</span><span className="lang-en">Consider dithering photos beforehand</span></li>
        </ul>
      </Step>

      <Step n="1.4" titleJa="入稿データの書き出し" titleEn="Export per-color PDFs">
        <p><span className="lang-ja">各色ごとに個別のPDF、または複数ページPDFとして書き出します。ファイル名は刷る順番とインク色がひと目で分かるよう統一します。</span>
        <span className="lang-en">Export each color as its own PDF (or as a multipage PDF). Use a naming convention that makes the print order obvious.</span></p>
        <div className="diagram" style={{padding:'14px 18px'}}>
          <div className="diagram-cap"><span className="ttl"><span className="lang-ja">命名規則 / Naming Convention</span><span className="lang-en">Naming Convention / 命名規則</span></span></div>
          <pre style={{fontFamily:'var(--font-mono)', fontSize:13, lineHeight:1.9, color:'var(--ui-text)'}}>
{`01_Yellow.pdf
02_Pink.pdf
03_Blue.pdf
04_Black.pdf`}
          </pre>
        </div>
      </Step>

      <Callout type="tip" titleJa="プロのコツ" titleEn="Pro tip"
        ja="グラデーションは「リソは原則ベタ／少数階調」と割り切り、思い切って網点パターンに置き換えるとレトロ印刷らしさが際立ちます。"
        en="Riso loves flat fills and few tonal steps. Lean into halftone patterns instead of smooth gradients."/>
    </>
  );
}

// =================
// Phase 2 — Setup
// =================
function Phase2() {
  return (
    <>
      <Step n="2.1" titleJa="インクドラムのセット（1パス目）" titleEn="Install pass-1 ink drums">
        <p><span className="lang-ja">1色目と2色目のインクドラム（例：ドラム1にYellow、ドラム2にPink）を本体にセットします。</span>
        <span className="lang-en">Insert the first two ink drums — e.g. Drum 1 = Yellow, Drum 2 = Pink.</span></p>
        <Callout type="tip" titleJa="先に刷る色の選び方" titleEn="Which color first?"
          ja="明るい色、または面積の広い色を先に刷ると、ローラーの汚れを減らし、後から重ねる色の発色が良くなります。"
          en="Print lighter / broader colors first to reduce roller contamination and improve overprint vibrancy."/>
      </Step>

      <Step n="2.2" titleJa="用紙のセット" titleEn="Load paper">
        <ul>
          <li><span className="lang-ja">給紙トレイに用紙をセットし、<strong>用紙ガイドをぴったり</strong>合わせる</span><span className="lang-en">Load paper, snug the feed guides against the stack</span></li>
          <li><span className="lang-ja">排紙トレイのガイドも用紙サイズに合わせて調整する</span><span className="lang-en">Adjust output tray guides to paper size</span></li>
          <li><span className="lang-ja">用紙の<strong>表裏</strong>と<strong>天地</strong>を確認</span><span className="lang-en">Verify front/back orientation and head/foot</span></li>
        </ul>
        <RisoMachineDiagram/>
      </Step>
    </>
  );
}

// =================
// Phase 3 — Pass 1
// =================
function Phase3() {
  return (
    <>
      <Step n="3.1" titleJa="データの送信と製版" titleEn="Send data · create master">
        <p><span className="lang-ja">PCから1色目・2色目のデータをプリンタードライバー経由で送信し、<strong>製版（マスター作成）</strong>を行います。</span>
        <span className="lang-en">Send pass-1 data through the print driver and let the machine cut new masters for both drums.</span></p>
      </Step>

      <Step n="3.2" titleJa="試し刷りと位置合わせ" titleEn="Test print · registration">
        <p><span className="lang-ja">数枚の試し刷りを行い、タッチパネルやハードキーの<strong>「天地（上下）」「左右」</strong>調整ボタンで、データ上の基準位置と実際の印刷位置が合うように調整します。</span>
        <span className="lang-en">Run a few test sheets. Use the panel's vertical / horizontal offset controls to align prints to the design's reference position.</span></p>
        <div className="diagram diagram-bg">
          <div className="diagram-cap"><span className="ttl">FIG.02 — Registration controls</span></div>
          <svg viewBox="0 0 500 140" style={{width:'100%'}}>
            <rect x="20" y="30" width="120" height="80" rx="6" fill="var(--ui-card-2)" stroke="var(--ui-line)"/>
            <text x="80" y="22" textAnchor="middle" fontSize="10" fontWeight="700" fill="var(--ui-text-dim)" letterSpacing="0.14em">Y / 天地</text>
            <polygon points="80,40 70,55 90,55" fill="var(--ink-pink)"/>
            <polygon points="80,100 70,85 90,85" fill="var(--ink-pink)"/>

            <rect x="190" y="30" width="120" height="80" rx="6" fill="var(--ui-card-2)" stroke="var(--ui-line)"/>
            <text x="250" y="22" textAnchor="middle" fontSize="10" fontWeight="700" fill="var(--ui-text-dim)" letterSpacing="0.14em">X / 左右</text>
            <polygon points="200,70 215,60 215,80" fill="var(--ink-blue)"/>
            <polygon points="300,70 285,60 285,80" fill="var(--ink-blue)"/>

            <rect x="360" y="30" width="120" height="80" rx="6" fill="var(--ui-card-2)" stroke="var(--ui-line)"/>
            <text x="420" y="22" textAnchor="middle" fontSize="10" fontWeight="700" fill="var(--ui-text-dim)" letterSpacing="0.14em">SKEW / 斜行</text>
            <line x1="370" y1="100" x2="470" y2="40" stroke="var(--ink-flo-orange)" strokeWidth="2"/>
          </svg>
        </div>
      </Step>

      <Step n="3.3" titleJa="本番印刷（多めに刷る）" titleEn="Production run — print extra">
        <p><span className="lang-ja">位置が決まったら本刷りを行います。</span>
        <span className="lang-en">Once registration is dialed in, print the run.</span></p>
        <Callout type="warn" titleJa="重要：希望枚数 + 20〜30%" titleEn="Important: print 20–30% extra"
          ja="2パス目で給紙ミスや版ズレによるロスが必ず発生します。希望枚数より2〜3割多めに刷っておくのが鉄則です。"
          en="Pass 2 always loses sheets to feed errors and misregistration. Always print 20–30% more than you actually need."/>
      </Step>
    </>
  );
}

// =================
// Phase 4 — Drying
// =================
function Phase4() {
  return (
    <>
      <Step n="4.1" titleJa="十分な乾燥時間を確保する" titleEn="Allow enough drying time">
        <p><span className="lang-ja">リソグラフのインク（大豆油・米ぬか油ベースの<strong>半水性インク</strong>）は、紙に浸透しながらゆっくり乾燥します。1パス目が終わったら、紙質やインク量に応じて<strong>数時間〜半日</strong>程度を目安に置きます。</span>
        <span className="lang-en">Riso's soy / rice-bran ink dries by absorption — wait several hours to half a day after pass 1, depending on paper and ink coverage.</span></p>
        <div className="dry-strip" style={{marginTop:14}}>
          <div className="dry-fill" style={{width:'66%'}}/>
          <span className="lbl">DRYING</span>
          <span className="v">~ 6h</span>
        </div>
      </Step>

      <Step n="4.2" titleJa="未乾燥のリスク" titleEn="Risk of premature pass 2">
        <Callout type="warn" titleJa="ローラー汚れ・裏移り" titleEn="Roller smudge & set-off"
          ja="未乾燥のまま2パス目に進むと、紙を送るゴムローラーにインクが移り、紙を汚す「ローラー汚れ」や「裏移り」の原因になります。"
          en="Going to pass 2 too early transfers ink to the feed rollers, smearing every subsequent sheet ('set-off')."/>
      </Step>

      <Step n="4.3" titleJa="乾燥チェック方法" titleEn="How to check it's dry">
        <ul>
          <li><span className="lang-ja">紙の隅を指で軽くこすり、インクが指に付かないことを確認</span><span className="lang-en">Rub a corner gently — no ink should transfer to your finger</span></li>
          <li><span className="lang-ja">2枚を重ね、強く押し付けても下の紙裏に色が移らないことを確認</span><span className="lang-en">Stack two sheets and press — no offset to the back of the upper sheet</span></li>
        </ul>
      </Step>
    </>
  );
}

// =================
// Phase 5 — Pass 2
// =================
function Phase5() {
  return (
    <>
      <Step n="5.1" titleJa="インクドラムの入れ替え" titleEn="Swap ink drums">
        <p><span className="lang-ja">ドラムを3色目・4色目（例：ドラム1にBlue、ドラム2にBlack）に交換します。</span>
        <span className="lang-en">Swap to the third and fourth drums — e.g. Drum 1 = Blue, Drum 2 = Black.</span></p>
        <div className="diagram diagram-bg">
          <div className="diagram-cap"><span className="ttl">FIG.03 — Drum swap procedure</span></div>
          <DrumSwapDiagram/>
        </div>
      </Step>

      <Step n="5.2" titleJa="用紙の再セット" titleEn="Reload dried sheets">
        <Callout type="warn" titleJa="絶対に間違えない：表裏・天地" titleEn="Never confuse: front/back & orientation"
          ja="乾燥した1パス目の用紙を給紙トレイにセットします。表裏（おもてうら）と天地（上下）を絶対に間違えないよう、束の上で1枚ずつ向きを確認してください。"
          en="Reload the dried sheets. Verify front/back AND head/foot before loading — getting it wrong ruins the entire run."/>
      </Step>

      <Step n="5.3" titleJa="データの送信と製版" titleEn="Send pass-2 data · create master">
        <p><span className="lang-ja">3色目・4色目のデータを送信し、製版します。</span>
        <span className="lang-en">Send pass-2 data and let the machine cut new masters.</span></p>
      </Step>

      <Step n="5.4" titleJa="シビアな位置合わせ" titleEn="Critical registration">
        <p><span className="lang-ja">ここが4色印刷の最難関です。試し刷りを行い、すでに刷られている1・2色目に対して、3・4色目がピタリと合うように微調整を繰り返します。わずかな斜行は給紙トレイの<strong>角度調整ダイヤル</strong>で補正します。</span>
        <span className="lang-en">This is the hardest moment of the whole run. Test, adjust, repeat — until pass-2 colors land precisely on top of pass-1. Use the feed-tray skew dial for tilt.</span></p>
      </Step>

      <Step n="5.5" titleJa="最終印刷" titleEn="Final run">
        <p><span className="lang-ja">ズレが許容範囲内に収まったら、残りの枚数を印刷します。</span>
        <span className="lang-en">Once registration is acceptable, print the remainder.</span></p>
        <div className="diagram diagram-bg">
          <div className="diagram-cap"><span className="ttl">2-PASS TIMELINE — interactive</span><span className="num">PRESS PLAY</span></div>
          <PassAnimation/>
        </div>
      </Step>
    </>
  );
}

// =================
// Phase 6 — Finishing
// =================
function Phase6() {
  return (
    <>
      <Step n="6.1" titleJa="最終乾燥" titleEn="Final dry">
        <p><span className="lang-ja">すべての印刷が完了したら、インクが完全に定着するまで風通しの良い場所で乾燥させます。</span>
        <span className="lang-en">After all printing, dry the sheets fully in a ventilated area until ink is fully set.</span></p>
      </Step>
      <Step n="6.2" titleJa="トンボの裁断" titleEn="Trim crop marks">
        <p><span className="lang-ja">乾燥後、必要に応じて裁断機でトンボ（トリムマーク）を切り落として完成です。</span>
        <span className="lang-en">When dry, trim crop marks with a guillotine cutter — and you're done.</span></p>
      </Step>
      <Step n="6.3" titleJa="保管" titleEn="Storage">
        <ul>
          <li><span className="lang-ja">湿気の少ない場所に平積みで保管</span><span className="lang-en">Store flat in a low-humidity area</span></li>
          <li><span className="lang-ja">蛍光色は紫外線で退色するため<strong>遮光保管</strong>が望ましい</span><span className="lang-en">Fluorescent inks fade in UV — keep finished prints in the dark</span></li>
        </ul>
      </Step>
      <Callout type="tip" titleJa="お疲れ様でした" titleEn="Well done"
        ja="6フェーズすべて完了です。サイドバーで進捗を確認し、未完了のチェックがないか見直してから片付けに入りましょう。"
        en="All six phases complete. Review the sidebar progress before cleaning up the machine."/>
    </>
  );
}

// =================
// Tips page
// =================
function TipsPage({tweaks}) {
  const isEn = tweaks?.lang === 'en';
  const big = isEn ? 'Troubleshooting' : 'トラブルシューティング';
  return (
    <article>
      <header className="phase-head">
        <div className="phase-tag"><span className="swatch"/> APPENDIX A</div>
        <h1 className="phase-title">
          <span className="layer" data-text={big}>{big}</span>
        </h1>
        <span className="phase-title-en">
          {isEn ? 'Diagnostic index' : 'Troubleshooting Index'}
        </span>
        <p className="phase-lead">
          <span className="lang-ja">紙詰まり・ローラー汚れ・インクかすれ・版ズレなど、現場でよくあるトラブルへの対処をまとめました。</span>
          <span className="lang-en">Common issues that come up at the machine, with quick fixes.</span>
        </p>
      </header>
      <div className="tips-grid">
        {TIPS.map(t => (
          <div className="tip-card" key={t.id}>
            <span className="num-pill">TIP {t.num}</span>
            <h4>
              <span className="lang-ja">{t.ja.t}</span>
              <span className="lang-en">{t.en.t}</span>
            </h4>
            <p>
              <span className="lang-ja">{t.ja.d}</span>
              <span className="lang-en">{t.en.d}</span>
            </p>
          </div>
        ))}
      </div>
    </article>
  );
}

// =================
// Glossary page
// =================
function GlossaryPage({tweaks}) {
  const isEn = tweaks?.lang === 'en';
  const big = isEn ? 'Glossary' : '用語集';
  return (
    <article>
      <header className="phase-head">
        <div className="phase-tag"><span className="swatch"/> APPENDIX B</div>
        <h1 className="phase-title">
          <span className="layer" data-text={big}>{big}</span>
        </h1>
        <span className="phase-title-en">
          {isEn ? 'Terms & abbreviations' : 'Glossary'}
        </span>
      </header>
      <div className="glossary">
        {GLOSSARY.map((g, i) => (
          <div className="gloss-row" key={i}>
            <div className="term">
              {isEn ? g.en : g.ja}
              <span className="en">{isEn ? g.ja : g.en}</span>
            </div>
            <div className="def">{isEn ? (g.dEn || g.d) : g.d}</div>
          </div>
        ))}
      </div>
    </article>
  );
}

// =================
// Step / CheckList / Callout
// =================
function Step({n, titleJa, titleEn, children}) {
  return (
    <section className="step">
      <span className="step-num">{n}</span>
      <h3 className="step-title">
        <span className="lang-ja">{titleJa}</span>
        <span className="lang-en">{titleEn}</span>
        <span className="step-title-en">
          <span className="lang-ja">{titleEn}</span>
          <span className="lang-en">{titleJa}</span>
        </span>
      </h3>
      <div className="step-body">{children}</div>
    </section>
  );
}

function CheckList({items, checks, toggle}) {
  return (
    <div className="check-list">
      <div className="check-list-title">
        <span className="lang-ja">フェーズ完了チェック</span>
        <span className="lang-en">Phase completion checklist</span>
      </div>
      {items.map(it => (
        <div key={it.id} className={`check-row ${checks[it.id]?'done':''}`} onClick={()=>toggle(it.id)}>
          <div className="box">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3">
              <polyline points="20 6 9 17 4 12"/>
            </svg>
          </div>
          <div className="label-text">
            <span className="lang-ja">{it.ja}</span>
            <span className="lang-en">{it.en}</span>
          </div>
        </div>
      ))}
    </div>
  );
}

function Callout({type='tip', titleJa, titleEn, ja, en}) {
  const icon = type === 'warn' ? '!' : (type === 'tip' ? 'i' : '?');
  return (
    <div className={`callout ${type}`}>
      <div className="callout-icon">{icon}</div>
      <div className="callout-body">
        <div className="callout-title">
          <span className="lang-ja">{titleJa}</span>
          <span className="lang-en">{titleEn}</span>
        </div>
        <div className="callout-text">
          <span className="lang-ja">{ja}</span>
          <span className="lang-en">{en}</span>
        </div>
      </div>
    </div>
  );
}

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