/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakSelect, TweakColor, TweakSlider, ALBUM_PAGES */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "blossom",
  "font": "serif",
  "cover": "0048",
  "paper": "warm"
}/*EDITMODE-END*/;

const PALETTES = {
  blossom: {
    name: "綻放 Blossom",
    bg: "#f4dde0",
    bg2: "#e8c8cd",
    paper: "#fdf6f0",
    paperEdge: "#f1e2d6",
    ink: "#3a1f24",
    accent: "#c4546a",
    accentSoft: "#d98a96",
    gold: "#a07650",
  },
  carnation: {
    name: "康乃馨 Carnation",
    bg: "#ead7d2",
    bg2: "#d8b8b3",
    paper: "#fbf3ec",
    paperEdge: "#ecd9cd",
    ink: "#3d2226",
    accent: "#b03e54",
    accentSoft: "#cc7283",
    gold: "#967049",
  },
  rose: {
    name: "玫瑰 Rose",
    bg: "#e8c5c5",
    bg2: "#cf9c9c",
    paper: "#faf1ec",
    paperEdge: "#e7d3c8",
    ink: "#34181d",
    accent: "#a8334a",
    accentSoft: "#c5697b",
    gold: "#8c6244",
  },
  peach: {
    name: "蜜桃 Peach",
    bg: "#f3d9c8",
    bg2: "#e2b89c",
    paper: "#fcf4ea",
    paperEdge: "#efddc9",
    ink: "#3a241c",
    accent: "#c95e3f",
    accentSoft: "#dd8e6d",
    gold: "#a06f3e",
  },
};

const FONTS = {
  serif: {
    name: "經典襯線 Serif",
    cn: "'Noto Serif TC', serif",
    en: "'Cormorant Garamond', 'Noto Serif TC', serif",
    display: "'Cormorant Garamond', 'Noto Serif TC', serif",
  },
  modern: {
    name: "現代無襯線 Modern",
    cn: "'Noto Sans TC', sans-serif",
    en: "'Inter', 'Noto Sans TC', sans-serif",
    display: "'Inter', 'Noto Sans TC', sans-serif",
  },
  editorial: {
    name: "雜誌 Editorial",
    cn: "'Noto Serif TC', serif",
    en: "'Playfair Display', 'Noto Serif TC', serif",
    display: "'Playfair Display', 'Noto Serif TC', serif",
  },
  handwritten: {
    name: "手寫 Handwritten",
    cn: "'Noto Serif TC', serif",
    en: "'Caveat', 'Noto Serif TC', cursive",
    display: "'Caveat', 'Noto Serif TC', cursive",
  },
};

const PAPERS = {
  warm: { name: "暖白", filter: "none" },
  cream: { name: "米白", filter: "sepia(0.05) saturate(0.95)" },
  film: { name: "底片感", filter: "sepia(0.08) contrast(1.04) saturate(0.92)" },
};

// ─────────────────────────────────────────────
// Photo curation: highlights from 55 source photos
// Mixes hero shots, candids, ceremony, service moments, group shots
// ─────────────────────────────────────────────
const PHOTOS = [
  { id: "0048", o: "p" }, { id: "0001", o: "p" }, { id: "0010", o: "p" },
  { id: "0004", o: "l" }, { id: "0007", o: "l" }, { id: "0008", o: "p" },
  { id: "0011", o: "p" }, { id: "0014", o: "p" }, { id: "0015", o: "p" },
  { id: "0017", o: "l" }, { id: "0018", o: "l" }, { id: "0020", o: "p" },
  { id: "0023", o: "p" }, { id: "0025", o: "p" }, { id: "0028", o: "p" },
  { id: "0029", o: "l" }, { id: "0030", o: "p" }, { id: "0033", o: "p" },
  { id: "0036", o: "p" }, { id: "0040", o: "p" }, { id: "0042", o: "l" },
  { id: "0044", o: "l" }, { id: "0046", o: "p" }, { id: "0050", o: "p" },
  { id: "0052", o: "p" }, { id: "0054", o: "p" }, { id: "0055", o: "p" },
];

const photoSrc = (id) => `photos/${id}.jpg`;

// ─────────────────────────────────────────────
// PAGE LAYOUT BUILDER
// Pages are designed as left/right spreads; index 0 is cover (right-only).
// We build a sequence of "leaves" — each leaf has a front (right side when closed)
// and a back (left side when opened).
// ─────────────────────────────────────────────

function buildPages(coverId) {
  const pages = [];

  // Page 0: COVER (right-side of closed book)
  pages.push({ kind: "cover", coverId });

  // Page 1: inside-cover (left when first opened) — dedication
  pages.push({ kind: "dedication" });

  // Page 2: title spread right
  pages.push({ kind: "title" });

  // Page 3: index / table of contents-ish "篇章" left side
  pages.push({ kind: "chapter", num: "01", cn: "花備好了", en: "Flowers Ready" });

  // 04-05: full bleed photo spread + portrait pair
  // Right side of chapter 01 → frontispiece using the (former) cover photo.
  pages.push({ kind: "fullbleed", id: "0048" });
  pages.push({ kind: "fullbleed", id: "0036" });

  // 06-07: photo + quote
  pages.push({ kind: "quote", text: "您的每件事，都是我們最重要的小事。", en: "Your every little thing — our greatest concern.", attribution: "永明社區發展協會" });
  pages.push({ kind: "single", id: "0008", caption: "逗陣。" });

  // 08-09: triple grid + hero
  pages.push({ kind: "triple", ids: ["0011", "0014", "0015"], heading: "棚下，巷口，街角" });
  pages.push({ kind: "hero", id: "0017", caption: "「各位媽媽好。」", en: "To all the mothers — hello." });

  // 過場三宮格 — 從「各位媽媽好」開場過渡到 chapter 02、同時讓 chapter 02 / 03 落在左頁
  pages.push({ kind: "triple", ids: ["0019", "0013", "0006"], heading: "棚下，鍋邊，門口" });

  // chapter 02
  pages.push({ kind: "chapter", num: "02", cn: "午後歡聚", en: "Afternoon Gathering" });
  pages.push({ kind: "fullbleed", id: "0004", caption: "可甜可鹹。", subcaption: "Sweet or savory." });

  // mosaic spread
  pages.push({ kind: "mosaic", ids: ["0020", "0023", "0025"], heading: "上台說幾句" });
  pages.push({ kind: "duo", ids: ["0028", "0030"], heading: "小朋友也來幫忙", sub: "Little hands, learning to give." });

  // single + double
  pages.push({ kind: "single", id: "0033", caption: "傳承。" });
  pages.push({ kind: "fullbleed", id: "0007", caption: "里上的媽媽，一位一位來。", subcaption: "Our mothers, one by one." });

  // chapter 03
  pages.push({ kind: "chapter", num: "03", cn: "一支一支地送", en: "One by One" });
  pages.push({ kind: "triple", ids: ["0001", "0018", "0044"], heading: "一個一個，慎重地遞過去" });

  // photo pair
  pages.push({ kind: "duo", ids: ["0040", "0046"], heading: "一支花，配一句祝福", sub: "One flower, one wish." });
  pages.push({ kind: "fullbleed", id: "0042", caption: "母親節快樂——今年我們也陪您過。", subcaption: "Happy Mother's Day — with you again this year." });

  // closing pair
  pages.push({ kind: "triple", ids: ["0050", "0052", "0054"], heading: "一個下午就這樣過完了" });
  pages.push({ kind: "single", id: "0055", caption: "謝謝里上的媽媽，我們下次活動見。" });

  // colophon
  pages.push({ kind: "colophon" });
  pages.push({ kind: "back" });

  return pages;
}

// ─────────────────────────────────────────────
// Page renderers
// ─────────────────────────────────────────────

function PageInner({ page, palette, fonts, paperFilter, side }) {
  const cn = fonts.cn;
  const en = fonts.en;
  const display = fonts.display;

  if (page.kind === "cover") {
    return (
      <div className="page-content cover-page cover-typeonly" style={{ fontFamily: cn, background: palette.paper, color: palette.ink }}>
        <img className="flora-deco flora-tl" src="art/carnations.png" alt="" />
        <img className="flora-deco flora-br" src="art/carnations.png" alt="" />

        {/* Top masthead bar — like a magazine cover header */}
        <div className="cover-mast" style={{ fontFamily: en, color: palette.ink }}>
          <span className="cm-issue">VOL. 01 · NO. 09</span>
          <span className="cm-rule" style={{ background: palette.ink, opacity: 0.4 }} />
          <span className="cm-date">MAY · MMXXVI</span>
        </div>

        {/* Cover lines — left vertical strip */}
        <div className="cover-lines" style={{ fontFamily: en }}>
          <div className="cl-item"><em>27</em> Frames<span className="cl-zh" style={{ fontFamily: cn }}>27 張選錄</span></div>
          <div className="cl-item"><em>03</em> Chapters<span className="cl-zh" style={{ fontFamily: cn }}>三個章節</span></div>
          <div className="cl-item"><em>01</em> Afternoon<span className="cl-zh" style={{ fontFamily: cn }}>一個下午</span></div>
        </div>

        <div className="cover-frame">
          <div className="cover-eyebrow" style={{ fontFamily: en, color: palette.accent }}>
            <span className="ce-rule" style={{ background: palette.accent }} />
            <span>The Mother&apos;s Day Issue</span>
            <span className="ce-rule" style={{ background: palette.accent }} />
          </div>
          <div className="cover-title" style={{ fontFamily: display }}>
            母親節<br /><em>感恩活動</em>
          </div>
          <div className="cover-rule" style={{ background: palette.gold }} />
          <div className="cover-meta" style={{ fontFamily: en }}>
            <span>05 · 09</span>
            <span className="cover-dot">·</span>
            <span>永明里 社區發展協會</span>
          </div>
        </div>

        {/* Bottom-right SKU like a real magazine */}
        <div className="cover-sku" style={{ fontFamily: en, color: palette.ink }}>
          <div className="sku-bars" aria-hidden="true">
            <i /><i /><i /><i /><i /><i /><i /><i /><i /><i /><i /><i />
          </div>
          <div className="sku-id">YM · 26 · 0509</div>
        </div>
      </div>
    );
  }

  if (page.kind === "dedication") {
    return (
      <div className="page-content dedication" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="ded-eyebrow" style={{ fontFamily: en, color: palette.accent }}>
          <span className="ee-rule" style={{ background: palette.accent }} />
          <span>Dedication · 獻辭</span>
        </div>
        <img className="flora-deco flora-ded" src="art/carnations.png" alt="" />
        <p className="ded-text">
          <span className="dropcap" style={{ fontFamily: display, color: palette.accent }}>獻</span>給<br />
          <span style={{ fontFamily: display, fontStyle: "italic", fontSize: "1.4em", color: palette.accent }}>里上的每一位媽媽</span><br />
          您在，永明里就在。<br />
          今年，我們又一起過了一個母親節。
        </p>
        <div className="ded-fleuron" style={{ color: palette.gold }}><Fleuron color={palette.gold} size={1.6} /></div>
        <p className="ded-en" style={{ fontFamily: en }}>
          For every mother in our neighbourhood. <br />You make this place home.
        </p>
      </div>
    );
  }

  if (page.kind === "title") {
    return (
      <div className="page-content title-page" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="title-mark" style={{ fontFamily: en, color: palette.accent }}>VOL.01</div>
        <h1 className="title-cn" style={{ fontFamily: display }}>
          母親節
        </h1>
        <h2 className="title-en" style={{ fontFamily: en, color: palette.accent }}>An Afternoon, May 9</h2>
        <div className="title-rule" style={{ background: palette.gold }} />
        <p className="title-body">
          今年的母親節，我們又把棚子搭起來。<br />
          椅子擺好、花備好、熱食也熱著。<br />
          五月九號這個下午，<br />
          是永明里陪著里上的媽媽們，<br />
          好好過的一天。
        </p>
        <p className="title-body-en" style={{ fontFamily: en }}>
          Carnations, hot food, a folding tent. <br />
          Yong Ming's afternoon — for the mothers of our neighbourhood.
        </p>
        <div className="title-foot" style={{ fontFamily: en, color: palette.accent }}>
          <span>55 frames · 27 selected</span>
        </div>
      </div>
    );
  }

  if (page.kind === "chapter") {
    return (
      <div className="page-content chapter" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="chapter-eyebrow" style={{ fontFamily: en, color: palette.accent }}>
          <span className="ch-bar" style={{ background: palette.accent }} />
          <span>Chapter</span>
          <span className="ch-dot">·</span>
          <span>篇章</span>
        </div>
        <div className="chapter-num" style={{ fontFamily: en, color: palette.accentSoft }}>
          {page.num}
        </div>
        <div className="chapter-rule" style={{ background: palette.gold }} />
        <h2 className="chapter-cn" style={{ fontFamily: display }}>{page.cn}</h2>
        <h3 className="chapter-en" style={{ fontFamily: en, color: palette.accent }}>{page.en}</h3>
        <div className="chapter-foot" style={{ fontFamily: en, color: palette.ink }}>
          <span className="cf-rule" style={{ background: palette.gold }} />
          <span>—— Turn the page ——</span>
        </div>
        <img className="flora-deco flora-chapter" src="art/carnations.png" alt="" />
      </div>
    );
  }

  if (page.kind === "fullbleed") {
    return (
      <div className="page-content fullbleed">
        <img src={photoSrc(page.id)} alt="" style={{ filter: paperFilter }} />
        <div className="fb-caption" style={{ fontFamily: cn }}>
          <div className="fb-cn" style={{ fontFamily: display }}>{page.caption}</div>
          {page.subcaption && (
            <div className="fb-en" style={{ fontFamily: en }}>{page.subcaption}</div>
          )}
        </div>
      </div>
    );
  }

  if (page.kind === "single") {
    return (
      <div className="page-content single" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="single-frame">
          <img src={photoSrc(page.id)} alt="" style={{ filter: paperFilter }} />
        </div>
        <div className="single-caption">
          <div className="cap-eyebrow" style={{ fontFamily: en, color: palette.accent }}>
            <span>Frame</span>
            <span className="ce-num">№ {page.id}</span>
          </div>
          <div className="cap-cn" style={{ fontFamily: display }}>{page.caption}</div>
          <div className="cap-rule" style={{ background: palette.accent }} />
          <div className="cap-foot" style={{ fontFamily: en, color: palette.accentSoft }}>Yong Ming · 09 May 2026</div>
        </div>
      </div>
    );
  }

  if (page.kind === "duo") {
    return (
      <div className="page-content duo" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="duo-head">
          <div className="duo-cn" style={{ fontFamily: display }}>{page.heading}</div>
          <div className="duo-en" style={{ fontFamily: en, color: palette.accent }}>{page.sub}</div>
        </div>
        <div className="duo-grid">
          {page.ids.map((id) => (
            <div className="duo-cell" key={id}>
              <img src={photoSrc(id)} alt="" style={{ filter: paperFilter }} />
              <div className="duo-tag" style={{ fontFamily: en, color: palette.accentSoft }}>{id}</div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  if (page.kind === "triple") {
    return (
      <div className="page-content triple" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="triple-head" style={{ fontFamily: display }}>{page.heading}</div>
        <div className="triple-grid">
          {page.ids.map((id, i) => (
            <div className={`tri-cell tri-${i}`} key={id}>
              <img src={photoSrc(id)} alt="" style={{ filter: paperFilter }} />
            </div>
          ))}
        </div>
      </div>
    );
  }

  if (page.kind === "mosaic") {
    return (
      <div className="page-content mosaic" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="mos-grid">
          <div className="mos-big">
            <img src={photoSrc(page.ids[0])} alt="" style={{ filter: paperFilter }} />
          </div>
          <div className="mos-small">
            <img src={photoSrc(page.ids[1])} alt="" style={{ filter: paperFilter }} />
          </div>
          <div className="mos-text">
            <div className="mos-h" style={{ fontFamily: display }}>{page.heading}</div>
            <div className="mos-line" style={{ background: palette.accent }} />
            <div className="mos-en" style={{ fontFamily: en, color: palette.accent }}>A Few Words</div>
          </div>
          <div className="mos-tall">
            <img src={photoSrc(page.ids[2])} alt="" style={{ filter: paperFilter }} />
          </div>
        </div>
      </div>
    );
  }

  if (page.kind === "hero") {
    return (
      <div className="page-content hero" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="hero-photo">
          <img src={photoSrc(page.id)} alt="" style={{ filter: paperFilter }} />
        </div>
        <div className="hero-text">
          <div className="hero-cn" style={{ fontFamily: display }}>{page.caption}</div>
          <div className="hero-en" style={{ fontFamily: en, color: palette.accent }}>{page.en}</div>
        </div>
      </div>
    );
  }

  if (page.kind === "quote") {
    return (
      <div className="page-content quote-page" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="quote-eyebrow" style={{ fontFamily: en, color: palette.accent }}>
          <span className="qe-rule" style={{ background: palette.accent }} />
          <span>Pull Quote</span>
        </div>
        <div className="quote-mark" style={{ fontFamily: en, color: palette.accentSoft }}>“</div>
        <blockquote className="quote-cn" style={{ fontFamily: display }}>
          {page.text}
        </blockquote>
        <div className="quote-en" style={{ fontFamily: en, color: palette.accent }}>
          {page.en}
        </div>
        <div className="quote-rule" style={{ background: palette.gold }} />
        <div className="quote-attr" style={{ fontFamily: en, color: palette.accentSoft }}>
          — {page.attribution}
        </div>
      </div>
    );
  }

  if (page.kind === "colophon") {
    return (
      <div className="page-content colophon" style={{ fontFamily: cn, color: palette.ink }}>
        <div className="col-mark" style={{ fontFamily: en, color: palette.accent }}>FIN.</div>
        <h3 className="col-h" style={{ fontFamily: display }}>關於這本相冊</h3>
        <div className="col-rule" style={{ background: palette.gold }} />
        <dl className="col-list">
          <dt>活動</dt><dd>母親節感恩活動</dd>
          <dt>日期</dt><dd>2026 · 05 · 09 (六)</dd>
          <dt>地點</dt><dd>永明里社區據點</dd>
          <dt>編成</dt><dd>2026 · 05 · 10</dd>
        </dl>
        <p className="col-thanks" style={{ fontFamily: en }}>
          謝謝里上每一雙幫忙的手，<br />謝謝每一位走出家門的媽媽。<br />明年，我們再把棚子搭起來。
        </p>
      </div>
    );
  }

  if (page.kind === "blank") {
    return (
      <div className="page-content blank" style={{ background: palette.paper }}>
        <img className="flora-deco flora-blank" src="art/carnations.png" alt="" />
      </div>
    );
  }

  if (page.kind === "back") {
    return (
      <div className="back-cover" style={{ fontFamily: en, color: "#fff" }}>
        <div className="back-mark">永明里社區發展協會</div>
        <div className="back-rule" />
        <div className="back-en">永明里里長候選人　李柏毅</div>
      </div>
    );
  }

  return <div className="page-content" />;
}

// Typographic floret ornament — fleuron, like classic letterpress books.
// No fake hand-drawn carnation; just an honest printer's mark.
function Fleuron({ color, size = 1, style = {} }) {
  return (
    <span
      className="fleuron"
      style={{
        color,
        fontSize: `${size}em`,
        fontFamily: "'Cormorant Garamond', 'Noto Serif TC', serif",
        fontStyle: "italic",
        lineHeight: 1,
        display: "inline-block",
        ...style,
      }}
      aria-hidden="true"
    >
      ❦
    </span>
  );
}

// Legacy stub — old corner ornament removed. Returns null so existing call sites are no-ops.
function CarnationCorner() { return null; }

// Unused legacy SVG body kept here only as comment so we don't touch later code by accident.
function _UnusedLegacyCarnation({ color, small }) {
  const size = small ? 140 : 220;
  return (
    <svg
      className={"carnation-corner" + (small ? " sm" : "")}
      viewBox="0 0 200 280"
      width={size}
      height={size * 1.4}
      style={{ position: "absolute", display: "none" }}
      preserveAspectRatio="xMidYMid meet"
    >
      <defs>
        <linearGradient id={"car-bloom-" + (small ? "s" : "l")} x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.18" />
          <stop offset="100%" stopColor={color} stopOpacity="0.32" />
        </linearGradient>
      </defs>

      {/* Stem — confident curve */}
      <path
        d="M100 130 C 100 170 96 200 92 240 C 90 256 86 268 80 276"
        stroke={color}
        strokeWidth="1.6"
        fill="none"
        strokeLinecap="round"
        opacity="0.85"
      />

      {/* slim ovate leaves, opposite pairs */}
      <g stroke={color} strokeWidth="1.2" fill={color} fillOpacity="0.08" strokeLinejoin="round" strokeLinecap="round" opacity="0.85">
        <path d="M99 168 C 75 162 56 168 46 178 C 60 184 84 180 98 174 Z" />
        <path d="M99 168 L 50 178" strokeWidth="0.6" fill="none" opacity="0.7" />

        <path d="M97 200 C 122 196 142 204 152 216 C 138 222 114 216 96 208 Z" />
        <path d="M97 200 L 148 216" strokeWidth="0.6" fill="none" opacity="0.7" />

        <path d="M93 234 C 70 232 52 240 44 252 C 58 256 80 250 92 242 Z" />
        <path d="M93 234 L 47 252" strokeWidth="0.6" fill="none" opacity="0.7" />
      </g>

      {/* Calyx — long cylindrical green base, defining feature of carnation */}
      <g stroke={color} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
        <path
          d="M86 110 C 84 118 84 128 88 134 C 94 138 106 138 112 134 C 116 128 116 118 114 110"
          fill={color}
          fillOpacity="0.12"
        />
        {/* sepal points at top of calyx */}
        <path d="M86 110 C 86 104 88 100 92 100" fill="none" />
        <path d="M93 110 C 93 102 94 96 97 94" fill="none" />
        <path d="M100 110 L 100 92" fill="none" />
        <path d="M107 110 C 107 102 106 96 103 94" fill="none" />
        <path d="M114 110 C 114 104 112 100 108 100" fill="none" />
        {/* vertical seam lines on calyx */}
        <path d="M92 116 L 92 132" strokeWidth="0.6" opacity="0.6" />
        <path d="M100 114 L 100 134" strokeWidth="0.6" opacity="0.6" />
        <path d="M108 116 L 108 132" strokeWidth="0.6" opacity="0.6" />
      </g>

      {/* BLOOM — main silhouette with deeply ruffled top edge */}
      <path
        d="M78 100
           C 76 92 70 86 66 80
           C 64 72 70 64 76 62
           C 74 54 80 48 86 50
           C 84 42 92 38 96 42
           C 94 34 102 30 106 36
           C 108 28 116 30 116 38
           C 122 36 128 42 126 50
           C 132 50 136 58 132 64
           C 138 66 140 76 134 82
           C 138 88 134 96 128 100
           C 130 106 124 112 116 110
           C 116 114 108 116 102 112
           C 100 116 92 116 88 110
           C 80 112 74 106 78 100 Z"
        fill={"url(#car-bloom-" + (small ? "s" : "l") + ")"}
        stroke={color}
        strokeWidth="1.4"
        strokeLinejoin="round"
      />

      {/* Inner petal layers — overlapping ruffled curves */}
      <g fill="none" stroke={color} strokeLinecap="round" strokeLinejoin="round">
        {/* back petal hints (top of bloom, upward frills) */}
        <g strokeWidth="1.1" opacity="0.85">
          <path d="M80 78 C 78 72 76 66 80 60 C 84 64 86 70 84 76" />
          <path d="M88 64 C 86 58 88 52 92 50 C 94 56 94 62 92 68" />
          <path d="M100 56 C 100 48 104 44 108 46 C 108 54 106 60 104 64" />
          <path d="M114 60 C 116 54 120 50 124 54 C 122 62 120 68 116 70" />
          <path d="M124 76 C 130 72 134 76 132 82 C 128 84 124 84 122 80" />
        </g>

        {/* middle ruffled layer */}
        <g strokeWidth="1" opacity="0.75">
          <path d="M82 92 C 80 86 82 80 86 78 C 90 84 90 90 88 96" />
          <path d="M94 84 C 94 76 98 72 102 76 C 102 84 100 90 96 92" />
          <path d="M108 80 C 110 74 116 72 118 78 C 116 86 112 90 110 90" />
          <path d="M122 92 C 126 88 130 90 128 96 C 124 98 120 96 120 94" />
        </g>

        {/* front ruffles — small frilly arcs near bottom of bloom */}
        <g strokeWidth="0.9" opacity="0.7">
          <path d="M86 100 Q 90 96 94 100 Q 98 96 102 100 Q 106 96 110 100 Q 114 96 118 100 Q 122 96 124 100" />
          <path d="M88 106 Q 92 102 96 106 Q 100 102 104 106 Q 108 102 112 106 Q 116 102 120 106" />
        </g>

        {/* fine petal-vein hatches inside bloom */}
        <g strokeWidth="0.4" opacity="0.5">
          <path d="M84 86 L 86 94" />
          <path d="M92 80 L 94 90" />
          <path d="M100 74 L 100 88" />
          <path d="M108 78 L 106 90" />
          <path d="M118 84 L 116 92" />
          <path d="M126 88 L 124 96" />
        </g>
      </g>

      {/* small bud at base of stem */}
      <g stroke={color} strokeWidth="1.1" fill={color} fillOpacity="0.1" strokeLinejoin="round" opacity="0.8">
        <path d="M76 256 C 74 252 76 248 80 248 C 84 248 86 252 84 256 C 84 260 80 262 78 260 C 76 260 76 258 76 256 Z" />
        <path d="M80 248 L 80 240" fill="none" strokeLinecap="round" />
      </g>
    </svg>
  );
}

// ─────────────────────────────────────────────
// FLIPBOOK
// ─────────────────────────────────────────────

function Flipbook({ pages, palette, fonts, paperFilter }) {
  // 用 StPageFlip 驅動翻頁、保留所有原本的 PageInner / PageNum 渲染
  const containerRef = useRef(null);
  const pageFlipRef = useRef(null);
  const [currentPage, setCurrentPage] = useState(0);
  const totalPages = pages.length;

  // 初始化 StPageFlip（只跑一次）
  useEffect(() => {
    if (!containerRef.current || pageFlipRef.current) return;
    if (typeof window.St === "undefined" || !window.St.PageFlip) {
      console.error("StPageFlip not loaded");
      return;
    }

    const pageFlip = new window.St.PageFlip(containerRef.current, {
      width: 560,
      height: 720,
      size: "stretch",
      minWidth: 320,
      maxWidth: 1100,
      minHeight: 420,
      maxHeight: 1400,
      maxShadowOpacity: 0.55,
      showCover: true,
      mobileScrollSupport: false,
      usePortrait: true,
      autoSize: true,
      drawShadow: true,
      flippingTime: 800,
      useMouseEvents: true,
      swipeDistance: 30,
    });

    pageFlip.loadFromHTML(containerRef.current.querySelectorAll(".page-wrapper"));
    pageFlip.on("flip", (e) => setCurrentPage(e.data));

    // 還原上次位置
    const saved = parseInt(localStorage.getItem("album-page") || "0", 10);
    if (!isNaN(saved) && saved > 0 && saved < totalPages) {
      pageFlip.flip(saved, "bottom");
    }

    pageFlipRef.current = pageFlip;
    return () => {
      try { pageFlip.destroy(); } catch (e) {}
      pageFlipRef.current = null;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // 持久化位置
  useEffect(() => {
    localStorage.setItem("album-page", String(currentPage));
  }, [currentPage]);

  // 從右下角斜翻、模擬翻書習慣手勢（不是平直翻頁）
  const next = useCallback(() => pageFlipRef.current?.flipNext("bottom"), []);
  const prev = useCallback(() => pageFlipRef.current?.flipPrev("bottom"), []);

  // 鍵盤
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === "ArrowRight" || e.key === " ") { e.preventDefault(); next(); }
      else if (e.key === "ArrowLeft") prev();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [next, prev]);

  return (
    <div className="book-stage stpf-stage">
      <div className="book-shadow" />
      <div ref={containerRef} className="stpf-book">
        {pages.map((page, i) => {
          const isHard = page.kind === "cover" || page.kind === "back";
          const side = i % 2 === 0 ? "right" : "left";
          return (
            <div
              key={i}
              className={"page-wrapper" + (isHard ? " page-hard" : "")}
              data-density={isHard ? "hard" : "soft"}
            >
              <div className="paper" style={{ background: palette.paper }}>
                <PageInner page={page} palette={palette} fonts={fonts} paperFilter={paperFilter} side={side} />
                <PageNum side={side} n={i} palette={palette} fonts={fonts} pages={pages} />
              </div>
            </div>
          );
        })}
      </div>

      {/* Controls */}
      <div className="controls">
        <button className="ctrl" onClick={prev} disabled={currentPage === 0} aria-label="prev">‹</button>
        <div className="ctrl-meta" style={{ fontFamily: fonts.en, color: palette.ink }}>
          {currentPage === 0 ? (
            <span>封面 · cover</span>
          ) : currentPage >= totalPages - 1 ? (
            <span>封底 · end</span>
          ) : (
            <span>{currentPage} / {totalPages - 2}</span>
          )}
        </div>
        <button className="ctrl" onClick={next} disabled={currentPage >= totalPages - 1} aria-label="next">›</button>
      </div>
    </div>
  );
}

// Editorial folio: a thin top rule with a section running-head, plus a bottom
// page-number block. Mimics how a magazine spread is anchored.
function sectionLabel(pages, n) {
  // Walk backward to the most recent chapter page; pages[0] = cover, etc.
  if (n <= 0) return { num: "", cn: "", en: "" };
  for (let i = n; i >= 0; i--) {
    const p = pages[i];
    if (p && p.kind === "chapter") return { num: p.num, cn: p.cn, en: p.en };
  }
  // Fallbacks for early pages before any chapter
  const p = pages[n];
  if (!p) return { num: "", cn: "", en: "" };
  if (p.kind === "dedication") return { num: "", cn: "獻辭", en: "Dedication" };
  if (p.kind === "title")      return { num: "", cn: "扉頁", en: "Title" };
  if (p.kind === "colophon")   return { num: "", cn: "版權", en: "Colophon" };
  return { num: "", cn: "母親節", en: "Mother's Day" };
}

function PageNum({ side, n, palette, fonts, pages }) {
  if (n <= 0) return null;
  // Cover/back-of-cover never get folios. Skip on chapter & cover-like pages
  // which have their own composition.
  const p = pages && pages[n];
  const skip = p && (p.kind === "cover" || p.kind === "back" || p.kind === "fullbleed");
  if (skip) return null;
  const sec = pages ? sectionLabel(pages, n) : { num: "", cn: "", en: "" };
  const isLeft = side === "left";
  return (
    <React.Fragment>
      <div className={"folio-top " + side} style={{ fontFamily: fonts.en, color: palette.ink }}>
        <span className="ft-rule" style={{ background: palette.accent, opacity: 0.55 }} />
        <span className="ft-text">
          {isLeft ? (
            <React.Fragment>
              <span className="ft-mag">永明里 · 母親節 MMXXVI</span>
            </React.Fragment>
          ) : (
            <React.Fragment>
              {sec.num && <span className="ft-num">{sec.num}</span>}
              <span className="ft-cn" style={{ fontFamily: fonts.cn }}>{sec.cn}</span>
              <span className="ft-sep">·</span>
              <span className="ft-en">{sec.en}</span>
            </React.Fragment>
          )}
        </span>
      </div>
      <div className={"folio-bottom " + side} style={{ fontFamily: fonts.en, color: palette.accent }}>
        <span className="fb-num">{String(n).padStart(2, "0")}</span>
      </div>
    </React.Fragment>
  );
}

// ─────────────────────────────────────────────
// APP
// ─────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const palette = PALETTES[t.palette] || PALETTES.blossom;
  const fonts = FONTS[t.font] || FONTS.serif;
  const paperFilter = (PAPERS[t.paper] || PAPERS.warm).filter;

  const pages = useMemo(() => buildPages(t.cover), [t.cover]);

  const coverOptions = ["0048", "0001", "0010", "0007", "0017", "0042", "0008"];

  return (
    <div className="app" style={{
      background: `radial-gradient(ellipse at 50% 30%, ${palette.bg} 0%, ${palette.bg2} 100%)`,
    }}>
      <div className="grain" />

      <header className="masthead" style={{ fontFamily: fonts.en, color: palette.ink }}>
        <div className="mast-l">
          <div className="mast-mark" style={{ background: palette.accent }} />
          <span>YONG MING · MOTHER&apos;S DAY · 2026</span>
        </div>
        <div className="mast-r">
          <span style={{ fontFamily: fonts.cn }}>母親節活動 · 紀念相冊</span>
        </div>
      </header>

      <Flipbook pages={pages} palette={palette} fonts={fonts} paperFilter={paperFilter} />

      <footer className="hint" style={{ fontFamily: fonts.en, color: palette.ink }}>
        <span>← →</span>
        <span style={{ fontFamily: fonts.cn }}>左右鍵翻頁，或點擊書本兩側</span>
        <span>·</span>
        <span style={{ fontFamily: fonts.cn }}>點擊右上角開啟調整面板</span>
      </footer>

      <TweaksPanel title="Tweaks · 調整">
        <TweakSection title="主題色 Palette">
          <TweakRadio
            value={t.palette}
            onChange={(v) => setTweak("palette", v)}
            options={Object.entries(PALETTES).map(([k, v]) => ({ value: k, label: v.name }))}
          />
        </TweakSection>
        <TweakSection title="字體 Typeface">
          <TweakSelect
            value={t.font}
            onChange={(v) => setTweak("font", v)}
            options={Object.entries(FONTS).map(([k, v]) => ({ value: k, label: v.name }))}
          />
        </TweakSection>
        <TweakSection title="紙感 Paper">
          <TweakRadio
            value={t.paper}
            onChange={(v) => setTweak("paper", v)}
            options={Object.entries(PAPERS).map(([k, v]) => ({ value: k, label: v.name }))}
          />
        </TweakSection>
        <TweakSection title="封面照片 Cover">
          <div className="cover-picker">
            {coverOptions.map((id) => (
              <button
                key={id}
                className={"cover-thumb" + (t.cover === id ? " selected" : "")}
                onClick={() => setTweak("cover", id)}
                style={{ borderColor: t.cover === id ? palette.accent : "transparent" }}
              >
                <img src={photoSrc(id)} alt="" />
                <span style={{ fontFamily: fonts.en }}>{id}</span>
              </button>
            ))}
          </div>
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
