"""
为艺术理论 v1 生成 5 张关键 SVG 插图。
- 风格：浅黄色渐变背景，渐变圆角矩形 + 简洁图标
- 主题：四把尺子 / 三大机制 / 5 大人物原型 / 情感账户 / 4 类体裁
- 输出：v1/svg/ 目录
"""
from pathlib import Path

ROOT = Path(r"E:\GitHub3\article\艺术理论\v1")
SVG_DIR = ROOT / "svg"
SVG_DIR.mkdir(exist_ok=True)

# 主题色（艺术理论 v1 的主色：紫色系，区别于健康理论的青绿）
THEMES = {
    "primary": "#7c3aed",         # 紫罗兰 - 主色
    "primary_light": "#a78bfa",
    "primary_dark": "#5b21b6",
    "secondary": "#db2777",        # 玫红 - 副色
    "secondary_light": "#f472b6",
    "warning": "#ea580c",          # 橙 - 警示
    "warning_light": "#fb923c",
    "info": "#0284c7",             # 蓝 - 信息
    "info_light": "#38bdf8",
    "neutral_dark": "#1f2937",
    "neutral": "#6b7280",
    "neutral_light": "#9ca3af",
    "bg_warm": "#fffbeb",
    "bg_warm_dark": "#fef3c7",
    "text": "#1f2328",
    "white": "#ffffff",
}


def svg_header(width: int, height: int, view_box: str = None) -> str:
    """SVG 公共头部：浅黄色渐变背景。"""
    vb = view_box or f"0 0 {width} {height}"
    return f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="{vb}" width="100%" height="auto" style="max-width:100%;">
  <defs>
    <linearGradient id="bg-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" stop-color="#fffbeb"/>
      <stop offset="100%" stop-color="#fef3c7"/>
    </linearGradient>
    <linearGradient id="primary-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="{THEMES['primary']}"/>
      <stop offset="100%" stop-color="{THEMES['primary_dark']}"/>
    </linearGradient>
    <linearGradient id="secondary-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="{THEMES['secondary']}"/>
      <stop offset="100%" stop-color="{THEMES['secondary_light']}"/>
    </linearGradient>
    <linearGradient id="info-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="{THEMES['info']}"/>
      <stop offset="100%" stop-color="{THEMES['info_light']}"/>
    </linearGradient>
    <linearGradient id="warning-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
      <stop offset="0%" stop-color="{THEMES['warning']}"/>
      <stop offset="100%" stop-color="{THEMES['warning_light']}"/>
    </linearGradient>
    <filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="3"/>
      <feOffset dx="0" dy="2" result="offsetblur"/>
      <feComponentTransfer>
        <feFuncA type="linear" slope="0.15"/>
      </feComponentTransfer>
      <feMerge>
        <feMergeNode/>
        <feMergeNode in="SourceGraphic"/>
      </feMerge>
    </filter>
  </defs>
  <rect width="100%" height="100%" fill="url(#bg-gradient)"/>
'''


def svg_footer() -> str:
    """SVG 公共尾部。"""
    return "</svg>\n"


# ==================== 1. 四把尺子在艺术创作中的应用 ====================
def make_four_rulers_art() -> str:
    """兜底 / 劳动 / 激励 / 意义 在艺术创作中的应用。"""
    W, H = 880, 600
    parts = [svg_header(W, H)]
    # 标题
    parts.append(f'  <text x="{W/2}" y="40" text-anchor="middle" font-size="24" font-weight="700" fill="{THEMES["text"]}">艺术理论 v1 · 四把尺子在创作中的应用</text>\n')
    parts.append(f'  <text x="{W/2}" y="62" text-anchor="middle" font-size="13" fill="{THEMES["neutral"]}">把"打动人心"拆解为可设计的"创作制度"</text>\n')
    # 四宫格
    grid_x, grid_y = 40, 90
    cell_w, cell_h = 200, 220
    gap_h, gap_v = 8, 12
    rulers = [
        ("兜底", "情感接住", "让观众在作品里\n'先被接住'", "🫂", "url(#primary-gradient)"),
        ("劳动", "创作者被看见", "让写作/表演/制作\n的劳动被承认", "✍️", "url(#info-gradient)"),
        ("激励", "打动人更划算", "让'打动人心'\n比'挑动情绪'更值得", "⚡", "url(#warning-gradient)"),
        ("意义", "观众保留自己", "不替观众活\n保留'怎么活'的定义权", "💡", "url(#secondary-gradient)"),
    ]
    # 重新计算坐标
    total_w = 4 * cell_w + 3 * gap_h
    start_x = (W - total_w) / 2
    for i, (name, subtitle, content, icon, color) in enumerate(rulers):
        x = start_x + i * (cell_w + gap_h)
        y = grid_y
        # 卡片背景
        parts.append(f'  <rect x="{x}" y="{y}" width="{cell_w}" height="{cell_h}" rx="14" fill="{color}" opacity="0.95" filter="url(#soft-shadow)"/>\n')
        # 序号圆
        parts.append(f'  <circle cx="{x+30}" cy="{y+30}" r="18" fill="white" opacity="0.95"/>\n')
        parts.append(f'  <text x="{x+30}" y="{y+36}" text-anchor="middle" font-size="18" font-weight="700" fill="{THEMES["primary_dark"]}">{i+1}</text>\n')
        # 名称
        parts.append(f'  <text x="{x+cell_w/2}" y="{y+80}" text-anchor="middle" font-size="20" font-weight="700" fill="white">{name}</text>\n')
        # 副标题
        parts.append(f'  <text x="{x+cell_w/2}" y="{y+102}" text-anchor="middle" font-size="13" fill="white" opacity="0.9">{subtitle}</text>\n')
        # 图标
        parts.append(f'  <text x="{x+cell_w/2}" y="{y+138}" text-anchor="middle" font-size="34">{icon}</text>\n')
        # 内容
        lines = content.split("\n")
        for j, line in enumerate(lines):
            parts.append(f'  <text x="{x+cell_w/2}" y="{y+170+j*16}" text-anchor="middle" font-size="11" fill="white" opacity="0.95">{line}</text>\n')
    # 底部：核心心法
    parts.append(f'  <rect x="60" y="345" width="{W-120}" height="50" rx="10" fill="white" opacity="0.7" stroke="{THEMES["primary"]}" stroke-width="2"/>\n')
    parts.append(f'  <text x="{W/2}" y="370" text-anchor="middle" font-size="14" font-weight="700" fill="{THEMES["primary_dark"]}">核心心法：先用兜底接住观众，再用劳动证明真诚，</text>\n')
    parts.append(f'  <text x="{W/2}" y="388" text-anchor="middle" font-size="14" font-weight="700" fill="{THEMES["primary_dark"]}">再用激励让打动人划算，最后用意义让观众保留自己。</text>\n')
    # 底部四阶段
    parts.append(f'  <text x="{W/2}" y="430" text-anchor="middle" font-size="15" font-weight="700" fill="{THEMES["text"]}">打动人心 = 四层同时发力</text>\n')
    flow_y = 470
    flow_w = 160
    flow_gap = 20
    flow_x = (W - 4*flow_w - 3*flow_gap) / 2
    flows = [
        ("吸引", "前 10 秒", "让人停下"),
        ("感动", "30-90 秒", "让人流泪"),
        ("温暖", "关屏之后", "主动转给别人"),
        ("长期", "多年之后", "还记得"),
    ]
    flow_colors = [THEMES["primary"], THEMES["secondary"], THEMES["warning"], THEMES["info"]]
    for i, (stage, timing, action) in enumerate(flows):
        x = flow_x + i * (flow_w + flow_gap)
        parts.append(f'  <rect x="{x}" y="{flow_y}" width="{flow_w}" height="80" rx="10" fill="white" opacity="0.9" stroke="{flow_colors[i]}" stroke-width="2"/>\n')
        parts.append(f'  <text x="{x+flow_w/2}" y="{flow_y+24}" text-anchor="middle" font-size="14" font-weight="700" fill="{flow_colors[i]}">{stage}</text>\n')
        parts.append(f'  <text x="{x+flow_w/2}" y="{flow_y+44}" text-anchor="middle" font-size="11" fill="{THEMES["text"]}">{timing}</text>\n')
        parts.append(f'  <text x="{x+flow_w/2}" y="{flow_y+62}" text-anchor="middle" font-size="12" fill="{THEMES["neutral_dark"]}">{action}</text>\n')
        # 箭头
        if i < 3:
            arr_x = x + flow_w + 2
            arr_y = flow_y + 40
            parts.append(f'  <path d="M {arr_x} {arr_y} L {arr_x+flow_gap-4} {arr_y} M {arr_x+flow_gap-10} {arr_y-5} L {arr_x+flow_gap-4} {arr_y} L {arr_x+flow_gap-10} {arr_y+5}" stroke="{THEMES["neutral"]}" stroke-width="2" fill="none"/>\n')
    return "".join(parts) + svg_footer()


# ==================== 2. 三大机制：吸引 / 感动 / 温暖 ====================
def make_three_mechanisms() -> str:
    """吸引 / 感动 / 温暖 三大机制。"""
    W, H = 880, 520
    parts = [svg_header(W, H)]
    # 标题
    parts.append(f'  <text x="{W/2}" y="40" text-anchor="middle" font-size="24" font-weight="700" fill="{THEMES["text"]}">感动人的三大机制</text>\n')
    parts.append(f'  <text x="{W/2}" y="62" text-anchor="middle" font-size="13" fill="{THEMES["neutral"]}">从"前 10 秒"到"关屏之后"——打动人心的三层递进</text>\n')
    # 三个大圆
    centers = [(180, 220), (440, 220), (700, 220)]
    radii = 90
    colors = [THEMES["primary"], THEMES["secondary"], THEMES["warning"]]
    titles = ["吸引", "感动", "温暖"]
    contents = [
        "前 10 秒\n让人停下",
        "30-90 秒\n让人流泪",
        "关屏之后\n主动转给别人"
    ]
    subtitles = [
        "认出自己 / 不被卖 / 还想看",
        "未表达的爱 / 错过的时光\n无声的牺牲 / 意料之外的温柔",
        "共鸣 / 关心 / 认同 / 传递"
    ]
    icons = ["🛑", "💧", "💌"]
    for i, ((cx, cy), r, color, title, content, sub, icon) in enumerate(zip(centers, [radii]*3, colors, titles, contents, subtitles, icons)):
        # 主圆
        parts.append(f'  <circle cx="{cx}" cy="{cy}" r="{r}" fill="{color}" opacity="0.95" filter="url(#soft-shadow)"/>\n')
        # 内圆
        parts.append(f'  <circle cx="{cx}" cy="{cy}" r="{r-12}" fill="white" opacity="0.15"/>\n')
        # 标题
        parts.append(f'  <text x="{cx}" y="{cy-30}" text-anchor="middle" font-size="24" font-weight="700" fill="white">{title}</text>\n')
        # 图标
        parts.append(f'  <text x="{cx}" y="{cy+5}" text-anchor="middle" font-size="40">{icon}</text>\n')
        # 内容
        for j, line in enumerate(content.split("\n")):
            parts.append(f'  <text x="{cx}" y="{cy+30+j*16}" text-anchor="middle" font-size="13" fill="white" opacity="0.95">{line}</text>\n')
        # 副标题（圆下方）
        for j, line in enumerate(sub.split("\n")):
            parts.append(f'  <text x="{cx}" y="{cy+r+30+j*16}" text-anchor="middle" font-size="11" fill="{THEMES["text"]}">{line}</text>\n')
    # 箭头
    arr_y = 220
    for i in range(2):
        x_start = centers[i][0] + radii
        x_end = centers[i+1][0] - radii
        parts.append(f'  <path d="M {x_start} {arr_y} L {x_end-10} {arr_y} M {x_end-15} {arr_y-5} L {x_end-5} {arr_y} L {x_end-15} {arr_y+5}" stroke="{THEMES["neutral"]}" stroke-width="2" fill="none"/>\n')
    # 底部：核心判断
    parts.append(f'  <rect x="60" y="410" width="{W-120}" height="80" rx="12" fill="white" opacity="0.7" stroke="{THEMES["primary"]}" stroke-width="2"/>\n')
    parts.append(f'  <text x="{W/2}" y="436" text-anchor="middle" font-size="14" font-weight="700" fill="{THEMES["primary_dark"]}">核心判断</text>\n')
    parts.append(f'  <text x="{W/2}" y="456" text-anchor="middle" font-size="12" fill="{THEMES["text"]}">只实现吸引 = 爆款（流量大但很快被忘掉）</text>\n')
    parts.append(f'  <text x="{W/2}" y="472" text-anchor="middle" font-size="12" fill="{THEMES["text"]}">只实现感动 = 文艺片（有人哭但传播不广）</text>\n')
    parts.append(f'  <text x="{W/2}" y="488" text-anchor="middle" font-size="13" font-weight="700" fill="{THEMES["primary_dark"]}">三层都实现 = 经典（可被反复看、反复推荐、十年后还活着）</text>\n')
    return "".join(parts) + svg_footer()


# ==================== 3. 5 大人物原型 ====================
def make_five_characters() -> str:
    """5 大"耐看"人物原型。"""
    W, H = 880, 540
    parts = [svg_header(W, H)]
    # 标题
    parts.append(f'  <text x="{W/2}" y="40" text-anchor="middle" font-size="24" font-weight="700" fill="{THEMES["text"]}">5 大"耐看"人物原型</text>\n')
    parts.append(f'  <text x="{W/2}" y="62" text-anchor="middle" font-size="13" fill="{THEMES["neutral"]}">所有"耐看"的人物原型都不靠"金手指/冲突/反转"——都靠"真实 + 安静 + 未完成"</text>\n')
    # 5 个原型卡片
    grid_y = 100
    card_w = 160
    card_h = 320
    gap = 12
    total_w = 5 * card_w + 4 * gap
    start_x = (W - total_w) / 2
    characters = [
        ("残缺的好人", "主角本质善良，\n但有真实缺点/创伤", "🤝", "观众不完美的自己\n在主角身上被看见", "url(#primary-gradient)"),
        ("普通的英雄", "没有超能力/金手指/\n霸总背景", "🌱", "我也想有勇气\n但我和他一样普通", "url(#info-gradient)"),
        ("安静的改变者", '不通过冲突/争吵\n而通过"做"', "🍵", "原来改变\n可以这么安静", "url(#warning-gradient)"),
        ("未完成的人", "结尾仍困惑/\n未解决/继续生活", "🌧", "原来不一定要\n'想通'才能继续", "url(#secondary-gradient)"),
        ("陌生人之间", "主角是陌生人\n被某种东西联系起来", "🤲", "原来陌生人之间\n可以这么温暖", "url(#primary-gradient)"),
    ]
    for i, (name, content, icon, why, color) in enumerate(characters):
        x = start_x + i * (card_w + gap)
        # 卡片
        parts.append(f'  <rect x="{x}" y="{grid_y}" width="{card_w}" height="{card_h}" rx="12" fill="{color}" opacity="0.95" filter="url(#soft-shadow)"/>\n')
        # 序号
        parts.append(f'  <circle cx="{x+22}" cy="{grid_y+22}" r="15" fill="white" opacity="0.95"/>\n')
        parts.append(f'  <text x="{x+22}" y="{grid_y+28}" text-anchor="middle" font-size="14" font-weight="700" fill="{THEMES["primary_dark"]}">{i+1}</text>\n')
        # 名称
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+65}" text-anchor="middle" font-size="15" font-weight="700" fill="white">{name}</text>\n')
        # 图标
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+115}" text-anchor="middle" font-size="40">{icon}</text>\n')
        # 内容
        for j, line in enumerate(content.split("\n")):
            parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+155+j*16}" text-anchor="middle" font-size="11" fill="white" opacity="0.95">{line}</text>\n')
        # 分隔
        parts.append(f'  <line x1="{x+20}" y1="{grid_y+205}" x2="{x+card_w-20}" y2="{grid_y+205}" stroke="white" stroke-width="1" opacity="0.4"/>\n')
        # 为什么
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+225}" text-anchor="middle" font-size="10" font-weight="700" fill="white" opacity="0.85">为什么打动</text>\n')
        for j, line in enumerate(why.split("\n")):
            parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+245+j*14}" text-anchor="middle" font-size="11" fill="white">{line}</text>\n')
    # 底部
    parts.append(f'  <rect x="60" y="450" width="{W-120}" height="60" rx="10" fill="white" opacity="0.7" stroke="{THEMES["primary"]}" stroke-width="2"/>\n')
    parts.append(f'  <text x="{W/2}" y="476" text-anchor="middle" font-size="13" font-weight="700" fill="{THEMES["primary_dark"]}">共同点：都不靠"金手指/冲突/反转"</text>\n')
    parts.append(f'  <text x="{W/2}" y="496" text-anchor="middle" font-size="12" fill="{THEMES["text"]}">都靠"真实 + 安静 + 未完成"——这就是 new/9.md 所说的"未被制度承认的温暖"</text>\n')
    return "".join(parts) + svg_footer()


# ==================== 4. 情感账户模型 ====================
def make_emotion_account() -> str:
    """情感账户的运行规则。"""
    W, H = 880, 520
    parts = [svg_header(W, H)]
    # 标题
    parts.append(f'  <text x="{W/2}" y="40" text-anchor="middle" font-size="24" font-weight="700" fill="{THEMES["text"]}">情感账户：为什么"千篇一律的爽文"打动不了人</text>\n')
    parts.append(f'  <text x="{W/2}" y="62" text-anchor="middle" font-size="13" fill="{THEMES["neutral"]}">观众的"情感账户"被透支——这就是为什么 100 个"复仇"让观众对"复仇"脱敏</text>\n')
    # 左侧：信用账户
    parts.append(f'  <text x="220" y="120" text-anchor="middle" font-size="16" font-weight="700" fill="{THEMES["primary_dark"]}">观众的情感账户</text>\n')
    # 信用条
    bar_x, bar_y, bar_w, bar_h = 80, 150, 280, 60
    parts.append(f'  <rect x="{bar_x}" y="{bar_y}" width="{bar_w}" height="{bar_h}" rx="8" fill="white" stroke="{THEMES["neutral"]}" stroke-width="2"/>\n')
    # 5 个格子表示账户被透支
    seg_w = bar_w / 5
    segments = [
        ("复仇", "透支", THEMES["warning"]),
        ("金手指", "透支", THEMES["warning"]),
        ("霸总", "透支", THEMES["warning"]),
        ("逆袭", "透支", THEMES["warning"]),
        ("觉醒", "透支", THEMES["warning"]),
    ]
    for i, (label, state, color) in enumerate(segments):
        x = bar_x + i * seg_w + 4
        parts.append(f'  <rect x="{x}" y="{bar_y+4}" width="{seg_w-8}" height="{bar_h-8}" rx="4" fill="{color}" opacity="0.85"/>\n')
        parts.append(f'  <text x="{x+(seg_w-8)/2}" y="{bar_y+24}" text-anchor="middle" font-size="10" font-weight="700" fill="white">{label}</text>\n')
        parts.append(f'  <text x="{x+(seg_w-8)/2}" y="{bar_y+44}" text-anchor="middle" font-size="9" fill="white" opacity="0.95">{state}</text>\n')
    parts.append(f'  <text x="{bar_x+bar_w/2}" y="{bar_y+bar_h+24}" text-anchor="middle" font-size="11" font-style="italic" fill="{THEMES["neutral"]}">观众对所有类似原型脱敏——即使新作品做得很好，也很难被打动</text>\n')
    # 箭头
    parts.append(f'  <path d="M {bar_x+bar_w+30} {bar_y+bar_h/2} L {bar_x+bar_w+70} {bar_y+bar_h/2} M {bar_x+bar_w+60} {bar_y+bar_h/2-5} L {bar_x+bar_w+70} {bar_y+bar_h/2} L {bar_x+bar_w+60} {bar_y+bar_h/2+5}" stroke="{THEMES["primary_dark"]}" stroke-width="2" fill="none"/>\n')
    parts.append(f'  <text x="{bar_x+bar_w+50}" y="{bar_y+bar_h/2-12}" text-anchor="middle" font-size="10" font-weight="700" fill="{THEMES["primary_dark"]}">破产</text>\n')
    # 右侧：创作者的应对
    parts.append(f'  <text x="640" y="120" text-anchor="middle" font-size="16" font-weight="700" fill="{THEMES["primary_dark"]}">创作者的应对</text>\n')
    # 5 个应对策略
    responses = [
        ('拒绝"完美复仇"', "让复仇不成功", "或成功后空虚"),
        ('拒绝"无代价超能力"', "让超能力", "有真实的代价"),
        ('拒绝"完美霸总"', "让霸总有", "真实的弱点/创伤"),
        ('拒绝"完美逆袭"', "让逆袭有", "真实的失去/代价"),
        ('拒绝"完美觉醒"', "让觉醒伴随", "真实的关系重建"),
    ]
    resp_x, resp_y = 460, 145
    resp_w, resp_h = 380, 56
    resp_gap = 6
    for i, (title, line1, line2) in enumerate(responses):
        y = resp_y + i * (resp_h + resp_gap)
        parts.append(f'  <rect x="{resp_x}" y="{y}" width="{resp_w}" height="{resp_h}" rx="8" fill="white" opacity="0.85" stroke="{THEMES["primary"]}" stroke-width="1.5"/>\n')
        parts.append(f'  <text x="{resp_x+15}" y="{y+22}" font-size="13" font-weight="700" fill="{THEMES["primary_dark"]}">{title}</text>\n')
        parts.append(f'  <text x="{resp_x+15}" y="{y+42}" font-size="11" fill="{THEMES["text"]}">{line1}{line2}</text>\n')
    # 底部
    parts.append(f'  <rect x="60" y="450" width="{W-120}" height="50" rx="10" fill="white" opacity="0.7" stroke="{THEMES["primary"]}" stroke-width="2"/>\n')
    parts.append(f'  <text x="{W/2}" y="475" text-anchor="middle" font-size="13" font-weight="700" fill="{THEMES["primary_dark"]}">3 个规则：存款（真实细节） / 取款（套路化情感） / 破产（脱敏）</text>\n')
    parts.append(f'  <text x="{W/2}" y="492" text-anchor="middle" font-size="11" fill="{THEMES["text"]}">v1 的核心：不是"取代"被透支的原型——是"提供新选择"</text>\n')
    return "".join(parts) + svg_footer()


# ==================== 5. 4 类体裁差异化 ====================
def make_four_genres() -> str:
    """4 类体裁的差异化方法。"""
    W, H = 880, 540
    parts = [svg_header(W, H)]
    # 标题
    parts.append(f'  <text x="{W/2}" y="40" text-anchor="middle" font-size="24" font-weight="700" fill="{THEMES["text"]}">4 类体裁的差异化方法</text>\n')
    parts.append(f'  <text x="{W/2}" y="62" text-anchor="middle" font-size="13" fill="{THEMES["neutral"]}">四把尺子的"目标"不变——"应用方式"随体裁调整</text>\n')
    # 4 个体裁卡片
    grid_y = 100
    card_w = 200
    card_h = 360
    gap = 12
    total_w = 4 * card_w + 3 * gap
    start_x = (W - total_w) / 2
    genres = [
        ("短剧", "30秒-3分钟", "🎬", "把'瞬间'做到极致", ["一秒都不能浪费", "一句话都不能解释", "一个动作都必须精准", "结尾必须不收拢"], "url(#primary-gradient)"),
        ("小说", "短篇-长篇", "📖", "把'人'做到极致", ["人物的'内面'必须可见", "细节'非必要但精准'", "时间可以'非顺序'", "结尾可以是'无事件'的"], "url(#info-gradient)"),
        ("电影", "90-120分钟", "🎥", "把'结构'做到极致", ["结构是'骨架'不能省", "画面是'语言'", "声音是'第二画面'", "节奏是'灵魂'"], "url(#warning-gradient)"),
        ("戏剧", "现场", "🎭", "把'现场'做到极致", ["演员的身体是'第一语言'", "现场感是'不可替代'", "观众的'共处'是'作品的一部分'", "不可重来是'礼物'"], "url(#secondary-gradient)"),
    ]
    for i, (name, duration, icon, theme, points, color) in enumerate(genres):
        x = start_x + i * (card_w + gap)
        # 卡片
        parts.append(f'  <rect x="{x}" y="{grid_y}" width="{card_w}" height="{card_h}" rx="14" fill="{color}" opacity="0.95" filter="url(#soft-shadow)"/>\n')
        # 序号
        parts.append(f'  <circle cx="{x+22}" cy="{grid_y+22}" r="15" fill="white" opacity="0.95"/>\n')
        parts.append(f'  <text x="{x+22}" y="{grid_y+28}" text-anchor="middle" font-size="14" font-weight="700" fill="{THEMES["primary_dark"]}">{i+1}</text>\n')
        # 名称
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+58}" text-anchor="middle" font-size="18" font-weight="700" fill="white">{name}</text>\n')
        # 时长
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+78}" text-anchor="middle" font-size="11" fill="white" opacity="0.85">{duration}</text>\n')
        # 图标
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+125}" text-anchor="middle" font-size="42">{icon}</text>\n')
        # 主题
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+155}" text-anchor="middle" font-size="13" font-weight="700" fill="white" opacity="0.95">{theme}</text>\n')
        # 分隔
        parts.append(f'  <line x1="{x+20}" y1="{grid_y+175}" x2="{x+card_w-20}" y2="{grid_y+175}" stroke="white" stroke-width="1" opacity="0.4"/>\n')
        # 4 大铁律
        parts.append(f'  <text x="{x+card_w/2}" y="{grid_y+195}" text-anchor="middle" font-size="10" font-weight="700" fill="white" opacity="0.85">4 大铁律</text>\n')
        for j, p in enumerate(points):
            parts.append(f'  <text x="{x+15}" y="{grid_y+218+j*32}" font-size="10" fill="white">· {p}</text>\n')
    return "".join(parts) + svg_footer()


# ==================== 主流程 ====================
def main() -> None:
    """生成 5 张 SVG 插图。"""
    svgs = [
        ("four-rulers-art.svg", make_four_rulers_art),
        ("three-mechanisms.svg", make_three_mechanisms),
        ("five-characters.svg", make_five_characters),
        ("emotion-account.svg", make_emotion_account),
        ("four-genres.svg", make_four_genres),
    ]
    for name, maker in svgs:
        path = SVG_DIR / name
        path.write_text(maker(), encoding="utf-8")
        size = path.stat().st_size
        print(f"[OK] {name} ({size:,} 字节)")


if __name__ == "__main__":
    main()
