/* global React, ReactDOM */
// Project Detail — full-screen overlay that expands FROM the clicked film frame.
// URL hash routing (#/projects/<slug>), browser-back closes, Close button reverses.
const { useState, useEffect, useRef, useCallback } = React;

// ---- content registry (only silicon-angel for the v1 template) ----
const DETAILS = {
  "silicon-angel": {
    title: "SILICON ANGEL",
    cn: "硅的天使",
    sub: "AIGC 账号运营 × 角色审美 × 衍生品企划",
    period: "2025 — NOW",
    eyebrow: "AIGC ACCOUNT EXHIBIT · 硅的天使 · ",
    lede: "一个从 AI 视觉内容出发，用真实用户反馈验证角色审美，并延展到系列企划与小型商品经营的个人商业实验。",
    keywords: ["AIGC", "账号运营", "角色审美", "衍生品企划", "IP 孵化"],
    layout: "silicon-angel",
    heroBg: "assets/sa/hero-bg.png",
    repVisual: "assets/sa/merch-butterfly.jpg",
    roles: ["AI 视觉生成", "内容选题", "系列企划", "商品上架与运营"],
    // Hero 仪表盘式视觉（小红书主页 + 内容卡 + 数据 + 产品漂浮）
    dashboard: {
      shot: "assets/sa/profile.jpg",
      cards: ["assets/sa/work-rock.jpg", "assets/sa/cny-giyu.jpg", "assets/sa/merch-butterfly.jpg", "assets/sa/gal-shibuya.jpg"],
      stats: [["7854", "粉丝"], ["22.7万", "获赞收藏"], ["AIGC", "内容方向"]],
      floatMerch: "assets/sa/merch-kanao-set.jpg"
    },
    // 内容矩阵 1 · 二次元角色视觉内容（卡片轮滑）
    feed: [
    { img: "assets/sa/feed1.jpg" }, { img: "assets/sa/feed2.jpg" }, { img: "assets/sa/feed3.jpg" },
    { img: "assets/sa/feed4.jpg" }, { img: "assets/sa/feed5.jpg" }, { img: "assets/sa/feed6.jpg" },
    { img: "assets/sa/feed7.jpg" }, { img: "assets/sa/feed8.jpg" }, { img: "assets/sa/feed9.jpg" },
    { img: "assets/sa/feed11.jpg" }],

    // 内容矩阵 2 · ai绘画相关教程（4 张静态卡）
    tutorials: [
    { img: "assets/sa/tut1.jpg", t: "AI 角色出图教程", likes: "3265", star: "2890" },
    { img: "assets/sa/tut2.jpg", t: "AI 绘画流程拆解", likes: "1872", star: "1564" },
    { img: "assets/sa/tut3.jpg", t: "角色设定 Prompt", likes: "2418", star: "2103" },
    { img: "assets/sa/tut4.jpg", t: "风格化二创教程", likes: "1530", star: "1247" }],

    // 增长截图（内容增长 section）
    growthShots: ["assets/sa/feed1.jpg", "assets/sa/feed2.jpg", "assets/sa/feed3.jpg", "assets/sa/feed4.jpg", "assets/sa/feed5.jpg", "assets/sa/feed6.jpg", "assets/sa/feed7.jpg", "assets/sa/feed8.jpg"],
    // ── 02 ACCOUNT OVERVIEW ──
    account: {
      shot: "assets/sa/avatar-new.png",
      handle: "硅的天使",
      xhs: "6150358880",
      ip: "上海",
      bioTags: ["AI Concept Designer", "Ai 教学", "同人制品", "oc 出设"],
      bioLine: "坚信数字时代最稀缺的就是审美。",
      bioFull: ["AI Concept Designer ｜小硅", "Ai教学 ｜ 同人制品 ｜ oc出设", "坚信数字时代最稀缺的就是审美", "纯手绘同人谷请戳 @硅的天使小铺", "欢迎来找小硅玩！"],
      stats: [["803", "关注"], ["7854", "粉丝"], ["22.7万", "获赞与收藏"]],
      types: ["AI 角色创作", "二次元插画", "原创角色设计", "IP 衍生品开发"],
      link: "https://xhslink.com/m/60MTGDbSPbG"
    },
    // Channel Expansion
    channels: {
      main: { name: "小红书 XIAOHONGSHU", note: "主平台 · 内容发布与用户验证", link: "https://xhslink.com/m/60MTGDbSPbG" },
      testing: { name: "抖音 DOUYIN", note: "测试渠道 · 短视频内容测试", link: "https://v.douyin.com/sR5jH1d6Lg8/" },
      planned: ["Instagram", "TikTok"],
      plannedNote: "海外视觉归档与内容测试渠道（暂不作为核心成果）"
    },
    // ── 03 COMMUNITY FAVORITES ──
    works: [
    { img: "assets/sa/cny-giyu.jpg", t: "义勇非要给我红包", sub: "鬼灭 · 新年贺图", type: "角色贺图", role: "鬼灭 / 富冈义勇", likes: "1.9万", star: "2240" },
    { img: "assets/sa/work-nezuko.jpg", t: "鬼灭杀青的日常", sub: "主角五人组 · 同人四格", type: "同人四格", role: "鬼灭 / 主角组", likes: "1万", star: "3302" },
    { img: "assets/sa/merch-kanao-set.jpg", t: "香香的走来～", sub: "香奈乎立牌套组", type: "衍生品预览", role: "鬼灭 / 香奈乎", likes: "8006", star: "1043" },
    { img: "assets/sa/merch-butterfly.jpg", t: "蝴蝶忍 × 女团私设", sub: "亚文化女团私服", type: "角色私设", role: "鬼灭 / 蝴蝶忍", likes: "7026", star: "2191" },
    { img: "assets/sa/feed-goose.jpg", t: "狛枝凪鹅", sub: "鹅鸭杀 × 弹丸论破 · 绝望学级裁判", type: "联动同人", role: "鹅鸭杀 × 弹丸论破", likes: "5362", star: "989" },
    { img: "assets/sa/feed-office.jpg", t: "无惨的株式会社", sub: "鬼灭转世篇 · 上弦神仙高层", type: "系列设定", role: "鬼灭 / 转世篇", likes: "2600", star: "735" },
    { img: "assets/sa/feed-rui.jpg", t: "下弦之伍 · 累 Rui", sub: "令人窒息的中层管理", type: "角色设定图", role: "鬼灭 / 累", likes: "2140", star: "574" },
    { img: "assets/sa/feed-rock.jpg", t: "摇滚淑女 · 君子好逑", sub: "幻影涂鸦 · AIGC", type: "视觉海报", role: "原创 / 涂鸦风", likes: "1090", star: "369" }],

    worksNote: "这些作品获得了大量用户收藏与互动，也成为后续衍生品开发的重要起点。",
    // ── WORKFLOW · 完整流程 ──
    flow: [
    ["选题", "TOPIC"],
    ["AI 生成", "AI GENERATE"],
    ["人工筛选", "CURATION"],
    ["二次设计", "REDESIGN"],
    ["打样", "SAMPLING"],
    ["上架", "LAUNCH"],
    ["内容回流", "CONTENT LOOP"]],

    flowNote: "通过观察用户反馈与角色热度，将高互动作品进一步开发为实体衍生品——这是从内容到产品的转化逻辑。",
    // ── 05 THEME COLLECTIONS （主题系列 / 谷子企划，点开看实物细节）──
    collections: [
    { no: "①", series: "紫蝶夜宴", role: "蝴蝶忍", img: "assets/sa/zd/cover.jpg",
      desc: "来源于账号互动最高的作品之一。以紫藤花、夜宴、蝶翼元素为主题进行衍生品设计。",
      items: ["徽章", "亚克力立牌", "纸制品"],
      gallery: ["assets/sa/zd/cover.jpg", "assets/sa/zd/set.png", "assets/sa/zd/acrylic.png", "assets/sa/zd/photo.jpg"] },
    { no: "②", series: "葡香假日", role: "甘露寺蜜璃", img: "assets/sa/px/cover.jpg",
      desc: "围绕甜美、果香与夏日假期氛围展开设计，粉绿撞色 + 葡萄与花卉元素。",
      items: ["立牌", "心型吧唧", "小卡", "挂件"],
      gallery: ["assets/sa/px/p2.jpg", "assets/sa/px/p3.jpg", "assets/sa/px/p4.jpg", "assets/sa/px/p5.jpg", "assets/sa/px/p6.jpg", "assets/sa/px/real.jpg"] },
    { no: "③", series: "芭蕾香香", role: "栗花落香奈乎", img: "assets/sa/kn/cover.jpg",
      desc: "结合芭蕾舞与角色气质进行视觉延展。粉蓝渐变 + 蕾丝缎带的甜美芭蕾风。",
      items: ["立牌", "钥匙扣", "小卡"],
      gallery: ["assets/sa/kn/real2.jpg", "assets/sa/kn/real3.jpg", "assets/sa/kn/k4.jpg", "assets/sa/kn/k5.jpg"] }],

    // ── GAL DEMON · 鬼灭同人复古辣妹概念企划（4 角色矩阵）──
    galDemon: {
      intro: "围绕「硅的天使」延展出的概念型角色系列企划。以平成辣妹、和风混搭、杂志封面感与谷美商品化为核心语言，尝试建立一个世界观统一、但风格差异鲜明的四角色视觉矩阵。",
      chars: [
      { no: "01", name: "NEZUKO", cn: "祢豆子", subt: "和ギャル · 黑粉平成风", cover: "assets/sa/nezuko-cover.png",
        keywords: ["黑粉和风", "棒棒糖", "豹纹", "平成杂志感"],
        detail: {
          cover: "assets/sa/nezuko-cover.png",
          enTitle: "NEZUKO", zhTitle: "和ギャル · 黑粉平成风",
          status: "CONCEPT ONLY · 设计展示中",
          intro: "将传统和风角色重新转译为黑粉豹纹系平成辣妹，以棒棒糖、粉黑配色、杂志封面感和甜酷反差，打造更具社交传播感的同人视觉企划。",
          keywords: ["黑粉和风", "棒棒糖", "豹纹", "平成杂志感", "甜酷反差", "复古辣妹"],
          designNote: "以「和风 × GAL 杂志」为核心方向，将角色原本柔和的气质转化为更强烈的粉黑视觉冲击。画面用豹纹、宝石贴纸、粗体杂志标题和高密度排版，强化平成辣妹杂志的热闹感与收藏感——刻意做成「信息量很满」的封面式构图，让角色像出现在一本限定特刊的封面。",
          products: [
          ["亚克力立牌", "ACRYLIC STAND", "以角色全身造型为主体，突出黑粉和风穿搭、蝴蝶结、厚底鞋与心形底座，强调站姿轮廓与粉黑配色。", "assets/sa/nezuko-stand.jpg"],
          ["徽章", "BADGE", "以表情与上半身为核心，强化甜酷感与平成辣妹氛围，用集中的面部视觉提升小尺寸辨识度。", "assets/sa/nezuko-badge.jpg"],
          ["珠光小卡", "HOLO CARD", "延续杂志封面语言，大字标题、豹纹、星星与宝石装饰，让小卡像一张可收藏的 GAL 特刊卡片。", "assets/sa/nezuko-card.jpg"],
          ["明信片", "POSTCARD", "偏完整画面展示，保留角色主视觉、背景纹理和主题文字，承载系列氛围与整体设定。", "assets/sa/nezuko-postcard.jpg"]]
        } },
      { no: "02", name: "WHITE ANGEL", cn: "香奈乎", subt: "透明感白系辣妹", cover: "assets/sa/gal-kanao/cover.png",
        keywords: ["透明感", "白蓝配色", "冰感", "清透甜系"],
        detail: {
          cover: "assets/sa/gal-kanao/cover.png",
          enTitle: "WHITE ANGEL", zhTitle: "透明感白系辣妹",
          status: "CONCEPT ONLY · 设计展示中",
          intro: "以白蓝冰感、透明感和清透甜系为核心，将「白」作为视觉主题，打造一组更冷感、更轻盈、更适合夏日氛围的复古辣妹风同人企划。",
          keywords: ["透明感", "白蓝配色", "冰感", "清透甜系", "白系辣妹", "夏日冷感"],
          designNote: "视觉重点是「盛れる白」。与粉黑系的强冲击不同，白系香奈乎更强调清透、干净、冰感和轻盈感。画面通过白色蝴蝶结、冰蓝渐变、星光、透明伞和冷色装饰，制造一种夏日冰饮般的视觉记忆点，让角色呈现「白得发光」的主视觉印象。",
          products: [
          ["亚克力立牌", "ACRYLIC STAND", "以白蓝色全身造型为主体，突出轻盈裙摆、透明伞、蝴蝶结和冰感配色，强调清透感与整体造型轮廓。", "assets/sa/gal-kanao/stand.png"],
          ["徽章", "BADGE", "以面部和上半身为核心，突出冷感眼神、白色蝴蝶结和清透妆感，小尺寸下保留白系视觉识别度。", "assets/sa/gal-kanao/badge.jpg"],
          ["商品版面", "LAYOUT", "完整商品版面与排布，呈现白系企划的整体视觉与系列氛围。", "assets/sa/gal-kanao/layout.jpg"],
          ["明信片", "POSTCARD", "作为完整氛围图展示，大面积浅色背景、角色主视觉和杂志式文字，呈现白系辣妹企划的整体调性。", "assets/sa/gal-kanao/postcard.jpg"]]

        } },
      { no: "03", name: "SHINOBU", cn: "蝴蝶忍", subt: "夜蝶御姐 · 紫黑恶罗系", cover: "assets/sa/shinobu-cover.png",
        keywords: ["紫黑恶罗", "御姐感", "夜蝶", "暗黑蕾丝"],
        detail: {
          cover: "assets/sa/shinobu-cover.png",
          enTitle: "SHINOBU", zhTitle: "夜蝶御姐 · 紫黑恶罗系",
          status: "CONCEPT ONLY · 未正式打样 / 未上架",
          intro: "将蝴蝶意象转译为紫黑恶罗系辣妹视觉，以夜蝶、暗黑蕾丝、毒感紫色和御姐气质，塑造更成熟、更危险、更华丽的同人视觉方向。",
          keywords: ["紫黑恶罗", "御姐感", "夜蝶", "暗黑蕾丝", "毒感", "华丽冷艳"],
          designNote: "以「夜间绽放的毒之花」为核心概念，将角色的蝴蝶意象与恶罗系辣妹风结合。画面用紫黑配色、蕾丝、玫瑰、蝴蝶、暗色高光和珠光装饰，强化冷艳、危险与高级感。相比其他角色更偏成熟、压迫感与夜场氛围，适合做成暗色系收藏向制品。",
          products: [
          ["亚克力立牌", "ACRYLIC STAND", "以黑紫全身造型为主体，突出长外披、扇子、蝴蝶纹样和心形底座，强调纵向气场与冷艳姿态。", "assets/sa/shinobu-stand.jpg"],
          ["徽章", "BADGE", "以半身和表情为核心，强化紫黑色调、眼神和夜蝶氛围，用浓缩画面表达御姐感与暗黑华丽感。", "assets/sa/shinobu-badge.jpg"],
          ["珠光小卡", "HOLO CARD", "紫色、黑色、蝴蝶、蕾丝和宝石装饰，突出珠光材质下的暗色闪烁，像一张夜蝶主题收藏卡。", "assets/sa/shinobu-card.jpg"],
          ["明信片", "POSTCARD", "保留完整构图和大量装饰元素，展示「恶罗ギャル降临」的主题标题、角色视觉和系列氛围。", "assets/sa/shinobu-postcard.jpg"]]

        } },
      { no: "04", name: "MITSURI", cn: "蜜璃", subt: "平成复古 · 糖果甜辣系", cover: "assets/sa/mitsuri-cover.png",
        keywords: ["糖果粉", "翻盖手机", "千禧复古", "甜辣感"],
        detail: {
          cover: "assets/sa/mitsuri-cover.png",
          enTitle: "MITSURI", zhTitle: "平成复古 · 糖果甜辣系",
          status: "CONCEPT ONLY · 设计展示中",
          intro: "以糖果粉、翻盖手机、甜辣穿搭和千禧复古元素重塑角色气质，将可爱感转译为更浓烈、更活泼、更有杂志感的平成辣妹视觉企划。",
          keywords: ["糖果粉", "翻盖手机", "千禧复古", "甜辣感", "平成辣妹", "粉黑玫瑰"],
          designNote: "核心是「甜，但不是普通甜」。画面通过糖果粉、黑色蕾丝、翻盖手机、玫瑰、宝石贴纸和高密度杂志排版，强化甜辣反差。相比白映姬的清透感，蜜璃更偏热闹、闪亮、可爱和主动出击的平成辣妹感，适合做成视觉冲击强的粉色主题系列。",
          products: [
          ["亚克力立牌", "ACRYLIC STAND", "以甜辣系全身造型为主体，突出粉黑配色、厚底鞋、蝴蝶结、玫瑰装饰和心形底座，可爱与辣妹感并存。", "assets/sa/mitsuri-stand.jpg"],
          ["徽章", "BADGE", "以面部和上半身为核心，突出糖果粉色、闪亮眼神、甜美表情和装饰感，强化可爱度与小尺寸收藏感。", "assets/sa/mitsuri-badge.jpg"],
          ["珠光小卡", "HOLO CARD", "粉色、黑色、玫瑰、宝石、杂志标题和高饱和装饰，突出珠光小卡的闪亮感与平成辣妹主题。", "assets/sa/mitsuri-card.jpg"],
          ["明信片", "POSTCARD", "保留完整主题排版和角色主视觉，展示「平成复古辣妹」的整体设定，承载更多装饰文字与系列氛围。", "assets/sa/mitsuri-postcard.jpg"]]
        } }]

    },
    productKinds: [
    ["亚克力立牌", "ACRYLIC STAND", "#ff8fc8"],
    ["珠光小卡", "HOLO CARD", "#c8a0ff"],
    ["爱心吧唧", "HEART BADGE", "#ff5fa8"],
    ["明信片", "POSTCARD", "#9be8ff"],
    ["钥匙扣", "KEYCHAIN", "#ffd36e"],
    ["套组", "COLLECTOR SET", "#ff7ae0"]],

    // ── 05b ORIGINAL GAL ──
    galIntro: "这一系列并非同人角色，而是围绕个人偏爱的涩谷 GAL 文化与和风元素进行的原创设计。",
    galKeywords: ["Shibuya Fashion", "GAL Culture", "Japanese Street Style", "Original Character Design"],
    gals: [
    { img: "assets/sa/gal-ootd.jpg", name: "私服少女", kw: ["弹丸论破", "针织 ootd", "JK"] },
    { img: "assets/sa/gal-shibuya.jpg", name: "千禧辣妹", kw: ["涩谷", "Y2K", "千禧风"] },
    { img: "", name: "待补图", kw: ["GAL", "原创"] },
    { img: "", name: "待补图", kw: ["和风", "辣妹"] }],

    // ── 06 LAUNCH MATERIALS ──
    launch: ["商品图", "杂志风海报", "九宫格预览", "预售图", "上架图"],
    launchCover: "assets/sa/merch-kanao-set.jpg",
    launchBadge: "杂志风主视觉",
    // ── 07 WORKFLOW ──
    workflow: [
    ["01", "CONTENT TEST", "内容测试", "用 AIGC 角色图测试粉丝审美反馈"],
    ["02", "VISUAL DIRECTION", "视觉方向", "根据互动数据和评论确认视觉方向"],
    ["03", "PRODUCT PLANNING", "产品企划", "规划立牌、小卡、钥匙扣、吧唧等 SKU"],
    ["04", "SAMPLE & PRODUCTION", "打样生产", "对接工厂，处理打样、材质、切边、颜色"],
    ["05", "LAUNCH & SALES", "宣发售卖", "制作物料，小红书 / 抖音宣发与售卖"],
    ["06", "REVIEW", "复盘", "销量、带粉、用户反馈复盘"]],

    // ── 08 RESULTS ──
    results: [
    ["7,829", "小红书粉丝", "XHS FOLLOWERS"],
    ["22.6万", "获赞与收藏", "LIKES & SAVES"],
    ["200+", "单款最高售出", "TOP SKU SOLD"],
    ["500+", "单品带粉", "FOLLOWERS / DROP"]],

    closedLoop: "内容 → 验证 → 企划 → 打样 → 宣发 → 售卖 → 复盘　完整闭环",
    // ── 09 PROVES ──
    proves: "它证明我能从 0 到 1 搭建并运营内容账号，用真实用户反馈验证审美与角色，把 AIGC 视觉孵化成实体 IP 商品，并具备小型商业闭环能力。",
    // ── STATUS ──
    statusTitle: "PHASE ONE COMPLETED.",
    statusBody: "目前暂无新的衍生品系列开发，项目阶段性暂停。第一阶段已完成从内容、IP 孵化到商品化的完整探索。",
    statusFuture: ["原创角色开发", "新衍生品品类", "AI 角色 IP 运营"]
  },

  "international-brands": {
    title: "GLOBAL BRAND CONTENT",
    cn: "国际品牌内容与商业传播",
    layout: "global-brand",
    accent: "#2a6fdb",
    keywords: []
  },

  "live-sports": {
    title: "LIVE & SPORTS CONCEPTS",
    cn: "赛事活动 × 线下体验策划",
    layout: "live-sports",
    accent: "#4fe08a",
    keywords: []
  },

  "aigc-commercial": {
    title: "AIGC COMMERCIAL SYSTEM",
    cn: "商业 AIGC 创意系统",
    layout: "aigc-stamps",
    accent: "#a8392b",
    keywords: []
  },

  "complex-briefs": {
    title: "COMPLEX BRIEFS, CLEAR COPY",
    cn: "复杂 Brief 的清晰表达",
    layout: "sample-wall",
    accent: "#5b7a5e",
    keywords: []
  },

  "prototype-lab": {
    title: "PROTOTYPE LAB",
    cn: "个人工具实验室 · Personal Tool Drawer",
    layout: "prototype-lab",
    accent: "#c4708a",
    keywords: []
  }
};
const ORDER = ["silicon-angel", "international-brands", "live-sports", "aigc-commercial", "complex-briefs", "prototype-lab"]; // for Next Case

function slugFromHash() {
  const m = (location.hash || "").match(/#\/projects\/([\w-]+)/);
  return m ? m[1] : null;
}

// ── bespoke renderer for SILICON ANGEL (Y2K digital-archive style) ──
function SASections({ d }) {
  const a = d.account;
  const ch = d.channels;
  const [lb, setLb] = useState(null); // active collection for the detail lightbox
  const [zoom, setZoom] = useState(null); // fullscreen image zoom
  useEffect(() => {
    if (!zoom) return;
    function onKey(e) {if (e.key === "Escape") {e.preventDefault();e.stopPropagation();setZoom(null);}}
    window.addEventListener("keydown", onKey, true);
    return () => window.removeEventListener("keydown", onKey, true);
  }, [zoom]);
  return (
    <div className="sa">
      {/* 02 MY ROLE & CHANNELS */}
      <section className="pd-sec">
        <div className="pd-sec-h"><span className="n" style={{ width: "17px" }}>02</span> MY ROLE &amp; CHANNELS <span className="zh">我的角色与渠道</span></div>
        {d.roles &&
        <div className="sax-roles">
            {d.roles.map((r, i) => <div className="sax-role" key={r}><span className="sax-role-no">0{i + 1}</span><span className="sax-role-t">{r}</span></div>)}
          </div>
        }

        {/* Channel Expansion */}
        {ch &&
        <div className="sa-channels">
          <div className="sa-ch-h">CHANNEL DISTRIBUTION · 渠道布局</div>
          <div className="sa-ch-grid">
            <a className="sa-ch main" href={ch.main.link} target="_blank" rel="noopener">
              <span className="sa-ch-tag">MAIN PLATFORM · 主阵地</span>
              <span className="sa-ch-name">{ch.main.name}</span>
              <span className="sa-ch-note">{ch.main.note}</span>
            </a>
            <a className="sa-ch testing" href={ch.testing.link} target="_blank" rel="noopener">
              <span className="sa-ch-tag">TESTING · 测试渠道</span>
              <span className="sa-ch-name">{ch.testing.name}</span>
              <span className="sa-ch-note">{ch.testing.note}</span>
            </a>
            <div className="sa-ch planned">
              <span className="sa-ch-tag">PLANNED · 计划渠道</span>
              <span className="sa-ch-name">{ch.planned.join(" · ")}</span>
              <span className="sa-ch-note">{ch.plannedNote}</span>
            </div>
          </div>
        </div>
        }
      </section>

      {/* 03 CONTENT MATRIX （合并 增长 + 矩阵）*/}
      <section className="pd-sec">
        <div className="pd-sec-h"><span className="n">03</span> CONTENT MATRIX <span className="zh">内容矩阵 · 内容分类 + </span></div>

        {/* A · AIGC 二次元内容创作 — static evidence cards */}
        <div className="sax-submh"><span className="ab">A</span> AIGC CONTENT <span className="zh">精选内容</span></div>
        <p className="sax-mnote">账号通过高频角色视觉内容吸引关注，并以点赞、收藏、评论验证用户审美偏好</p>
        <div className="sax-grid sax-grid-vis">
          {d.works.map((w, i) =>
          <figure className="sax-card" key={i} onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: w.img, cap: w.t });}}>
              <div className="sax-card-img"><img src={w.img} alt={w.t} loading="lazy" /><span className="sax-card-no">{String(i + 1).padStart(2, "0")}</span></div>
              <figcaption>
                <div className="sax-card-t">{w.t}</div>
                <div className="sax-card-meta"><span className="ty">{w.type}</span><span className="ro">{w.role}</span></div>
                <div className="sax-card-stat"><span className="lk">♥ {w.likes}</span><span className="st">★ {w.star}</span></div>
              </figcaption>
            </figure>
          )}
        </div>

        {/* B · AI Art Tutorials — static cards */}
        <div className="sax-submh" style={{ marginTop: 36 }}><span className="ab">B</span> AI ART TUTORIALS <span className="zh">AI 绘画相关教程</span></div>
        <p className="sax-mnote">把创作过程拆解成教程，承接「想学怎么做」的用户需求，提升收藏与账号粘性</p>
        {d.tutorials &&
        <div className="sax-grid sax-grid-tut">
            {d.tutorials.map((t, i) =>
          <figure className="sax-card tut" key={i} onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: t.img, cap: t.t });}}>
                <div className="sax-card-img"><img src={t.img} alt={t.t} loading="lazy" /><span className="sax-card-no tut">TUTORIAL</span></div>
                <figcaption>
                  <div className="sax-card-t">{t.t}</div>
                  <div className="sax-card-stat"><span className="lk">♥ {t.likes}</span><span className="st">★ {t.star}</span></div>
                </figcaption>
              </figure>
          )}
          </div>
        }

        {/* C · Merchandise Direction — transition strip */}
        <div className="sax-submh" style={{ marginTop: 34 }}><span className="ab">C</span> MERCHANDISE DIRECTION <span className="zh">衍生品方向 · 转化入口</span></div>
        <div className="sax-transition">
          <p className="sax-tr-line">高互动内容成为衍生品企划的重要来源。</p>
          <div className="sax-chips">
            {d.collections.map((c) =>
            <button className="sax-chip" key={c.series} onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}document.getElementById("sax-merch")?.scrollIntoView({ behavior: "smooth" });}}>{c.series}<span> {c.role}</span></button>
            )}
            <span className="sax-chip-arrow">↓ 详见 衍生品延展</span>
          </div>
        </div>
      </section>

      {/* 04 MERCHANDISE EXPANSION */}
      <section className="pd-sec" id="sax-merch">
        <div className="pd-sec-h"><span className="n">04</span> MERCHANDISE EXPANSION <span className="zh">衍生品延展</span></div>
        <p className="sax-mnote" style={{ maxWidth: 760 }}>通过观察用户对角色、风格与情绪标签的反馈，将高互动视觉内容延展为系列衍生品。</p>
        <div className="sa-subh" style={{ marginTop: 18 }}>主推系列 · FLAGSHIP SERIES · 点击查看实物细节</div>
        <div className="sa-cols">
          {d.collections.map((c) =>
          <button className="sa-col sa-col-btn" key={c.series} onClick={() => {if (c.detail || (c.gallery || []).length) {try {window.playSelect && window.playSelect();} catch (e) {}setLb(c);}}}>
              <div className="sa-col-img">{c.img ? <img src={c.img} alt={c.series} loading="lazy" /> : <span className="sa-ph">IMAGE<br />待补图</span>}<span className="sa-col-no">{c.no}</span>
                {(c.detail || (c.gallery || []).length > 0) && <span className="sa-col-zoom">⊕ 查看企划</span>}
              </div>
              <div className="sa-col-body">
                <div className="sa-col-title">{c.series} <span>{c.role}</span></div>
                <p>{c.desc}</p>
                <div className="sa-col-items">{c.items.map((it) => <span key={it}>{it}</span>)}</div>
              </div>
            </button>
          )}
        </div>

        {/* GAL DEMON — fan-made gyaru concept matrix */}
        {d.galDemon &&
        <div className="sa-gd">
          <div className="sa-subh" style={{ marginTop: 30 }}>FAN-MADE GYARU CONCEPT · 鬼灭同人 · 复古辣妹视觉企划</div>
          <div className="sa-gd-title">GAL <span>DEMON</span></div>
          <div className="sa-gd-cn">复古辣妹风同人企划</div>
          <p className="sa-gal-intro" style={{ marginTop: 12 }}>{d.galDemon.intro}</p>
          <div className="sa-gd-grid">
            {d.galDemon.chars.map((c) =>
            <button className="sa-gd-card" key={c.name} onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setLb({ series: c.cn, role: c.name, detail: c.detail });}}>
                <div className="sa-gd-img">{c.cover ? <img src={c.cover} alt={c.cn} loading="lazy" /> : <span className="sa-ph">OC<br />待补图</span>}<span className="sa-gd-no">{c.no}</span><span className="sa-col-zoom">⊕ 查看企划</span></div>
                <div className="sa-gd-name">{c.name} <span>/ {c.cn}</span></div>
                <div className="sa-gd-sub">{c.subt}</div>
                <div className="sa-gd-kw">{c.keywords.map((k) => <span key={k}>{k}</span>)}</div>
              </button>
            )}
          </div>
        </div>
        }
      </section>

      {/* 05 WORKFLOW */}
      <section className="pd-sec">
        <div className="pd-sec-h"><span className="n">05</span> WORKFLOW <span className="zh">工作流程</span></div>
        <div className="sa-wf sa-wf-grid">
          {d.flow.map(([cn, en], i) =>
          <div className="sa-wf-node" key={en}><span className="wf-no">{String(i + 1).padStart(2, "0")}</span><span className="wf-cn">{cn}</span><span className="wf-en">{en}</span></div>
          )}
        </div>
      </section>

      {/* 06 PROJECT PROOF & FUTURE */}
      <section className="pd-sec pd-proves">
        <div className="pd-sec-h"><span className="n">06</span> PROJECT PROOF &amp; FUTURE <span className="zh">能力证明与未来探索</span></div>
        <p className="pd-proves-txt">{d.proves}</p>
        <div className="sax-future">
          <div className="sa-future-label" style={{ fontSize: "30px", opacity: "1", textAlign: "center" }}>  未来探索 · FUTURE EXPLORATION</div>
          <div className="sa-future">{d.statusFuture.map((f) => <span key={f}>{f}</span>)}</div>
        </div>
      </section>

      {/* detail lightbox for theme collections */}
      {lb &&
      <div className="sa-lb" onClick={(e) => {if (e.target.classList.contains("sa-lb")) setLb(null);}}>
          <div className="sa-lb-card">
            <div className="sa-lb-bar">
              <span className="sa-lb-t">{lb.series} <span>{lb.role}</span></span>
              <button className="sa-lb-x" onClick={() => setLb(null)} aria-label="Close">✕</button>
            </div>
            {lb.detail ?
          <div className="sa-cc">
                {lb.detail.cover &&
            <div className="sa-cc-hero">
                  <img src={lb.detail.cover} alt={lb.series} />
                  <span className="sa-cc-status">● {lb.detail.status}</span>
                </div>
            }
                <div className="sa-cc-body">
                  {!lb.detail.cover && <div className="sa-cc-statusline">● {lb.detail.status}</div>}
                  <div className="sa-cc-eyebrow">{lb.detail.enTitle} · {lb.detail.zhTitle}</div>
                  <p className="sa-cc-intro">{lb.detail.intro}</p>
                  {lb.detail.designNote && <>
                    <div className="sa-cc-lab">设计说明 · DESIGN NOTE</div>
                    <p className="sa-cc-note">{lb.detail.designNote}</p>
                  </>}
                  <div className="sa-cc-meta">
                    <div className="sa-cc-block">
                      <div className="sa-cc-lab">视觉关键词 · KEYWORDS</div>
                      <div className="sa-cc-chips">{lb.detail.keywords.map((k) => <span key={k}>{k}</span>)}</div>
                    </div>
                    {lb.detail.skus &&
                <div className="sa-cc-block">
                      <div className="sa-cc-lab">拟开发 SKU · PLANNED</div>
                      <div className="sa-cc-chips sku">{lb.detail.skus.map((k) => <span key={k}>{k}</span>)}</div>
                    </div>
                }
                  </div>

                  {/* products with descriptions (concept matrix) */}
                  {lb.detail.products && <>
                    <div className="sa-cc-lab" style={{ marginTop: 18 }}>四种制品设计 · PRODUCT DESIGNS</div>
                    <div className="sa-cc-prod">
                      {lb.detail.products.map(([cn, en, desc, img], i) =>
                  <div className="sa-cc-pr" key={i}>
                          <div className="sa-cc-pr-img">{img ? <img src={img} alt={cn} className="sa-zoomable" onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: img, cap: cn });}} /> : <span className="sa-ph">设计图<br />待补</span>}</div>
                          <div className="sa-cc-pr-body">
                            <div className="sa-cc-pr-h">{cn} <span>{en}</span></div>
                            <p>{desc}</p>
                          </div>
                        </div>
                  )}
                    </div>
                  </>}

                  {/* legacy flat shots grid */}
                  {lb.detail.shots && <>
                    <div className="sa-cc-lab" style={{ marginTop: 18 }}>制品视觉 · PRODUCT VISUALS</div>
                    <div className="sa-cc-grid">
                      {lb.detail.shots.map(([img, cn, en], i) =>
                  <figure className="sa-cc-shot" key={i}>
                          <div className="sa-cc-img"><img src={img} alt={cn} className="sa-zoomable" onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: img, cap: cn });}} /></div>
                          <figcaption><b>{cn}</b><span>{en}</span></figcaption>
                        </figure>
                  )}
                    </div>
                  </>}

                  {/* extra art */}
                  {lb.detail.extra &&
              <div className="sa-cc-grid" style={{ gridTemplateColumns: "repeat(2,1fr)", marginTop: 12 }}>
                      {lb.detail.extra.map(([img, cap], i) =>
                <figure className="sa-cc-shot" key={i}><div className="sa-cc-img" style={{ aspectRatio: "4/5" }}><img src={img} alt={cap} className="sa-zoomable" onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: img, cap });}} /></div><figcaption><b>{cap}</b></figcaption></figure>
                )}
                    </div>
              }
                </div>
              </div> :

          <>
                <div className="sa-lb-grid">
                  {(lb.gallery || []).map((g, i) => <div className="sa-lb-img" key={i}><img src={g} alt={lb.series + "-" + i} className="sa-zoomable" onClick={() => {try {window.playSelect && window.playSelect();} catch (e) {}setZoom({ src: g, cap: lb.series });}} /></div>)}
                </div>
                <div className="sa-lb-foot">{lb.items.join(" · ")}　＊ 实物细节图，可继续补充更多</div>
              </>
          }
          </div>
        </div>
      }

      {/* fullscreen image zoom */}
      {zoom &&
      <div className="sa-zoom" onClick={() => setZoom(null)}>
          <img src={zoom.src} alt={zoom.cap} />
          <div className="sa-zoom-cap">{zoom.cap}　·　点击任意处关闭 ✕</div>
        </div>
      }
    </div>);

}

function ProjectDetail() {
  const [slug, setSlug] = useState(slugFromHash());
  const [shown, setShown] = useState(!!slugFromHash());
  const cardRef = useRef(null);
  const scrollRef = useRef(null);

  // apply FLIP transform from the origin film-frame rect → fullscreen
  const playOpen = useCallback(() => {
    const card = cardRef.current;if (!card) return;
    const o = window.__detailOrigin;
    card.style.transition = "none";
    if (o) {
      const cw = window.innerWidth,ch = window.innerHeight;
      const sx = o.width / cw,sy = o.height / ch;
      const ox = o.left + o.width / 2 - cw / 2,oy = o.top + o.height / 2 - ch / 2;
      card.style.transformOrigin = "center center";
      card.style.transform = `translate(${ox}px,${oy}px) scale(${sx},${sy})`;
      card.style.opacity = "0.4";
      card.style.borderRadius = "10px";
    } else {
      card.style.transform = "scale(.94)";card.style.opacity = "0";card.style.borderRadius = "0px";
    }
    // force reflow so the FROM state is committed, then flip to the resting state
    void card.offsetWidth;
    card.style.transition = "transform .62s cubic-bezier(.16,.84,.3,1), opacity .42s ease, border-radius .5s ease";
    card.style.transform = "none";
    card.style.opacity = "1";
    card.style.borderRadius = "0px";
    // safety snap: if the transition clock is throttled (background/hidden iframe),
    // force the resting (visible) state so the panel never gets stuck transparent.
    clearTimeout(window.__pdSnap);
    window.__pdSnap = setTimeout(() => {
      const c = cardRef.current;if (!c) return;
      c.style.transition = "none";c.style.transform = "none";c.style.opacity = "1";c.style.borderRadius = "0px";
    }, 700);
  }, []);

  const playClose = useCallback((done) => {
    const card = cardRef.current;if (!card) {done && done();return;}
    const o = window.__detailOrigin;
    card.style.transition = "transform .5s cubic-bezier(.6,.04,.5,1), opacity .4s ease, border-radius .4s ease";
    if (o) {
      const cw = window.innerWidth,ch = window.innerHeight;
      const sx = o.width / cw,sy = o.height / ch;
      const ox = o.left + o.width / 2 - cw / 2,oy = o.top + o.height / 2 - ch / 2;
      card.style.transform = `translate(${ox}px,${oy}px) scale(${sx},${sy})`;
      card.style.opacity = "0";card.style.borderRadius = "10px";
    } else {card.style.transform = "scale(.92)";card.style.opacity = "0";}
    setTimeout(() => {done && done();}, 480);
  }, []);

  // react to hash changes (also browser back/forward)
  useEffect(() => {
    function onHash() {
      const s = slugFromHash();
      if (s && DETAILS[s]) {
        setSlug(s);setShown(true);
      } else if (shown) {
        // closing
        playClose(() => {setShown(false);setSlug(null);});
      }
    }
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, [shown, playClose]);

  // opener used by the film reel
  useEffect(() => {
    window.__openProject = (s, originEl) => {
      if (!DETAILS[s]) return;
      if (originEl && originEl.getBoundingClientRect) {
        const r = originEl.getBoundingClientRect();
        window.__detailOrigin = { left: r.left, top: r.top, width: r.width, height: r.height };
      } else window.__detailOrigin = null;
      if (location.hash !== "#/projects/" + s) {window.__pdPushed = true;location.hash = "#/projects/" + s;} else
      {setSlug(s);setShown(true);}
    };
    // open on initial load if hash already points to a project
    const s0 = slugFromHash();
    if (s0 && DETAILS[s0]) {window.__detailOrigin = null;setSlug(s0);setShown(true);}
    return () => {try {delete window.__openProject;} catch (e) {}};
  }, []);

  // when shown becomes true → play open anim + lock body scroll + reset scroll
  useEffect(() => {
    if (shown) {
      playOpen();
      const prev = document.body.style.overflow;
      document.body.style.overflow = "hidden";
      if (scrollRef.current) scrollRef.current.scrollTop = 0;
      return () => {document.body.style.overflow = prev;};
    }
  }, [shown, slug, playOpen]);

  const close = useCallback(() => {
    try {window.playClose && window.playClose();} catch (e) {}
    // if we pushed a hash entry to open, go back so the URL + history stay clean;
    // otherwise (deep-loaded directly) clear the hash in place.
    if (window.__pdPushed) {
      window.__pdPushed = false;
      history.back();
    } else {
      history.replaceState("", document.title, location.pathname + location.search);
      window.dispatchEvent(new HashChangeEvent("hashchange"));
    }
  }, []);

  // ESC closes
  useEffect(() => {
    if (!shown) return;
    function onKey(e) {if (e.key === "Escape") {e.preventDefault();close();}}
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [shown, close]);

  const nextCase = useCallback(() => {
    const idx = ORDER.indexOf(slug);
    const nx = ORDER[(idx + 1) % ORDER.length];
    try {window.playSelect && window.playSelect();} catch (e) {}
    window.__detailOrigin = null;
    if (nx === slug) {if (scrollRef.current) scrollRef.current.scrollTop = 0;return;}
    location.hash = "#/projects/" + nx;
  }, [slug]);

  if (!shown || !slug || !DETAILS[slug]) return null;
  const d = DETAILS[slug];
  const GBC = window.GBCSections;
  const AIGC = window.AIGCStamps;
  const SW = window.SampleWall;
  const LAB = window.LabSections;

  return (
    <div className="pd-overlay" role="dialog" aria-label={d.title}>
      <div className={"pd-card" + (d.layout === "global-brand" || d.layout === "live-sports" ? " pd-card-portfolio" : "") + (d.layout === "aigc-stamps" ? " pd-card-aigc" : "") + (d.layout === "sample-wall" ? " pd-card-cbcc" : "") + (d.layout === "prototype-lab" ? " pd-card-lab" : "") + (d.layout === "silicon-angel" ? " pd-card-coquette" : "")} ref={cardRef}>
        {d.layout === "silicon-angel" && <>
          <span className="pd-card-bow" style={{ top: "6px", left: "6px" }} />
          <span className="pd-card-bow" style={{ top: "6px", right: "6px", transform: "scaleX(-1)" }} />
          <span className="pd-card-bow" style={{ bottom: "6px", left: "6px", transform: "scaleY(-1)" }} />
          <span className="pd-card-bow" style={{ bottom: "6px", right: "6px", transform: "scale(-1,-1)" }} />
        </>}
        <div className="pd-scroll" ref={scrollRef} data-lenis-prevent>
          {/* sticky bar */}
          <div className="pd-bar">
            <span className="pd-tag">CASE FILE · {d.cn}</span>
            <span className="pd-bar-sp" />
            <button className="pd-x" onClick={close} aria-label="Close">CLOSE ✕</button>
          </div>

          {/* HERO */}
          {d.layout === "silicon-angel" ?
          <header className="sax-hero">
              <div className="sax-hero-bg" style={{ backgroundImage: `url(${d.heroBg})` }} />
              <div className="sax-hero-grad" />
              <div className="sax-hero-inner">
                <div className="sax-hero-l">
                  <div className="sax-eyebrow">{d.eyebrow}</div>
                  <h1 className="sax-h1">{d.title}<span className="sax-cn">硅的天使</span></h1>
                  <div className="sax-sub">{d.sub}</div>
                  <div className="sax-period">{d.period}</div>
                  <p className="sax-lede">{d.lede}</p>
                  <div className="sax-kw">{d.keywords.map((k) => <span key={k}>{k}</span>)}</div>
                </div>
                {/* ACCOUNT EXHIBIT CARD — 账号展品卡（艺术馆展签风） */}
                <aside className="sax-exhibit">
                  <div className="sax-ex-tag">EXHIBIT A · ACCOUNT</div>
                  <div className="sax-ex-head">
                    <div className="sax-ex-avatar"><img src={d.account.shot} alt="avatar" /></div>
                    <div className="sax-ex-id">
                      <div className="sax-ex-name">{d.account.handle}</div>
                      <div className="sax-ex-meta">小红书号 {d.account.xhs}　·　IP {d.account.ip}</div>
                    </div>
                  </div>
                  <div className="sax-ex-stats">
                    {d.account.stats.map(([n, l]) => <div key={l}><b>{n}</b><span>{l}</span></div>)}
                  </div>
                  <div className="sax-ex-bio">
                    {d.account.bioFull.map((line, i) => <div key={i}>{line}</div>)}
                  </div>
                  <a className="sax-ex-link" href={d.account.link} target="_blank" rel="noopener">VISIT ON 小红书 ↗</a>
                  <div className="sax-ex-foot">● LIVE EXHIBIT · 实时账号数据</div>
                </aside>
              </div>
            </header> :
          d.layout === "global-brand" || d.layout === "live-sports" || d.layout === "aigc-stamps" || d.layout === "sample-wall" || d.layout === "prototype-lab" ? null :
          <header className="pd-hero">
            <div className="pd-hero-txt">
              <div className="pd-eyebrow">{d.eyebrow || "PROJECT FILE"}</div>
              <h1 className="pd-h1">{d.title}<span className="pd-cn"> / {d.cn}</span></h1>
              <div className="pd-sub">{d.sub}</div>
              <p className="pd-lede">{d.lede}</p>
              <div className="pd-kw">{d.keywords.map((k) => <span key={k}>{k}</span>)}</div>
            </div>
            <div className="pd-hero-cover">
              <div className="pd-cover-img" style={{ backgroundImage: `url(${d.cover})` }} />
              {d.coverTag && <div className="pd-cover-tag">{d.coverTag}</div>}
            </div>
          </header>
          }

          {/* SILICON ANGEL — bespoke 6-section layout */}
          {d.layout === "silicon-angel" && <SASections d={d} />}

          {/* GLOBAL BRAND CONTENT — bespoke editorial layout */}
          {d.layout === "global-brand" && GBC && <GBC d={d} />}

          {/* LIVE & SPORTS CONCEPTS — same editorial system, sports dataset */}
          {d.layout === "live-sports" && GBC && <GBC d={d} data={window.SPORTS_DATA} />}

          {/* AIGC COMMERCIAL SYSTEM — bespoke stamp-archive layout */}
          {d.layout === "aigc-stamps" && AIGC && <AIGC d={d} />}

          {/* COMPLEX BRIEFS, CLEAR COPY — grey-green sample wall */}
          {d.layout === "sample-wall" && SW && <SW d={d} />}

          {/* PROTOTYPE LAB — Coquette personal tool drawer */}
          {d.layout === "prototype-lab" && LAB && <LAB d={d} />}

          {/* OVERVIEW */}
          {d.overview &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">01</span> OVERVIEW <span className="zh">概览</span></div>
            <div className="pd-overview">
              {d.overview.map(([k, v]) =>
              <div className="pd-ov" key={k}><div className="k">{k}</div><div className="v">{v}</div></div>
              )}
            </div>
          </section>
          }

          {/* INSIGHT */}
          {d.insight &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">02</span> {d.insightLabel || "INSIGHT"} <span className="zh">{d.insightZh || "洞察"}</span></div>
            <p className="pd-insight">{d.insight}</p>
          </section>
          }

          {/* BRAND CASES (collection projects) */}
          {d.brands &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">02</span> BRAND CASES <span className="zh">品牌案例</span></div>
            <div className="pd-brands">
              {d.brands.map((b, i) =>
              <div className="pd-brand" key={b.name} style={{ "--bc": b.color }}>
                  <div className="pb-top">
                    <span className="pb-flag" style={{ background: b.color }}>{b.iata}</span>
                    <div className="pb-name">{b.name}<span className="pb-en"> {b.en}</span></div>
                    <span className="pb-no">{String(i + 1).padStart(2, "0")}</span>
                  </div>
                  <div className="pb-core">{b.core}</div>
                  <div className="pb-hi">{b.highlights.map((h) => <span key={h}>{h}</span>)}</div>
                </div>
              )}
            </div>
          </section>
          }

          {/* WORKFLOW */}
          {d.workflow && d.layout !== "silicon-angel" &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">03</span> {d.workflowLabel || "WORKFLOW"} <span className="zh">{d.workflowZh || "工作流"}</span></div>
            <div className="pd-flow">
              {d.workflow.map(([n, en, zh, desc]) =>
              <div className="pd-step" key={n}>
                  <div className="st-no">{n}</div>
                  <div className="st-en">{en}</div>
                  <div className="st-zh">{zh}</div>
                  <div className="st-de">{desc}</div>
                </div>
              )}
            </div>
          </section>
          }

          {/* PRODUCTS */}
          {d.products &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">04</span> PRODUCT SHOWCASE <span className="zh">衍生品</span></div>
            <div className="pd-prod">
              {d.products.map(([cn, en, c], i) =>
              <div className="pd-tile" key={en} style={{ "--pc": c }}>
                  <div className="pt-thumb"><span className="pt-glow" /><span className="pt-no">{String(i + 1).padStart(2, "0")}</span></div>
                  <div className="pt-cn">{cn}</div>
                  <div className="pt-en">{en}</div>
                </div>
              )}
            </div>
            <div className="pd-note">＊ 商品视觉占位，可替换为真实成品照 / 打样图</div>
          </section>
          }

          {/* LAUNCH MATERIALS */}
          {d.launch && d.layout !== "silicon-angel" &&
          <section className="pd-sec">
            <div className="pd-sec-h"><span className="n">05</span> {d.launchLabel || "LAUNCH MATERIALS"} <span className="zh">{d.launchZh || "宣发物料"}</span></div>
            <div className="pd-launch">
              <div className="pl-feature" style={{ backgroundImage: `url(${d.launchCover || d.cover})` }}>
                <span className="pl-badge">{d.launchBadge || "杂志风主视觉"}</span>
              </div>
              <div className="pl-grid">
                {d.launch.map((m, i) =>
                <div className="pl-cell" key={m}><span className="pl-n">{String(i + 1).padStart(2, "0")}</span>{m}</div>
                )}
              </div>
            </div>
          </section>
          }

          {/* RESULTS */}
          {d.results && d.layout !== "silicon-angel" &&
          <section className="pd-sec pd-results">
            <div className="pd-sec-h"><span className="n">06</span> RESULTS <span className="zh">成果</span></div>
            <div className="pd-stats">
              {d.results.map(([big, cn, en]) =>
              <div className="pd-stat" key={en}><div className="big">{big}</div><div className="cn">{cn}</div><div className="en">{en}</div></div>
              )}
            </div>
            {d.closedLoop && <div className="pd-loop">◆ {d.closedLoop}</div>}
          </section>
          }

          {/* PROVES */}
          {d.proves && d.layout !== "silicon-angel" &&
          <section className="pd-sec pd-proves">
            <div className="pd-sec-h"><span className="n">07</span> WHAT THIS PROVES <span className="zh">它证明了</span></div>
            <p className="pd-proves-txt">{d.proves}</p>
          </section>
          }

          {/* FOOT NAV */}
          <footer className="pd-foot">
            <button className="pd-fbtn" onClick={close}>← BACK TO PROJECTS</button>
            <button className="pd-fbtn ghost" onClick={() => {try {window.__openChat && window.__openChat();} catch (e) {}}}>◉ TALK TO ANNIE</button>
            <button className="pd-fbtn next" onClick={nextCase}>NEXT CASE →</button>
          </footer>
        </div>
      </div>
    </div>);

}

// mount into its own root so it's decoupled from the main App tree
(function mount() {
  let host = document.getElementById("detail-root");
  if (!host) {host = document.createElement("div");host.id = "detail-root";document.body.appendChild(host);}
  ReactDOM.createRoot(host).render(<ProjectDetail />);
})();