#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
How解构结果可视化脚本 V2

改进版：
- 使用标签页展示多个帖子
- 参考 visualize_inspiration_points.py 的帖子详情展示
- 分层可折叠的匹配结果
"""

import json
from pathlib import Path
from typing import Dict, List
import sys
import html as html_module

# 添加项目根目录到路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

from script.data_processing.path_config import PathConfig


# 注意：已改用基于相似度的显示方式，不再使用关系类型
# def get_relation_color(relation: str) -> str:
#     """根据关系类型返回对应的颜色"""
#     color_map = {
#         "same": "#10b981",           # 绿色 - 同义
#         "contains": "#3b82f6",       # 蓝色 - 包含
#         "contained_by": "#8b5cf6",   # 紫色 - 被包含
#         "coordinate": "#f59e0b",     # 橙色 - 同级
#         "overlap": "#ec4899",        # 粉色 - 部分重叠
#         "related": "#6366f1",        # 靛蓝 - 相关
#         "unrelated": "#9ca3af"       # 灰色 - 无关
#     }
#     return color_map.get(relation, "#9ca3af")
#
#
# def get_relation_label(relation: str) -> str:
#     """返回关系类型的中文标签"""
#     label_map = {
#         "same": "同义",
#         "contains": "包含",
#         "contained_by": "被包含",
#         "coordinate": "同级",
#         "overlap": "部分重叠",
#         "related": "相关",
#         "unrelated": "无关"
#     }
#     return label_map.get(relation, relation)


def generate_historical_post_card_html(post_detail: Dict, inspiration_point: Dict) -> str:
    """生成历史帖子的紧凑卡片HTML"""
    title = post_detail.get("title", "无标题")
    body_text = post_detail.get("body_text", "")
    images = post_detail.get("images", [])
    like_count = post_detail.get("like_count", 0)
    collect_count = post_detail.get("collect_count", 0)
    comment_count = post_detail.get("comment_count", 0)
    author = post_detail.get("channel_account_name", "")
    link = post_detail.get("link", "#")
    publish_time = post_detail.get("publish_time", "")

    # 获取灵感点信息
    point_name = inspiration_point.get("点的名称", "")
    point_desc = inspiration_point.get("点的描述", "")

    # 准备详情数据（用于模态框）
    import json
    post_detail_data = {
        "title": title,
        "body_text": body_text,
        "images": images,
        "like_count": like_count,
        "comment_count": comment_count,
        "collect_count": collect_count,
        "author": author,
        "publish_time": publish_time,
        "link": link
    }
    post_data_json = json.dumps(post_detail_data, ensure_ascii=False)
    post_data_json_escaped = html_module.escape(post_data_json)

    # 截取正文预览（前80个字符）
    body_preview = body_text[:80] + "..." if len(body_text) > 80 else body_text

    # 生成缩略图
    thumbnail_html = ""
    if images:
        thumbnail_html = f'<img src="{images[0]}" alt="Post thumbnail" class="historical-post-thumbnail" loading="lazy">'

    html = f'''
    <div class="historical-post-card" data-post-data='{post_data_json_escaped}' onclick="showPostDetail(this)">
        <div class="historical-post-image">
            {thumbnail_html}
            {f'<div class="post-card-image-count">{len(images)}</div>' if len(images) > 1 else ''}
        </div>
        <div class="historical-post-content">
            <div class="historical-post-title">{html_module.escape(title)}</div>
            <div class="historical-inspiration-info">
                <span class="inspiration-type-badge-small">灵感点</span>
                <span class="inspiration-name-small">{html_module.escape(point_name)}</span>
            </div>
            <div class="historical-inspiration-desc">{html_module.escape(point_desc[:100])}{"..." if len(point_desc) > 100 else ""}</div>
            <div class="historical-post-meta">
                <span class="historical-post-time">📅 {publish_time}</span>
            </div>
            <div class="historical-post-stats">
                <span>❤ {like_count}</span>
                <span>⭐ {collect_count}</span>
                <a href="{link}" target="_blank" class="view-link" onclick="event.stopPropagation()">查看原帖 →</a>
            </div>
        </div>
    </div>
    '''
    return html


def generate_post_detail_html(post_data: Dict, post_idx: int) -> str:
    """生成帖子详情HTML（紧凑的卡片样式，点击可展开）"""
    post_detail = post_data.get("帖子详情", {})

    title = post_detail.get("title", "无标题")
    body_text = post_detail.get("body_text", "")
    images = post_detail.get("images", [])
    like_count = post_detail.get("like_count", 0)
    comment_count = post_detail.get("comment_count", 0)
    collect_count = post_detail.get("collect_count", 0)
    author = post_detail.get("channel_account_name", "")
    publish_time = post_detail.get("publish_time", "")
    link = post_detail.get("link", "")
    post_id = post_data.get("帖子id", f"post-{post_idx}")

    # 准备详情数据（用于模态框）
    import json
    post_detail_data = {
        "title": title,
        "body_text": body_text,
        "images": images,
        "like_count": like_count,
        "comment_count": comment_count,
        "collect_count": collect_count,
        "author": author,
        "publish_time": publish_time,
        "link": link
    }
    post_data_json = json.dumps(post_detail_data, ensure_ascii=False)
    post_data_json_escaped = html_module.escape(post_data_json)

    # 生成缩略图HTML
    thumbnail_html = ""
    if images and len(images) > 0:
        # 使用第一张图片作为缩略图，添加懒加载
        thumbnail_html = f'<img src="{images[0]}" class="post-card-thumbnail" alt="缩略图" loading="lazy">'
    else:
        thumbnail_html = '<div class="post-card-thumbnail-placeholder">📄</div>'

    # 截断正文用于预览
    body_preview = body_text[:80] + "..." if len(body_text) > 80 else body_text

    html = f'''
    <div class="post-card-compact" data-post-data='{post_data_json_escaped}' onclick="showPostDetail(this)">
        <div class="post-card-image">
            {thumbnail_html}
            {f'<div class="post-card-image-count">📷 {len(images)}</div>' if len(images) > 1 else ''}
        </div>
        <div class="post-card-content">
            <div class="post-card-title">{html_module.escape(title)}</div>
            <div class="post-card-preview">{html_module.escape(body_preview) if body_preview else "暂无正文"}</div>
            <div class="post-card-meta">
                <span class="post-card-author">👤 {html_module.escape(author)}</span>
                <span class="post-card-time">📅 {publish_time}</span>
            </div>
            <div class="post-card-stats">
                <span>👍 {like_count}</span>
                <span>💬 {comment_count if comment_count else 0}</span>
                <span>⭐ {collect_count if collect_count else 0}</span>
            </div>
        </div>
    </div>
    '''
    return html


def generate_inspiration_detail_html(inspiration_point: Dict, feature_status_map: Dict[str, str] = None, point_type: str = "灵感点") -> str:
    """生成点详情HTML

    Args:
        inspiration_point: 点数据
        feature_status_map: 特征名称到状态的映射 {特征名称: "相同"|"相似"|"无关"}
        point_type: 点类型（灵感点/关键点/目的点）
    """
    name = inspiration_point.get("名称", "")
    desc = inspiration_point.get("描述", "")
    features = inspiration_point.get("特征列表", [])

    if feature_status_map is None:
        feature_status_map = {}

    # 计算该灵感点的整体结论
    feature_statuses = []
    features_html_list = []
    for f in features:
        feature_name = f if isinstance(f, str) else f.get("特征名称", "")
        weight = f.get("权重", 1.0) if isinstance(f, dict) else 1.0

        # 获取该特征的状态
        status = feature_status_map.get(feature_name, "无关")
        feature_statuses.append(status)

        if status == "相同":
            status_class = "feature-same"
            status_label = "相同"
        elif status == "相似":
            status_class = "feature-similar"
            status_label = "相似"
        else:
            status_class = "feature-unrelated"
            status_label = "无关"

        features_html_list.append(
            f'<span class="feature-tag {status_class}">'
            f'<span class="feature-status-label">{status_label}</span> '
            f'{html_module.escape(feature_name)} '
            f'<span class="feature-weight">({weight})</span>'
            f'</span>'
        )

    features_html = "".join(features_html_list)

    # 计算灵感点结论
    has_same = "相同" in feature_statuses
    has_similar = "相似" in feature_statuses
    has_unrelated = "无关" in feature_statuses

    if not has_unrelated:
        # 没有无关的 -> 找到
        insp_conclusion = "找到"
        insp_conclusion_class = "insp-conclusion-found"
    elif has_same or has_similar:
        # 有相同或相似，但也有无关 -> 部分找到
        insp_conclusion = "部分找到"
        insp_conclusion_class = "insp-conclusion-partial"
    else:
        # 都是无关 -> 都找不到
        insp_conclusion = "都找不到"
        insp_conclusion_class = "insp-conclusion-not-found"

    # 根据点类型设置图标
    point_icons = {
        "灵感点": "💡",
        "关键点": "🔑",
        "目的点": "🎯"
    }
    point_icon = point_icons.get(point_type, "💡")

    html = f'''
    <div class="inspiration-detail-card">
        <div class="inspiration-header">
            <span class="inspiration-type-badge">{point_icon} {point_type}</span>
            <h3 class="inspiration-name">{html_module.escape(name)}</h3>
            <span class="inspiration-conclusion {insp_conclusion_class}">{insp_conclusion}</span>
        </div>
        <div class="inspiration-description">
            <div class="desc-label">描述:</div>
            <div class="desc-text">{html_module.escape(desc)}</div>
        </div>
        <div class="inspiration-features">
            <div class="features-label">特征列表:</div>
            <div class="features-tags">{features_html}</div>
        </div>
    </div>
    '''
    return html


def load_feature_category_mapping(config: PathConfig) -> Dict:
    """加载特征名称到分类的映射"""
    mapping_file = config.feature_category_mapping_file

    try:
        with open(mapping_file, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception as e:
        print(f"警告: 无法加载特征分类映射文件: {e}")
        return {}


def load_feature_source_mapping(config: PathConfig) -> Dict:
    """加载特征名称到帖子来源的映射"""
    mapping_file = config.feature_source_mapping_file

    try:
        with open(mapping_file, "r", encoding="utf-8") as f:
            data = json.load(f)
            # 转换为便于查询的格式: {特征名称: [来源列表]}
            result = {}
            for feature_type in ["灵感点", "关键点", "目的点"]:
                if feature_type in data:
                    for item in data[feature_type]:
                        feature_name = item.get("特征名称")
                        if feature_name:
                            result[feature_name] = item.get("特征来源", [])
            return result
    except Exception as e:
        print(f"警告: 无法加载特征来源映射文件: {e}")
        return {}


def generate_single_match_html(match: Dict, match_idx: int, post_idx: int, insp_idx: int, feature_idx: int, category_mapping: Dict = None, source_mapping: Dict = None, current_point_type: str = "灵感点") -> str:
    """生成单个匹配项的HTML

    Args:
        match: 单个匹配数据
        match_idx: 匹配项索引
        post_idx: 帖子索引
        insp_idx: 灵感点索引
        feature_idx: 特征索引
        category_mapping: 特征分类映射
        source_mapping: 特征来源映射
        current_point_type: 当前点的类型（灵感点/关键点/目的点）
    """
    persona_name = match.get("人设特征名称", "")
    feature_type = match.get("特征类型", "")
    feature_categories = match.get("特征分类", [])
    persona_level = match.get("人设特征层级", "")
    match_result = match.get("匹配结果", {})
    similarity = match_result.get("相似度", 0.0)
    explanation = match_result.get("说明", "")

    # 根据相似度确定颜色和标签
    if similarity >= 0.9:
        color = "#10b981"  # 绿色 - 相同
        label = "相同"
    elif similarity >= 0.8:
        color = "#f59e0b"  # 橙色 - 相似
        label = "相似"
    else:
        color = "#9ca3af"  # 灰色 - 无关
        label = "无关"

    match_id = f"post-{post_idx}-insp-{insp_idx}-feat-{feature_idx}-match-{match_idx}"

    # 判断是否同层级匹配
    is_same_level = (persona_level == current_point_type)
    same_level_class = "match-same-level" if is_same_level else ""

    # 生成合并的层级-类型标签
    combined_badge_html = ""
    if persona_level and feature_type:
        combined_text = f"{persona_level}-{feature_type}"
        # 同层级用特殊样式
        if is_same_level:
            combined_badge_html = f'<span class="feature-combined-badge combined-badge-same">[{html_module.escape(combined_text)}]</span>'
        else:
            combined_badge_html = f'<span class="feature-combined-badge">[{html_module.escape(combined_text)}]</span>'

    categories_badge_html = ""
    if feature_categories:
        categories_text = " / ".join(feature_categories)
        categories_badge_html = f'<span class="feature-category-badge">{html_module.escape(categories_text)}</span>'

    # 获取该人设特征的分类信息
    categories_html = ""
    if category_mapping and persona_name:
        found_categories = None
        # 依次在灵感点、关键点、目的点中查找
        for persona_type in ["灵感点", "关键点", "目的点"]:
            if persona_type in category_mapping:
                type_mapping = category_mapping[persona_type]
                if persona_name in type_mapping:
                    found_categories = type_mapping[persona_name].get("所属分类", [])
                    break

        if found_categories:
            # 简洁样式：[大类/中类/小类]
            categories_reversed = list(reversed(found_categories))
            categories_text = "/".join(categories_reversed)
            categories_html = f'<span class="category-simple">[{html_module.escape(categories_text)}]</span>'

    # 获取该人设特征的历史帖子来源
    historical_posts_html = ""
    if source_mapping and persona_name and persona_name in source_mapping:
        source_list = source_mapping[persona_name]
        if source_list:
            historical_cards = []
            for source_item in source_list:
                post_detail = source_item.get("帖子详情", {})
                if post_detail:
                    card_html = generate_historical_post_card_html(post_detail, source_item)
                    historical_cards.append(card_html)

            if historical_cards:
                historical_posts_html = f'''
                <div class="historical-posts-section">
                    <h4 class="historical-posts-title">历史帖子来源</h4>
                    <div class="historical-posts-grid">
                        {"".join(historical_cards)}
                    </div>
                </div>
                '''

    # 生成历史帖子HTML
    historical_posts_html = ""
    if source_mapping and persona_name and persona_name in source_mapping:
        source_list = source_mapping[persona_name]
        if source_list:
            for source_item in source_list[:5]:  # 最多5个
                post_detail = source_item.get("帖子详情", {})
                if post_detail:
                    card_html = generate_historical_post_card_html(post_detail, source_item)
                    historical_posts_html += card_html

    # 将数据编码到data属性中
    import html as html_encode
    data_explanation = html_encode.escape(explanation)
    data_historical = html_encode.escape(historical_posts_html)

    # 生成紧凑的匹配项HTML（可点击，弹出模态框）
    html = f'''
    <div class="match-item-compact {same_level_class}"
         data-persona-name="{html_module.escape(persona_name)}"
         data-feature-type="{html_module.escape(feature_type)}"
         data-persona-level="{html_module.escape(persona_level)}"
         data-similarity="{similarity}"
         data-label="{label}"
         data-explanation="{data_explanation}"
         data-historical-posts="{data_historical}"
         onclick="showMatchDetail(this)">
        {combined_badge_html}
        <span class="persona-name">{html_module.escape(persona_name)}</span>
        <span class="score-badge">相似度: {similarity:.2f}</span>
        <span class="relation-badge" style="background: {color};">{label}</span>
    </div>
    '''
    return html


def generate_match_results_html(how_steps: List[Dict], feature_idx: int, insp_idx: int, post_idx: int, category_mapping: Dict = None, source_mapping: Dict = None, current_point_type: str = "灵感点", feature_number: int = 1) -> str:
    """生成可折叠的匹配结果HTML

    Args:
        how_steps: how步骤列表
        feature_idx: 特征索引
        insp_idx: 灵感点索引
        post_idx: 帖子索引
        category_mapping: 特征分类映射
        source_mapping: 特征来源映射
        current_point_type: 当前点的类型（灵感点/关键点/目的点）
        feature_number: 特征序号（从1开始）
    """
    if not how_steps or len(how_steps) == 0:
        return ""

    step = how_steps[0]
    features = step.get("特征列表", [])

    if feature_idx >= len(features):
        return ""

    feature_data = features[feature_idx]
    feature_name = feature_data.get("特征名称", "")
    feature_weight = feature_data.get("权重", 1.0)
    match_results = feature_data.get("匹配结果", [])

    if category_mapping is None:
        category_mapping = {}

    # 按相似度排序
    sorted_matches = sorted(match_results, key=lambda x: x.get("匹配结果", {}).get("相似度", 0), reverse=True)

    # 找出最高相似度，确定状态
    max_similarity = 0.0
    if match_results:
        max_similarity = max(match.get("匹配结果", {}).get("相似度", 0) for match in match_results)

    # 根据最高相似度确定状态
    if max_similarity >= 0.9:
        status = "相同"
        status_class = "status-same"
    elif max_similarity >= 0.8:
        status = "相似"
        status_class = "status-similar"
    else:
        status = "无关"
        status_class = "status-unrelated"

    found_status_html = f'<span class="feature-match-status {status_class}">{status}</span>'

    # 统计相似度分布
    similarity_ranges = {
        "相同 (≥0.9)": 0,
        "相似 (0.8-0.9)": 0,
        "无关 (<0.8)": 0
    }
    for match in match_results:
        similarity = match.get("匹配结果", {}).get("相似度", 0)
        if similarity >= 0.9:
            similarity_ranges["相同 (≥0.9)"] += 1
        elif similarity >= 0.8:
            similarity_ranges["相似 (0.8-0.9)"] += 1
        else:
            similarity_ranges["无关 (<0.8)"] += 1

    # 生成统计信息
    stats_items = []
    range_colors = {
        "相同 (≥0.9)": "#10b981",
        "相似 (0.8-0.9)": "#f59e0b",
        "无关 (<0.8)": "#9ca3af"
    }
    for range_name, count in similarity_ranges.items():
        if count > 0:
            color = range_colors[range_name]
            stats_items.append(f'<span class="stat-badge" style="background: {color};">{range_name}: {count}</span>')
    stats_html = "".join(stats_items)

    # 按人设特征层级分组匹配项
    level_groups = {
        "灵感点": {"标签": [], "分类": []},
        "关键点": {"标签": [], "分类": []},
        "目的点": {"标签": [], "分类": []}
    }

    for i, match in enumerate(sorted_matches):
        persona_level = match.get("人设特征层级", "")
        feature_type = match.get("特征类型", "")

        if persona_level in level_groups and feature_type in ["标签", "分类"]:
            level_groups[persona_level][feature_type].append((i, match))

    # 生成分组的匹配项HTML
    matches_html = ""

    # 按层级顺序显示：灵感点 -> 关键点 -> 目的点
    level_index = 1
    for level_name in ["灵感点", "关键点", "目的点"]:
        level_data = level_groups[level_name]
        total_count = len(level_data["标签"]) + len(level_data["分类"])

        if total_count == 0:
            continue

        # 生成该层级的折叠区域
        level_section_id = f"post-{post_idx}-{current_point_type}-{insp_idx}-feat-{feature_idx}-level-{level_name}"

        # 找出该层级的最高分匹配
        all_level_matches = level_data["标签"] + level_data["分类"]
        top_match = None
        max_similarity = 0
        for _, match in all_level_matches:
            similarity = match.get("匹配结果", {}).get("相似度", 0)
            if similarity > max_similarity:
                max_similarity = similarity
                top_match = match

        # 生成最高分特征信息
        top_match_html = ""
        if top_match:
            top_persona_name = top_match.get("人设特征名称", "")
            top_feature_type = top_match.get("特征类型", "")
            if max_similarity >= 0.9:
                similarity_label = "相同"
                similarity_color = "#10b981"
            elif max_similarity >= 0.8:
                similarity_label = "相似"
                similarity_color = "#f59e0b"
            else:
                similarity_label = "无关"
                similarity_color = "#9ca3af"

            top_match_html = f'''
            <div class="level-top-match">
                <span class="top-match-label">最高:</span>
                <span class="top-match-type">[{html_module.escape(top_feature_type)}]</span>
                <span class="top-match-name">{html_module.escape(top_persona_name)}</span>
                <span class="top-match-score" style="background: {similarity_color}; color: white;">{max_similarity:.2f} {similarity_label}</span>
            </div>
            '''

        # 计算该层级的相似度分布
        level_stats = {"相同": 0, "相似": 0, "无关": 0}
        for _, match in all_level_matches:
            similarity = match.get("匹配结果", {}).get("相似度", 0)
            if similarity >= 0.9:
                level_stats["相同"] += 1
            elif similarity >= 0.8:
                level_stats["相似"] += 1
            else:
                level_stats["无关"] += 1

        # 生成统计标签
        level_stats_html = ""
        if level_stats["相同"] > 0:
            level_stats_html += f'<span class="stat-badge" style="background: #10b981;">相同: {level_stats["相同"]}</span>'
        if level_stats["相似"] > 0:
            level_stats_html += f'<span class="stat-badge" style="background: #f59e0b;">相似: {level_stats["相似"]}</span>'
        if level_stats["无关"] > 0:
            level_stats_html += f'<span class="stat-badge" style="background: #9ca3af;">无关: {level_stats["无关"]}</span>'

        matches_html += f'''
        <div class="level-group-section">
            <div class="level-group-header" onclick="toggleMatchGroup(event, '{level_section_id}')">
                <div class="level-header-left">
                    <span class="expand-icon" id="{level_section_id}-icon">▶</span>
                    <h4 class="level-group-title">{feature_number}.{level_index} 匹配人设{level_name} ({total_count})</h4>
                    <div class="level-stats">{level_stats_html}</div>
                </div>
                {top_match_html}
            </div>
            <div class="level-group-content" id="{level_section_id}-content" style="display: none;">
        '''

        # 该层级下的标签分组
        subgroup_index = 1
        if level_data["标签"]:
            group_id = f"post-{post_idx}-{current_point_type}-{insp_idx}-feat-{feature_idx}-level-{level_name}-label"
            group_matches_html = ""

            # 找出标签中的最高分
            tag_top_match = None
            tag_max_similarity = 0
            for i, match in level_data["标签"]:
                similarity = match.get("匹配结果", {}).get("相似度", 0)
                if similarity > tag_max_similarity:
                    tag_max_similarity = similarity
                    tag_top_match = match

                match_html = generate_single_match_html(
                    match, i, post_idx, insp_idx, feature_idx,
                    category_mapping, source_mapping, current_point_type
                )
                group_matches_html += match_html

            # 生成标签最高分信息
            tag_top_html = ""
            if tag_top_match:
                tag_persona_name = tag_top_match.get("人设特征名称", "")
                tag_persona_level = tag_top_match.get("人设特征层级", "")
                tag_feature_type = tag_top_match.get("特征类型", "")
                if tag_max_similarity >= 0.9:
                    tag_color = "#10b981"
                    tag_label = "相同"
                elif tag_max_similarity >= 0.8:
                    tag_color = "#f59e0b"
                    tag_label = "相似"
                else:
                    tag_color = "#9ca3af"
                    tag_label = "无关"

                # 生成层级-类型标签
                tag_combined = f"[{tag_persona_level}-{tag_feature_type}]" if tag_persona_level and tag_feature_type else ""

                tag_top_html = f'''
                <div class="subgroup-top-match">
                    <span class="subgroup-top-label">最高:</span>
                    <span class="subgroup-top-combined">{tag_combined}</span>
                    <span class="subgroup-top-name">{html_module.escape(tag_persona_name)}</span>
                    <span class="subgroup-top-score" style="background: {tag_color}; color: white;">{tag_max_similarity:.2f} {tag_label}</span>
                </div>
                '''

            matches_html += f'''
            <div class="match-subgroup-section">
                <div class="match-subgroup-header" onclick="toggleMatchGroup(event, '{group_id}')">
                    <div class="subgroup-header-left">
                        <span class="expand-icon" id="{group_id}-icon">▼</span>
                        <h5 class="match-subgroup-title">{feature_number}.{level_index}.{subgroup_index} 标签 ({len(level_data["标签"])})</h5>
                    </div>
                    {tag_top_html}
                </div>
                <div class="match-subgroup-content" id="{group_id}-content">
                    {group_matches_html}
                </div>
            </div>
            '''
            subgroup_index += 1

        # 该层级下的分类分组
        if level_data["分类"]:
            group_id = f"post-{post_idx}-{current_point_type}-{insp_idx}-feat-{feature_idx}-level-{level_name}-category"
            group_matches_html = ""

            # 找出分类中的最高分
            cat_top_match = None
            cat_max_similarity = 0
            for i, match in level_data["分类"]:
                similarity = match.get("匹配结果", {}).get("相似度", 0)
                if similarity > cat_max_similarity:
                    cat_max_similarity = similarity
                    cat_top_match = match

                match_html = generate_single_match_html(
                    match, i, post_idx, insp_idx, feature_idx,
                    category_mapping, source_mapping, current_point_type
                )
                group_matches_html += match_html

            # 生成分类最高分信息
            cat_top_html = ""
            if cat_top_match:
                cat_persona_name = cat_top_match.get("人设特征名称", "")
                cat_persona_level = cat_top_match.get("人设特征层级", "")
                cat_feature_type = cat_top_match.get("特征类型", "")
                if cat_max_similarity >= 0.9:
                    cat_color = "#10b981"
                    cat_label = "相同"
                elif cat_max_similarity >= 0.8:
                    cat_color = "#f59e0b"
                    cat_label = "相似"
                else:
                    cat_color = "#9ca3af"
                    cat_label = "无关"

                # 生成层级-类型标签
                cat_combined = f"[{cat_persona_level}-{cat_feature_type}]" if cat_persona_level and cat_feature_type else ""

                cat_top_html = f'''
                <div class="subgroup-top-match">
                    <span class="subgroup-top-label">最高:</span>
                    <span class="subgroup-top-combined">{cat_combined}</span>
                    <span class="subgroup-top-name">{html_module.escape(cat_persona_name)}</span>
                    <span class="subgroup-top-score" style="background: {cat_color}; color: white;">{cat_max_similarity:.2f} {cat_label}</span>
                </div>
                '''

            matches_html += f'''
            <div class="match-subgroup-section">
                <div class="match-subgroup-header" onclick="toggleMatchGroup(event, '{group_id}')">
                    <div class="subgroup-header-left">
                        <span class="expand-icon" id="{group_id}-icon">▼</span>
                        <h5 class="match-subgroup-title">{feature_number}.{level_index}.{subgroup_index} 分类 ({len(level_data["分类"])})</h5>
                    </div>
                    {cat_top_html}
                </div>
                <div class="match-subgroup-content" id="{group_id}-content">
                    {group_matches_html}
                </div>
            </div>
            '''
            subgroup_index += 1

        matches_html += '''
            </div>
        </div>
        '''

        level_index += 1

    section_id = f"post-{post_idx}-insp-{insp_idx}-feat-{feature_idx}-section"

    # 找出所有匹配中的最高分
    overall_top_match = None
    overall_max_similarity = 0
    for match in match_results:
        similarity = match.get("匹配结果", {}).get("相似度", 0)
        if similarity > overall_max_similarity:
            overall_max_similarity = similarity
            overall_top_match = match

    # 生成最高分信息
    overall_top_html = ""
    if overall_top_match:
        top_persona_name = overall_top_match.get("人设特征名称", "")
        top_feature_type = overall_top_match.get("特征类型", "")
        top_persona_level = overall_top_match.get("人设特征层级", "")
        if overall_max_similarity >= 0.9:
            top_color = "#10b981"
            top_label = "相同"
        elif overall_max_similarity >= 0.8:
            top_color = "#f59e0b"
            top_label = "相似"
        else:
            top_color = "#9ca3af"
            top_label = "无关"

        overall_top_html = f'''
        <div class="overall-top-match">
            <span class="overall-top-label">最高:</span>
            <span class="overall-top-combined">[{html_module.escape(top_persona_level)}-{html_module.escape(top_feature_type)}]</span>
            <span class="overall-top-name">{html_module.escape(top_persona_name)}</span>
            <span class="overall-top-score" style="background: {top_color}; color: white;">{overall_max_similarity:.2f} {top_label}</span>
        </div>
        '''

    html = f'''
    <div class="match-results-section">
        <div class="match-section-header collapsible-header" onclick="toggleFeatureSection(event, '{section_id}')">
            <div class="header-left">
                <span class="expand-icon" id="{section_id}-icon">▼</span>
                <h4>{feature_number}. 匹配结果: {html_module.escape(feature_name)} <span class="feature-weight-display">(权重: {feature_weight})</span></h4>
                {found_status_html}
            </div>
            <div class="match-stats">{stats_html}</div>
            {overall_top_html}
        </div>
        <div class="matches-list" id="{section_id}-content">
            {matches_html}
        </div>
    </div>
    '''
    return html


def generate_toc_html(post_data: Dict, post_idx: int, feature_status_map: Dict[str, str] = None, overall_conclusion: str = "") -> str:
    """生成目录导航HTML

    Args:
        post_data: 帖子数据
        post_idx: 帖子索引
        feature_status_map: 特征名称到状态的映射 {特征名称: "相同"|"相似"|"无关"}
        overall_conclusion: 整体结论
    """
    how_result = post_data.get("how解构结果", {})

    if feature_status_map is None:
        feature_status_map = {}

    toc_items = []

    # 帖子详情
    toc_items.append(f'<div class="toc-item toc-level-1" onclick="scrollToSection(\'post-{post_idx}-detail\')"><span class="toc-badge toc-badge-post">帖子详情</span> 帖子信息</div>')

    # 处理不同类型的点
    point_types = [
        ("灵感点列表", "灵感点", "toc-badge-inspiration", "💡"),
        ("目的点列表", "目的点", "toc-badge-purpose", "🎯"),
        ("关键点列表", "关键点", "toc-badge-key", "🔑")
    ]

    for list_key, point_name, badge_class, icon in point_types:
        point_list = how_result.get(list_key, [])

        if not point_list:
            continue

        # 点类型分组标题
        toc_items.append(f'<div class="toc-item toc-level-1 toc-group-header"><span class="toc-badge {badge_class}">{icon} {point_name}</span></div>')

        for point_idx, point in enumerate(point_list):
            name = point.get("名称", f"{point_name} {point_idx + 1}")
            name_short = name[:18] + "..." if len(name) > 18 else name

            # 计算该点的整体状态
            how_steps = point.get("how步骤列表", [])
            point_status = "无关"
            has_same = False
            has_similar = False

            if how_steps:
                features = how_steps[0].get("特征列表", [])
                for feature_data in features:
                    feature_name = feature_data.get("特征名称", "")
                    status = feature_status_map.get(feature_name, "无关")
                    if status == "相同":
                        has_same = True
                        break
                    elif status == "相似":
                        has_similar = True

                if has_same:
                    point_status = "找到"
                    point_status_class = "toc-point-found"
                elif has_similar:
                    point_status = "部分找到"
                    point_status_class = "toc-point-partial"
                else:
                    point_status = "都找不到"
                    point_status_class = "toc-point-notfound"
            else:
                point_status_class = "toc-point-notfound"

            toc_items.append(f'<div class="toc-item toc-level-2 {point_status_class}" onclick="scrollToSection(\'post-{post_idx}-point-{list_key}-{point_idx}\')"><span class="toc-badge {badge_class}">{point_name}</span> {html_module.escape(name_short)} <span class="toc-point-status">[{point_status}]</span></div>')

            # 特征列表
            if how_steps:
                features = how_steps[0].get("特征列表", [])
                for feat_idx, feature_data in enumerate(features):
                    feature_name = feature_data.get("特征名称", f"特征 {feat_idx + 1}")

                    # 获取状态
                    status = feature_status_map.get(feature_name, "无关")
                    if status == "相同":
                        status_class = "toc-feature-same"
                        status_label = "相同"
                    elif status == "相似":
                        status_class = "toc-feature-similar"
                        status_label = "相似"
                    else:
                        status_class = "toc-feature-unrelated"
                        status_label = "无关"

                    toc_items.append(f'<div class="toc-item toc-level-3 {status_class}" onclick="scrollToSection(\'post-{post_idx}-feat-{point_idx}-{feat_idx}\')"><span class="toc-badge toc-badge-feature">特征</span> {html_module.escape(feature_name)} <span class="toc-feature-status">[{status_label}]</span></div>')

    # 整体结论HTML
    conclusion_html = ""
    if overall_conclusion:
        if overall_conclusion == "找到":
            conclusion_class = "conclusion-found"
            conclusion_icon = "✓"
        elif overall_conclusion == "部分找到":
            conclusion_class = "conclusion-partial"
            conclusion_icon = "~"
        else:  # 都找不到
            conclusion_class = "conclusion-not-found"
            conclusion_icon = "✗"

        conclusion_html = f'''
        <div class="toc-conclusion {conclusion_class}">
            <span class="conclusion-icon">{conclusion_icon}</span>
            <span class="conclusion-text">{overall_conclusion}</span>
        </div>
        '''

    return f'''
    <div class="toc-container">
        <div class="toc-header">目录导航</div>
        {conclusion_html}
        <div class="toc-content">
            {"".join(toc_items)}
        </div>
    </div>
    '''


def generate_post_content_html(post_data: Dict, post_idx: int, category_mapping: Dict = None, source_mapping: Dict = None) -> str:
    """生成单个帖子的完整内容HTML"""
    # 2. 灵感点详情和匹配结果
    how_result = post_data.get("how解构结果", {})
    inspiration_list = how_result.get("灵感点列表", [])

    # 先计算所有特征的状态（基于最高相似度）
    feature_status_map = {}  # {特征名称: "相同"|"相似"|"无关"}
    for inspiration_point in inspiration_list:
        how_steps = inspiration_point.get("how步骤列表", [])
        if how_steps:
            features = how_steps[0].get("特征列表", [])
            for feature_data in features:
                feature_name = feature_data.get("特征名称", "")
                match_results = feature_data.get("匹配结果", [])

                # 找出最高相似度
                max_similarity = 0.0
                if match_results:
                    max_similarity = max(match.get("匹配结果", {}).get("相似度", 0) for match in match_results)

                # 根据最高相似度确定状态
                if max_similarity >= 0.9:
                    feature_status_map[feature_name] = "相同"
                elif max_similarity >= 0.8:
                    feature_status_map[feature_name] = "相似"
                else:
                    feature_status_map[feature_name] = "无关"

    # 1. 帖子详情
    post_detail_html = generate_post_detail_html(post_data, post_idx)

    # 生成所有灵感点的详情HTML（传入状态映射）
    inspirations_detail_html = ""
    for insp_idx, inspiration_point in enumerate(inspiration_list):
        inspiration_detail = generate_inspiration_detail_html(inspiration_point, feature_status_map)
        inspirations_detail_html += f'''
        <div id="post-{post_idx}-insp-{insp_idx}" class="inspiration-detail-item content-section">
            {inspiration_detail}
        </div>
        '''

    # 生成所有匹配结果HTML，按照how步骤分组
    all_matches_html = ""
    for insp_idx, inspiration_point in enumerate(inspiration_list):
        inspiration_name = inspiration_point.get("名称", f"灵感点 {insp_idx + 1}")
        how_steps = inspiration_point.get("how步骤列表", [])

        if how_steps:
            # 为每个灵感点创建一个区域
            for step_idx, step in enumerate(how_steps):
                step_name = step.get("步骤名称", f"步骤 {step_idx + 1}")
                features = step.get("特征列表", [])

                # 生成该步骤下所有特征的匹配结果
                features_html = ""
                for feat_idx, feature_data in enumerate(features):
                    match_html = generate_match_results_html([step], feat_idx, insp_idx, post_idx, category_mapping, source_mapping, "灵感点", feat_idx + 1)
                    features_html += f'<div id="post-{post_idx}-feat-{insp_idx}-{feat_idx}" class="feature-match-wrapper">{match_html}</div>'

                # 生成步骤区域（可折叠）
                step_section_id = f"post-{post_idx}-step-{insp_idx}-{step_idx}"
                all_matches_html += f'''
                <div class="step-section">
                    <div class="step-header collapsible-header" onclick="toggleStepSection('{step_section_id}')">
                        <div class="header-left">
                            <span class="expand-icon" id="{step_section_id}-icon">▼</span>
                            <h3 class="step-name">{html_module.escape(step_name)}</h3>
                        </div>
                        <span class="step-inspiration-name">来自: {html_module.escape(inspiration_name)}</span>
                    </div>
                    <div class="step-features-list" id="{step_section_id}-content">
                        {features_html}
                    </div>
                </div>
                '''

    html = f'''
    <div class="post-content-wrapper">
        <!-- 第一个框：左右分栏（帖子详情 + 灵感点详情） -->
        <div class="top-section-box">
            <div class="two-column-layout">
                <div class="left-column">
                    <div id="post-{post_idx}-detail" class="post-detail-wrapper">
                        {post_detail_html}
                    </div>
                </div>
                <div class="right-column">
                    <div class="inspirations-detail-wrapper">
                        {inspirations_detail_html}
                    </div>
                </div>
            </div>
        </div>

        <!-- 下面：所有匹配结果 -->
        <div class="matches-section">
            {all_matches_html}
        </div>
    </div>
    '''
    return html


def generate_combined_html(posts_data: List[Dict], category_mapping: Dict = None, source_mapping: Dict = None) -> str:
    """生成包含所有帖子的单一HTML（左边目录，右边内容）"""

    # 生成统一的目录（包含所有帖子）
    all_toc_items = []

    for post_idx, post in enumerate(posts_data):
        post_detail = post.get("帖子详情", {})
        title = post_detail.get("title", "无标题")
        post_id = post_detail.get("post_id", f"post_{post_idx}")

        # 帖子标题作为一级目录（可折叠）
        all_toc_items.append(f'''
        <div class="toc-item toc-level-0 toc-post-header collapsed" data-post-id="{post_idx}" onclick="toggleTocPost(event, {post_idx})">
            <span class="toc-expand-icon">▼</span>
            <div class="toc-item-content">
                <span class="toc-badge toc-badge-post">📄 帖子</span> {html_module.escape(title[:30])}...
            </div>
        </div>
        <div class="toc-children hidden" id="toc-post-{post_idx}-children">
        ''')

        # 获取特征状态映射
        feature_status_map = {}
        how_result = post.get("how解构结果", {})

        # 先收集所有特征状态
        for point_list_key in ["灵感点列表", "目的点列表", "关键点列表"]:
            point_list = how_result.get(point_list_key, [])
            for point in point_list:
                how_steps = point.get("how步骤列表", [])
                if how_steps:
                    features = how_steps[0].get("特征列表", [])
                    for feature_data in features:
                        feature_name = feature_data.get("特征名称", "")
                        match_results = feature_data.get("匹配结果", [])
                        max_similarity = 0.0
                        if match_results:
                            max_similarity = max(match.get("匹配结果", {}).get("相似度", 0) for match in match_results)
                        if max_similarity >= 0.9:
                            feature_status_map[feature_name] = "相同"
                        elif max_similarity >= 0.8:
                            feature_status_map[feature_name] = "相似"
                        else:
                            feature_status_map[feature_name] = "无关"

        # 生成点类型目录
        point_types = [
            ("灵感点列表", "灵感点", "toc-badge-inspiration", "💡"),
            ("目的点列表", "目的点", "toc-badge-purpose", "🎯"),
            ("关键点列表", "关键点", "toc-badge-key", "🔑")
        ]

        for list_key, point_name, badge_class, icon in point_types:
            point_list = how_result.get(list_key, [])
            if not point_list:
                continue

            # 点类型分组标题（可折叠），去掉"列表"两字
            group_id = f"post-{post_idx}-{list_key}"
            all_toc_items.append(f'''
            <div class="toc-item toc-level-1 toc-group-header collapsed" onclick="toggleTocGroup(event, '{group_id}')">
                <span class="toc-expand-icon">▼</span>
                <div class="toc-item-content">
                    {icon} {point_name}
                </div>
            </div>
            <div class="toc-children hidden" id="toc-{group_id}-children">
            ''')

            for point_idx, point in enumerate(point_list):
                name = point.get("名称", f"{point_name} {point_idx + 1}")
                name_short = name[:18] + "..." if len(name) > 18 else name

                # 计算该点的状态
                how_steps = point.get("how步骤列表", [])
                point_status = "无关"
                has_same = False
                has_similar = False

                if how_steps:
                    features = how_steps[0].get("特征列表", [])
                    has_unrelated = False
                    for feature_data in features:
                        feature_name = feature_data.get("特征名称", "")
                        status = feature_status_map.get(feature_name, "无关")
                        if status == "相同":
                            has_same = True
                        elif status == "相似":
                            has_similar = True
                        elif status == "无关":
                            has_unrelated = True

                    # 统一使用与详情页相同的逻辑
                    if not has_unrelated:
                        # 没有无关的 -> 找到
                        point_status = "找到"
                        point_status_class = "toc-point-found"
                    elif has_same or has_similar:
                        # 有相同或相似，但也有无关 -> 部分找到
                        point_status = "部分找到"
                        point_status_class = "toc-point-partial"
                    else:
                        # 都是无关 -> 都找不到
                        point_status = "都找不到"
                        point_status_class = "toc-point-notfound"
                else:
                    point_status = "都找不到"
                    point_status_class = "toc-point-notfound"

                # 点项（可折叠，点击切换到该点的视图）
                # 确保ID唯一：包含list_key以区分不同类型的点
                point_item_id = f"post-{post_idx}-{list_key}-point-{point_idx}"
                point_view_id = f"view-post-{post_idx}-point-{list_key}-{point_idx}"
                all_toc_items.append(f'''
                <div class="toc-item toc-level-2 {point_status_class} collapsed" onclick="toggleTocPoint(event, '{point_item_id}', '{point_view_id}')">
                    <span class="toc-expand-icon">▼</span>
                    <div class="toc-item-content">
                        [{point_name}] {html_module.escape(name_short)}
                        <span class="toc-point-status">[{point_status}]</span>
                    </div>
                </div>
                <div class="toc-children hidden" id="toc-{point_item_id}-children">
                ''')

                # 特征列表
                if how_steps:
                    features = how_steps[0].get("特征列表", [])
                    for feat_idx, feature_data in enumerate(features):
                        feature_name = feature_data.get("特征名称", f"特征 {feat_idx + 1}")
                        status = feature_status_map.get(feature_name, "无关")

                        if status == "相同":
                            status_class = "toc-feature-same"
                            status_label = "相同"
                        elif status == "相似":
                            status_class = "toc-feature-similar"
                            status_label = "相似"
                        else:
                            status_class = "toc-feature-unrelated"
                            status_label = "无关"

                        # 特征项（点击直接跳转，不展开子项）
                        all_toc_items.append(f'''
                    <div class="toc-item toc-level-3 {status_class}" onclick="clickFeature(event, '{point_view_id}', 'post-{post_idx}-feat-{point_idx}-{feat_idx}')">
                        <div class="toc-item-content">
                            [特征] {html_module.escape(feature_name)}
                            <span class="toc-feature-status">[{status_label}]</span>
                        </div>
                    </div>
                        ''')

                # 关闭点项的children
                all_toc_items.append('</div>')

            # 关闭点类型分组的children
            all_toc_items.append('</div>')

        # 关闭帖子的children
        all_toc_items.append('</div>')

    # 生成所有独立的内容视图
    all_content_views = []

    for post_idx, post in enumerate(posts_data):
        post_detail = post.get("帖子详情", {})
        how_result = post.get("how解构结果", {})

        # 1. 生成"仅帖子详情"的视图
        post_detail_html = generate_post_detail_html(post, post_idx)
        post_only_view = f'''
        <div class="content-view" id="view-post-{post_idx}-detail" style="display: none;">
            <div class="post-content-wrapper">
                <div class="top-section-box">
                    <div id="post-{post_idx}-detail" class="post-detail-wrapper">
                        {post_detail_html}
                    </div>
                </div>
            </div>
        </div>
        '''
        all_content_views.append(post_only_view)

        # 2. 为每个点生成独立视图（包含帖子详情+点详情+匹配结果）
        for point_list_key in ["灵感点列表", "目的点列表", "关键点列表"]:
            point_list = how_result.get(point_list_key, [])
            # 提取点类型（去掉"列表"）
            point_type = point_list_key.replace("列表", "")

            for point_idx, point in enumerate(point_list):
                # 计算该点的特征状态映射
                point_feature_status_map = {}
                how_steps = point.get("how步骤列表", [])
                if how_steps:
                    features = how_steps[0].get("特征列表", [])
                    for feature_data in features:
                        feature_name = feature_data.get("特征名称", "")
                        match_results = feature_data.get("匹配结果", [])
                        max_similarity = 0.0
                        if match_results:
                            max_similarity = max(match.get("匹配结果", {}).get("相似度", 0) for match in match_results)
                        if max_similarity >= 0.9:
                            point_feature_status_map[feature_name] = "相同"
                        elif max_similarity >= 0.8:
                            point_feature_status_map[feature_name] = "相似"
                        else:
                            point_feature_status_map[feature_name] = "无关"

                # 生成点的详情HTML，传入特征状态映射和点类型
                point_detail_html = generate_inspiration_detail_html(point, point_feature_status_map, point_type)

                # 生成该点的所有特征匹配结果
                point_name = point.get("名称", f"点 {point_idx + 1}")
                matches_html = ""
                if how_steps:
                    for step_idx, step in enumerate(how_steps):
                        step_name = step.get("步骤名称", f"步骤 {step_idx + 1}")
                        features = step.get("特征列表", [])

                        features_html = ""
                        for feat_idx, feature_data in enumerate(features):
                            match_html = generate_match_results_html([step], feat_idx, point_idx, post_idx, category_mapping, source_mapping, point_list_key.replace("列表", ""), feat_idx + 1)
                            features_html += f'<div id="post-{post_idx}-feat-{point_idx}-{feat_idx}" class="feature-match-wrapper">{match_html}</div>'

                        step_section_id = f"post-{post_idx}-step-{point_idx}-{step_idx}"
                        matches_html += f'''
                        <div class="step-section">
                            <div class="step-header collapsible-header" onclick="toggleStepSection('{step_section_id}')">
                                <div class="header-left">
                                    <span class="expand-icon" id="{step_section_id}-icon">▼</span>
                                    <h3 class="step-name">{html_module.escape(step_name)}</h3>
                                </div>
                                <span class="step-inspiration-name">来自: {html_module.escape(point_name)}</span>
                            </div>
                            <div class="step-features-list" id="{step_section_id}-content">
                                {features_html}
                            </div>
                        </div>
                        '''

                # 组合成完整视图
                point_view_id = f"view-post-{post_idx}-point-{point_list_key}-{point_idx}"
                point_view = f'''
                <div class="content-view" id="{point_view_id}" style="display: none;">
                    <div class="post-content-wrapper">
                        <div class="top-section-box">
                            <div class="two-column-layout">
                                <div class="left-column">
                                    <div class="post-detail-wrapper">
                                        {post_detail_html}
                                    </div>
                                </div>
                                <div class="right-column">
                                    <div class="inspirations-detail-wrapper">
                                        <div id="post-{post_idx}-point-{point_list_key}-{point_idx}" class="inspiration-detail-item content-section">
                                            {point_detail_html}
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="matches-section">
                            {matches_html}
                        </div>
                    </div>
                </div>
                '''
                all_content_views.append(point_view)

    # 组合所有内容视图
    all_contents_html = "\n".join(all_content_views)

    # 组合目录HTML
    toc_items_html = "\n".join(all_toc_items)

    html = f'''
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How解构结果可视化</title>
        <style>
            * {{
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }}

            body {{
                font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
                background: #f5f5f5;
                color: #333;
                line-height: 1.6;
            }}

            /* 两栏布局容器 */
            .page-container {{
                display: flex;
                height: 100vh;
                overflow: hidden;
            }}

            /* 左侧目录 */
            .left-sidebar {{
                width: 420px;
                background: white;
                border-right: 2px solid #e5e7eb;
                display: flex;
                flex-direction: column;
                overflow: hidden;
            }}

            /* 右侧内容区 */
            .right-content {{
                flex: 1;
                overflow-y: auto;
                background: #f5f5f5;
                padding: 0;
                position: relative;
            }}

            /* 吸顶面包屑导航 */
            .breadcrumb-nav {{
                position: sticky;
                top: 0;
                left: 0;
                right: 0;
                background: white;
                border-bottom: 2px solid #e5e7eb;
                padding: 12px 30px;
                display: flex;
                align-items: center;
                gap: 8px;
                font-size: 14px;
                z-index: 100;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
            }}

            .breadcrumb-item {{
                color: #667eea;
                cursor: pointer;
                transition: all 0.2s;
                font-weight: 500;
            }}

            .breadcrumb-item:hover {{
                color: #5568d3;
                text-decoration: underline;
            }}

            .breadcrumb-separator {{
                color: #9ca3af;
                user-select: none;
            }}

            .content-view {{
                padding: 30px;
                width: 100%;
                height: 100%;
            }}

            .content-view.active {{
                display: block !important;
            }}

            .post-content-wrapper {{
                max-width: 1600px;
                margin: 0 auto;
                display: flex;
                flex-direction: column;
                gap: 30px;
            }}

            .container {{
                max-width: 1600px;
                margin: 0 auto;
                background: white;
                min-height: 100vh;
            }}

            .header {{
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 20px 30px;
                text-align: center;
            }}

            .header h1 {{
                font-size: 28px;
                font-weight: bold;
                margin-bottom: 5px;
            }}

            .header p {{
                font-size: 14px;
                opacity: 0.9;
            }}

            .toc-header {{
                padding: 15px 20px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                font-weight: 600;
                font-size: 16px;
                border-bottom: 2px solid #5a67d8;
            }}

            .toc-content {{
                padding: 10px;
                overflow-y: auto;
                flex: 1;
            }}

            .toc-level-0 {{
                color: #111827;
                font-weight: 700;
                font-size: 15px;
                background: #f9fafb;
                margin-top: 8px;
                margin-bottom: 4px;
            }}

            .toc-post-header {{
                font-weight: 700;
            }}

            .toc-badge-info {{
                background: #dbeafe;
                color: #1e40af;
            }}

            .toc-item {{
                padding: 10px 15px;
                margin: 4px 0;
                cursor: pointer;
                border-radius: 6px;
                font-size: 14px;
                transition: all 0.2s;
                user-select: none;
                display: flex;
                align-items: center;
                gap: 8px;
            }}

            .toc-item:hover {{
                background: #f9fafb;
            }}

            .toc-item.active {{
                color: #667eea;
                font-weight: 600;
            }}

            .toc-item.active-ancestor {{
                color: #667eea;
            }}

            .toc-expand-icon {{
                font-size: 10px;
                transition: transform 0.2s;
                color: #9ca3af;
                flex-shrink: 0;
            }}

            .toc-item.collapsed .toc-expand-icon {{
                transform: rotate(-90deg);
            }}

            .toc-item-content {{
                flex: 1;
                min-width: 0;
            }}

            /* 子项隐藏 */
            .toc-children {{
                display: block;
            }}

            .toc-children.hidden {{
                display: none;
            }}

            .toc-level-1 {{
                color: #111827;
                font-weight: 500;
                padding-left: 20px;
            }}

            .toc-level-2 {{
                color: #6b7280;
                font-size: 13px;
                padding-left: 40px;
            }}

            .toc-level-3 {{
                padding-left: 60px;
                font-size: 12px;
                color: #9ca3af;
            }}

            .toc-level-4 {{
                padding-left: 80px;
                font-size: 11px;
                color: #9ca3af;
            }}

            .toc-feature-status {{
                font-weight: 500;
                font-size: 10px;
                padding: 2px 6px;
                border-radius: 4px;
                margin-left: auto;
                background: #f3f4f6;
                color: #6b7280;
            }}

            /* 目录整体结论 */
            .toc-conclusion {{
                padding: 15px 20px;
                margin: 10px;
                border-radius: 8px;
                display: flex;
                align-items: center;
                gap: 10px;
                font-weight: 600;
                font-size: 14px;
            }}

            .toc-conclusion.conclusion-found {{
                background: #d1fae5;
                color: #065f46;
                border: 2px solid #10b981;
            }}

            .toc-conclusion.conclusion-partial {{
                background: #fed7aa;
                color: #92400e;
                border: 2px solid #f59e0b;
            }}

            .toc-conclusion.conclusion-not-found {{
                background: #fee2e2;
                color: #991b1b;
                border: 2px solid #ef4444;
            }}

            .conclusion-icon {{
                font-size: 18px;
                font-weight: 700;
            }}

            .conclusion-text {{
                flex: 1;
            }}

            .toc-badge {{
                display: inline-block;
                font-size: 12px;
                margin-right: 6px;
                opacity: 0.8;
            }}

            .toc-group-header {{
                font-weight: 600;
                cursor: pointer !important;
            }}

            .toc-point-status {{
                font-size: 10px;
                font-weight: 500;
                padding: 2px 6px;
                border-radius: 4px;
                margin-left: auto;
                background: #f3f4f6;
                color: #6b7280;
            }}

            .main-content {{
                min-width: 0;
                display: flex;
                flex-direction: column;
                gap: 30px;
            }}

            /* 顶部框：包含帖子详情和灵感点详情 */
            .top-section-box {{
                background: white;
                border: 1px solid #e5e7eb;
                border-radius: 12px;
                padding: 25px;
                box-shadow: 0 2px 8px rgba(0,0,0,0.05);
            }}

            /* 顶部框内的两栏布局 */
            .two-column-layout {{
                display: grid;
                grid-template-columns: 380px 1fr;
                gap: 25px;
                align-items: start;
            }}

            .left-column {{
                position: relative;
            }}

            .post-detail-wrapper {{
                /* 帖子详情区域 */
            }}

            .right-column {{
                min-width: 0;
            }}

            .inspirations-detail-wrapper {{
                display: flex;
                flex-direction: column;
                gap: 20px;
                max-height: 600px;
                overflow-y: auto;
                padding-right: 10px;
            }}

            .inspiration-detail-item {{
                /* 单个灵感点详情 */
            }}

            /* 匹配结果区域 */
            .matches-section {{
                display: flex;
                flex-direction: column;
                gap: 20px;
            }}

            /* 步骤区域 */
            .step-section {{
                background: white;
                border: 2px solid #e5e7eb;
                border-radius: 12px;
                overflow: hidden;
                box-shadow: 0 2px 8px rgba(0,0,0,0.05);
                transition: all 0.3s ease;
            }}

            .step-section:hover {{
                box-shadow: 0 4px 12px rgba(0,0,0,0.08);
                border-color: #d1d5db;
            }}

            .step-header {{
                padding: 18px 24px;
                background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);
                border-bottom: 2px solid #e5e7eb;
                display: flex;
                justify-content: space-between;
                align-items: center;
                cursor: pointer;
                user-select: none;
                transition: all 0.3s ease;
            }}

            .step-header:hover {{
                background: linear-gradient(135deg, #f3f4f6 0%, #f9fafb 100%);
            }}

            .step-name {{
                font-size: 18px;
                color: #111827;
                font-weight: 600;
                margin: 0;
            }}

            .step-inspiration-name {{
                font-size: 14px;
                color: #6b7280;
                font-style: italic;
            }}

            .step-features-list {{
                padding: 20px;
                display: flex;
                flex-direction: column;
                gap: 15px;
            }}

            .feature-match-wrapper {{
                /* 特征匹配容器 */
            }}

            .content-section {{
                scroll-margin-top: 80px;
            }}

            /* 帖子详情卡片（紧凑样式） */
            .post-card-compact {{
                display: grid;
                grid-template-columns: 200px 1fr;
                gap: 20px;
                background: white;
                border: 1px solid #e5e7eb;
                border-radius: 12px;
                overflow: hidden;
                padding: 20px;
                cursor: pointer;
                transition: all 0.3s;
                margin-bottom: 30px;
            }}

            .post-card-compact:hover {{
                box-shadow: 0 4px 12px rgba(0,0,0,0.1);
                transform: translateY(-2px);
                border-color: #667eea;
            }}

            .post-card-image {{
                position: relative;
                display: flex;
                align-items: center;
                justify-content: center;
            }}

            .post-card-thumbnail {{
                width: 100%;
                height: 150px;
                object-fit: contain;
                border-radius: 8px;
                background: #f9fafb;
            }}

            .post-card-thumbnail-placeholder {{
                width: 100%;
                height: 150px;
                display: flex;
                align-items: center;
                justify-content: center;
                background: #f3f4f6;
                color: #9ca3af;
                font-size: 48px;
                border-radius: 8px;
            }}

            .post-card-image-count {{
                position: absolute;
                bottom: 8px;
                right: 8px;
                background: rgba(0, 0, 0, 0.7);
                color: white;
                padding: 4px 8px;
                border-radius: 12px;
                font-size: 11px;
                font-weight: 600;
            }}

            .post-card-content {{
                display: flex;
                flex-direction: column;
                gap: 12px;
            }}

            .post-card-title {{
                font-size: 18px;
                font-weight: 600;
                color: #111827;
                line-height: 1.4;
                overflow: hidden;
                text-overflow: ellipsis;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
            }}

            .post-card-preview {{
                font-size: 14px;
                color: #6b7280;
                line-height: 1.6;
                overflow: hidden;
                text-overflow: ellipsis;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
            }}

            .post-card-meta {{
                display: flex;
                gap: 15px;
                font-size: 13px;
                color: #9ca3af;
            }}

            .post-card-stats {{
                display: flex;
                gap: 15px;
                font-size: 13px;
                color: #6b7280;
                font-weight: 500;
            }}

            /* 灵感点详情卡片样式保持不变 */

            .inspiration-detail-card {{
                background: linear-gradient(135deg, #f9fafb 0%, #ffffff 100%);
                padding: 25px;
                border-bottom: 2px solid #e5e7eb;
            }}

            .inspiration-header {{
                margin-bottom: 15px;
                display: flex;
                align-items: center;
                gap: 10px;
                flex-wrap: wrap;
            }}

            .inspiration-conclusion {{
                padding: 6px 14px;
                border-radius: 16px;
                font-size: 13px;
                font-weight: 700;
                margin-left: auto;
            }}

            .inspiration-conclusion.insp-conclusion-found {{
                background: #d1fae5;
                color: #065f46;
                border: 2px solid #10b981;
            }}

            .inspiration-conclusion.insp-conclusion-partial {{
                background: #fed7aa;
                color: #92400e;
                border: 2px solid #f59e0b;
            }}

            .inspiration-conclusion.insp-conclusion-not-found {{
                background: #fee2e2;
                color: #991b1b;
                border: 2px solid #ef4444;
            }}

            .inspiration-type-badge {{
                display: inline-block;
                padding: 4px 12px;
                background: #fef3c7;
                color: #92400e;
                border-radius: 12px;
                font-size: 12px;
                font-weight: 600;
            }}

            .inspiration-name {{
                font-size: 20px;
                color: #111827;
                font-weight: 600;
                margin: 0;
            }}

            .inspiration-description {{
                margin-bottom: 15px;
            }}

            .desc-label {{
                font-weight: 600;
                color: #6b7280;
                font-size: 13px;
                margin-bottom: 8px;
            }}

            .desc-text {{
                color: #4b5563;
                font-size: 14px;
                line-height: 1.7;
            }}

            .inspiration-features {{
                margin-top: 15px;
            }}

            .features-label {{
                font-weight: 600;
                color: #6b7280;
                font-size: 13px;
                margin-bottom: 8px;
            }}

            .features-tags {{
                display: flex;
                flex-wrap: wrap;
                gap: 8px;
            }}

            .feature-tag {{
                padding: 5px 12px;
                background: #667eea;
                color: white;
                border-radius: 16px;
                font-size: 13px;
                font-weight: 500;
                display: inline-flex;
                align-items: center;
                gap: 4px;
            }}

            .feature-tag.feature-same {{
                background: #10b981;
            }}

            .feature-tag.feature-similar {{
                background: #f59e0b;
            }}

            .feature-tag.feature-unrelated {{
                background: #9ca3af;
            }}

            .feature-status-label {{
                font-weight: 700;
                font-size: 11px;
                padding: 2px 6px;
                background: rgba(255, 255, 255, 0.3);
                border-radius: 4px;
            }}

            /* 匹配结果部分 */
            .match-results-section {{
                padding: 48px 25px;
                border-bottom: none;
            }}

            .match-results-section:first-child {{
                padding-top: 25px;
            }}

            .match-section-header {{
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 10px 0 24px 0;
                background: transparent;
                border: none;
                border-bottom: 1px solid #e5e7eb;
                border-radius: 0;
                gap: 12px;
                cursor: pointer;
                user-select: none;
                transition: all 0.2s ease;
            }}

            .match-section-header:hover {{
                border-bottom-color: #9ca3af;
            }}

            .header-left {{
                display: flex;
                align-items: center;
                gap: 10px;
                flex: 1;
            }}

            .collapsible-header {{
                cursor: pointer;
                user-select: none;
                transition: background 0.2s;
                padding: 10px;
                margin: -10px;
                border-radius: 6px;
            }}

            .collapsible-header:hover {{
                background: #f9fafb;
            }}

            .overall-top-match {{
                display: inline-flex;
                align-items: center;
                gap: 8px;
                padding: 6px 12px;
                background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
                border-radius: 8px;
                font-size: 13px;
                border: 1px solid #bae6fd;
                flex-shrink: 0;
            }}

            .overall-top-label {{
                font-weight: 700;
                color: #0369a1;
            }}

            .overall-top-combined {{
                padding: 3px 8px;
                background: linear-gradient(135deg, #e0e7ff 0%, #fef3c7 100%);
                color: #4338ca;
                border-radius: 6px;
                font-size: 11px;
                font-weight: 600;
                border: 1px solid #c7d2fe;
            }}

            .overall-top-name {{
                font-weight: 700;
                color: #1e40af;
            }}

            .overall-top-score {{
                padding: 4px 12px;
                border-radius: 12px;
                font-size: 13px;
                font-weight: 700;
                margin-left: auto;
            }}

            .match-section-header .header-left {{
                display: flex;
                align-items: center;
                gap: 10px;
                flex: 1;
            }}

            .match-section-header h4 {{
                font-size: 18px;
                color: #111827;
                margin: 0;
            }}

            .match-stats {{
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
            }}

            .stat-badge {{
                padding: 4px 10px;
                border-radius: 12px;
                color: white;
                font-size: 12px;
                font-weight: 600;
            }}

            .matches-list {{
                display: flex;
                flex-direction: column;
                gap: 8px;
                transition: all 0.3s ease;
                overflow: hidden;
            }}

            .match-group-section {{
                margin-bottom: 20px;
                background: white;
                border: 1px solid #e5e7eb;
                border-radius: 8px;
                overflow: hidden;
            }}

            .match-group-header {{
                padding: 12px 18px;
                background: linear-gradient(135deg, #f3f4f6 0%, #e5e7eb 100%);
                border-bottom: 2px solid #d1d5db;
                cursor: pointer;
                user-select: none;
                display: flex;
                align-items: center;
                gap: 10px;
                transition: background 0.2s;
            }}

            .match-group-header:hover {{
                background: linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%);
            }}

            .match-group-title {{
                font-size: 15px;
                font-weight: 600;
                color: #374151;
                margin: 0;
            }}

            .match-group-content {{
                padding: 15px;
                display: flex;
                flex-direction: row;
                flex-wrap: wrap;
                gap: 10px;
            }}

            /* 层级分组样式 - 极简无边框 */
            .level-group-section {{
                background: transparent;
                border: none;
                border-radius: 0;
                overflow: visible;
            }}

            .level-group-header {{
                padding: 20px 0 16px 0;
                background: transparent;
                border-bottom: 1px solid #e5e7eb;
                cursor: pointer;
                user-select: none;
                display: flex;
                justify-content: space-between;
                align-items: center;
                transition: all 0.2s ease;
            }}

            .level-group-header:hover {{
                border-bottom-color: #9ca3af;
            }}

            .level-group-header .expand-icon {{
                color: #6b7280;
                font-size: 13px;
            }}

            .level-header-left {{
                display: flex;
                align-items: center;
                gap: 8px;
            }}

            .level-group-title {{
                font-size: 15px;
                font-weight: 600;
                color: #111827;
                margin: 0;
            }}

            .level-stats {{
                display: inline-flex;
                gap: 8px;
                align-items: center;
            }}

            .level-top-match {{
                display: inline-flex;
                align-items: center;
                gap: 6px;
                font-size: 12px;
                color: #6b7280;
            }}

            .top-match-label {{
                font-weight: 500;
                color: #9ca3af;
            }}

            .top-match-type {{
                padding: 2px 6px;
                background: #f3f4f6;
                border-radius: 4px;
                font-size: 11px;
                font-weight: 500;
                color: #6b7280;
            }}

            .top-match-name {{
                font-weight: 500;
                color: #374151;
            }}

            .top-match-score {{
                padding: 3px 10px;
                border-radius: 12px;
                font-size: 12px;
                font-weight: 700;
                margin-left: auto;
            }}

            .level-group-content {{
                padding: 0;
                background: transparent;
                transition: all 0.3s ease;
                overflow: hidden;
            }}

            .level-group-content.collapsed {{
                display: none;
            }}

            /* 子分组样式 - 极简 */
            .match-subgroup-section {{
                display: block;
                width: 100%;
                background: transparent;
                border-radius: 0;
                overflow: visible;
            }}

            .match-subgroup-header {{
                padding: 12px 0 8px 0;
                background: transparent;
                cursor: pointer;
                user-select: none;
                display: flex;
                justify-content: space-between;
                align-items: center;
                transition: all 0.2s ease;
                border-bottom: 1px solid #f3f4f6;
            }}

            .match-subgroup-header:hover {{
                border-bottom-color: #e5e7eb;
            }}

            .subgroup-header-left {{
                display: flex;
                align-items: center;
                gap: 8px;
            }}

            .match-subgroup-title {{
                font-size: 13px;
                font-weight: 600;
                color: #374151;
                margin: 0;
            }}

            .subgroup-top-match {{
                display: inline-flex;
                align-items: center;
                gap: 6px;
                font-size: 11px;
                color: #6b7280;
            }}

            .subgroup-top-label {{
                font-weight: 500;
                color: #9ca3af;
            }}

            .subgroup-top-combined {{
                padding: 2px 6px;
                background: #f3f4f6;
                color: #6b7280;
                border-radius: 4px;
                font-size: 10px;
                font-weight: 500;
            }}

            .subgroup-top-name {{
                font-weight: 500;
                color: #374151;
            }}

            .subgroup-top-score {{
                padding: 2px 8px;
                border-radius: 10px;
                font-size: 11px;
                font-weight: 600;
            }}

            .match-subgroup-content {{
                padding: 0;
                display: flex;
                flex-direction: row;
                flex-wrap: wrap;
                gap: 8px;
                transition: all 0.3s ease;
                overflow: hidden;
                background: transparent;
            }}

            .match-item-compact {{
                display: inline-flex;
                align-items: center;
                gap: 6px;
                padding: 8px 14px;
                background: transparent;
                border: 1.5px solid #e5e7eb;
                border-radius: 8px;
                font-size: 13px;
                transition: all 0.3s ease;
                cursor: pointer;
            }}

            .match-item-compact:hover {{
                border-color: #667eea;
                box-shadow: 0 4px 8px rgba(102, 126, 234, 0.15);
                transform: translateY(-2px);
                background: #fafbff;
            }}

            .match-item-compact:active {{
                transform: translateY(0);
            }}

            /* 匹配项中的层级-类型标签 */
            .match-item-compact .feature-combined-badge {{
                color: #9ca3af;
            }}

            /* 匹配详情模态框 */
            .match-modal {{
                display: none;
                position: fixed;
                z-index: 3000;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                animation: fadeIn 0.2s;
            }}

            .match-modal-content {{
                position: relative;
                background: white;
                margin: 5% auto;
                padding: 0;
                width: 80%;
                max-width: 900px;
                max-height: 80vh;
                border-radius: 12px;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
                overflow: hidden;
                animation: slideDown 0.3s;
            }}

            .match-modal-header {{
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 20px 25px;
                display: flex;
                align-items: center;
                justify-content: space-between;
            }}

            .match-modal-title {{
                font-size: 18px;
                font-weight: 600;
                margin: 0;
            }}

            .match-modal-close {{
                color: white;
                font-size: 32px;
                font-weight: 300;
                cursor: pointer;
                background: none;
                border: none;
                padding: 0;
                line-height: 1;
                transition: transform 0.2s;
            }}

            .match-modal-close:hover {{
                transform: scale(1.2);
            }}

            .match-modal-body {{
                padding: 25px;
                max-height: calc(80vh - 80px);
                overflow-y: auto;
            }}

            .match-detail-section {{
                margin-bottom: 25px;
            }}

            .match-detail-section h3 {{
                font-size: 16px;
                font-weight: 600;
                color: #374151;
                margin-bottom: 12px;
                padding-bottom: 8px;
                border-bottom: 2px solid #e5e7eb;
            }}

            .match-explanation-text {{
                line-height: 1.8;
                color: #4b5563;
                padding: 15px;
                background: #f9fafb;
                border-radius: 8px;
                border-left: 4px solid #667eea;
            }}


            .match-item-collapsible {{
                border: 1px solid #e5e7eb;
                border-radius: 8px;
                overflow: hidden;
                background: white;
                transition: box-shadow 0.2s;
            }}

            .match-item-collapsible:hover {{
                box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            }}

            .match-header {{
                padding: 12px 16px;
                cursor: pointer;
                user-select: none;
                transition: background 0.2s;
            }}

            .match-header:hover {{
                background: #f9fafb;
            }}

            .match-header-left {{
                display: flex;
                align-items: center;
                gap: 10px;
            }}

            .expand-icon {{
                color: #9ca3af;
                font-size: 14px;
                transition: transform 0.3s ease;
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 20px;
                height: 20px;
                flex-shrink: 0;
            }}

            .expand-icon.expanded {{
                transform: rotate(0deg);
            }}

            /* 折叠状态时旋转 */
            .collapsed .expand-icon {{
                transform: rotate(-90deg);
            }}

            .persona-name {{
                font-weight: 600;
                font-size: 14px;
                color: #111827;
            }}

            .match-item-compact .persona-name {{
                font-weight: 500;
                font-size: 13px;
                color: #374151;
            }}

            .relation-badge {{
                padding: 3px 10px;
                border-radius: 12px;
                color: white;
                font-size: 11px;
                font-weight: 600;
            }}

            .score-badge {{
                padding: 3px 10px;
                border-radius: 12px;
                background: #e5e7eb;
                color: #374151;
                font-size: 11px;
                font-weight: 600;
            }}

            .feature-combined-badge {{
                padding: 3px 8px;
                border-radius: 10px;
                background: transparent;
                color: #9ca3af;
                font-size: 10px;
                font-weight: 500;
                border: none;
            }}

            .feature-combined-badge.combined-badge-same {{
                background: transparent;
                color: #9ca3af;
                border: none;
                box-shadow: none;
                font-weight: 500;
            }}

            .feature-category-badge {{
                padding: 3px 8px;
                border-radius: 10px;
                background: #dbeafe;
                color: #1e40af;
                font-size: 10px;
                font-weight: 500;
                border: 1px solid #93c5fd;
            }}

            /* 同层级匹配 - 统一边框颜色 */
            .match-item-compact.match-same-level {{
                border: 1.5px solid #e5e7eb;
                background: transparent;
                box-shadow: none;
            }}

            .match-item-compact.match-same-level:hover {{
                border-color: #667eea;
                box-shadow: 0 4px 8px rgba(102, 126, 234, 0.15);
                transform: translateY(-2px);
                background: #fafbff;
            }}

            .level-badge {{
                padding: 4px 10px;
                border-radius: 12px;
                font-size: 11px;
                font-weight: 600;
                margin-right: 6px;
            }}

            .level-badge-match {{
                background: #e0e7ff;
                color: #4338ca;
                border: 1px solid #a5b4fc;
            }}

            .level-badge-category {{
                background: #fef3c7;
                color: #92400e;
                border: 1px solid #fcd34d;
            }}

            .feature-match-status {{
                padding: 5px 12px;
                border-radius: 12px;
                font-size: 12px;
                font-weight: 700;
                margin-left: 12px;
            }}

            .feature-match-status.status-same {{
                background: #d1fae5;
                color: #065f46;
                border: 2px solid #10b981;
            }}

            .feature-match-status.status-similar {{
                background: #fed7aa;
                color: #92400e;
                border: 2px solid #f59e0b;
            }}

            .feature-match-status.status-unrelated {{
                background: #e5e7eb;
                color: #4b5563;
                border: 2px solid #9ca3af;
            }}

            .match-content {{
                padding: 16px;
                background: #f9fafb;
                border-top: 1px solid #e5e7eb;
            }}

            .match-explanation {{
                font-size: 13px;
                color: #4b5563;
                line-height: 1.7;
                margin-bottom: 16px;
            }}

            /* 历史帖子来源区域 */
            .historical-posts-section {{
                margin-top: 20px;
                padding-top: 20px;
                border-top: 2px solid #e5e7eb;
            }}

            .historical-posts-title {{
                font-size: 14px;
                font-weight: 600;
                color: #374151;
                margin-bottom: 12px;
            }}

            .historical-posts-grid {{
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
                gap: 16px;
            }}

            .historical-post-card {{
                display: grid;
                grid-template-columns: 120px 1fr;
                gap: 12px;
                background: white;
                border: 1px solid #e5e7eb;
                border-radius: 8px;
                padding: 12px;
                transition: all 0.2s;
                cursor: pointer;
            }}

            .historical-post-card:hover {{
                border-color: #667eea;
                box-shadow: 0 2px 8px rgba(102, 126, 234, 0.1);
                transform: translateY(-2px);
            }}

            .historical-post-image {{
                position: relative;
            }}

            .historical-post-thumbnail {{
                width: 100%;
                height: 100px;
                object-fit: contain;
                border-radius: 6px;
                background: #f9fafb;
            }}

            .historical-post-content {{
                display: flex;
                flex-direction: column;
                gap: 8px;
            }}

            .historical-post-title {{
                font-size: 13px;
                font-weight: 600;
                color: #1f2937;
                line-height: 1.4;
                overflow: hidden;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
            }}

            .historical-inspiration-info {{
                display: flex;
                align-items: center;
                gap: 6px;
            }}

            .inspiration-type-badge-small {{
                padding: 2px 6px;
                border-radius: 4px;
                background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
                color: white;
                font-size: 10px;
                font-weight: 600;
            }}

            .inspiration-name-small {{
                font-size: 11px;
                color: #667eea;
                font-weight: 500;
            }}

            .historical-inspiration-desc {{
                font-size: 11px;
                color: #6b7280;
                line-height: 1.5;
                overflow: hidden;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
            }}

            .historical-post-meta {{
                margin: 4px 0;
            }}

            .historical-post-time {{
                font-size: 11px;
                color: #9ca3af;
            }}

            .historical-post-stats {{
                display: flex;
                align-items: center;
                gap: 10px;
                font-size: 11px;
                color: #9ca3af;
            }}

            .view-link {{
                margin-left: auto;
                color: #667eea;
                text-decoration: none;
                font-weight: 500;
            }}

            .view-link:hover {{
                color: #764ba2;
            }}

            .category-simple {{
                color: #9ca3af;
                font-size: 12px;
                font-weight: 400;
                margin-right: 6px;
            }}

            /* 帖子详情模态框 */
            .post-detail-modal {{
                display: none;
                position: fixed;
                z-index: 4000;
                left: 0;
                top: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.7);
                overflow: auto;
                animation: fadeIn 0.3s;
            }}

            .post-detail-modal.active {{
                display: flex;
                align-items: center;
                justify-content: center;
                padding: 40px 20px;
            }}

            .post-detail-content {{
                position: relative;
                background: white;
                border-radius: 16px;
                max-width: 900px;
                width: 100%;
                max-height: 90vh;
                overflow-y: auto;
                box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            }}

            .post-detail-close {{
                position: sticky;
                top: 20px;
                right: 20px;
                float: right;
                font-size: 36px;
                font-weight: 300;
                color: #9ca3af;
                background: white;
                border: none;
                cursor: pointer;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.2s;
                z-index: 10;
                box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            }}

            .post-detail-close:hover {{
                color: #ef4444;
                background: #fee2e2;
                transform: rotate(90deg);
            }}

            .post-detail-header {{
                padding: 40px 40px 20px 40px;
                border-bottom: 2px solid #e5e7eb;
            }}

            .post-detail-title {{
                font-size: 28px;
                font-weight: bold;
                color: #111827;
                line-height: 1.4;
                margin-bottom: 15px;
            }}

            .post-detail-meta {{
                display: flex;
                justify-content: space-between;
                align-items: center;
                color: #6b7280;
                font-size: 14px;
                gap: 20px;
            }}

            .post-detail-author {{
                font-weight: 500;
            }}

            .post-detail-time {{
                color: #9ca3af;
            }}

            .post-detail-stats {{
                display: flex;
                gap: 15px;
                font-weight: 500;
            }}

            .post-detail-body {{
                padding: 30px 40px;
            }}

            .post-detail-desc {{
                font-size: 15px;
                color: #4b5563;
                line-height: 1.8;
                margin-bottom: 25px;
                white-space: pre-wrap;
            }}

            .post-detail-images {{
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
                gap: 15px;
                margin-top: 20px;
            }}

            .post-detail-image {{
                width: 100%;
                border-radius: 8px;
                object-fit: cover;
                cursor: pointer;
                transition: transform 0.2s;
            }}

            .post-detail-image:hover {{
                transform: scale(1.02);
            }}

            .post-detail-footer {{
                padding: 20px 40px 30px 40px;
                border-top: 1px solid #e5e7eb;
                text-align: center;
            }}

            .post-detail-link {{
                display: inline-block;
                padding: 12px 30px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                text-decoration: none;
                border-radius: 8px;
                font-weight: 500;
                transition: all 0.3s;
            }}

            .post-detail-link:hover {{
                transform: translateY(-2px);
                box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
            }}

            /* 响应式 */
            @media (max-width: 1400px) {{
                .content-with-toc {{
                    grid-template-columns: 240px 1fr;
                }}

                .two-column-layout {{
                    grid-template-columns: 320px 1fr;
                }}
            }}

            @media (max-width: 1200px) {{
                .content-with-toc {{
                    grid-template-columns: 200px 1fr;
                }}

                .two-column-layout {{
                    grid-template-columns: 280px 1fr;
                }}
            }}

            @media (max-width: 1024px) {{
                .page-container {{
                    flex-direction: column;
                    height: auto;
                }}

                .left-sidebar {{
                    width: 100%;
                    max-height: 300px;
                    border-right: none;
                    border-bottom: 2px solid #e5e7eb;
                }}

                .right-content {{
                    height: auto;
                }}

                .two-column-layout {{
                    grid-template-columns: 1fr;
                }}

                .inspirations-detail-wrapper {{
                    max-height: none;
                }}

                .post-card-compact {{
                    grid-template-columns: 150px 1fr;
                }}
            }}

            @media (max-width: 768px) {{
                .header {{
                    padding: 15px 20px;
                }}

                .header h1 {{
                    font-size: 24px;
                }}

                .left-sidebar {{
                    max-height: 250px;
                }}

                .post-info-section {{
                    padding: 20px;
                }}
            }}
        </style>
    </head>
    <body>
        <div class="page-container">
            <!-- 左侧目录 -->
            <div class="left-sidebar">
                <div class="header">
                    <h1>How 解构结果</h1>
                    <p>灵感点特征匹配分析</p>
                </div>
                <div class="toc-content">
                    {toc_items_html}
                </div>
            </div>

            <!-- 右侧内容 -->
            <div class="right-content">
                <!-- 吸顶面包屑导航 -->
                <div class="breadcrumb-nav" id="breadcrumb-nav">
                    <span class="breadcrumb-item" id="breadcrumb-point">-</span>
                    <span class="breadcrumb-separator" id="sep-1" style="display:none;">></span>
                    <span class="breadcrumb-item" id="breadcrumb-step" style="display:none;">-</span>
                    <span class="breadcrumb-separator" id="sep-2" style="display:none;">></span>
                    <span class="breadcrumb-item" id="breadcrumb-feature" style="display:none;">-</span>
                    <span class="breadcrumb-separator" id="sep-3" style="display:none;">></span>
                    <span class="breadcrumb-item" id="breadcrumb-level" style="display:none;">-</span>
                    <span class="breadcrumb-separator" id="sep-4" style="display:none;">></span>
                    <span class="breadcrumb-item" id="breadcrumb-subgroup" style="display:none;">-</span>
                </div>
                {all_contents_html}
            </div>
        </div>

        <!-- 匹配详情模态框 -->
        <div id="matchModal" class="match-modal" onclick="closeMatchModal(event)">
            <div class="match-modal-content" onclick="event.stopPropagation()">
                <div class="match-modal-header">
                    <h2 class="match-modal-title" id="matchModalTitle"></h2>
                    <button class="match-modal-close" onclick="closeMatchModal()">&times;</button>
                </div>
                <div class="match-modal-body" id="matchModalBody"></div>
            </div>
        </div>

        <!-- 帖子详情模态框 -->
        <div id="postDetailModal" class="post-detail-modal" onclick="closePostDetail(event)"></div>

        <script>
            // 切换内容视图
            function showContentView(viewId, clickedElement) {{
                // 隐藏所有视图
                var allViews = document.querySelectorAll('.content-view');
                allViews.forEach(function(view) {{
                    view.style.display = 'none';
                    view.classList.remove('active');
                }});

                // 显示指定视图
                var targetView = document.getElementById(viewId);
                if (targetView) {{
                    targetView.style.display = 'block';
                    targetView.classList.add('active');
                }}

                // 更新目录项的active状态：清除所有，然后标记当前项和祖先
                var tocItems = document.querySelectorAll('.toc-item');
                tocItems.forEach(function(item) {{
                    item.classList.remove('active', 'active-ancestor');
                }});

                // 标记当前激活项
                var activeItem = clickedElement || (event && event.currentTarget);
                if (activeItem && activeItem.classList.contains('toc-item')) {{
                    activeItem.classList.add('active');

                    // 标记所有祖先节点
                    var parent = activeItem.parentElement;
                    while (parent) {{
                        // 查找上一个兄弟节点中的toc-item
                        var prevSibling = parent.previousElementSibling;
                        if (prevSibling && prevSibling.classList.contains('toc-item')) {{
                            prevSibling.classList.add('active-ancestor');
                        }}
                        parent = parent.parentElement;
                        // 到达toc-content就停止
                        if (parent && parent.classList.contains('toc-content')) {{
                            break;
                        }}
                    }}
                }}
            }}

            // 折叠/展开帖子
            function toggleTocPost(event, postIdx) {{
                event.stopPropagation();
                var item = event.currentTarget;
                var children = document.getElementById('toc-post-' + postIdx + '-children');

                item.classList.toggle('collapsed');
                children.classList.toggle('hidden');
            }}

            // 折叠/展开点类型分组
            function toggleTocGroup(event, groupId) {{
                event.stopPropagation();
                var item = event.currentTarget;
                var children = document.getElementById('toc-' + groupId + '-children');

                item.classList.toggle('collapsed');
                children.classList.toggle('hidden');
            }}

            // 折叠/展开点项（同时切换到该点的内容视图）
            function toggleTocPoint(event, pointItemId, viewId) {{
                event.stopPropagation();

                // 如果点击的是展开图标，只切换折叠状态
                if (event.target.classList.contains('toc-expand-icon')) {{
                    event.preventDefault();
                    var item = event.currentTarget;
                    var children = document.getElementById('toc-' + pointItemId + '-children');
                    item.classList.toggle('collapsed');
                    children.classList.toggle('hidden');
                }} else {{
                    // 如果点击的是其他部分，切换到该点的视图
                    showContentView(viewId, event.currentTarget);

                    // 滚动到右侧内容区域的顶部
                    var rightContent = document.querySelector('.right-content');
                    if (rightContent) {{
                        rightContent.scrollTo({{ top: 0, behavior: 'smooth' }});
                    }}
                }}
            }}

            // 折叠/展开特征项（特征有子层级）
            function toggleTocFeature(event, featureItemId, viewId, featureSectionId) {{
                event.stopPropagation();

                // 如果点击的是展开图标，只切换折叠状态
                if (event.target.classList.contains('toc-expand-icon')) {{
                    event.preventDefault();
                    var item = event.currentTarget;
                    var children = document.getElementById('toc-' + featureItemId + '-children');
                    item.classList.toggle('collapsed');
                    children.classList.toggle('hidden');
                }} else {{
                    // 如果点击的是其他部分，切换到该点的视图并滚动到特征
                    showContentView(viewId, event.currentTarget);

                    setTimeout(function() {{
                        var element = document.getElementById(featureSectionId);
                        if (element) {{
                            element.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                        }}
                    }}, 100);
                }}
            }}

            // 滚动到层级分组（在特征下的子层级）
            function scrollToLevelSection(event, viewId, levelSectionId) {{
                event.stopPropagation();

                // 先切换到对应点的视图
                showContentView(viewId, event.currentTarget);

                // 等待视图切换完成后滚动到层级分组位置
                setTimeout(function() {{
                    var element = document.getElementById(levelSectionId);
                    if (element) {{
                        element.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                    }}
                }}, 100);
            }}

            // 点击特征：先切换到对应点的视图，再滚动到特征位置
            function clickFeature(event, pointViewId, featureSectionId) {{
                event.stopPropagation();

                // 先切换到对应点的视图
                showContentView(pointViewId, event.currentTarget);

                // 等待视图切换完成后滚动到特征位置
                setTimeout(function() {{
                    var element = document.getElementById(featureSectionId);
                    if (element) {{
                        element.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                    }}
                }}, 100);
            }}

            function scrollToSection(sectionId) {{
                var element = document.getElementById(sectionId);
                if (element) {{
                    element.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                }}
            }}

            function toggleMatch(matchId) {{
                var content = document.getElementById(matchId + '-content');
                var icon = document.getElementById(matchId + '-icon');

                if (content.style.display === 'none') {{
                    content.style.display = 'block';
                    icon.classList.add('expanded');
                }} else {{
                    content.style.display = 'none';
                    icon.classList.remove('expanded');
                }}
            }}

            function toggleFeatureSection(event, sectionId) {{
                event.stopPropagation();

                var content = document.getElementById(sectionId + '-content');
                var icon = document.getElementById(sectionId + '-icon');

                if (!content || !icon) {{
                    console.error('Element not found:', sectionId);
                    return;
                }}

                var isHidden = content.style.display === 'none' || !content.style.display || window.getComputedStyle(content).display === 'none';

                if (isHidden) {{
                    content.style.display = 'flex';
                    icon.textContent = '▼';
                }} else {{
                    content.style.display = 'none';
                    icon.textContent = '▶';
                }}
            }}

            function toggleStepSection(sectionId) {{
                var content = document.getElementById(sectionId + '-content');
                var icon = document.getElementById(sectionId + '-icon');

                if (content.style.display === 'none') {{
                    content.style.display = 'flex';
                    icon.textContent = '▼';
                }} else {{
                    content.style.display = 'none';
                    icon.textContent = '▶';
                }}
            }}

            function toggleMatchGroup(event, groupId) {{
                event.stopPropagation();

                var content = document.getElementById(groupId + '-content');
                var icon = document.getElementById(groupId + '-icon');

                if (!content || !icon) {{
                    console.error('Element not found:', groupId);
                    return;
                }}

                var isHidden = content.style.display === 'none' || !content.style.display || window.getComputedStyle(content).display === 'none';

                if (isHidden) {{
                    // 根据class决定使用什么display值
                    if (content.classList.contains('match-subgroup-content')) {{
                        content.style.display = 'flex';
                    }} else {{
                        content.style.display = 'block';
                    }}
                    icon.textContent = '▼';
                }} else {{
                    content.style.display = 'none';
                    icon.textContent = '▶';
                }}
            }}

            function showMatchDetail(element) {{
                var modal = document.getElementById('matchModal');
                var title = document.getElementById('matchModalTitle');
                var body = document.getElementById('matchModalBody');

                // 从data属性读取数据
                var personaName = element.dataset.personaName;
                var featureType = element.dataset.featureType;
                var personaLevel = element.dataset.personaLevel;
                var similarity = parseFloat(element.dataset.similarity);
                var label = element.dataset.label;
                var explanation = element.dataset.explanation;
                var historicalPosts = element.dataset.historicalPosts;

                // 设置标题 - 合并显示层级和类型
                var titleText = '';
                if (personaLevel && featureType) {{
                    titleText = '[' + personaLevel + '-' + featureType + '] ';
                }}
                titleText += personaName + ' (相似度: ' + similarity.toFixed(2) + ' - ' + label + ')';
                title.textContent = titleText;

                // 生成内容
                var bodyHTML = '<div class="match-detail-section">';
                bodyHTML += '<h3>匹配说明</h3>';
                bodyHTML += '<div class="match-explanation-text">' + explanation + '</div>';
                bodyHTML += '</div>';

                // 如果有历史帖子
                if (historicalPosts && historicalPosts.trim().length > 0) {{
                    bodyHTML += '<div class="match-detail-section">';
                    bodyHTML += '<h3>历史帖子来源</h3>';
                    bodyHTML += '<div class="historical-posts-grid">';
                    bodyHTML += historicalPosts;
                    bodyHTML += '</div>';
                    bodyHTML += '</div>';
                }}

                body.innerHTML = bodyHTML;
                modal.style.display = 'block';
            }}

            function closeMatchModal(event) {{
                var modal = document.getElementById('matchModal');
                if (!event || event.target === modal) {{
                    modal.style.display = 'none';
                }}
            }}

            // ESC键关闭模态框
            document.addEventListener('keydown', function(event) {{
                if (event.key === 'Escape') {{
                    closeMatchModal();
                }}
            }});

            function showPostDetail(element) {{
                const postDataStr = element.dataset.postData;
                if (!postDataStr) return;

                try {{
                    const postData = JSON.parse(postDataStr);

                    // 生成图片HTML（添加懒加载）
                    let imagesHtml = '';
                    if (postData.images && postData.images.length > 0) {{
                        imagesHtml = postData.images.map(img =>
                            `<img src="${{img}}" class="post-detail-image" alt="图片" loading="lazy">`
                        ).join('');
                    }} else {{
                        imagesHtml = '<div style="text-align: center; color: #9ca3af; padding: 40px;">暂无图片</div>';
                    }}

                    const modalHtml = `
                        <div class="post-detail-content" onclick="event.stopPropagation()">
                            <button class="post-detail-close" onclick="closePostDetail()">×</button>
                            <div class="post-detail-header">
                                <div class="post-detail-title">${{postData.title || '无标题'}}</div>
                                <div class="post-detail-meta">
                                    <div>
                                        <span class="post-detail-author">👤 ${{postData.author}}</span>
                                        <span class="post-detail-time"> · 📅 ${{postData.publish_time}}</span>
                                    </div>
                                    <div class="post-detail-stats">
                                        <span>👍 ${{postData.like_count}}</span>
                                        <span>💬 ${{postData.comment_count}}</span>
                                        <span>⭐ ${{postData.collect_count}}</span>
                                    </div>
                                </div>
                            </div>
                            <div class="post-detail-body">
                                ${{postData.body_text ? `<div class="post-detail-desc">${{postData.body_text}}</div>` : '<div style="color: #9ca3af;">暂无正文</div>'}}
                                <div class="post-detail-images">
                                    ${{imagesHtml}}
                                </div>
                            </div>
                            <div class="post-detail-footer">
                                <a href="${{postData.link}}" target="_blank" class="post-detail-link">
                                    在小红书查看完整内容 →
                                </a>
                            </div>
                        </div>
                    `;

                    let modal = document.getElementById('postDetailModal');
                    if (!modal) {{
                        modal = document.createElement('div');
                        modal.id = 'postDetailModal';
                        modal.className = 'post-detail-modal';
                        modal.onclick = closePostDetail;
                        document.body.appendChild(modal);
                    }}

                    modal.innerHTML = modalHtml;
                    modal.classList.add('active');
                    document.body.style.overflow = 'hidden';
                }} catch (e) {{
                    console.error('解析帖子数据失败:', e);
                }}
            }}

            function closePostDetail(event) {{
                if (event && event.target !== event.currentTarget) return;

                const modal = document.getElementById('postDetailModal');
                if (modal) {{
                    modal.classList.remove('active');
                    document.body.style.overflow = '';
                }}
            }}

            function moveImage(postId, direction) {{
                var carousel = document.querySelector(`[data-post-id="${{postId}}"]`);
                var track = document.getElementById(postId + '-track');
                var totalImages = parseInt(carousel.getAttribute('data-total-images'));

                if (!carousel.currentIndex) {{
                    carousel.currentIndex = 0;
                }}

                carousel.currentIndex = (carousel.currentIndex + direction + totalImages) % totalImages;
                track.style.transform = `translateX(-${{carousel.currentIndex * 100}}%)`;

                updateIndicators(postId, carousel.currentIndex);
            }}

            function jumpToImage(postId, index) {{
                var carousel = document.querySelector(`[data-post-id="${{postId}}"]`);
                var track = document.getElementById(postId + '-track');

                carousel.currentIndex = index;
                track.style.transform = `translateX(-${{index * 100}}%)`;

                updateIndicators(postId, index);
            }}

            function updateIndicators(postId, activeIndex) {{
                var indicators = document.querySelectorAll(`#${{postId}}-indicators .indicator`);
                indicators.forEach((indicator, i) => {{
                    if (i === activeIndex) {{
                        indicator.classList.add('active');
                    }} else {{
                        indicator.classList.remove('active');
                    }}
                }});
            }}

            // 目录激活状态追踪
            function updateTocActiveState() {{
                const rightContent = document.querySelector('.right-content');
                if (!rightContent) return;

                // 找到当前激活的view
                const activeView = document.querySelector('.content-view[style*="display: block"], .content-view:not([style*="display: none"])');
                if (!activeView) return;

                // 在激活的view中查找所有sections
                const sections = activeView.querySelectorAll('[id]');
                const tocItems = document.querySelectorAll('.toc-item');

                let currentActive = null;
                let maxVisibility = 0;

                // 找到当前在视口中最visible的section
                sections.forEach(section => {{
                    if (!section.id) return;

                    const rect = section.getBoundingClientRect();
                    const sectionTop = rect.top;
                    const sectionBottom = rect.bottom;
                    const windowHeight = window.innerHeight;

                    // 计算section在视口中的可见度
                    if (sectionTop < windowHeight && sectionBottom > 0) {{
                        const visibleTop = Math.max(sectionTop, 0);
                        const visibleBottom = Math.min(sectionBottom, windowHeight);
                        const visibility = visibleBottom - visibleTop;

                        // 优先选择顶部在视口上半部分的section
                        if (sectionTop < windowHeight / 2 && visibility > maxVisibility) {{
                            maxVisibility = visibility;
                            currentActive = section.id;
                        }}
                    }}
                }});

                // 更新目录项的激活状态
                tocItems.forEach(item => {{
                    // 移除所有激活状态和祖先状态
                    item.classList.remove('active');
                    item.classList.remove('active-ancestor');

                    const onclick = item.getAttribute('onclick');
                    if (!onclick) return;

                    // 检查是否匹配当前活动section
                    if (currentActive && onclick.includes(currentActive)) {{
                        item.classList.add('active');

                        // 标记所有祖先节点
                        let parent = item.parentElement;
                        while (parent) {{
                            if (parent.classList && parent.classList.contains('toc-item')) {{
                                parent.classList.add('active-ancestor');
                            }}
                            parent = parent.parentElement;
                        }}
                    }}
                }});

                // 更新面包屑导航
                updateBreadcrumb(currentActive);
            }}

            // 更新面包屑导航（只显示右侧内容层级，不显示帖子信息）
            function updateBreadcrumb(currentSectionId) {{
                const breadcrumbPoint = document.getElementById('breadcrumb-point');
                const breadcrumbStep = document.getElementById('breadcrumb-step');
                const breadcrumbFeature = document.getElementById('breadcrumb-feature');
                const breadcrumbLevel = document.getElementById('breadcrumb-level');
                const breadcrumbSubgroup = document.getElementById('breadcrumb-subgroup');

                const sep1 = document.getElementById('sep-1');
                const sep2 = document.getElementById('sep-2');
                const sep3 = document.getElementById('sep-3');
                const sep4 = document.getElementById('sep-4');

                // 隐藏所有可选元素
                [breadcrumbStep, breadcrumbFeature, breadcrumbLevel, breadcrumbSubgroup, sep1, sep2, sep3, sep4].forEach(el => {{
                    if (el) el.style.display = 'none';
                }});

                if (!currentSectionId) {{
                    breadcrumbPoint.textContent = '-';
                    return;
                }}

                // 从当前section找到所在的view
                let currentView = null;
                const allViews = document.querySelectorAll('.content-view');
                allViews.forEach(view => {{
                    if (view.style.display !== 'none' && view.querySelector('#' + currentSectionId)) {{
                        currentView = view;
                    }}
                }});

                if (!currentView) return;

                // 从view ID解析信息: view-post-0-point-灵感点列表-0
                const viewId = currentView.id;
                const viewMatch = viewId.match(/view-post-(\d+)-point-(.+?)-(\d+)/);

                if (viewMatch) {{
                    const postIdx = viewMatch[1];
                    const pointType = viewMatch[2].replace('列表', '');
                    const pointIdx = parseInt(viewMatch[3]);

                    // 1. 点信息（总是显示）
                    const pointElement = currentView.querySelector('.inspiration-detail-card .inspiration-name');
                    const pointName = pointElement ? pointElement.textContent : `${{pointType}} ${{pointIdx + 1}}`;
                    breadcrumbPoint.textContent = `${{pointType}} ${{pointIdx + 1}}: ${{pointName.substring(0, 20)}}${{pointName.length > 20 ? '...' : ''}}`;
                    breadcrumbPoint.onclick = function() {{
                        showContentView(viewId, this);
                        const rightContent = document.querySelector('.right-content');
                        if (rightContent) rightContent.scrollTo({{ top: 0, behavior: 'smooth' }});
                    }};

                    // 2. 步骤信息（如果在步骤section中）
                    if (currentSectionId.includes('step')) {{
                        const stepMatch = currentSectionId.match(/step-\d+-(\d+)/);
                        if (stepMatch) {{
                            sep1.style.display = 'inline';
                            breadcrumbStep.style.display = 'inline';
                            breadcrumbStep.textContent = `步骤 ${{parseInt(stepMatch[1]) + 1}}`;
                            breadcrumbStep.onclick = function() {{
                                const el = document.getElementById(currentSectionId);
                                if (el) el.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                            }};
                        }}
                    }}

                    // 3. 特征信息（如果在特征相关section中）
                    if (currentSectionId.includes('feat')) {{
                        const featMatch = currentSectionId.match(/feat-(\d+)-(\d+)/);
                        if (featMatch) {{
                            const featIdx = parseInt(featMatch[2]);

                            // 查找特征名称
                            const featureSection = document.getElementById('post-' + postIdx + '-feat-' + pointIdx + '-' + featIdx);
                            let featureName = `特征 ${{featIdx + 1}}`;
                            if (featureSection) {{
                                const header = featureSection.querySelector('.match-section-header h4');
                                if (header) {{
                                    const match = header.textContent.match(/匹配结果:\s*(.+?)\s*\(/);
                                    if (match) featureName = match[1].substring(0, 15) + (match[1].length > 15 ? '...' : '');
                                }}
                            }}

                            sep2.style.display = 'inline';
                            breadcrumbFeature.style.display = 'inline';
                            breadcrumbFeature.textContent = featureName;
                            breadcrumbFeature.onclick = function() {{
                                if (featureSection) featureSection.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                            }};

                            // 4. 层级分组信息（如果在level section中）
                            if (currentSectionId.includes('level')) {{
                                const levelMatch = currentSectionId.match(/level-(.+?)(?:-|$)/);
                                if (levelMatch) {{
                                    const levelName = levelMatch[1];
                                    const levelElement = document.getElementById(currentSectionId);
                                    let levelTitle = `匹配人设${{levelName}}`;
                                    if (levelElement) {{
                                        const header = levelElement.querySelector('.level-group-title');
                                        if (header) levelTitle = header.textContent.trim();
                                    }}

                                    sep3.style.display = 'inline';
                                    breadcrumbLevel.style.display = 'inline';
                                    breadcrumbLevel.textContent = levelTitle.substring(0, 20);
                                    breadcrumbLevel.onclick = function() {{
                                        if (levelElement) levelElement.scrollIntoView({{ behavior: 'smooth', block: 'start' }});
                                    }};
                                }}
                            }}
                        }}
                    }}
                }}
            }}

            // 监听滚动事件
            document.addEventListener('DOMContentLoaded', function() {{
                // 默认显示第一个视图
                var allViews = document.querySelectorAll('.content-view');
                if (allViews.length > 0) {{
                    // 找到第一个点视图（跳过帖子详情视图）
                    var firstPointView = null;
                    var firstPointViewId = null;
                    for (var i = 0; i < allViews.length; i++) {{
                        if (allViews[i].id.includes('point') && allViews[i].id.includes('灵感点列表')) {{
                            firstPointView = allViews[i];
                            firstPointViewId = allViews[i].id;
                            break;
                        }}
                    }}

                    // 如果有点视图，显示第一个点；否则显示第一个帖子详情
                    var defaultView = firstPointView || allViews[0];
                    defaultView.style.display = 'block';
                    defaultView.classList.add('active');

                    // 展开第一个帖子
                    var firstPost = document.querySelector('.toc-post-header');
                    if (firstPost) {{
                        firstPost.classList.remove('collapsed');
                        var postIdx = firstPost.getAttribute('data-post-id');
                        var postChildren = document.getElementById('toc-post-' + postIdx + '-children');
                        if (postChildren) {{
                            postChildren.classList.remove('hidden');
                        }}
                    }}

                    // 展开第一个灵感点分组
                    var firstInspGroup = document.querySelector('[onclick*="post-0-灵感点列表"]');
                    if (firstInspGroup && firstInspGroup.classList.contains('toc-group-header')) {{
                        firstInspGroup.classList.remove('collapsed');
                        var groupChildren = document.getElementById('toc-post-0-灵感点列表-children');
                        if (groupChildren) {{
                            groupChildren.classList.remove('hidden');
                        }}
                    }}

                    // 展开第一个灵感点
                    var firstPoint = document.querySelector('.toc-level-2[onclick*="view-post-0-point-灵感点列表-0"]');
                    if (firstPoint) {{
                        firstPoint.classList.remove('collapsed');
                        var pointId = firstPoint.getAttribute('onclick').match(/toggleTocPoint\(event,\s*'([^']+)'/);
                        if (pointId && pointId[1]) {{
                            var pointChildren = document.getElementById('toc-' + pointId[1] + '-children');
                            if (pointChildren) {{
                                pointChildren.classList.remove('hidden');
                            }}
                        }}
                    }}

                    // 激活对应的目录项
                    if (firstPointViewId) {{
                        // 找到对应的目录项并添加active类
                        var tocItems = document.querySelectorAll('.toc-item');
                        tocItems.forEach(function(item) {{
                            var onclick = item.getAttribute('onclick');
                            if (onclick && onclick.includes(firstPointViewId)) {{
                                item.classList.add('active');

                                // 标记祖先节点
                                var parent = item.parentElement;
                                while (parent) {{
                                    if (parent.classList && parent.classList.contains('toc-item')) {{
                                        parent.classList.add('active-ancestor');
                                    }}
                                    parent = parent.parentElement;
                                }}
                            }}
                        }});
                    }}
                }}

                const rightContent = document.querySelector('.right-content');
                if (rightContent) {{
                    rightContent.addEventListener('scroll', function() {{
                        // 使用节流避免频繁触发
                        if (this.scrollTimeout) clearTimeout(this.scrollTimeout);
                        this.scrollTimeout = setTimeout(updateTocActiveState, 50);
                    }});

                    // 初始化时更新一次
                    updateTocActiveState();
                }}
            }});
        </script>
    </body>
    </html>
    '''
    return html


def minify_html(html: str) -> str:
    """压缩HTML，去除多余空格和换行"""
    import re

    # 保护script和style标签内容
    scripts = []
    styles = []

    def save_script(match):
        scripts.append(match.group(0))
        return f"___SCRIPT_{len(scripts)-1}___"

    def save_style(match):
        styles.append(match.group(0))
        return f"___STYLE_{len(styles)-1}___"

    # 保存script和style
    html = re.sub(r'<script[^>]*>.*?</script>', save_script, html, flags=re.DOTALL)
    html = re.sub(r'<style[^>]*>.*?</style>', save_style, html, flags=re.DOTALL)

    # 去除HTML注释
    html = re.sub(r'<!--.*?-->', '', html, flags=re.DOTALL)

    # 去除多余空格和换行
    html = re.sub(r'\s+', ' ', html)
    html = re.sub(r'>\s+<', '><', html)

    # 恢复script和style
    for i, script in enumerate(scripts):
        html = html.replace(f"___SCRIPT_{i}___", script)
    for i, style in enumerate(styles):
        html = html.replace(f"___STYLE_{i}___", style)

    return html.strip()


def main():
    """主函数"""
    # 使用路径配置
    config = PathConfig()

    # 确保输出目录存在
    config.ensure_dirs()

    # 获取路径
    input_dir = config.how_results_dir
    output_file = config.visualization_file

    print(f"账号: {config.account_name}")
    print(f"输入目录: {input_dir}")
    print(f"输出文件: {output_file}")
    print()

    print(f"读取 how 解构结果: {input_dir}")

    # 加载特征分类映射
    print(f"加载特征分类映射...")
    category_mapping = load_feature_category_mapping(config)
    print(f"已加载 {sum(len(v) for v in category_mapping.values())} 个特征分类")

    # 加载特征来源映射
    print(f"加载特征来源映射...")
    source_mapping = load_feature_source_mapping(config)
    print(f"已加载 {len(source_mapping)} 个特征的来源信息")

    json_files = list(input_dir.glob("*_how.json"))
    print(f"找到 {len(json_files)} 个文件\n")

    posts_data = []
    for i, file_path in enumerate(json_files, 1):
        print(f"读取文件 [{i}/{len(json_files)}]: {file_path.name}")
        with open(file_path, "r", encoding="utf-8") as f:
            post_data = json.load(f)
            posts_data.append(post_data)

    print(f"\n生成合并的 HTML...")
    html_content = generate_combined_html(posts_data, category_mapping, source_mapping)

    # 保存原始版本
    print(f"保存原始HTML到: {output_file}")
    with open(output_file, "w", encoding="utf-8") as f:
        f.write(html_content)

    original_size = len(html_content) / 1024 / 1024
    print(f"原始HTML大小: {original_size:.1f} MB")

    # 压缩HTML
    print(f"\n压缩HTML...")
    minified_html = minify_html(html_content)

    minified_file = data_dir / "当前帖子_how解构结果_可视化.min.html"
    print(f"保存压缩HTML到: {minified_file}")
    with open(minified_file, "w", encoding="utf-8") as f:
        f.write(minified_html)

    minified_size = len(minified_html) / 1024 / 1024
    print(f"压缩HTML大小: {minified_size:.1f} MB (减少 {(1 - minified_size/original_size)*100:.1f}%)")

    # Gzip压缩
    import gzip
    print(f"\n生成Gzip压缩版本...")
    gzip_file = data_dir / "当前帖子_how解构结果_可视化.html.gz"
    with gzip.open(gzip_file, "wb") as f:
        f.write(minified_html.encode('utf-8'))

    gzip_size = gzip_file.stat().st_size / 1024 / 1024
    print(f"Gzip压缩大小: {gzip_size:.1f} MB (比原始减少 {(1 - gzip_size/original_size)*100:.1f}%)")

    print(f"\n完成! 生成了3个版本:")
    print(f"1. 原始版本: {output_file} ({original_size:.1f} MB)")
    print(f"2. 压缩版本: {minified_file} ({minified_size:.1f} MB)")
    print(f"3. Gzip版本: {gzip_file} ({gzip_size:.1f} MB)")
    print(f"\n建议分享: {gzip_file.name} (浏览器可直接打开)")


if __name__ == "__main__":
    main()
