| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- // ==============================================================================
- // 江中猴菇饮 OTC · VOC 深度洞察报告 v2 · 主渲染器
- // ==============================================================================
- // v2 设计哲学:用户决策路径追踪(不再是"方法论展示")
- // 叙事线:全景漏斗 → 嵌套洞察 → 痛声地图 → 产品适配 → 定位推导 → 行动蓝图
- //
- // 报告结构(6 章 × ~24 slides):
- // 01 · Cover
- // 02 · Agenda(新叙事线说明)
- // 03-05 · Ch1 全景漏斗(3 子章):TAM/SAM/SOM + 6级病程 + 目标区间
- // 06-10 · Ch2 嵌套洞察(5 子章):每个病程阶段×细分症状×用户选择
- // 11-14 · Ch3 痛声地图(4 子章):每层未满足需求 + 需求空白矩阵
- // 15-18 · Ch4 产品适配(4 子章):产品力边界 + 米稀归因 + 插入点 + 场景
- // 19-22 · Ch5 定位推导(4 子章):心智阶梯 + 差异化 + 聚焦 + 定位陈述
- // 23-25 · Ch6 行动蓝图(3 子章):P0/P1 + 验证 + 数据缺口
- // ==============================================================================
- const STYLES = require('./voc-styles.js');
- const SCRIPTS = require('./voc-scripts.js');
- const HGY = require('./houguyin-analyze.js');
- const CH1 = require('./houguyin-v2-ch1-funnel.js');
- const CH2 = require('./houguyin-v2-ch2-nested.js');
- const CH3 = require('./houguyin-v2-ch3-pain.js');
- const CH4 = require('./houguyin-v2-ch4-fit.js');
- const CH5 = require('./houguyin-v2-ch5-position.js');
- const CH6 = require('./houguyin-v2-ch6-action.js');
- // ============================================================
- // 主题色(猴菇饮专属色板 · v2 沿用)
- // ============================================================
- const BRAND = {
- JIANG_GREEN: '#2D9C5D', // 江中主色(品牌/机会/定位)
- HOUGU_TAN: '#E8A87C', // 猴菇暖棕(产品适配)
- DEEP_AMBER: '#C96E3F', // 猴头菇深色(礼品/传统)
- CREAM: '#F5E6D3', // 米黄色(米稀联想)
- TECH_BLUE: '#0085CA', // 信任蓝(市场全景/TAM)
- WARM_ORANGE: '#FF8C42', // 温暖橙(嵌套洞察/场景)
- CORAL: '#FF6B6B', // 珊瑚红(痛声/痛点)
- SAGE: '#87A96B', // 鼠尾草绿(行动蓝图)
- PURPLE: '#8B5CF6', // 紫色(定位推导/理论)
- ROSE: '#FF4D8D', // 玫瑰(竞品对比)
- };
- // ============================================================
- // 6 章元信息(用户决策路径递进)
- // ============================================================
- const CHAPTERS = [
- { id: 1, num: '1', key: 'funnel', title: '全景漏斗', en: 'MARKET FUNNEL', tone: 'blue', color: BRAND.TECH_BLUE, icon: '🔭',
- summary: 'TAM 2.5亿胃病人群 → SAM 可服务市场 → SOM 猴菇饮的战场。6级病程分层,锁定我们的目标区间。' },
- { id: 2, num: '2', key: 'nested', title: '嵌套洞察', en: 'NESTED INSIGHT', tone: 'orange', color: BRAND.WARM_ORANGE, icon: '🔬',
- summary: '每个病程阶段 × 每个细分症状 × 用户选了什么产品。嵌套逻辑:先看阶段,再看症状,再看选择。' },
- { id: 3, num: '3', key: 'pain', title: '痛声地图', en: 'PAIN MAP', tone: 'rose', color: BRAND.CORAL, icon: '🔥',
- summary: '每一层产品的用户都在痛苦。把 VOC 痛声按层铺开,提炼跨层共性未满足需求,画出"声量×满足度"四象限。' },
- { id: 4, num: '4', key: 'fit', title: '产品适配', en: 'PRODUCT FIT', tone: 'amber', color: BRAND.HOUGU_TAN, icon: '🎯',
- summary: '猴菇饮的真实能力边界在哪?米稀成功的可迁移因子 × 饼干失败的红线 × 精准插入点 × 场景适配。' },
- { id: 5, num: '5', key: 'position', title: '定位推导', en: 'POSITIONING', tone: 'purple', color: BRAND.PURPLE, icon: '💡',
- summary: '里斯品类战略 × 特劳特定位。心智阶梯分析 → 差异化锚点 → 聚焦方向 → 一句话定位陈述 → VOC验证。' },
- { id: 6, num: '6', key: 'action', title: '行动蓝图', en: 'ACTION PLAN', tone: 'green', color: BRAND.SAGE, icon: '🚀',
- summary: 'P0 立即行动 + P1 三个月验证 + 数据缺口与下一轮采集计划。从洞察到落地的最短路径。' },
- ];
- // ============================================================
- // 各章节 subsections 清单
- // ============================================================
- const CHAPTER_SUBSECTIONS = {
- 'funnel': [
- 'TAM · 2.5亿胃病人群 × 100亿市场全景',
- 'SAM · 可服务市场 × 6级病程分层',
- 'SOM · 猴菇饮的目标区间 × 5000万→5亿路径',
- ],
- 'nested': [
- '治疗级+化药级 · 5大症状 × 对应产品 × 未满足需求',
- '中成药养护 · 4大症状 × 中成药产品 × 未满足需求',
- '保健+功能食品 · 4大需求场景 × 产品 × 未满足需求',
- '未病/预防 · 4大触发场景 × 行为 × 空白',
- '嵌套全景 · 4阶段×全症状×产品×机会 总览矩阵',
- ],
- 'pain': [
- '化药级痛声 · "有效但不敢停" × PPI依赖焦虑',
- '中成药痛声 · "苦涩难咽年轻人不买" × 代际断层',
- '功能食品痛声 · "吃了个寂寞" × 无OTC信任',
- '跨层汇总 · 5大共性未满足需求 × 声量-满足度四象限',
- ],
- 'fit': [
- '产品力实事求是 · 猴头菇的真实效用边界',
- '米稀成功归因 × 可迁移因子 vs 饼干失败红线',
- '精准插入点 · 3大机会×无人地带坐标',
- '场景适配 · PPI伴侣/日常养护/药店推荐/礼品',
- ],
- 'position': [
- '里斯品类战略 · 品类进化树 × 品类分化机会',
- '特劳特心智阶梯 · 胃病用户脑中的产品序列',
- '差异化锚点 · vs 药品 / vs 保健品 / vs 食品',
- '定位陈述 · 一句话定位 × VOC 验证证据',
- ],
- 'action': [
- 'P0 行动 · 产品/渠道/话术立即落地',
- 'P1 验证 · 3个月内数据闭环',
- '数据缺口 × 下一轮采集计划',
- ],
- };
- // ============================================================
- // 每章 hero line(divider 用)
- // ============================================================
- const CHAPTER_HERO_LINES = {
- 'funnel': '中国 <strong style="color:#0085CA;">2.5 亿</strong>胃病患者,<strong style="color:#FF8C42;">100 亿</strong> OTC 胃药市场。从全量到可服务再到可获取——<strong style="color:#2D9C5D;">TAM → SAM → SOM</strong> 三级漏斗,帮总经理看清"几亿人里我们能切多少"。6 级病程分层锁定猴菇饮的<strong style="color:#E8A87C;">精准战场</strong>。',
- 'nested': '嵌套逻辑来了:<strong style="color:#FF8C42;">第一层</strong>按病程阶段(由重到轻 6 级),<strong style="color:#8B5CF6;">第二层</strong>在每个阶段内按细分症状展开(胃酸/胃痛/胃胀/嗳气),<strong style="color:#FF6B6B;">第三层</strong>看这个症状下用户选了什么产品、有什么未满足需求。从用户真实决策路径中找出猴菇饮的切入缝隙。',
- 'pain': '每一层产品的用户都在痛苦。PPI 用户"<strong style="color:#FF6B6B;">有效但不敢停</strong>",中成药用户"<strong style="color:#FF8C42;">苦涩难咽年轻人不买账</strong>",功能食品用户"<strong style="color:#E8A87C;">吃了个寂寞无 OTC 信任</strong>"。把每层的 VOC 痛声铺开,提炼出 <strong style="color:#8B5CF6;">5 大跨层共性未满足需求</strong>——哪里最痛、哪里最空。',
- 'fit': '猴菇饮的真实能力边界在哪?不吹不黑——<strong style="color:#E8A87C;">猴头菇的效用</strong>是什么?<strong style="color:#2D9C5D;">米稀 7.5 亿成功</strong>的因子哪些可以迁移?<strong style="color:#FF6B6B;">饼干失败</strong>的红线在哪?实事求是画出"我们能接住的需求"和"绝对不能碰的区域",找到<strong style="color:#8B5CF6;">精准插入点</strong>。',
- 'position': '洞察做完了,是时候<strong style="color:#8B5CF6;">收敛为定位</strong>。用<strong style="color:#2D9C5D;">里斯品类战略</strong>看"我在哪个品类竞争",用<strong style="color:#8B5CF6;">特劳特定位</strong>看"我在用户心智中占什么位置"。从心智阶梯 → 差异化锚点 → 聚焦方向,推导出一句话定位——<strong style="color:#E8A87C;">能写在盒子上、药店店员能说出来、用户能记住</strong>的那一句。',
- 'action': '从洞察到落地的最短路径。<strong style="color:#87A96B;">P0 立即行动</strong>:产品规格/渠道选择/话术定稿。<strong style="color:#0085CA;">P1 三个月验证</strong>:数据闭环 + 定位验证。<strong style="color:#FF8C42;">数据缺口</strong>:哪些结论还需要补充 VOC 采集来夯实。<strong style="color:#2D9C5D;">5000 万 → 5 亿</strong>的 3 阶段路径。',
- };
- // ============================================================
- // utils
- // ============================================================
- function esc(s) {
- return String(s ?? '').replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
- }
- function fmtNum(n) {
- if (n == null || isNaN(n)) return '—';
- if (n >= 10000) return (n / 10000).toFixed(1).replace(/\.0$/, '') + 'w';
- if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
- return String(n);
- }
- function sn(n) { return String(n).padStart(2, '0'); }
- // ============================================================
- // SLIDE_RENDERERS 注册表
- // ============================================================
- const SLIDE_RENDERERS = {
- // Ch1 全景漏斗
- 'funnel-1': CH1.renderSub1,
- 'funnel-2': CH1.renderSub2,
- 'funnel-3': CH1.renderSub3,
- // Ch2 嵌套洞察
- 'nested-1': CH2.renderSub1,
- 'nested-2': CH2.renderSub2,
- 'nested-3': CH2.renderSub3,
- 'nested-4': CH2.renderSub4,
- 'nested-5': CH2.renderSub5,
- // Ch3 痛声地图
- 'pain-1': CH3.renderSub1,
- 'pain-2': CH3.renderSub2,
- 'pain-3': CH3.renderSub3,
- 'pain-4': CH3.renderSub4,
- // Ch4 产品适配
- 'fit-1': CH4.renderSub1,
- 'fit-2': CH4.renderSub2,
- 'fit-3': CH4.renderSub3,
- 'fit-4': CH4.renderSub4,
- // Ch5 定位推导
- 'position-1': CH5.renderSub1,
- 'position-2': CH5.renderSub2,
- 'position-3': CH5.renderSub3,
- 'position-4': CH5.renderSub4,
- // Ch6 行动蓝图
- 'action-1': CH6.renderSub1,
- 'action-2': CH6.renderSub2,
- 'action-3': CH6.renderSub3,
- };
- // ============================================================
- // 共用组件
- // ============================================================
- function renderNav() {
- const dots = [
- { tip: '封面', href: '#s0' },
- { tip: '目录', href: '#agenda' },
- ...CHAPTERS.map((c) => ({ tip: `${c.num} ${c.title}`, href: `#${c.key}` })),
- ];
- return `<nav class="nav-rail" aria-label="章节导航">
- ${dots.map((d, i) => `<a class="nav-dot${i === 0 ? ' active' : ''}" href="${d.href}" data-tip="${esc(d.tip)}" data-idx="${i}"></a>`).join('')}
- </nav>
- <div class="top-bar">
- <div class="brand-logo">江中<span class="dot">·</span>产品开发部 / 猴菇饮 OTC VOC 深度洞察 v2.0</div>
- <div class="text-mono text-xs" style="color:var(--text-3);">用户决策路径追踪 / 嵌套逻辑 / 里斯×特劳特定位</div>
- </div>`;
- }
- function renderCover(opts = {}) {
- const data = HGY.loadMerged();
- const meta = HGY.getMeta(data);
- return `<section class="slide cover-slide" id="s0" data-slide-num="01/${sn(opts.slideTotal || 26)}">
- <div class="cover-inner">
- <div class="cover-eyebrow">JIANGZHONG · VOC DEEP INSIGHT</div>
- <h1 class="cover-title">猴菇饮 OTC<br><span class="accent" style="color:${BRAND.JIANG_GREEN};">用户决策路径 × 定位策略</span></h1>
- <div class="cover-subtitle">基于 <strong>${meta.rawItemsCount || '—'}</strong> 条原始 VOC → 筛选去噪去重 → <strong>${meta.comments || '—'}</strong> 条精准 VOC 的嵌套洞察 · v2.0</div>
- <div class="cover-meta">
- <div class="meta-item"><span class="meta-label">方法论</span><span class="meta-value">用户决策路径追踪 × 里斯品类战略 × 特劳特定位</span></div>
- <div class="meta-item"><span class="meta-label">数据源</span><span class="meta-value">${Object.keys(meta.platforms || {}).length} 平台 / ${meta.keywords || 0} 关键词</span></div>
- <div class="meta-item"><span class="meta-label">数据管线</span><span class="meta-value">${meta.rawItemsCount || 0} 条采集 → 去噪去重 → ${meta.comments || 0} 条精准 VOC(过滤率 ${meta.rawItemsCount ? Math.round((1 - meta.comments / meta.rawItemsCount) * 100) : 0}%)</span></div>
- <div class="meta-item"><span class="meta-label">报告结构</span><span class="meta-value">6 章 · 全景→嵌套→痛声→适配→定位→行动</span></div>
- <div class="meta-item"><span class="meta-label">生成日期</span><span class="meta-value">${opts.collectedAt || new Date().toISOString().slice(0, 10)}</span></div>
- </div>
- </div>
- </section>`;
- }
- function renderAgenda(opts = {}) {
- return `<section class="slide agenda-slide" id="agenda" data-slide-num="02/${sn(opts.slideTotal || 26)}">
- <div class="section-inner">
- <div class="agenda-eyebrow">REPORT STRUCTURE</div>
- <h2 class="agenda-title">报告结构 · 用户决策路径追踪</h2>
- <p style="color:var(--text-2); font-size:0.92rem; margin:12px 0 28px; max-width:680px; line-height:1.7;">
- v2 改变了叙事逻辑:不再是"我用了什么分析方法",而是<strong>"用户在经历什么 → 每一步选了什么 → 哪里没被满足 → 我们切哪里 → 怎么定位"</strong>。<br>
- 嵌套结构:病程阶段(第一层)→ 细分症状(第二层)→ 产品选择 × 未满足需求(第三层)。
- </p>
- <div class="agenda-grid" style="display:grid; grid-template-columns:repeat(3, 1fr); gap:16px;">
- ${CHAPTERS.map((c) => `
- <a class="agenda-card" href="#${c.key}" style="border-left:4px solid ${c.color}; padding:16px 18px; background:var(--bg-1); border-radius:var(--radius-sm); text-decoration:none; display:block;">
- <div style="display:flex; align-items:center; gap:8px; margin-bottom:8px;">
- <span style="font-size:1.3rem;">${c.icon}</span>
- <span class="text-mono text-xs" style="color:${c.color}; font-weight:700; letter-spacing:0.12em;">${c.en}</span>
- </div>
- <div style="font-size:0.95rem; font-weight:700; color:var(--text-1); margin-bottom:4px;">Ch${c.num} · ${esc(c.title)}</div>
- <div style="font-size:0.78rem; color:var(--text-3); line-height:1.5;">${esc(c.summary).slice(0, 60)}…</div>
- </a>`).join('')}
- </div>
- </div>
- </section>`;
- }
- function renderDivider(chapter, slideNum, slideTotal) {
- const c = chapter;
- const heroLine = CHAPTER_HERO_LINES[c.key] || c.summary;
- return `<section class="slide divider-slide" id="${c.key}" data-tone="${c.tone}" data-slide-num="${sn(slideNum)}/${sn(slideTotal)}">
- <div class="divider-inner">
- <div class="divider-eyebrow" style="color:${c.color};">${c.icon} CHAPTER ${c.num}</div>
- <h2 class="divider-title" style="color:${c.color};">${esc(c.title)}</h2>
- <div class="divider-en" style="color:${c.color}80;">${c.en}</div>
- <div class="divider-hero">${heroLine}</div>
- <div class="divider-subsections">
- ${(CHAPTER_SUBSECTIONS[c.key] || []).map((s, i) => `<div class="divider-sub-item"><span class="sub-num" style="color:${c.color};">${c.num}.${i + 1}</span> ${esc(s)}</div>`).join('')}
- </div>
- </div>
- </section>`;
- }
- function renderComingSoon(ctx) {
- const { chapter: c, subIdx, slideNum, slideTotal, subTitle } = ctx;
- return `<section class="report-section" id="${c.key}-${subIdx}" data-tone="${c.tone}" data-slide-num="${sn(slideNum)}/${sn(slideTotal)}">
- <div class="section-inner" style="display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:480px;">
- <div style="font-size:3rem; margin-bottom:16px; opacity:0.5;">${c.icon}</div>
- <div class="text-mono text-xs" style="color:${c.color}; letter-spacing:0.15em; margin-bottom:8px;">Ch${c.num}.${subIdx} · ${esc(c.title)}</div>
- <h3 style="color:var(--text-1); font-size:1.4rem; margin-bottom:12px;">${esc(subTitle || '')}</h3>
- <div style="color:var(--text-3); font-size:0.88rem;">内容将在下一批次填充 · Coming Soon</div>
- </div>
- </section>`;
- }
- // ============================================================
- // 主组装
- // ============================================================
- function buildHTML(opts = {}) {
- const data = HGY.loadMerged();
- const meta = HGY.getMeta(data);
- // 计算 slide 总数
- let slideTotal = 2;
- for (const c of CHAPTERS) {
- slideTotal += 1 + (CHAPTER_SUBSECTIONS[c.key] || []).length;
- }
- const slides = [];
- slides.push(renderCover({ ...opts, slideTotal }));
- slides.push(renderAgenda({ slideTotal }));
- let slideNum = 3;
- for (const c of CHAPTERS) {
- // divider
- slides.push(renderDivider(c, slideNum, slideTotal));
- slideNum++;
- // subsections
- const subs = CHAPTER_SUBSECTIONS[c.key] || [];
- for (let i = 0; i < subs.length; i++) {
- const subIdx = i + 1;
- const rendererKey = `${c.key}-${subIdx}`;
- const renderer = SLIDE_RENDERERS[rendererKey];
- const ctx = {
- chapter: c,
- subIdx,
- slideNum,
- slideTotal,
- subTitle: subs[i],
- data,
- meta,
- };
- if (renderer) {
- try {
- slides.push(renderer(ctx));
- } catch (err) {
- console.warn(` ⚠ ${rendererKey} 渲染失败: ${err.message}`);
- slides.push(renderComingSoon(ctx));
- }
- } else {
- slides.push(renderComingSoon(ctx));
- }
- slideNum++;
- }
- }
- return `<!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>江中猴菇饮 OTC · VOC 深度洞察 v2 · 用户决策路径追踪</title>
- ${STYLES}
- <style>
- /* ── v2 专属样式补丁(cover / agenda / divider) ── */
- .slide {
- min-height: 100vh; position: relative; border-bottom: 1px solid var(--border);
- display: flex; flex-direction: column; justify-content: center;
- scroll-snap-align: start; scroll-snap-stop: always; overflow: hidden; isolation: isolate;
- }
- .slide::before {
- content: attr(data-slide-num);
- position: absolute; top: clamp(20px,3vh,36px); right: clamp(24px,4vw,60px);
- font-family: var(--font-mono); font-weight: 600; font-size: clamp(0.68rem,0.75vw,0.78rem);
- letter-spacing: 0.25em; color: var(--text-3); z-index: 4; pointer-events: none;
- }
- /* ── Cover ── */
- .cover-slide {
- padding: clamp(80px,12vh,140px) clamp(24px,6vw,80px);
- background:
- radial-gradient(ellipse 60% 80% at 30% 30%, rgba(245,166,35,0.08) 0%, transparent 70%),
- radial-gradient(ellipse 40% 60% at 80% 70%, rgba(139,92,246,0.05) 0%, transparent 70%),
- var(--bg-0);
- }
- .cover-inner { max-width: var(--max-w); width: 100%; position: relative; z-index: 2; }
- .cover-eyebrow {
- font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.22em;
- text-transform: uppercase; color: var(--text-3); margin-bottom: 32px;
- display: flex; align-items: center; gap: 14px;
- }
- .cover-eyebrow::before { content: ''; width: 32px; height: 2px; background: var(--amber); }
- .cover-slide .cover-title {
- font-family: var(--font-head); font-weight: 900; letter-spacing: -0.04em;
- line-height: 0.92; font-size: clamp(3.5rem,11vw,9rem); color: #fff;
- background: linear-gradient(135deg, #fff 30%, rgba(245,166,35,0.9) 100%);
- -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
- }
- .cover-slide .cover-title .accent { -webkit-text-fill-color: currentColor; }
- .cover-subtitle {
- font-size: clamp(1rem,1.6vw,1.4rem); color: var(--text-2); max-width: 780px;
- margin-top: 28px; line-height: 1.7;
- }
- .cover-slide .cover-meta {
- display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px;
- margin-top: clamp(40px,6vh,72px); padding-top: clamp(20px,3vh,36px);
- border-top: 1px solid var(--border); max-width: 900px;
- }
- .meta-item {
- display: flex; flex-direction: column; gap: 4px;
- padding: 10px 14px; background: var(--bg-1); border: 1px solid var(--border);
- border-radius: var(--radius-sm);
- }
- .meta-label {
- font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 0.15em;
- text-transform: uppercase; color: var(--text-3); font-weight: 500;
- }
- .meta-value { font-size: 0.85rem; color: var(--text-1); font-weight: 600; }
- /* ── Agenda ── */
- .agenda-slide {
- padding: clamp(60px,10vh,120px) clamp(24px,6vw,80px);
- background: var(--bg-0);
- }
- .agenda-eyebrow {
- font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.18em;
- text-transform: uppercase; color: var(--amber); font-weight: 500; margin-bottom: 14px;
- display: flex; align-items: center; gap: 10px;
- }
- .agenda-eyebrow::before { content: ''; width: 24px; height: 1px; background: var(--amber); }
- .agenda-title {
- font-family: var(--font-head); font-weight: 700; letter-spacing: -0.02em;
- line-height: 1.1; font-size: clamp(2rem,4vw,3rem); color: var(--text-1);
- }
- .agenda-card { transition: all 0.35s cubic-bezier(.2,.7,.2,1); }
- .agenda-card:hover { transform: translateY(-4px); border-color: var(--border-strong); box-shadow: 0 12px 40px rgba(0,0,0,0.35); }
- /* ── Chapter Divider ── */
- .divider-slide {
- padding: clamp(80px,12vh,140px) clamp(24px,6vw,80px);
- background: var(--bg-0); text-align: left;
- }
- .divider-slide::after {
- content: ''; position: absolute; inset: 0; pointer-events: none; z-index: -1;
- background:
- radial-gradient(ellipse 70% 60% at 85% 15%, var(--slide-glow-1, rgba(245,166,35,0.06)), transparent 55%),
- radial-gradient(ellipse 60% 50% at 15% 85%, var(--slide-glow-2, rgba(139,92,246,0.04)), transparent 55%);
- }
- .divider-slide[data-tone="amber"] { --slide-glow-1: rgba(245,166,35,0.10); --slide-glow-2: rgba(245,166,35,0.04); }
- .divider-slide[data-tone="rose"] { --slide-glow-1: rgba(255,77,141,0.09); --slide-glow-2: rgba(255,77,141,0.04); }
- .divider-slide[data-tone="green"] { --slide-glow-1: rgba(0,220,130,0.08); --slide-glow-2: rgba(0,220,130,0.03); }
- .divider-slide[data-tone="purple"] { --slide-glow-1: rgba(139,92,246,0.10); --slide-glow-2: rgba(139,92,246,0.04); }
- .divider-slide[data-tone="blue"] { --slide-glow-1: rgba(59,130,246,0.08); --slide-glow-2: rgba(59,130,246,0.03); }
- .divider-slide[data-tone="orange"] { --slide-glow-1: rgba(255,140,66,0.10); --slide-glow-2: rgba(255,140,66,0.04); }
- .divider-inner { max-width: var(--max-w); width: 100%; position: relative; }
- .divider-eyebrow {
- font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.22em;
- text-transform: uppercase; font-weight: 600; margin-bottom: 16px;
- }
- .divider-title {
- font-family: var(--font-head); font-weight: 900; letter-spacing: -0.03em;
- line-height: 1; font-size: clamp(3rem,8vw,6rem); margin-bottom: 8px;
- }
- .divider-en {
- font-family: var(--font-mono); font-size: 0.78rem; letter-spacing: 0.22em;
- text-transform: uppercase; margin-bottom: 28px;
- }
- .divider-hero {
- font-size: clamp(0.95rem,1.3vw,1.15rem); color: var(--text-2); line-height: 1.8;
- max-width: 860px; margin-bottom: 32px;
- }
- .divider-subsections { display: flex; flex-direction: column; gap: 10px; max-width: 700px; }
- .divider-sub-item {
- font-size: 0.88rem; color: var(--text-2); line-height: 1.5;
- padding: 8px 14px; background: var(--bg-1); border: 1px solid var(--border);
- border-radius: var(--radius-sm); display: flex; align-items: center; gap: 10px;
- }
- .sub-num {
- font-family: var(--font-mono); font-weight: 700; font-size: 0.78rem;
- letter-spacing: 0.1em; min-width: 28px;
- }
- </style>
- </head>
- <body>
- ${renderNav()}
- <main class="slides-container">
- ${slides.join('\n')}
- </main>
- <script>${SCRIPTS}</script>
- </body>
- </html>`;
- }
- module.exports = {
- buildHTML,
- CHAPTERS,
- CHAPTER_SUBSECTIONS,
- BRAND,
- CHAPTER_HERO_LINES,
- };
|