// ===== NEXTAGE shared data + primitives =====
const AURAS = [
  { id: 'em', name: 'エメラルド', c: 'oklch(0.78 0.17 163)' },
  { id: 'sky', name: 'スカイ', c: 'oklch(0.75 0.15 235)' },
  { id: 'amber', name: 'アンバー', c: 'oklch(0.82 0.16 75)' },
  { id: 'rose', name: 'ローズ', c: 'oklch(0.72 0.19 355)' },
  { id: 'violet', name: 'バイオレット', c: 'oklch(0.68 0.19 295)' },
  { id: 'flame', name: 'フレイム', c: 'oklch(0.7 0.2 35)' },
];
const auraC = (id) => (AURAS.find(a => a.id === id) || AURAS[0]).c;

const S = (k, a, h, tpl) => ({ k, a, h, tpl });
const INITIAL_ROADMAP = {
  id: 'rm1',
  title: '声活アクションプラン',
  owner: 'たちばな',
  slug: 'tachibana/seikatsu',
  published: true,
  stages: [
    { id: 's1', title: '声の土台をつくる', aura: 'em', steps: [
      S('BODY', '鏡の前で、肩の力を抜いて立つ', '頭のてっぺんが糸で吊られているイメージで', 0),
      S('BREATH', 'お腹に手を当てて、4秒吸う', '肩が上がったらやり直し', 0),
      S('BREATH', '8秒かけて「スー」と吐き切る', '最後まで音の太さを変えない', 0),
      S('BREATH', '吸う→吐くを5セット', '終わったら首と肩を軽く回す', 0),
      S('CHECK', '今日の体の重さを10段階でメモ', '数字は毎日比べるためのもの', 1),
      S('DONE', '明日も同じ時間にアラームをセット', '続けるコツは「同じ時間」', 0),
    ]},
    { id: 's2', title: '毎日の発声ルーティン', aura: 'sky', steps: [
      S('MOUTH', '割りばしを横にくわえて「あ・え・い・う・え・お・あ・お」', '口角が下がらないように', 2),
      S('MOUTH', 'リップロールを30秒', '唇が止まったら息の量を増やす', 2),
      S('PITCH', 'いちばん低い音から高い音まで「ん〜」で上がる', '喉ではなく鼻の奥に響かせる', 2),
      S('PITCH', '話す高さ（地声）を1音決める', 'ピアノアプリで音名をメモ', 1),
      S('READ', '外郎売の冒頭を1回読む', 'うまさより、最後まで止まらないこと', 2),
      S('READ', 'もう1回、半分の速さで読む', '子音をはっきり置く', 2),
      S('LOG', '今日のルーティンにかかった時間を記録', '15分以内が目安', 1),
    ]},
    { id: 's3', title: '録音して聴き返す', aura: 'amber', steps: [
      S('REC', 'スマホのボイスメモを開く', '機内モードにすると通知が入らない', 1),
      S('REC', '外郎売の冒頭を1回だけ録音する', '撮り直さない。今の声を残す', 3),
      S('LISTEN', 'イヤホンで1回聴く', '恥ずかしさは成長のサイン', 1),
      S('LISTEN', '気になった所を1つだけ書く', '1つに絞ると直せる', 1),
      S('LOG', 'ファイル名に日付をつけて保存', '1か月後に聴き比べる', 1),
    ]},
    { id: 's4', title: 'ボイスサンプルを作る', aura: 'rose', steps: [
      S('PLAN', '自分の得意な役を3つ書き出す', '「言われたことがある役」も入れる', 1),
      S('SCRIPT', '1役につき15秒のセリフを選ぶ', '感情が1つだけのセリフにする', 2),
      S('REC', '静かな部屋で、3役を録る', '布団をかぶるだけでも音が変わる', 3),
      S('EDIT', '頭と終わりの無音を切る', '0.5秒だけ残す', 2),
      S('CHECK', '友だち1人に聴いてもらう', '聞くのは「どの役が一番か」だけ', 1),
      S('DONE', '完成版をクラウドに保存する', 'URLを控えておく', 2),
    ]},
    { id: 's5', title: '事務所・オーディションに出す', aura: 'violet', steps: [
      S('LIST', '応募したい事務所を3つ選ぶ', '所属声優の声の傾向を見る', 1),
      S('READ', '1社の募集要項を最後まで読む', '締切と形式だけメモ', 1),
      S('SEND', 'ボイスサンプルを1社に送る', '送った日を記録', 2),
      S('NEXT', '次に送る日をカレンダーに入れる', '1社で止めない', 0),
    ]},
  ],
};

// 受講者の初期進捗（デモ用）: stageId -> cleared count, 'new' flags
const INITIAL_PROGRESS = { s1: 6, s2: 3, s3: 0, s4: 0, s5: 0 };

// ===== primitives =====
function Logo({ size = 18, color, mark = true, style }) {
  return (
    <span className="logo" style={{ fontSize: size, color, ...style }}>
      {mark && <span className="logo-mark"><i /><i /><i /></span>}
      NEXTAGE
    </span>
  );
}

function LogoPattern({ opacity = 0.05, color = '#0f1f19', rows = 16 }) {
  const row = Array.from({ length: 10 }, (_, i) => <span key={i}>NEXTAGE</span>);
  return (
    <div className="lpat" style={{ opacity, color }} aria-hidden>
      <div className="lpat-in">
        {Array.from({ length: rows }, (_, r) => <div className="lpat-row" key={r}>{row}</div>)}
      </div>
    </div>
  );
}

// スライド1枚を表示するコンポーネント（画像スライドまたはデザインテンプレート）
// 引数: step（スライドのデータ情報）, idx（現在のスライド番号 0始まり）, total（全体の枚数）, style（CSSスタイル）
// 戻り値: 画面に表示されるスライドのJSX要素
function Slide({ step, idx, total, style }) {
  if (!step) return null;

  // 画像（写真やスライドの画像ファイル）が登録されている場合は、画像を16:9の比率で表示します
  // （アルバムの台紙に写真をきれいに貼り付けるような処理です）
  if (step.image) {
    return (
      <div className="slide slide-real-image" style={style}>
        <img src={step.image} alt={step.a || 'スライド'} style={{ width: '100%', height: '100%', objectFit: 'contain', display: 'block' }} />
        <div className="sl-n" style={{ background: 'rgba(0,0,0,0.55)', padding: '2px 8px', borderRadius: 6, color: '#fff' }}>
          {String(idx + 1).padStart(2, '0')} / {String(total).padStart(2, '0')}
        </div>
      </div>
    );
  }

  // 画像がまだない場合は、見やすいCSSデザインテンプレートで文字を表示します
  return (
    <div className={'slide tpl' + (step.tpl ?? 0)} style={style}>
      <div className="sl-n">{String(idx + 1).padStart(2, '0')} / {String(total).padStart(2, '0')}</div>
      <div className="sl-k">{step.k}</div>
      <div className="sl-a">{step.a}</div>
      {step.h && <div className="sl-h">{step.h}</div>}
    </div>
  );
}

function CheckIcon({ size = 14, color = '#fff' }) {
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.2 3L13 4.5" stroke={color} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" /></svg>
  );
}
function Chevron({ dir = 'r', size = 14 }) {
  const r = { r: 0, l: 180, d: 90, u: -90 }[dir];
  return (
    <svg width={size} height={size} viewBox="0 0 16 16" style={{ transform: `rotate(${r}deg)` }} fill="none"><path d="M6 3l5 5-5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" /></svg>
  );
}

// 縁 (frame) — the core product surface
function Frame({ cfg, stage, cleared, total, compact, children, frameRef, onSlideClick, fx }) {
  const isPro = cfg.plan === 'pro';
  const style = isPro ? 'glass' : (cfg.frameStyle === 'black' ? 'black' : 'white');
  const gc = cfg.glassColor;
  const pct = total ? (cleared / total) * 100 : 0;
  const fill = style === 'glass' ? '#fff' : auraC(stage.aura);
  return (
    <div ref={frameRef} className={'frame fr-' + style + (compact ? ' compact' : '')} style={{ '--gc': gc, '--aura': auraC(stage.aura) }}>
      <div className="fr-slide" onClick={onSlideClick}>{children}</div>
      <div className="fr-band">
        <div className="fr-title">{stage.title}</div>
        <div className="fr-right">
          {isPro && (
            <div className="fr-gauge">
              <div className="fr-gtrack"><div className="fr-gfill" style={{ width: pct + '%', background: fill, boxShadow: `0 0 10px ${fill}` }} /></div>
              <span>{cleared}/{total}</span>
            </div>
          )}
          {(!isPro || cfg.poweredBy) && (
            <div className="fr-pow">Powered by <Logo size={10} color="currentColor" /></div>
          )}
        </div>
      </div>
      {fx}
    </div>
  );
}

Object.assign(window, { AURAS, auraC, INITIAL_ROADMAP, INITIAL_PROGRESS, Logo, LogoPattern, Slide, CheckIcon, Chevron, Frame });
