/* =========================================================
   THÁCH THỨC LỤC ĐỊA MỚI — Page components
   Prologue · CharactersIntro · CharacterCard · Theory
   ChapterHighlight (with expand) · RadarTest · Closing
   ========================================================= */

const { useState: useStateP, useEffect: useEffectP, useRef: useRefP } = React;

/* ---------- Reusable: Lazy image (no placeholder rectangle) ---------- */
function SceneImage({ src, alt, caption }) {
  const [loaded, setLoaded] = useStateP(false);
  const [failed, setFailed] = useStateP(false);
  if (failed) return null;
  return (
    <div className={"scene-img" + (loaded ? " loaded" : "")}>
      <img
        src={"assets/img/" + src}
        alt={alt}
        loading="lazy"
        onLoad={() => setLoaded(true)}
        onError={() => setFailed(true)}
      />
      {caption && <div className="scene-caption">{caption}</div>}
    </div>
  );
}

/* ---------- Prologue 1: from Ch1 — Vàng Cũ Sáng Lần Cuối ---------- */
function Prologue1({ onJump, onPreviewHover, onPreviewLeave }) {
  return (
    <div className="page-content">
      <Eyebrow left>Chương I · Lời tiên tri</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Vàng Cũ Sáng Lần Cuối</h1>
      <Ornament />
      <p className="lead">
        Cánh đồng Tarsen mùa đó vàng đến mức người ta tưởng mặt trời đã ngã xuống đất. Lúa cao ngang vai. Đêm tiệc mừng vụ thu hoạch cuối cùng. Một sứ giả lao vào đại sảnh — quần áo rách, kiếm gãy, máu khô — và nói một câu duy nhất trước khi gục xuống:
      </p>
      <div className="callout">
        <span className="callout-label">Lời từ kẻ vừa trở về phía Đông</span>
        <em>"Quái không rớt vàng nữa."</em>
      </div>
      <p className="dropcap">
        Mỗi ngành nghề trong thời đại chúng ta đều đã nghe câu này — bằng từ khác nhau, từ những sứ giả khác nhau. Doanh thu giảm dù chi tiêu tăng. Khách cũ ít mua lại. Đối thủ làm cùng việc với một phần ba nhân lực. Nhân viên giỏi nghỉ — không vì lương, vì <em>chán</em>. Trong các buổi họp, cụm từ <em>"ngày xưa"</em> xuất hiện ngày càng nhiều.
      </p>
      <p>
        Đây không phải mùa xấu. Đây là <strong>chu kỳ kết thúc</strong> — và nhầm hai cái này với nhau là sai lầm đắt nhất trong sự nghiệp bạn.
      </p>
      <div className="folio">— tr. 7 —</div>
    </div>
  );
}

/* ---------- Prologue 2: Cánh cửa mở — Bạn đang ở map nào? ---------- */
function Prologue2({ onJump, onPreviewHover, onPreviewLeave }) {
  return (
    <div className="page-content">
      <Eyebrow left>Chương I · Cánh cửa mở</Eyebrow>
      <h2 style={{ marginTop: 6 }}>Bạn đang ở map nào?</h2>
      <Ornament glyph="⚜" />
      <p>
        Vương quốc này có hai lục địa: <strong>Cựu Địa</strong> — nơi luật chơi cũ vẫn còn nuôi sống, và <strong>Tân Địa</strong> — vùng đất mới mở sau khi <em>AI</em> phát quang trong sương xanh phía Đông. Giữa hai lục địa là <strong>Cổng Lửa</strong> — không khóa, nhưng rất nhiều người không bước qua.
      </p>
      <div className="theory-diagram" style={{ marginTop: 8 }}>
        <p className="small" style={{ marginBottom: 8 }}>Ba câu hỏi soi gương</p>
        <ol style={{ fontSize: 14.5, paddingLeft: 18, lineHeight: 1.6, margin: 0 }}>
          <li>Bạn đang ở map nào? Cựu Địa, Cổng, hay đã bước qua?</li>
          <li>Quái lớn nhất bạn đang đánh tên là gì? Quái Lặp? Lâu Đài Ảo? Vương Quốc Băng?</li>
          <li>Class hiện tại của bạn còn dùng được trong 5 năm tới không?</li>
        </ol>
      </div>
      <p style={{ marginTop: 14 }}>
        Trả lời xong, lật trang — gặp{" "}
        <CharLink id="aldric"  onJump={() => onJump(9)}  onHover={onPreviewHover} onLeave={onPreviewLeave}>Aldric</CharLink>,{" "}
        <CharLink id="brennon" onJump={() => onJump(10)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Brennon</CharLink>,{" "}
        <CharLink id="kael"    onJump={() => onJump(11)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Kael</CharLink>,{" "}
        <CharLink id="sora"    onJump={() => onJump(12)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Sora</CharLink>, và hai bóng người ở rìa câu chuyện:{" "}
        <CharLink id="heskel"  onJump={() => onJump(13)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Heskel</CharLink> và{" "}
        <CharLink id="mentor"  onJump={() => onJump(14)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Vị Thầy Câm</CharLink>.
      </p>
      <div className="folio">— tr. 8 —</div>
    </div>
  );
}

/* ---------- Characters intro page ---------- */
function CharactersIntro({ onJump, onPreviewHover, onPreviewLeave }) {
  const order = ["aldric", "brennon", "kael", "sora", "heskel", "mentor"];
  return (
    <div className="page-content">
      <Eyebrow left>Chương III</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Sáu Người Chơi</h1>
      <p className="lead" style={{ marginTop: 6 }}>
        Trong vương quốc này, sáu loại người chơi được ghi danh. Mỗi người có một map xuất phát, một quái chính, và một lựa chọn — bước qua Cổng Lửa, đứng giữ Cổng, hoặc đứng ngoài làm thầy.
      </p>
      <Ornament />
      <div className="char-thumb-grid">
        {order.map((id, i) => {
          const c = CHARACTERS[id];
          const page = 9 + i;
          return (
            <div
              key={id}
              className={"char-thumb tone-" + c.color}
              onClick={() => onJump(page)}
              onMouseEnter={(e) => onPreviewHover(id, e)}
              onMouseLeave={onPreviewLeave}>
              <div className="small">{c.tag}</div>
              <div className="char-thumb-name">{c.name.split("—")[0].trim()}</div>
              <div className="char-thumb-epithet">{c.epithet}</div>
              <SceneImage src={c.portrait} alt={c.portraitAlt} />
              <div className="char-thumb-short">{c.short}</div>
            </div>
          );
        })}
      </div>
      <div className="folio">— tr. 9 —</div>
    </div>
  );
}

/* ---------- Single character card ---------- */
function CharacterCard({ characterId, onJump, onPreviewHover, onPreviewLeave }) {
  const c = CHARACTERS[characterId];
  if (!c) return <div className="page-content"><p>Không có nhân vật này.</p></div>;

  const otherIds = Object.keys(CHARACTERS).filter(k => k !== characterId);
  const idxOf = {
    aldric: 9, brennon: 10, kael: 11, sora: 12, heskel: 13, mentor: 14,
  };

  return (
    <div className={"race-page char-page tone-" + c.color}>
      <div className="race-header">
        <div className="race-tag">{c.tag}</div>
        <div className="race-name">{c.name}</div>
        <div className="race-epithet">{c.epithet}</div>
      </div>

      <div className="race-body">
        <div className="race-portrait">
          <SceneImage src={c.portrait} alt={c.portraitAlt} />
        </div>
        <div className="race-info">
          <h3 style={{ marginBottom: 6 }}>Tiểu sử</h3>
          <p>{c.short}</p>

          <h3 style={{ marginBottom: 6, marginTop: 12 }}>Chỉ số cốt lõi</h3>
          <div className="race-stats">
            {c.stats.map(([lbl, val], i) => (
              <div className="stat" key={i}>
                <span className="lbl">{lbl} · {val}</span>
                <div className="bar"><div className="fill" style={{ width: val + "%" }} /></div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="race-skills">
        <h3>Kỹ năng đặc trưng</h3>
        <div className="skill-grid">
          {c.skills.map((s, i) => (
            <div className="skill" key={i}>
              <div className="skill-name">{s.name}</div>
              <div>{s.desc}</div>
              <div className="skill-cost">{s.cost}</div>
            </div>
          ))}
        </div>
      </div>

      <div className="callout char-realworld">
        <span className="callout-label">Trong đời thực</span>
        {c.realWorld}
      </div>

      <p style={{ marginTop: 12, fontSize: 13, color: "var(--ink-soft)" }}>
        Xem thêm:{" "}
        {otherIds.slice(0, 3).map((o, i) => (
          <React.Fragment key={o}>
            <CharLink id={o} onJump={() => onJump(idxOf[o])} onHover={onPreviewHover} onLeave={onPreviewLeave}>
              {CHARACTERS[o].name.split("—")[0].trim()}
            </CharLink>
            {i < 2 ? " · " : ""}
          </React.Fragment>
        ))}
      </p>
    </div>
  );
}

/* ---------- Theory 1: Cây Lửa — 5 nhánh ---------- */
function Theory1({ onJump, onPreviewHover, onPreviewLeave }) {
  const branches = [
    { color: "Đỏ",    name: "AI Operation",      desc: "Prompting, tool, automation cá nhân.",   tone: "fire-red" },
    { color: "Xanh",  name: "Workflow & System", desc: "Quy trình, SOP, dashboard, automation đội.", tone: "fire-blue" },
    { color: "Tím",   name: "Data Sight",         desc: "Đọc số, dự báo, kiểm chứng giả định.",   tone: "fire-purple" },
    { color: "Trắng", name: "Human Trust",        desc: "Giao tiếp, đàm phán, leadership, network.", tone: "fire-white" },
    { color: "Vàng",  name: "Domain Mastery",     desc: "Chuyên môn ngành sâu — rễ của cả cây.",  tone: "fire-gold" },
  ];
  return (
    <div className="page-content">
      <Eyebrow left>Chương IV · Cây Lửa</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Năm Nhánh Lửa</h1>
      <Ornament glyph="⚹" />
      <p className="lead">
        Ở trung tâm Tân Địa có một cây cổ thụ phát sáng — <strong>Cây Lửa</strong>. Năm nhánh, năm loại lửa, năm năng lực cốt lõi của thời AI.
      </p>
      <div className="flame-tree">
        {branches.map(b => (
          <div key={b.color} className={"flame-branch " + b.tone}>
            <div className="flame-icon">★</div>
            <div className="flame-info">
              <div className="flame-name">Lửa {b.color}</div>
              <div className="flame-role">{b.name}</div>
              <div className="flame-desc">{b.desc}</div>
            </div>
          </div>
        ))}
      </div>
      <div className="callout">
        <span className="callout-label">Lời Vị Thầy Câm</span>
        <em>"Lửa Đỏ là câu hỏi đúng. Lửa Xanh là quy trình đúng. Lửa Tím là số đúng. Lửa Trắng là người đúng. Lửa Vàng là việc đúng. Đốt sai một nhánh, cả cây chết."</em>
      </div>
      <div className="folio">— tr. 15 —</div>
    </div>
  );
}

/* ---------- Theory 2: 12 class ---------- */
function Theory2({ onJump }) {
  const classes = [
    { name: "AI Flamebearer",        combo: "Đỏ + Trắng",         price: "25–200tr" },
    { name: "Workflow Smith",        combo: "Xanh + Vàng",        price: "30–500tr",  star: true, note: "Class của Brennon" },
    { name: "Data Seer",             combo: "Tím + Xanh",         price: "25–200tr",  star: true, note: "Class của Sora" },
    { name: "Trust Keeper",          combo: "Trắng + Vàng",       price: "30–300tr" },
    { name: "Global Merchant",       combo: "Đỏ + Vàng",          price: "biến động" },
    { name: "Shadow Creator",        combo: "Đỏ + Tím + Trắng",   price: "20–500tr" },
    { name: "AI Business Architect", combo: "Cả 5 nhánh Tier 2+", price: "80–600tr",  star: true, note: "Class của Kael" },
    { name: "AI Finance Operator",   combo: "Đỏ + Tím + Vàng (finance)", price: "40–400tr" },
    { name: "AI Growth Operator",    combo: "Đỏ + Tím + Vàng (mkt/sales)", price: "35–800tr" },
    { name: "AI Talent Builder",     combo: "Đỏ + Trắng + Vàng (HR)", price: "30–280tr" },
    { name: "Fractional Expert",     combo: "Vàng Tier 4 + Trắng Tier 3+", price: "150–400tr" },
    { name: "AI Ops Architect",      combo: "Xanh Tier 4 + Đỏ Tier 3+", price: "50–800tr" },
  ];
  return (
    <div className="page-content">
      <Eyebrow left>Chương IV · Class Mới</Eyebrow>
      <h2 style={{ marginTop: 6 }}>Mười Hai Class Trong Thời AI</h2>
      <p style={{ marginTop: 8 }}>
        Khi đủ skill và đủ case study, một <em>class mới</em> mở ra. Đây không phải nhãn — là <strong>danh tính nghề được thị trường trao</strong> qua khách hàng trả tiền.
      </p>
      <div className="class-list">
        {classes.map((cls, i) => (
          <div key={i} className={"class-row" + (cls.star ? " starred" : "")}>
            <div className="class-num">{String(i + 1).padStart(2, "0")}</div>
            <div className="class-name">
              {cls.name}
              {cls.star && <span className="class-note">— {cls.note}</span>}
            </div>
            <div className="class-combo">{cls.combo}</div>
            <div className="class-price">{cls.price}/tháng</div>
          </div>
        ))}
      </div>
      <div className="callout">
        <span className="callout-label">Bẫy thường gặp</span>
        Cố gắng unlock cả 3 class cùng lúc trong 6 tháng đầu. Chọn <strong>một class chính</strong>, build case study trong 12 tháng, sau đó mới mở rộng.
      </div>
      <div className="folio">— tr. 16 —</div>
    </div>
  );
}

/* ---------- Chapter highlight with "Đọc tiếp" expand ---------- */
function ChapterHighlight({ chapterId, onJump, onPreviewHover, onPreviewLeave }) {
  const ch = CHAPTERS[chapterId];
  const [expanded, setExpanded] = useStateP(false);
  if (!ch) return null;

  const teasers = {
    ch8: {
      teaser: (
        <>
          <p className="dropcap">
            Một làng nhỏ ở rìa Tân Địa. Làng của những người làm sổ sách. <strong>Quái Lặp</strong> tấn công — khối khổng lồ bằng giấy tờ, bảng tính, email lộn xộn. Người trong làng chạy quanh cố cứu sổ sách. Vô ích — càng cứu, quái càng lớn.
          </p>
          <p>
            <CharLink id="brennon" onJump={() => onJump(10)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Brennon</CharLink>{" "}
            đứng nhìn năm phút. Anh hiểu ngay — không phải vì{" "}
            <CharLink id="kael" onJump={() => onJump(11)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Kael</CharLink>{" "}
            giải thích. Vì cảnh này — anh đã thấy. Trong phòng kế toán mỗi cuối tháng. Trong phòng hành chính của em gái. Trong chính mình mỗi quý khi tổng hợp báo cáo. Ở Cựu Địa, Quái Lặp <em>vô hình</em>. Người ta gọi nó là "công việc cuối tháng" hoặc "thủ tục giấy tờ". Ở Tân Địa, nó có hình. Có thể đánh.
          </p>
          <div className="callout">
            <span className="callout-label">Cấu tạo Quái Lặp — phải có cả 5 thành phần</span>
            Input lặp · Process cố định · Output chuẩn · Tần suất 5+ lần/tuần · Ít quyết định phán đoán. Đủ 5 → automation. Không thương lượng.
          </div>
        </>
      ),
      expand: (
        <>
          <h4>Ba quy trình bạn có thể tự động hóa tuần này</h4>
          <p>Không cần code. Không cần biết kỹ thuật. Chỉ cần biết viết prompt tốt + có template chuẩn + có 4–8 giờ trong tuần này.</p>
          <ol>
            <li><strong>Tổng hợp báo cáo định kỳ.</strong> Cuối tuần/tháng phải tổng hợp từ nhiều nguồn thành 1 báo cáo chuẩn. AI đọc file, tổng hợp theo template, viết phần diễn giải nháp. Tiết kiệm 60–80%.</li>
            <li><strong>Trả lời email/tin nhắn lặp lại.</strong> 30–50% email là câu hỏi tương tự lặp lại. AI phân loại + tạo bản nháp + đề xuất action. Tiết kiệm 40–60%.</li>
            <li><strong>Soạn tài liệu chuẩn.</strong> Proposal, hợp đồng nháp, JD, SOP. AI làm 70% từ template + dữ liệu cụ thể. Tiết kiệm 50–70%.</li>
          </ol>
          <h4>Đo ROI</h4>
          <p>12 giờ tiết kiệm/tháng × 150K/giờ = 1.8tr/tháng/nhân viên. 10 nhân viên = 18tr/tháng = 216tr/năm cho <em>một quy trình duy nhất</em>. Đây là case kinh doanh không cần tranh luận — không ai có thể nói "AI là trend" khi nhìn số này.</p>
          <h4>Bốn bẫy automation cần tránh</h4>
          <ol>
            <li>Automation quy trình đang sai → sai nhanh hơn.</li>
            <li>Tự động hóa rồi quên kiểm tra → AI bịa số âm thầm.</li>
            <li>Đào tạo người dùng không kỹ → workflow đẹp mà team vẫn làm tay cũ.</li>
            <li>Automation việc đáng lẽ phải bỏ hẳn → tự động hóa lãng phí.</li>
          </ol>
        </>
      ),
    },
    ch9: {
      teaser: (
        <>
          <p className="dropcap">
            Thung Lũng Pha Lê. Giữa thung lũng là một <strong>lâu đài</strong>. Pha lê. Lộng lẫy. Đối xứng đến mức không thật. Bên trong có nhiều người mặc áo sang trọng tự xưng "AI Expert", "Strategy Consultant", "Future Specialist". Slide đẹp. Lời hay. Khóa học giá cao.
          </p>
          <p>
            Vorlin — người dẫn đầu — bảo:{" "}
            <em>"Khách hàng X tăng 472% doanh thu sau 90 ngày. NDA, không tiết lộ tên được. Nhưng anh có thể là người tiếp theo."</em>{" "}
            <CharLink id="sora" onJump={() => onJump(12)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Sora</CharLink>{" "}
            22 tuổi đứng ở rìa sảnh, đôi mắt cô quét. Cô nghiêng đầu nhẹ.
          </p>
          <p>
            <em>"Mấy người này không có khoảng trống giữa các câu nói,"</em> cô nói khẽ với{" "}
            <CharLink id="kael" onJump={() => onJump(11)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Kael</CharLink>.{" "}
            <em>"Nghĩa là họ không suy nghĩ."</em>
          </p>
          <div className="callout">
            <span className="callout-label">Vì sao Lâu Đài Ảo sinh sôi nhanh trong thời AI</span>
            AI hạ rào cản tạo content. Slide đẹp, video glossy, sách trắng — vài giờ với AI. <strong>Người làm thật và người diễn thật có công cụ giống nhau.</strong> Khác biệt không nằm ở output bề mặt — nằm ở case study có số liệu cụ thể, kiểm chứng được, không né câu hỏi sâu.
          </div>
        </>
      ),
      expand: (
        <>
          <h4>Bảy dấu hiệu của Fake AI Expert</h4>
          <ol>
            <li>Slide rất đẹp, case study mơ hồ ("NDA cho mọi thứ").</li>
            <li>Nói nhiều buzzword ("disrupt", "unlock potential"), ít cụ thể.</li>
            <li>Không có chuyên môn ngành ("dạy AI cho mọi ngành").</li>
            <li>Bán 20 khóa học, chưa làm xong 1 dự án thật.</li>
            <li>Sợ câu hỏi kỹ thuật — chuyển chủ đề khi bị hỏi sâu.</li>
            <li>Vinh quang cá nhân quá lớn — không khoe khách hàng, chỉ khoe bản thân.</li>
            <li>Không có khách hàng dài hạn — khách dùng 1 lần rồi không quay lại.</li>
          </ol>
          <h4>Năm câu hỏi để lọc 90% Lâu Đài Ảo</h4>
          <ol>
            <li>Anh đã làm dự án nào với khách hàng cụ thể trong 6 tháng qua? Cho tôi số liệu trước-sau.</li>
            <li>Khi AI sai trong dự án, anh xử lý thế nào? Cho ví dụ cụ thể.</li>
            <li>Trong ngành tôi, AI làm tốt cái gì, làm tệ cái gì? 3 ví dụ mỗi loại.</li>
            <li>Tôi có thể nói chuyện với 1 khách hàng cũ của anh không?</li>
            <li>Sau 3 tháng tôi không thấy kết quả, mình sẽ làm gì?</li>
          </ol>
          <p>
            Sora — không ai bảo — lấy <strong>mảnh kim loại xanh</strong> của mình ra. Không như vũ khí. Cô cứa nhẹ vào cổ tay trái. Một giọt máu thật. Đau thật.
          </p>
          <p>
            Lâu Đài rung chuyển. Pha lê nứt. Người trong lâu đài tan ra như sương. Cô nhìn quanh — không có vinh quang, không có lời khen, chỉ có sàn pha lê đang vỡ.
          </p>
          <p style={{ fontStyle: "italic", color: "var(--blood)" }}>
            "Hóa ra giả là thế này..."
          </p>
        </>
      ),
    },
    ch11: {
      teaser: (
        <>
          <p className="dropcap">
            Một vương quốc lớn ở giữa Tân Địa. Kiến trúc lộng lẫy. <strong>Hoàn toàn phủ băng.</strong> Cờ phướn đóng băng giữa gió. Quân lính đóng băng giữa bước đi. 412 người còn sống sót trong tổng số 12.000 — mỗi tuần thêm một mảnh thành đóng băng.
          </p>
          <p>
            Vương quốc này tên là <strong>Aldoran</strong>. Vua nó là{" "}
            <CharLink id="aldric" onJump={() => onJump(9)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Aldric</CharLink>{" "}
            — Lãnh Chúa Cựu Địa mà{" "}
            <CharLink id="brennon" onJump={() => onJump(10)} onHover={onPreviewHover} onLeave={onPreviewLeave}>Brennon</CharLink>{" "}
            đã phục vụ 21 năm. Ông đã giữ vương quốc này 47 năm, ở cả hai map. Aldric đã già hơn.
          </p>
          <div className="callout">
            <span className="callout-label">Bốn lớp băng của Frozen Kingdom</span>
            (1) Quy trình băng — SOP cũ không ai dám sửa. (2) Dữ liệu băng — số liệu rải rác, quyết định bằng cảm tính. (3) Quyết định băng — họp nhiều, quyết ít. (4) Văn hóa băng — nhân viên không dám nói thật.
          </div>
          <p>
            Chín đoàn đã đến trước Brennon. Tất cả thất bại — vì họ đến <em>một class</em>. <strong>Frozen Kingdom phải phá bằng combo.</strong>
          </p>
        </>
      ),
      expand: (
        <>
          <h4>Bốn class phá băng — combo</h4>
          <ul>
            <li><strong>Workflow Smith</strong> phá quy trình băng — vẽ lại SOP, automation phần lặp.</li>
            <li><strong>Data Seer</strong> phá dữ liệu băng — xây dashboard, chuẩn hóa số.</li>
            <li><strong>AI Business Architect</strong> phá quyết định băng — khung quyết định mới, phân quyền.</li>
            <li><strong>AI Flamebearer / Trust Keeper</strong> phá văn hóa băng — tạo không gian phản hồi an toàn.</li>
          </ul>
          <p>Bài học cá nhân: nếu bạn ở trong tổ chức đóng băng, <strong>đừng cố một mình giải quyết</strong>. Tìm 3 người trong tổ chức mỗi người mạnh một nhánh khác. Tạo coalition. Một mình không đủ.</p>
          <h4>Cảnh đặt vương miện</h4>
          <p>
            Aldric quay lại. Đã già hơn nhiều so với Chương 1. Mệt mỏi. Ông nhìn bốn người đoàn — Brennon, Sora, Kael, Lyra — và lần đầu trong cả sách, ông <strong>mỉm cười</strong>.
          </p>
          <p>
            Ông tháo vương miện trên đầu. Đặt xuống ghế đá. Rồi đặt <strong>đồng tiền vàng cổ hai mặt</strong> lên trên vương miện. Một mặt cánh đồng lúa, một mặt cánh cổng. Ông nói:
          </p>
          <p style={{ fontStyle: "italic", color: "var(--gold)" }}>
            "Ta đã giữ cái này quá lâu. Đến lượt người biết cầm Lửa Mới."
          </p>
          <p>
            Rồi ông quay đi. Không nhìn lại. Tiếng gậy chống của ông chạm xuống sàn đá vọng dài trong sảnh băng đang tan.
          </p>
          <p>
            Brennon bước tới. Nhặt đồng tiền lên. Không cầm vương miện — chỉ đồng tiền. Anh đưa cho <strong>Sora</strong>. Sora — 22 tuổi, chưa từng ở Cựu Địa — nhận đồng tiền. Nhìn cả hai mặt. Cô hiểu — lần đầu trong đời cô hiểu: Cựu Địa đã trao cái gì cho cô. Không qua sách. Qua một đồng tiền có hai mặt.
          </p>
        </>
      ),
    },
  };

  const content = teasers[chapterId] || { teaser: <p>Đang viết...</p>, expand: null };

  return (
    <div className="page-content chapter-highlight">
      <Eyebrow left>Chương {ch.num} · Trận đánh</Eyebrow>
      <h1 style={{ marginTop: 6 }}>{ch.title}</h1>
      <Ornament glyph="⚔" />

      <SceneImage src={ch.scene} alt={ch.sceneAlt} caption={`Cảnh: ${ch.title}`} />

      <div className="callout chapter-quote">
        <span className="callout-label">Quote</span>
        <em>"{ch.quote}"</em>
      </div>

      <div className="chapter-teaser">{content.teaser}</div>

      {content.expand && (
        <>
          <button
            className="expand-btn"
            onClick={() => setExpanded(e => !e)}
            aria-expanded={expanded}>
            {expanded ? "▲ Thu lại" : "▼ Đọc tiếp toàn bộ tóm tắt chương"}
          </button>
          {expanded && (
            <div className="chapter-expand">
              {content.expand}
              <div className="chapter-full-link">
                <button
                  className="expand-btn"
                  onClick={() => onJump(22 + parseInt(chapterId.slice(2), 10))}>
                  📜 Đọc toàn văn Chương {ch.num} →
                </button>
              </div>
            </div>
          )}
        </>
      )}

      <div className="folio">— tr. {17 + Object.keys(CHAPTERS).indexOf(chapterId)} —</div>
    </div>
  );
}

/* ---------- Radar test (ADKAR 5-trục) ---------- */
function RadarTest() {
  const axes = ["Mindset", "Vision", "Learning", "Planning", "Commitment"];
  const [scores, setScores] = useStateP([12, 10, 8, 14, 9]);
  const svgRef = useRefP(null);
  const N = 5, R = 110, MAX = 20;

  const pt = (i, v) => {
    const a = -Math.PI / 2 + (2 * Math.PI * i) / N;
    const r = (v / MAX) * R;
    return [r * Math.cos(a), r * Math.sin(a)];
  };
  // Labels live well outside the polygon (~30px gap) so they never overlap.
  const labelR = R + 38;

  const polyPts = scores.map((s, i) => pt(i, s).join(",")).join(" ");
  const total = scores.reduce((a, b) => a + b, 0);

  const stage = total <= 30 ? "Vẫn ở Cựu Địa — chưa biết Cổng đã mở"
              : total <= 50 ? "Đã thấy Cổng — chưa bước qua"
              : total <= 70 ? "Đã bước qua Cổng — đang ở rừng Tân Địa"
              : total <= 85 ? "Đang build class — có nền, chưa unlock"
              :              "Đã unlock class — sẵn sàng mentor người khác";

  const weakIdx = scores.reduce((min, s, i, arr) => (s < arr[min] ? i : min), 0);
  const weakAxis = axes[weakIdx];

  return (
    <div className="page-content radar-test">
      <Eyebrow left>Chương VI · Bài kiểm tra</Eyebrow>
      <h2 style={{ marginTop: 6 }}>Bạn đang ở map nào?</h2>
      <p style={{ marginTop: 4, fontSize: 14 }}>
        Đo nhanh 5 trục ADKAR. Mỗi trục 0–20 điểm. Kéo slider thử trước — bài kiểm tra đầy đủ 20 câu nằm trong Phụ lục E của ebook.
      </p>
      <Ornament glyph="✦" />

      <div className="radar-wrap">
        <svg ref={svgRef} viewBox="-180 -170 360 340" className="radar-svg">
          {[5, 10, 15, 20].map(level => {
            const pts = [];
            for (let i = 0; i < N; i++) pts.push(pt(i, level).join(","));
            return <polygon key={level} points={pts.join(" ")} className="radar-grid" />;
          })}
          {axes.map((_, i) => {
            const [x, y] = pt(i, MAX);
            return <line key={i} x1="0" y1="0" x2={x} y2={y} className="radar-axis" />;
          })}
          <polygon points={polyPts} className="radar-area" />
          {scores.map((s, i) => {
            const [x, y] = pt(i, s);
            return <circle key={i} cx={x} cy={y} r="4" className="radar-point" />;
          })}
          {axes.map((label, i) => {
            const a = -Math.PI / 2 + (2 * Math.PI * i) / N;
            const x = labelR * Math.cos(a);
            const y = labelR * Math.sin(a);
            return (
              <text
                key={i}
                x={x} y={y}
                className="radar-label"
                textAnchor={Math.abs(x) < 6 ? "middle" : (x > 0 ? "start" : "end")}
                dominantBaseline={y < -6 ? "auto" : (y > 6 ? "hanging" : "middle")}>
                {label}
              </text>
            );
          })}
        </svg>

        <div className="radar-controls">
          {axes.map((label, i) => (
            <div className="radar-slider-row" key={label}>
              <span className="radar-slider-label">{label}</span>
              <input
                type="range" min="0" max="20" step="1"
                value={scores[i]}
                onChange={(e) => {
                  const v = +e.target.value;
                  setScores(prev => prev.map((s, j) => j === i ? v : s));
                }}
              />
              <span className="radar-slider-val">{scores[i]}</span>
            </div>
          ))}
          <div className="radar-total">
            <div><span className="lbl">Tổng / 100</span><span className="val">{total}</span></div>
            <div className="radar-stage">{stage}</div>
            <div className="radar-weak">Trục yếu nhất: <strong>{weakAxis}</strong> — đầu tư trước.</div>
          </div>
        </div>
      </div>

      <p className="small" style={{ marginTop: 14 }}>
        Phụ lục E của ebook có 20 câu hỏi đầy đủ (4 câu × 5 trục) + lời khuyên chi tiết cho từng trục yếu.
      </p>
      <div className="folio">— tr. 21 —</div>
    </div>
  );
}

/* ---------- Closing CTA ---------- */
function Closing({ onJump }) {
  return (
    <div className="page-content closing">
      <Eyebrow left>Hồi kết</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Còn bạn —</h1>
      <h1 style={{ marginTop: 0, color: "var(--gold)" }}>Bạn đang ở map nào?</h1>
      <Ornament glyph="ᛏ" />

      <p className="lead">
        Sách này có 12 chương + 5 phụ lục — khoảng 80.000 từ. Trang web bạn vừa đọc là bản highlight cho blog. Nếu nó chạm bạn, ebook đầy đủ đợi sau cổng tiếp theo.
      </p>

      <div className="closing-actions">
        <a href="#" className="cta-btn primary" data-action="download-ebook">
          📜 Tải Ebook Đầy Đủ
        </a>
        <a href="https://hocvienx5.com" className="cta-btn secondary" target="_blank" rel="noreferrer">
          → Học Viện X5 · Cộng đồng đi cùng
        </a>
      </div>

      <div className="callout">
        <span className="callout-label">Bốn câu hỏi để bắt đầu hôm nay</span>
        <ol style={{ margin: "8px 0 0", paddingLeft: 18, lineHeight: 1.7 }}>
          <li>Bạn đang ở map nào? (Cựu Địa · Cổng · Tân Địa · Đã unlock class)</li>
          <li>Quái lớn nhất hiện tại là gì? (Quái Lặp · Chợ Câm · Lâu Đài Ảo · Frozen Kingdom · Gate Blockers)</li>
          <li>Class hiện tại còn dùng được trong 5 năm tới không?</li>
          <li>Một việc nhỏ bạn sẽ làm trong 7 ngày tới — viết ra: <em>việc gì, ngày nào, ai giúp.</em></li>
        </ol>
      </div>

      <p style={{ marginTop: 18, fontStyle: "italic", color: "var(--ink-soft)" }}>
        Cổng Lửa không khóa. Không ai có thể bước qua thay bạn. Nhưng cũng không ai có thể cấm bạn bước qua — kể cả chính bạn.
      </p>

      <div className="folio">— Hết Quyển I · tr. 22 —</div>
    </div>
  );
}

/* ---------- Full chapter page — renders markdown via marked.js ---------- */
function renderMarkdown(md) {
  if (!md) return "";
  if (window.marked && typeof window.marked.parse === "function") {
    try { return window.marked.parse(md, { breaks: false, gfm: true }); }
    catch (e) { console.error("marked failed:", e); }
  }
  // Fallback — wrap in <pre> so content is still readable
  const esc = String(md).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  return "<pre>" + esc + "</pre>";
}

function FulltextIntro({ onJump }) {
  return (
    <div className="page-content">
      <Eyebrow left>Phần VII · Toàn Văn</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Toàn Văn — 12 Chương</h1>
      <Ornament glyph="✦" />
      <p className="lead">
        Sau đây là bản đầy đủ — 12 chương sách. Không cắt, không tóm. Mở cánh cổng từ Tarsen tới Vương Quốc Đột Phá theo đúng thứ tự câu chuyện.
      </p>
      <ol className="fulltext-toc">
        {Object.values(CHAPTERS).map((ch, i) => (
          <li key={ch.id} onClick={() => onJump(23 + i)}>
            <span className="ft-num">Ch. {ch.num}</span>
            <span className="ft-title">{ch.title}</span>
            <span className="ft-quote">"{ch.quote}"</span>
          </li>
        ))}
      </ol>
      <div className="folio">— tr. 23 —</div>
    </div>
  );
}

function ChapterFull({ chapterId }) {
  const ch = CHAPTERS[chapterId];
  if (!ch) return <div className="page-content">Chương không tồn tại.</div>;
  const md = (window.CHAPTER_CONTENT && window.CHAPTER_CONTENT[ch.contentKey]) || "";
  const html = renderMarkdown(md);
  return (
    <div className="page-content chapter-full">
      <Eyebrow left>Chương {ch.num} · Toàn văn</Eyebrow>
      <div className="chapter-md-body" dangerouslySetInnerHTML={{ __html: html }} />
      <div className="folio">— Hết Chương {ch.num} —</div>
    </div>
  );
}

function AppendixIntro({ onJump }) {
  return (
    <div className="page-content">
      <Eyebrow left>Phần VIII · Phụ Lục</Eyebrow>
      <h1 style={{ marginTop: 6 }}>Năm Quyển Phụ Lục</h1>
      <Ornament glyph="ᛟ" />
      <p className="lead">
        Phần tham chiếu cho người muốn đi sâu — skill tree đầy đủ, catalog 12 class, quest pack 30 ngày, bảng thuật ngữ, và bài kiểm tra ADKAR 20 câu.
      </p>
      <ol className="fulltext-toc">
        {Object.values(APPENDICES).map((ap, i) => (
          <li key={ap.id} onClick={() => onJump(36 + i)}>
            <span className="ft-num">Phụ lục {ap.code}</span>
            <span className="ft-title">{ap.title}</span>
            <span className="ft-quote">{ap.sub}</span>
          </li>
        ))}
      </ol>
      <div className="folio">— tr. 36 —</div>
    </div>
  );
}

function AppendixFull({ appendixId }) {
  const ap = APPENDICES[appendixId];
  if (!ap) return <div className="page-content">Phụ lục không tồn tại.</div>;
  const md = (window.APPENDIX_CONTENT && window.APPENDIX_CONTENT[ap.contentKey]) || "";
  const html = renderMarkdown(md);
  return (
    <div className="page-content chapter-full appendix-full">
      <Eyebrow left>Phụ lục {ap.code}</Eyebrow>
      <div className="chapter-md-body" dangerouslySetInnerHTML={{ __html: html }} />
      <div className="folio">— Hết Phụ Lục {ap.code} —</div>
    </div>
  );
}

Object.assign(window, {
  SceneImage,
  Prologue1, Prologue2,
  CharactersIntro, CharacterCard,
  Theory1, Theory2,
  ChapterHighlight,
  RadarTest, Closing,
  FulltextIntro, ChapterFull, AppendixIntro, AppendixFull,
});
