{% extends "base.html" %}
{% load static %}

{% block title %}AgomTradePro - 决策工作台{% endblock %}

{% block extra_css %}
<link rel="stylesheet" href="{% static 'css/decision-workspace.css' %}">
<style>
/* 6-Step Funnel Styles */
.funnel-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px 0;
}

.funnel-header {
    text-align: center;
    margin-bottom: 30px;
}

.workspace-shell {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}

.workspace-sidebar {
    display: flex;
    flex-direction: column;
    gap: 16px;
    position: sticky;
    top: 20px;
}

.workspace-sidebar-card {
    background: var(--color-card-bg, #ffffff);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    box-shadow: var(--shadow-sm);
    padding: 20px;
}

.workspace-sidebar-title {
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 12px;
    color: var(--color-text-primary);
}

.workspace-sidebar-subtitle {
    color: var(--color-text-secondary);
    font-size: 13px;
    line-height: 1.6;
}

.workspace-kpi-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    margin-top: 16px;
}

.workspace-kpi {
    background: var(--color-bg-secondary, #f8fafc);
    border-radius: 12px;
    padding: 12px;
}

.workspace-kpi-label {
    display: block;
    font-size: 12px;
    color: var(--color-text-secondary);
    margin-bottom: 6px;
}

.workspace-kpi-value {
    font-size: 16px;
    font-weight: 700;
    color: var(--color-text-primary);
}

.workspace-position-list {
    list-style: none;
    padding: 0;
    margin: 14px 0 0 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.workspace-position-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--color-border);
}

.workspace-position-item:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.workspace-position-code {
    font-weight: 600;
    color: var(--color-text-primary);
}

.workspace-position-meta {
    font-size: 12px;
    color: var(--color-text-secondary);
}

.workspace-freshness-panel {
    margin-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.workspace-freshness-card {
    border: 1px solid #d8e1ea;
    border-radius: 12px;
    padding: 12px 14px;
    background: #f8fbfd;
}

.workspace-freshness-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
}

.workspace-freshness-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--color-text-primary);
}

.workspace-freshness-badge {
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    padding: 3px 8px;
    font-size: 11px;
    font-weight: 700;
}

.workspace-freshness-badge-success {
    background: #e8f7ee;
    color: #217346;
}

.workspace-freshness-badge-warning {
    background: #fff3dd;
    color: #9a6220;
}

.workspace-freshness-badge-danger {
    background: #fdecec;
    color: #b42318;
}

.workspace-freshness-meta {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px 12px;
    font-size: 12px;
    color: var(--color-text-secondary);
}

.workspace-freshness-note {
    margin-top: 8px;
    font-size: 12px;
    color: var(--color-text-secondary);
    line-height: 1.5;
}

.workspace-exit-summary {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 12px;
}

.workspace-exit-pill {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border-radius: 999px;
    background: #ecf1f8;
    color: #425164;
    font-size: 12px;
    font-weight: 700;
}

.workspace-exit-pill-urgent {
    background: #ffe7e7;
    color: #a33434;
}

.workspace-exit-pill-sell {
    background: #ffecec;
    color: #b42318;
}

.workspace-exit-pill-reduce {
    background: #fff0d9;
    color: #9a6220;
}

.workspace-exit-card {
    border: 1px solid #dde6f0;
    border-radius: 14px;
    background: #fbfcfe;
    padding: 12px;
}

.workspace-exit-card + .workspace-exit-card {
    margin-top: 10px;
}

.workspace-exit-card.is-selected {
    border-color: #3756a4;
    box-shadow: 0 0 0 2px rgba(55, 86, 164, 0.12);
}

.workspace-exit-head {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 8px;
}

.workspace-exit-code {
    font-weight: 700;
    color: var(--color-text-primary);
}

.workspace-exit-badge {
    border-radius: 999px;
    padding: 3px 8px;
    font-size: 11px;
    font-weight: 700;
    background: #eef3ff;
    color: #3756a4;
}

.workspace-exit-badge-sell {
    background: #ffe4e4;
    color: #a33434;
}

.workspace-exit-badge-reduce {
    background: #fff1d8;
    color: #9a6220;
}

.workspace-exit-badge-hold {
    background: #edf6ea;
    color: #2c6f3c;
}

.workspace-exit-meta,
.workspace-exit-note {
    font-size: 12px;
    color: var(--color-text-secondary);
    line-height: 1.6;
}

.workspace-exit-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 10px;
}

.workspace-exit-actions a {
    font-size: 12px;
    font-weight: 600;
    color: #164ca1;
    text-decoration: none;
}

.workspace-exit-actions a:hover {
    text-decoration: underline;
}

.workspace-main {
    min-width: 0;
}

.funnel-title {
    font-size: 28px;
    font-weight: 700;
    color: var(--color-text-primary);
    margin-bottom: 8px;
}

.funnel-subtitle {
    color: var(--color-text-secondary);
    font-size: 14px;
}

.funnel-stepper {
    display: flex;
    justify-content: space-between;
    margin-bottom: 40px;
    position: relative;
    isolation: isolate;
    background: var(--color-card-bg, #ffffff);
    padding: 20px;
    border-radius: 16px;
    box-shadow: var(--shadow-sm);
}

.funnel-stepper::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 40px;
    right: 40px;
    height: 2px;
    background: var(--color-border);
    z-index: 0;
    pointer-events: none;
}

.step-button {
    position: relative;
    z-index: 1;
    background: var(--color-card-bg, #ffffff);
    border: 2px solid var(--color-border);
    border-radius: 20px;
    padding: 8px 16px;
    font-weight: 600;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    gap: 8px;
}

.step-button::before {
    content: '';
    position: absolute;
    inset: 2px;
    border-radius: 999px;
    background: var(--color-card-bg, #ffffff);
    z-index: 0;
}

.step-button > span {
    position: relative;
    z-index: 1;
}

.step-button.completed {
    background: #f0fdf4;
    border-color: #22c55e;
    color: #166534;
}

.step-button.completed::before {
    background: #f0fdf4;
}

.step-button.active {
    background: #eff6ff;
    border-color: #3b82f6;
    color: #1e3a8a;
    box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
}

.step-button.active::before {
    background: #eff6ff;
}

.step-button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.step-number {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--color-bg-secondary, #f1f5f9);
    font-size: 12px;
}

.step-button.completed .step-number {
    background: #22c55e;
    color: white;
}

.step-button.active .step-number {
    background: #3b82f6;
    color: white;
}

.funnel-content-area {
    background: var(--color-card-bg, #ffffff);
    border-radius: 16px;
    box-shadow: var(--shadow-sm);
    padding: 30px;
    min-height: 400px;
}

.funnel-next-panel {
    position: sticky;
    bottom: 0;
    z-index: 20;
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin: 30px -30px -30px;
    padding: 14px 30px;
    border-top: 1px solid var(--color-border);
    background: rgba(255, 255, 255, 0.96);
    box-shadow: 0 -8px 20px rgba(15, 23, 42, 0.08);
    backdrop-filter: blur(8px);
}

.funnel-next-spacer {
    flex-grow: 1;
}

/* Spinner for HTMX loading */
.htmx-indicator {
    display: none;
    text-align: center;
    padding: 40px;
}
.htmx-request .htmx-indicator {
    display: block;
}
.htmx-request.htmx-indicator {
    display: block;
}

@media (max-width: 1100px) {
    .workspace-shell {
        grid-template-columns: 1fr;
    }

    .workspace-sidebar {
        position: static;
    }
}
</style>
{% endblock %}

{% block content %}
<div class="funnel-container" x-data="decisionFunnel()">
    
    <div class="funnel-header">
                    <h1 class="funnel-title">投资决策工作台</h1>
                    <p class="funnel-subtitle">统一工作流：从宏观环境评估到推荐筛选，生成账户级交易计划并审批执行。</p>
    </div>

    <div class="workspace-shell">
        <aside class="workspace-sidebar">
            <div class="workspace-sidebar-card">
                <div class="workspace-sidebar-title">决策账户</div>
                <p class="workspace-sidebar-subtitle">页面级直接切换账户。后续推荐、审批和冲突都按该账户口径刷新。</p>
                <select id="workspace-account-selector" name="account_id" class="form-select" style="width: 100%; margin-top: 14px;" onchange="handleWorkspaceAccountChange()">
                    <option value="">加载账户中...</option>
                </select>
            </div>

            <div class="workspace-sidebar-card">
                <div class="workspace-sidebar-title">账户现状</div>
                <div style="display: flex; justify-content: space-between; align-items: center; gap: 12px;">
                    <div>
                        <div style="font-weight: 700; color: var(--color-text-primary);" data-workspace-account-name>默认账户</div>
                        <div id="workspace-account-meta" class="workspace-sidebar-subtitle">等待账户加载</div>
                    </div>
                    <span id="workspace-account-status" class="badge badge-neutral">未加载</span>
                </div>

                <div class="workspace-kpi-grid">
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">总资产</span>
                        <span class="workspace-kpi-value" id="workspace-total-value">-</span>
                    </div>
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">现金</span>
                        <span class="workspace-kpi-value" id="workspace-cash-value">-</span>
                    </div>
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">持仓市值</span>
                        <span class="workspace-kpi-value" id="workspace-market-value">-</span>
                    </div>
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">收益率</span>
                        <span class="workspace-kpi-value" id="workspace-return-value">-</span>
                    </div>
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">持仓数</span>
                        <span class="workspace-kpi-value" id="workspace-position-count">-</span>
                    </div>
                    <div class="workspace-kpi">
                        <span class="workspace-kpi-label">最大回撤</span>
                        <span class="workspace-kpi-value" id="workspace-drawdown-value">-</span>
                    </div>
                </div>
            </div>

            <div class="workspace-sidebar-card">
                <div class="workspace-sidebar-title">当前持仓摘要</div>
                <ul id="workspace-position-list" class="workspace-position-list">
                    <li class="workspace-sidebar-subtitle">等待账户加载</li>
                </ul>
            </div>

            <div class="workspace-sidebar-card">
                <div class="workspace-sidebar-title">退出链路</div>
                <p class="workspace-sidebar-subtitle">统一退出建议、调仓计划与信号契约的当前卖出跟踪入口。</p>
                {% if workspace_exit_watch_summary.total %}
                <div class="workspace-exit-summary">
                    <span class="workspace-exit-pill workspace-exit-pill-urgent">立即处理 {{ workspace_exit_watch_summary.urgent_count|default:0 }}</span>
                    <span class="workspace-exit-pill workspace-exit-pill-sell">SELL {{ workspace_exit_watch_summary.sell_count|default:0 }}</span>
                    <span class="workspace-exit-pill workspace-exit-pill-reduce">REDUCE {{ workspace_exit_watch_summary.reduce_count|default:0 }}</span>
                    <span class="workspace-exit-pill">HOLD {{ workspace_exit_watch_summary.hold_count|default:0 }}</span>
                </div>
                {% endif %}
                {% if workspace_selected_exit_item %}
                <div class="workspace-exit-card is-selected" style="margin-top: 14px;">
                    <div class="workspace-exit-head">
                        <span class="workspace-exit-code">{{ workspace_selected_exit_item.asset_code }}</span>
                        {% if workspace_selected_exit_item.asset_name %}<span>{{ workspace_selected_exit_item.asset_name }}</span>{% endif %}
                        <span class="workspace-exit-badge workspace-exit-badge-{{ workspace_selected_exit_item.exit_action|lower }}">{{ workspace_selected_exit_item.exit_action_label }}</span>
                    </div>
                    <div class="workspace-exit-meta">
                        账户 {{ workspace_selected_exit_item.account_name }} · {{ workspace_selected_exit_item.decision_side_label }} · {{ workspace_selected_exit_item.contract_status_label }}
                    </div>
                    <div class="workspace-exit-note">
                        {{ workspace_selected_exit_item.exit_reason_text|default:"当前未触发退出动作。" }}
                    </div>
                    <div class="workspace-exit-actions">
                        <a href="{{ workspace_selected_exit_item.decision_workspace_url }}">停留在当前工作台</a>
                        <a href="{{ workspace_selected_exit_item.dashboard_detail_url }}">回到 Dashboard 右侧详情</a>
                        {% if workspace_selected_exit_item.transition_plan_detail_url %}
                        <a href="{{ workspace_selected_exit_item.transition_plan_detail_url }}" target="_blank" rel="noopener">调仓计划 API</a>
                        {% endif %}
                    </div>
                </div>
                {% endif %}
                {% if workspace_exit_watchlist %}
                <div style="margin-top: 12px;">
                    {% for item in workspace_exit_watchlist %}
                    <div class="workspace-exit-card{% if item.is_selected %} is-selected{% endif %}">
                        <div class="workspace-exit-head">
                            <span class="workspace-exit-code">{{ item.asset_code }}</span>
                            <span class="workspace-exit-badge workspace-exit-badge-{{ item.exit_action|lower }}">{{ item.exit_action }}</span>
                            <span>{{ item.priority_label }}</span>
                        </div>
                        <div class="workspace-exit-meta">{{ item.account_name }} · {{ item.exit_source }}</div>
                        <div class="workspace-exit-note">{{ item.invalidation_summary }}</div>
                        <div class="workspace-exit-actions">
                            <a href="{{ item.decision_workspace_url }}">在 Workspace 中定位</a>
                            <a href="{{ item.dashboard_detail_url }}">回到 Dashboard 右侧详情</a>
                        </div>
                    </div>
                    {% endfor %}
                </div>
                {% else %}
                <ul class="workspace-position-list">
                    <li class="workspace-sidebar-subtitle">当前没有需要跟踪的退出项。</li>
                </ul>
                {% endif %}
            </div>

            <div class="workspace-sidebar-card">
                <div class="workspace-sidebar-title">口径说明</div>
                <p class="workspace-sidebar-subtitle">
                    Step 1-3 会显示当前账户上下文，但分析结论仍是系统级宏观口径；
                    Step 4-6 的推荐、交易计划和审批执行才真正按账户决策口径刷新。
                </p>
            </div>
        </aside>

        <div class="workspace-main">
            <!-- Stepper Navigation -->
            <div class="funnel-stepper">
                <template x-for="step in steps" :key="step.n">
                    <button 
                        class="step-button"
                        :class="{
                            'active': currentStep === step.n, 
                            'completed': step.n < currentStep
                        }"
                        :disabled="step.n > maxReached"
                        @click="goToStep(step.n)"
                    >
                        <span class="step-number" x-text="step.n < currentStep ? '✓' : step.n"></span>
                        <span x-text="step.label"></span>
                    </button>
                </template>
            </div>

            <!-- Content Area loaded via HTMX -->
            <div class="funnel-content-area">
                <div id="funnel-loading-indicator" class="htmx-indicator">
                    <div class="app-spinner"></div>
                    <p>正在加载上下文...</p>
                </div>
                
                <!-- Step 1 Container -->
                <div x-show="currentStep === 1" 
                     id="step-1-container"
                     hx-get="/api/decision/context/step1/" 
                     hx-include="#workspace-account-selector"
                     hx-trigger="load, stepChanged1 from:body" 
                     hx-target="#step-1-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-1-content"></div>
                </div>

                <!-- Step 2 Container -->
                <div x-show="currentStep === 2" 
                     id="step-2-container"
                     hx-get="/api/decision/context/step2/" 
                     hx-include="#workspace-account-selector"
                     hx-trigger="stepChanged2 from:body" 
                     hx-target="#step-2-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-2-content"></div>
                </div>

                <!-- Step 3 Container -->
                <div x-show="currentStep === 3" 
                     id="step-3-container"
                     hx-get="/api/decision/context/step3/" 
                     hx-include="#workspace-account-selector"
                     hx-trigger="stepChanged3 from:body" 
                     hx-target="#step-3-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-3-content"></div>
                </div>

                <!-- Step 4 Container (Unified Recommendations list) -->
                <div x-show="currentStep === 4" 
                     id="step-4-container"
                     hx-get="/api/decision/context/step4/" 
                     hx-include="#workspace-account-selector"
                     hx-trigger="stepChanged4 from:body" 
                     hx-target="#step-4-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-4-content"></div>
                </div>

                <!-- Step 5 Container (Transition Plan) -->
                <div x-show="currentStep === 5" 
                     id="step-5-container"
                     hx-get="/api/decision/context/step5/" 
                     hx-include="#workspace-account-selector"
                     hx-trigger="stepChanged5 from:body" 
                     hx-target="#step-5-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-5-content"></div>
                </div>

                <!-- Step 6 Container (Approval & Execution) -->
                <div x-show="currentStep === 6" 
                     id="step-6-container"
                     hx-get="/api/decision/context/step6/" 
                     hx-trigger="stepChanged6 from:body" 
                     hx-target="#step-6-content"
                     hx-indicator="#funnel-loading-indicator">
                    <div id="step-6-content"></div>
                </div>
                
                <!-- Next Step Control Panel -->
                <div class="funnel-next-panel">
                    <button class="btn btn-outline" x-show="currentStep > 1" @click="goToStep(currentStep - 1)">
                        ← 返回上一步
                    </button>
                    <div class="funnel-next-spacer"></div>
                    <button class="btn btn-primary" x-show="currentStep < 6" @click="progressToNextStep()">
                        <span x-text="'进入 ' + getNextStepName() + ' →'"></span>
                    </button>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
document.addEventListener('alpine:init', () => {
    Alpine.data('decisionFunnel', () => ({
        currentStep: 1,
        maxReached: 1,
        steps: [
            { n: 1, label: '环境评估' },
            { n: 2, label: '方向选择' },
            { n: 3, label: '板块偏好' },
            { n: 4, label: '推优筛选' },
            { n: 5, label: '交易计划' },
            { n: 6, label: '审批执行' }
        ],
        
        async init() {
            window.decisionFunnelState = this;
            const params = new URLSearchParams(window.location.search);
            const requestedStep = parseInt(params.get('step'));

            if (window.initializeDecisionWorkspace) {
                await window.initializeDecisionWorkspace();
            }

            if (requestedStep && requestedStep >= 1 && requestedStep <= 6) {
                const targetStep = normalizeDecisionStepRequest(requestedStep);
                this.maxReached = Math.max(this.maxReached, targetStep);
                this.currentStep = targetStep;
                this.$nextTick(() => {
                    document.body.dispatchEvent(new Event(`stepChanged${this.currentStep}`));
                });
                if (targetStep !== requestedStep) {
                    window.showToast(getDecisionStepGuardMessage(requestedStep), 'warning');
                }
            }
        },

        goToStep(stepNum) {
            syncDecisionFunnelGuardrails();
            const targetStep = normalizeDecisionStepRequest(stepNum);
            if (targetStep !== stepNum) {
                window.showToast(getDecisionStepGuardMessage(stepNum), 'warning');
            }
            if (targetStep <= this.maxReached) {
                this.currentStep = targetStep;
                document.body.dispatchEvent(new Event(`stepChanged${this.currentStep}`));
            }
        },

        progressToNextStep() {
            if (this.currentStep < 6) {
                const nextStep = this.currentStep + 1;
                if (!canAccessDecisionStep(nextStep)) {
                    window.showToast(getDecisionStepGuardMessage(nextStep), 'warning');
                    return;
                }
                this.currentStep = nextStep;
                if (this.currentStep > this.maxReached) {
                    this.maxReached = this.currentStep;
                }
                document.body.dispatchEvent(new Event(`stepChanged${this.currentStep}`));
            }
        },
        
        getNextStepName() {
            if (this.currentStep < 6) {
                return this.steps[this.currentStep].label;
            }
            return '';
        }
    }));
});
</script>

<div id="approvalModal" class="modal-overlay">
    <div class="modal-container approval-modal">
        <div class="modal-header">
            <h3>推荐详情与风控预览</h3>
            <button class="modal-close" onclick="closeApprovalModal()">×</button>
        </div>
        <div class="modal-body">
            <!-- 推荐标识 -->
            <div class="approval-section">
                <h4 class="section-label">推荐信息</h4>
                <div class="info-grid">
                    <div class="info-item">
                        <span class="info-label">推荐ID:</span>
                        <span class="info-value" id="modal-recommendation-id">-</span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">证券:</span>
                        <span class="info-value" id="modal-security-code">-</span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">方向:</span>
                        <span class="info-value direction" id="modal-side">-</span>
                    </div>
                    <div class="info-item">
                        <span class="info-label">置信度:</span>
                        <span class="info-value" id="modal-confidence">-</span>
                    </div>
                </div>
            </div>

            <!-- 估值与价格区间 -->
            <div class="approval-section">
                <h4 class="section-label">估值与价格区间</h4>
                <div class="price-grid">
                    <div class="price-item">
                        <span class="price-label">公允价值</span>
                        <span class="price-value" id="modal-fair-value">-</span>
                    </div>
                    <div class="price-item">
                        <span class="price-label">入场区间</span>
                        <span class="price-value" id="modal-entry-range">-</span>
                    </div>
                    <div class="price-item">
                        <span class="price-label">目标区间</span>
                        <span class="price-value" id="modal-target-range">-</span>
                    </div>
                    <div class="price-item">
                        <span class="price-label">止损价格</span>
                        <span class="price-value stop-loss" id="modal-stop-loss">-</span>
                    </div>
                </div>
            </div>

            <!-- 仓位建议 -->
            <div class="approval-section">
                <h4 class="section-label">仓位建议</h4>
                <div class="position-grid">
                    <div class="position-item">
                        <span class="position-label">建议仓位比例</span>
                        <span class="position-value" id="modal-position-pct">-</span>
                    </div>
                    <div class="position-item">
                        <span class="position-label">建议数量</span>
                        <span class="position-value" id="modal-suggested-qty">-</span>
                    </div>
                    <div class="position-item">
                        <span class="position-label">最大资金</span>
                        <span class="position-value" id="modal-max-capital">-</span>
                    </div>
                </div>
            </div>

            <!-- 风险检查结果 -->
            <div class="approval-section">
                <h4 class="section-label">风险检查</h4>
                <div id="modal-risk-checks" class="risk-checks-list">
                    <div class="risk-check-loading">加载中...</div>
                </div>
            </div>

            <!-- Top-down 信息 -->
            <div class="approval-section">
                <h4 class="section-label">Top-down 分析</h4>
                <div class="topdown-grid">
                    <div class="topdown-item">
                        <span class="topdown-label">当前 Regime:</span>
                        <span class="topdown-value" id="modal-regime">-</span>
                    </div>
                    <div class="topdown-item">
                        <span class="topdown-label">Regime 置信度:</span>
                        <span class="topdown-value" id="modal-regime-confidence">-</span>
                    </div>
                    <div class="topdown-item">
                        <span class="topdown-label">政策档位:</span>
                        <span class="topdown-value" id="modal-policy-level">-</span>
                    </div>
                    <div class="topdown-item">
                        <span class="topdown-label">Beta Gate:</span>
                        <span class="topdown-value" id="modal-beta-gate">-</span>
                    </div>
                </div>
            </div>

            <!-- Bottom-up 分数 -->
            <div class="approval-section">
                <h4 class="section-label">Bottom-up 评分</h4>
                <div class="scores-grid">
                    <div class="score-item">
                        <span class="score-label">Alpha 模型</span>
                        <div class="score-bar">
                            <div class="score-fill" id="modal-alpha-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-alpha-score-value">-</span>
                    </div>
                    <div class="score-item">
                        <span class="score-label">舆情</span>
                        <div class="score-bar">
                            <div class="score-fill" id="modal-sentiment-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-sentiment-score-value">-</span>
                    </div>
                    <div class="score-item">
                        <span class="score-label">资金流向</span>
                        <div class="score-bar">
                            <div class="score-fill" id="modal-flow-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-flow-score-value">-</span>
                    </div>
                    <div class="score-item">
                        <span class="score-label">技术面</span>
                        <div class="score-bar">
                            <div class="score-fill" id="modal-technical-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-technical-score-value">-</span>
                    </div>
                    <div class="score-item">
                        <span class="score-label">基本面</span>
                        <div class="score-bar">
                            <div class="score-fill" id="modal-fundamental-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-fundamental-score-value">-</span>
                    </div>
                    <div class="score-item">
                        <span class="score-label">综合分数</span>
                        <div class="score-bar composite">
                            <div class="score-fill" id="modal-composite-score" style="width: 0%"></div>
                        </div>
                        <span class="score-value" id="modal-composite-score-value">-</span>
                    </div>
                </div>
            </div>

            <!-- 决策理由 -->
            <div class="approval-section">
                <h4 class="section-label">决策理由</h4>
                <div class="reason-codes" id="modal-reason-codes">
                    <!-- 原因代码标签 -->
                </div>
                <p class="human-rationale" id="modal-human-rationale">-</p>
            </div>

            <div class="approval-section">
                <h4 class="section-label">估值修复辅助信息</h4>
                <div class="valuation-repair-panel">
                    <div class="valuation-repair-grid">
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">修复阶段</span>
                            <span class="valuation-repair-value" id="modal-repair-phase">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">信号</span>
                            <span class="valuation-repair-value" id="modal-repair-signal">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">综合分位</span>
                            <span class="valuation-repair-value" id="modal-repair-percentile">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">修复进度</span>
                            <span class="valuation-repair-value" id="modal-repair-progress">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">修复速度</span>
                            <span class="valuation-repair-value" id="modal-repair-speed">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">预计到目标</span>
                            <span class="valuation-repair-value" id="modal-repair-eta">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">修复置信度</span>
                            <span class="valuation-repair-value" id="modal-repair-confidence">-</span>
                        </div>
                        <div class="valuation-repair-item">
                            <span class="valuation-repair-label">数据日期</span>
                            <span class="valuation-repair-value" id="modal-repair-asof">-</span>
                        </div>
                    </div>
                    <div class="valuation-repair-note" id="modal-repair-note">
                        未命中估值修复快照，仅作为可选辅助信息。
                    </div>
                </div>
            </div>

            <div class="approval-section">
                <h4 class="section-label">当前阶段说明</h4>
                <div class="info-note" style="padding: 14px 16px; border-radius: 12px; background: rgba(14, 116, 144, 0.08); color: var(--color-text);">
                    Step 4 仅用于查看推荐细节与风控预览，不会直接创建审批请求。请先将推荐纳入 Step 5 的交易计划，再在 Step 6 发起审批。
                </div>
            </div>
        </div>
        <div class="modal-footer">
            <button class="btn btn-outline" onclick="closeApprovalModal()">关闭</button>
            <button id="queue-plan-btn" class="btn btn-primary" onclick="queueRecommendationForPlan()">纳入计划并前往 Step 5</button>
        </div>
    </div>
</div>

<script>
// ===== 全局状态 =====
const workspaceParams = new URLSearchParams(window.location.search);
let currentRecommendation = null;
let currentWorkspaceRecommendations = [];
let currentTransitionPlanId = workspaceParams.get('plan_id') || '';
let currentPlanApprovalRequestId = '';
let currentTransitionPlanCanEnterApproval = false;
let currentTransitionPlanActiveOrdersCount = 0;
let userAccounts = [];
let workspaceInitialized = false;
const selectedRecommendationIds = new Set();
const recommendationAutoRefreshAttempts = new Set();
const workspaceBridge = {
    source: workspaceParams.get('source') || (workspaceParams.get('execute_request') ? 'alpha-trigger-execute' : ''),
    securityCode: workspaceParams.get('security_code') || workspaceParams.get('asset_code') || '',
    action: workspaceParams.get('action') || workspaceParams.get('direction') || '',
    legacyRequestId: workspaceParams.get('execute_request') || '',
    handled: false,
    highlightedRecommendationId: '',
};
const requestedWorkspaceAccountId = workspaceParams.get('account_id') || '';

function getLatestRecommendationUpdatedAt(recommendations) {
    return (recommendations || []).reduce((latest, recommendation) => {
        const timestamp = recommendation.updated_at || recommendation.created_at;
        if (!timestamp) {
            return latest;
        }
        const parsed = new Date(timestamp);
        if (Number.isNaN(parsed.getTime())) {
            return latest;
        }
        return !latest || parsed > latest ? parsed : latest;
    }, null);
}

function shouldAutoRefreshRecommendations(recommendations) {
    if (!recommendations || recommendations.length === 0) {
        return true;
    }
    const latestUpdatedAt = getLatestRecommendationUpdatedAt(recommendations);
    if (!latestUpdatedAt) {
        return false;
    }
    const todayStart = new Date();
    todayStart.setHours(0, 0, 0, 0);
    return latestUpdatedAt < todayStart;
}

function formatRepairPercent(value) {
    if (value === null || value === undefined || value === '') return '-';
    return `${(Number(value) * 100).toFixed(1)}%`;
}

function formatRepairFloat(value) {
    if (value === null || value === undefined || value === '') return '-';
    return Number(value).toFixed(2);
}

function formatRepairEta(value) {
    if (value === null || value === undefined || value === '') return '-';
    return `${value}d`;
}

function showBridgeBanner(message, tone = 'info') {
    const banner = document.getElementById('recommendation-bridge-banner');
    if (!banner) return;
    banner.className = `bridge-banner bridge-banner-${tone}`;
    banner.textContent = message;
    banner.style.display = 'block';
}

function escapeHtml(value) {
    return String(value ?? '')
        .replaceAll('&', '&amp;')
        .replaceAll('<', '&lt;')
        .replaceAll('>', '&gt;')
        .replaceAll('"', '&quot;')
        .replaceAll("'", '&#39;');
}

function buildEquityDetailUrl(securityCode) {
    const code = String(securityCode || '').trim().toUpperCase();
    return code ? `/equity/detail/${encodeURIComponent(code)}/` : '';
}

function renderSecurityLabel(securityName, securityCode, extraClass = '') {
    const code = String(securityCode || '').trim();
    const name = String(securityName || '').trim();
    const classAttr = extraClass ? ` security-display ${extraClass}` : ' security-display';
    const detailUrl = buildEquityDetailUrl(code);
    const tagName = detailUrl ? 'a' : 'span';
    const hrefAttr = detailUrl ? ` href="${escapeHtml(detailUrl)}" title="打开个股详情"` : '';
    if (!name || name === code) {
        return `<${tagName} class="${classAttr.trim()}"${hrefAttr}><span class="security-display-name">${escapeHtml(code || '-')}</span></${tagName}>`;
    }
    return `
        <${tagName} class="${classAttr.trim()}"${hrefAttr}>
            <span class="security-display-name">${escapeHtml(name)}</span>
            <span class="security-display-code">${escapeHtml(code)}</span>
        </${tagName}>
    `;
}

function parsePriceValue(value) {
    const parsed = Number.parseFloat(String(value ?? '').replace(/,/g, ''));
    return Number.isFinite(parsed) ? parsed : null;
}

function midpointValue(low, high) {
    const lowValue = parsePriceValue(low);
    const highValue = parsePriceValue(high);
    if (lowValue !== null && highValue !== null && lowValue > 0 && highValue > 0) {
        return (lowValue + highValue) / 2;
    }
    if (lowValue !== null && lowValue > 0) {
        return lowValue;
    }
    if (highValue !== null && highValue > 0) {
        return highValue;
    }
    return null;
}

function formatSignedPercent(value) {
    if (!Number.isFinite(value)) {
        return '-';
    }
    const sign = value > 0 ? '+' : '';
    return `${sign}${value.toFixed(1)}%`;
}

function formatDecisionDateTime(value) {
    if (!value) {
        return '';
    }
    const parsed = new Date(value);
    if (Number.isNaN(parsed.getTime())) {
        return String(value);
    }
    return parsed.toLocaleString('zh-CN', {
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
    });
}

function calculateRewardRisk(entryPrice, targetPrice, stopLossPrice) {
    if (!entryPrice || !targetPrice || !stopLossPrice || entryPrice <= 0) {
        return null;
    }
    const upsidePct = ((targetPrice - entryPrice) / entryPrice) * 100;
    const downsidePct = ((entryPrice - stopLossPrice) / entryPrice) * 100;
    if (downsidePct <= 0) {
        return null;
    }
    return {
        upsidePct,
        downsidePct,
        ratio: upsidePct / downsidePct,
    };
}

function normalizeRewardRiskMetrics(contract) {
    if (!contract || typeof contract !== 'object') {
        return null;
    }
    const upsidePct = Number(contract.upside_pct ?? contract.upsidePct);
    const downsidePct = Number(contract.downside_pct ?? contract.downsidePct);
    const ratio = Number(contract.ratio);
    if (!Number.isFinite(upsidePct) || !Number.isFinite(downsidePct) || !Number.isFinite(ratio)) {
        return null;
    }
    return { upsidePct, downsidePct, ratio };
}

function renderRewardRiskPill(metrics) {
    if (!metrics) {
        return `<span class="decision-brief-pill muted">收益风险比 -</span>`;
    }
    const ratioClass = metrics.ratio >= 2 ? 'strong' : metrics.ratio >= 1 ? 'neutral' : 'weak';
    return `
        <span class="decision-brief-pill ${ratioClass}">
            收益风险比 ${metrics.ratio.toFixed(1)}x
            <small>${formatSignedPercent(metrics.upsidePct)} / -${Math.abs(metrics.downsidePct).toFixed(1)}%</small>
        </span>
    `;
}

function renderDataAsOf(dataAsOf) {
    const value = String(dataAsOf || '').trim();
    if (!value) {
        return '';
    }
    return `<span class="decision-brief-asof">数据 ${escapeHtml(formatDecisionDateTime(value))}</span>`;
}

function renderRecommendationDecisionBrief(rec) {
    const reasonCodes = Array.isArray(rec.reason_codes) ? rec.reason_codes : [];
    const rationale = String(rec.human_rationale || reasonCodes.join(', ') || '暂无推荐理由').trim();
    const entryMid = midpointValue(rec.entry_price_low, rec.entry_price_high);
    const targetMid = midpointValue(rec.target_price_low, rec.target_price_high);
    const stopLoss = parsePriceValue(rec.stop_loss_price);
    const rewardRisk = calculateRewardRisk(entryMid, targetMid, stopLoss);
    const riskText = stopLoss
        ? `跌破 ${rec.stop_loss_price} 后重新评估`
        : '缺少止损价，需补齐后再进入执行';
    return `
        <div class="decision-brief">
            <div class="decision-brief-item">
                <span class="decision-brief-label">投资论点</span>
                <strong>${escapeHtml(rationale)}</strong>
            </div>
            <div class="decision-brief-item">
                <span class="decision-brief-label">关键风险</span>
                <strong>${escapeHtml(riskText)}</strong>
            </div>
            <div class="decision-brief-item compact">
                <span class="decision-brief-label">纪律</span>
                ${renderRewardRiskPill(rewardRisk)}
            </div>
        </div>
    `;
}

function renderOrderDecisionBrief(order) {
    const executionPrice = parsePriceValue(order.execution_price);
    const takeProfit = parsePriceValue(order.take_profit_price);
    const stopLoss = parsePriceValue(order.stop_loss_price);
    const rewardRisk = normalizeRewardRiskMetrics(order.reward_risk)
        || calculateRewardRisk(executionPrice, takeProfit, stopLoss);
    const invalidationText = String(order.risk_summary || order.invalidation_description || '').trim();
    const thesis = String(order.thesis || '').trim();
    const fallbackSummary = `${order.action || 'HOLD'} ${order.security_code || ''}，数量变化 ${order.delta_qty ?? '-'}`;
    return `
        <div class="decision-brief decision-brief-plan">
            <div class="decision-brief-item">
                <span class="decision-brief-label">执行摘要</span>
                <strong>${escapeHtml(thesis || fallbackSummary)}</strong>
                ${renderDataAsOf(order.data_asof)}
            </div>
            <div class="decision-brief-item">
                <span class="decision-brief-label">关键风险</span>
                <strong>${escapeHtml(invalidationText || '证伪条件待补充')}</strong>
            </div>
            <div class="decision-brief-item compact">
                <span class="decision-brief-label">纪律</span>
                ${renderRewardRiskPill(rewardRisk)}
            </div>
        </div>
    `;
}

function getUserActionText(action, label = '') {
    const normalizedLabel = String(label || '').trim();
    if (normalizedLabel) {
        return normalizedLabel;
    }
    return {
        PENDING: '待决策',
        WATCHING: '观察中',
        ADOPTED: '已采纳',
        IGNORED: '已忽略',
    }[action] || action || '待决策';
}

function normalizeWorkspaceBridgeUserAction(action) {
    const normalized = String(action || '').trim().toUpperCase();
    return {
        WATCH: 'watch',
        WATCHING: 'watch',
        ADOPT: 'adopt',
        ADOPTED: 'adopt',
        IGNORE: 'ignore',
        IGNORED: 'ignore',
        PENDING: 'pending',
    }[normalized] || '';
}

function getWorkspaceAccountSelector() {
    return document.getElementById('workspace-account-selector');
}

function getSelectedWorkspaceAccountId() {
    return getWorkspaceAccountSelector()?.value || 'default';
}

function getSelectedWorkspaceAccountName() {
    const selector = getWorkspaceAccountSelector();
    if (!selector) {
        return '默认账户';
    }
    const option = selector.options[selector.selectedIndex];
    return option?.textContent?.trim() || '默认账户';
}

function updateWorkspacePlanId(planId) {
    currentTransitionPlanId = planId || '';
    const url = new URL(window.location.href);
    if (currentTransitionPlanId) {
        url.searchParams.set('plan_id', currentTransitionPlanId);
    } else {
        url.searchParams.delete('plan_id');
    }
    window.history.replaceState({}, '', url.toString());
}

function applyTransitionPlanState(plan) {
    currentTransitionPlanId = plan?.plan_id || '';
    currentPlanApprovalRequestId = plan?.approval_request_id || '';
    currentTransitionPlanCanEnterApproval = Boolean(plan?.can_enter_approval);
    currentTransitionPlanActiveOrdersCount = Array.isArray(plan?.orders)
        ? plan.orders.filter(order => order.action !== 'HOLD').length
        : 0;
    updateWorkspacePlanId(currentTransitionPlanId);
    syncDecisionFunnelGuardrails();
}

function getAdoptedRecommendations() {
    return currentWorkspaceRecommendations.filter(rec => rec.user_action === 'ADOPTED');
}

function getEligiblePlanRecommendationIds() {
    const adoptedIds = new Set(getAdoptedRecommendations().map(rec => rec.recommendation_id));
    if (selectedRecommendationIds.size > 0) {
        return Array.from(selectedRecommendationIds).filter(recommendationId => adoptedIds.has(recommendationId));
    }
    return Array.from(adoptedIds);
}

function canAccessDecisionStep(stepNum) {
    if (stepNum <= 4) {
        return true;
    }
    if (stepNum === 5) {
        return Boolean(currentTransitionPlanId) || getEligiblePlanRecommendationIds().length > 0;
    }
    if (stepNum === 6) {
        return Boolean(currentTransitionPlanId && currentPlanApprovalRequestId);
    }
    return false;
}

function getDecisionStepGuardMessage(stepNum) {
    if (stepNum === 5) {
        return 'Step 4 需要至少 1 条已采纳推荐，才能进入交易计划。';
    }
    if (stepNum === 6) {
        return 'Step 6 只接受已提交审批请求的交易计划，请先在 Step 5 完成保存并提交审批。';
    }
    return '当前步骤暂不可进入。';
}

function normalizeDecisionStepRequest(stepNum) {
    if (!Number.isInteger(stepNum) || stepNum < 1 || stepNum > 6) {
        return 1;
    }
    if (stepNum <= 4 || canAccessDecisionStep(stepNum)) {
        return stepNum;
    }
    if (stepNum === 6 && canAccessDecisionStep(5)) {
        return 5;
    }
    return 4;
}

function syncDecisionFunnelGuardrails() {
    const funnel = window.decisionFunnelState;
    if (!funnel) {
        return;
    }
    const normalizedMax = normalizeDecisionStepRequest(Number(funnel.maxReached || 1));
    if (normalizedMax !== funnel.maxReached) {
        funnel.maxReached = normalizedMax;
    }
    const normalizedCurrent = normalizeDecisionStepRequest(Number(funnel.currentStep || 1));
    if (normalizedCurrent !== funnel.currentStep) {
        funnel.currentStep = normalizedCurrent;
        document.body.dispatchEvent(new Event(`stepChanged${normalizedCurrent}`));
    }
}

function syncWorkspaceAccountSummary() {
    const selectedName = getSelectedWorkspaceAccountName();
    document.querySelectorAll('[data-workspace-account-name]').forEach(node => {
        node.textContent = selectedName;
    });
}

function formatWorkspaceCurrency(value) {
    const numericValue = Number(value);
    if (!Number.isFinite(numericValue)) {
        return '-';
    }
    return new Intl.NumberFormat('zh-CN', {
        style: 'currency',
        currency: 'CNY',
        maximumFractionDigits: 0,
    }).format(numericValue);
}

function formatWorkspacePercent(value, digits = 2) {
    const numericValue = Number(value);
    if (!Number.isFinite(numericValue)) {
        return '-';
    }
    return `${numericValue.toFixed(digits)}%`;
}

function setWorkspaceSnapshotValue(id, value) {
    const node = document.getElementById(id);
    if (node) {
        node.textContent = value;
    }
}

function renderWorkspacePositionList(positions, emptyMessage) {
    const list = document.getElementById('workspace-position-list');
    if (!list) {
        return;
    }

    if (!Array.isArray(positions) || positions.length === 0) {
        list.innerHTML = `<li class="workspace-sidebar-subtitle">${escapeHtml(emptyMessage)}</li>`;
        return;
    }

    list.innerHTML = positions.slice(0, 5).map(position => {
        const assetName = position.asset_name || position.asset_code || '-';
        const pnlValue = Number(position.unrealized_pnl_pct);
        const pnlText = formatWorkspacePercent(position.unrealized_pnl_pct);
        const pnlColor = Number.isFinite(pnlValue) && pnlValue < 0
            ? 'var(--color-danger)'
            : 'var(--color-success)';
        return `
            <li class="workspace-position-item">
                <div>
                    <div class="workspace-position-code">${escapeHtml(position.asset_code || '-')}</div>
                    <div class="workspace-position-meta">${escapeHtml(assetName)} · ${position.quantity || 0}股 · 成本 ${formatWorkspaceCurrency(position.avg_cost)}</div>
                </div>
                <div style="text-align: right;">
                    <div class="workspace-position-code">${formatWorkspaceCurrency(position.market_value)}</div>
                    <div class="workspace-position-meta" style="color: ${pnlColor};">浮盈 ${pnlText}</div>
                </div>
            </li>
        `;
    }).join('');
}

function renderWorkspaceDefaultSnapshot() {
    const meta = document.getElementById('workspace-account-meta');
    const status = document.getElementById('workspace-account-status');

    if (meta) {
        meta.textContent = '系统默认口径，未绑定模拟账户快照';
    }
    if (status) {
        status.className = 'badge badge-neutral';
        status.textContent = '系统级';
    }

    setWorkspaceSnapshotValue('workspace-total-value', '-');
    setWorkspaceSnapshotValue('workspace-cash-value', '-');
    setWorkspaceSnapshotValue('workspace-market-value', '-');
    setWorkspaceSnapshotValue('workspace-return-value', '-');
    setWorkspaceSnapshotValue('workspace-position-count', '-');
    setWorkspaceSnapshotValue('workspace-drawdown-value', '-');
    renderWorkspacePositionList([], '默认账户仅展示系统级上下文，不展示持仓快照。');
}

function renderWorkspaceAccountSnapshot(detailData, positionsData) {
    const account = detailData?.account || {};
    const meta = document.getElementById('workspace-account-meta');
    const status = document.getElementById('workspace-account-status');
    const accountTypeText = account.account_type === 'real' ? '实盘账户' : '模拟账户';
    const autoTradingText = account.auto_trading_enabled ? '自动交易开启' : '人工决策模式';

    if (meta) {
        meta.textContent = `${accountTypeText} · ${autoTradingText} · 仓位上限 ${formatWorkspacePercent(account.max_position_pct)}`;
    }
    if (status) {
        status.className = account.is_active ? 'badge badge-success' : 'badge badge-neutral';
        status.textContent = account.is_active ? '运行中' : '已停用';
    }

    setWorkspaceSnapshotValue('workspace-total-value', formatWorkspaceCurrency(account.total_value));
    setWorkspaceSnapshotValue('workspace-cash-value', formatWorkspaceCurrency(account.current_cash));
    setWorkspaceSnapshotValue('workspace-market-value', formatWorkspaceCurrency(account.current_market_value));
    setWorkspaceSnapshotValue('workspace-return-value', formatWorkspacePercent(account.total_return));
    setWorkspaceSnapshotValue(
        'workspace-position-count',
        String(positionsData?.total_positions ?? detailData?.total_positions ?? positionsData?.positions?.length ?? 0)
    );
    setWorkspaceSnapshotValue('workspace-drawdown-value', formatWorkspacePercent(account.max_drawdown));

    renderWorkspacePositionList(
        positionsData?.positions || [],
        '当前账户暂无持仓，可继续使用工作台筛选和审批。'
    );
}

async function loadWorkspaceAccountSnapshot() {
    syncWorkspaceAccountSummary();
    const accountId = getSelectedWorkspaceAccountId();
    if (!accountId || accountId === 'default') {
        renderWorkspaceDefaultSnapshot();
        return;
    }

    const meta = document.getElementById('workspace-account-meta');
    const status = document.getElementById('workspace-account-status');

    if (meta) {
        meta.textContent = '正在同步账户快照...';
    }
    if (status) {
        status.className = 'badge badge-neutral';
        status.textContent = '加载中';
    }
    renderWorkspacePositionList([], '正在加载持仓摘要...');

    try {
        const [detailRes, positionsRes] = await Promise.all([
            fetch(`/api/account/accounts/${encodeURIComponent(accountId)}/`, {
                headers: { 'X-CSRFToken': window.csrfToken }
            }),
            fetch(`/api/account/accounts/${encodeURIComponent(accountId)}/positions/`, {
                headers: { 'X-CSRFToken': window.csrfToken }
            }),
        ]);
        const [detailData, positionsData] = await Promise.all([
            detailRes.json(),
            positionsRes.json(),
        ]);

        if (!detailData?.success) {
            throw new Error(detailData?.error || '账户详情加载失败');
        }
        if (!positionsData?.success) {
            throw new Error(positionsData?.error || '账户持仓加载失败');
        }

        renderWorkspaceAccountSnapshot(detailData, positionsData);
    } catch (error) {
        console.error('加载账户快照失败:', error);
        if (meta) {
            meta.textContent = '账户快照加载失败';
        }
        if (status) {
            status.className = 'badge badge-danger';
            status.textContent = '异常';
        }
        setWorkspaceSnapshotValue('workspace-total-value', '-');
        setWorkspaceSnapshotValue('workspace-cash-value', '-');
        setWorkspaceSnapshotValue('workspace-market-value', '-');
        setWorkspaceSnapshotValue('workspace-return-value', '-');
        setWorkspaceSnapshotValue('workspace-position-count', '-');
        setWorkspaceSnapshotValue('workspace-drawdown-value', '-');
        renderWorkspacePositionList([], `账户快照加载失败: ${error.message}`);
    }
}

function refreshCurrentDecisionStep() {
    const currentStep = Number(window.decisionFunnelState?.currentStep || 1);
    if (currentStep >= 1 && currentStep <= 6) {
        document.body.dispatchEvent(new Event(`stepChanged${currentStep}`));
    }
}

function refreshWorkspaceDecisionLists() {
    loadRecommendations();
    loadApprovals();
    loadConflicts();
    loadTransitionPlanStep();
    loadExecutionPlanPanel();
}

function syncIgnoredRecommendationsFilterButton() {
    const toggleButton = document.getElementById('ignored-filter-toggle');
    const decisionFilter = document.getElementById('decision-filter');
    if (!toggleButton || !decisionFilter) {
        return;
    }

    const ignoredOnly = decisionFilter.value === 'IGNORED';
    toggleButton.className = ignoredOnly ? 'btn btn-primary btn-sm' : 'btn btn-outline btn-sm';
    toggleButton.innerHTML = ignoredOnly ? '<i class="bi bi-eye-slash"></i> 退出已忽略' : '<i class="bi bi-filter"></i> 已忽略';
    toggleButton.setAttribute('aria-pressed', ignoredOnly ? 'true' : 'false');
    toggleButton.title = ignoredOnly ? '切回全部用户动作' : '快捷查看已忽略推荐';
}

function toggleIgnoredRecommendationsFilter() {
    const decisionFilter = document.getElementById('decision-filter');
    if (!decisionFilter) {
        return;
    }

    decisionFilter.value = decisionFilter.value === 'IGNORED' ? '' : 'IGNORED';
    syncIgnoredRecommendationsFilterButton();
    loadRecommendations();
}

function handleWorkspaceAccountChange() {
    const accountId = getSelectedWorkspaceAccountId();
    const url = new URL(window.location.href);
    if (accountId && accountId !== 'default') {
        url.searchParams.set('account_id', accountId);
    } else {
        url.searchParams.delete('account_id');
    }
    selectedRecommendationIds.clear();
    applyTransitionPlanState(null);
    window.history.replaceState({}, '', url.toString());
    loadWorkspaceAccountSnapshot();
    refreshCurrentDecisionStep();
    refreshWorkspaceDecisionLists();
    syncDecisionFunnelGuardrails();
}

async function bootstrapWorkspaceBridge() {
    if (!workspaceBridge.securityCode || workspaceBridge.handled) {
        return;
    }

    const accountId = getSelectedWorkspaceAccountId();
    showBridgeBanner(`正在将 ${workspaceBridge.securityCode} 同步到决策工作台...`);

    try {
        const refreshData = await window.fetchJsonOrThrow('/api/decision/workspace/recommendations/refresh/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                account_id: accountId,
                security_codes: [workspaceBridge.securityCode],
                force: false,
            }),
        });
        if (!refreshData.success) {
            throw new Error(refreshData.error || '刷新失败');
        }

        let listUrl = `/api/decision/workspace/recommendations/?account_id=${encodeURIComponent(accountId)}&security_code=${encodeURIComponent(workspaceBridge.securityCode)}&include_ignored=true`;
        const listData = await window.fetchJsonOrThrow(listUrl, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });
        const targetRecommendation = listData?.data?.recommendations?.[0];

        if (!targetRecommendation) {
            showBridgeBanner(`已触发 ${workspaceBridge.securityCode} 推荐同步，但工作台尚未返回可用推荐。`, 'warning');
            workspaceBridge.handled = true;
            return;
        }

        workspaceBridge.highlightedRecommendationId = targetRecommendation.recommendation_id;

        const bridgeUserAction = normalizeWorkspaceBridgeUserAction(workspaceBridge.action);
        if (bridgeUserAction) {
            const actionData = await window.fetchJsonOrThrow('/api/decision/workspace/recommendations/action/', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'X-CSRFToken': window.csrfToken,
                },
                body: JSON.stringify({
                    recommendation_id: targetRecommendation.recommendation_id,
                    account_id: accountId,
                    action: bridgeUserAction,
                    note: workspaceBridge.source ? `source=${workspaceBridge.source}` : '',
                }),
            });
            if (!actionData.success) {
                throw new Error(actionData.error || '用户动作写入失败');
            }
            showBridgeBanner(`${workspaceBridge.securityCode} 已同步到工作台，并标记为${getUserActionText(actionData.data.recommendation.user_action, actionData.data.recommendation.user_action_label)}。`, 'success');
        } else {
            showBridgeBanner(`${workspaceBridge.securityCode} 已同步到工作台；请先核对退出详情，再选择观察、采纳或忽略。`, 'success');
        }

        workspaceBridge.handled = true;
    } catch (error) {
        console.error('bootstrapWorkspaceBridge failed:', error);
        showBridgeBanner(`同步 ${workspaceBridge.securityCode} 到工作台失败: ${error.message}`, 'danger');
        workspaceBridge.handled = true;
    }
}

// ===== 初始化 =====
window.initializeDecisionWorkspace = async function() {
    if (workspaceInitialized) {
        return;
    }
    workspaceInitialized = true;

    // 加载账户列表
    await loadUserAccounts();
    await bootstrapWorkspaceBridge();
    refreshWorkspaceDecisionLists();

    // 模态框点击外部关闭
    document.getElementById('approvalModal').addEventListener('click', function(e) {
        if (e.target === this) {
            closeApprovalModal();
        }
    });
};

document.addEventListener('DOMContentLoaded', function() {
    if (document.getElementById('workspace-account-selector') && window.initializeDecisionWorkspace) {
        window.initializeDecisionWorkspace();
    }
});

document.body.addEventListener('htmx:afterSwap', function(event) {
    const targetId = event.detail?.target?.id;
    if (targetId && targetId.startsWith('step-')) {
        syncWorkspaceAccountSummary();
        syncIgnoredRecommendationsFilterButton();
    }
});

// ===== 加载用户账户 =====
async function loadUserAccounts() {
    try {
        const data = await window.fetchJsonOrThrow('/api/account/accounts/?active_only=false', {
            headers: { 'X-CSRFToken': window.csrfToken }
        });

        if (data.success && Array.isArray(data.accounts)) {
            userAccounts = data.accounts;
            const selector = getWorkspaceAccountSelector();
            if (!selector) {
                return;
            }

            const options = '<option value="default">默认账户</option>' +
                userAccounts.map(acc =>
                    `<option value="${acc.account_id}">${acc.account_name} (${acc.initial_capital}元)</option>`
                ).join('');

            selector.innerHTML = options;

            if (requestedWorkspaceAccountId && userAccounts.some(acc => String(acc.account_id) === requestedWorkspaceAccountId)) {
                selector.value = requestedWorkspaceAccountId;
            } else if (userAccounts.length > 0) {
                selector.value = String(userAccounts[0].account_id);
            } else {
                selector.value = 'default';
            }
        }
        await loadWorkspaceAccountSnapshot();
        refreshCurrentDecisionStep();
    } catch (error) {
        console.error('加载账户失败:', error);
    }
}

// ===== 加载推荐列表 =====
async function loadRecommendations() {
    const container = document.getElementById('recommendations-list');
    if (!container) {
        return;
    }
    syncWorkspaceAccountSummary();
    syncIgnoredRecommendationsFilterButton();
    const accountId = getSelectedWorkspaceAccountId();
    const statusFilter = document.getElementById('status-filter')?.value || '';
    const decisionFilter = document.getElementById('decision-filter')?.value || '';

    container.innerHTML = `
        <div class="app-loading-state app-loading-state--compact">
            <div class="app-spinner" aria-hidden="true"></div>
            <p class="app-loading-text">加载中...</p>
        </div>
    `;

    try {
        let url = '/api/decision/workspace/recommendations/';
        const params = new URLSearchParams();
        params.append('account_id', accountId || 'default');
        if (statusFilter) params.append('status', statusFilter);
        if (decisionFilter) params.append('user_action', decisionFilter);
        if (decisionFilter === 'IGNORED') params.append('include_ignored', 'true');
        if (workspaceBridge.securityCode) params.append('security_code', workspaceBridge.securityCode);
        if (params.toString()) url += '?' + params.toString();

        const data = await window.fetchJsonOrThrow(url, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });

        if (data.success && data.data) {
            const recommendations = data.data.recommendations || [];
            const totalCount = data.data.total_count || 0;
            currentWorkspaceRecommendations = recommendations;

            if (
                shouldAutoRefreshRecommendations(recommendations) &&
                !workspaceBridge.securityCode &&
                !statusFilter &&
                !decisionFilter &&
                !recommendationAutoRefreshAttempts.has(accountId || 'default')
            ) {
                recommendationAutoRefreshAttempts.add(accountId || 'default');
                try {
                    const refreshData = await window.fetchJsonOrThrow('/api/decision/workspace/recommendations/refresh/', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'X-CSRFToken': window.csrfToken
                        },
                        body: JSON.stringify({
                            account_id: accountId || 'default',
                            force: true,
                        })
                    });
                    if (refreshData.success) {
                        return loadRecommendations();
                    }
                } catch (error) {
                    console.error('自动刷新推荐失败:', error);
                }
            }

            renderRecommendations(recommendations, totalCount);
        } else {
            currentWorkspaceRecommendations = [];
            container.innerHTML = `
                <div class="error-state">
                    <p>加载失败: ${data.error || '未知错误'}</p>
                </div>
            `;
        }
    } catch (error) {
        currentWorkspaceRecommendations = [];
        container.innerHTML = `
            <div class="error-state">
                <p>网络错误: ${error.message}</p>
            </div>
        `;
    }
}

// ===== 渲染推荐列表 =====
function renderRecommendations(recommendations, totalCount) {
    const container = document.getElementById('recommendations-list');
    if (!container) {
        return;
    }
    currentWorkspaceRecommendations = recommendations || [];
    const recommendationsCount = document.getElementById('recommendations-count');
    if (recommendationsCount) {
        recommendationsCount.textContent = totalCount;
    }
    const recCountBadge = document.getElementById('rec-count-badge');
    if (recCountBadge) {
        recCountBadge.textContent = totalCount;
    }
    const selectedCount = document.getElementById('selected-rec-count');
    if (selectedCount) {
        selectedCount.textContent = String(selectedRecommendationIds.size);
    }

    if (!recommendations || recommendations.length === 0) {
        container.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📭</div>
                <p>暂无推荐建议</p>
            </div>
        `;
        return;
    }

    container.innerHTML = recommendations.map(rec => `
        <div class="recommendation-card recommendation-card-${String(rec.side || 'hold').toLowerCase()} ${workspaceBridge.highlightedRecommendationId === rec.recommendation_id ? 'recommendation-card-highlight' : ''}" data-recommendation-id="${rec.recommendation_id}">
                <div class="rec-header">
                    <div class="rec-asset">
                        <label style="display: inline-flex; align-items: center; gap: 6px; margin-right: 10px;">
                            <input type="checkbox" ${selectedRecommendationIds.has(rec.recommendation_id) ? 'checked' : ''} onchange="toggleRecommendationSelection('${rec.recommendation_id}', this.checked)" />
                            <span style="font-size: 12px; color: var(--color-text-muted);">计划</span>
                        </label>
                    ${renderSecurityLabel(rec.security_name, rec.security_code, 'rec-asset-title')}
                    <span class="rec-side rec-side-${rec.side.toLowerCase()}">${rec.side}</span>
                    <span class="rec-user-action rec-user-action-${String(rec.user_action || 'PENDING').toLowerCase()}">${getUserActionText(rec.user_action, rec.user_action_label)}</span>
                </div>
                <div class="rec-confidence">
                    置信度: <strong>${(rec.confidence * 100).toFixed(1)}%</strong>
                </div>
            </div>
            <div class="rec-body">
                <div class="rec-scores">
                    <div class="score-summary">
                        <span class="score-label">综合分:</span>
                        <span class="score-value-composite">${rec.composite_score.toFixed(2)}</span>
                    </div>
                    <div class="score-breakdown">
                        <span title="Alpha模型">α:${rec.alpha_model_score.toFixed(2)}</span>
                        <span title="舆情">S:${rec.sentiment_score.toFixed(2)}</span>
                        <span title="资金流">F:${rec.flow_score.toFixed(2)}</span>
                        <span title="技术面">T:${rec.technical_score.toFixed(2)}</span>
                        <span title="基本面">F:${rec.fundamental_score.toFixed(2)}</span>
                    </div>
                </div>
                <div class="rec-prices">
                    <div class="price-info">
                        <span class="price-label">公允:</span>
                        <span class="price-value">${rec.fair_value}</span>
                    </div>
                    <div class="price-info">
                        <span class="price-label">入场:</span>
                        <span class="price-value">${rec.entry_price_low} - ${rec.entry_price_high}</span>
                    </div>
                    <div class="price-info">
                        <span class="price-label">目标:</span>
                        <span class="price-value">${rec.target_price_low} - ${rec.target_price_high}</span>
                    </div>
                </div>
                <div class="rec-position">
                    <span class="position-label">仓位:</span>
                    <span class="position-value">${rec.position_pct}% (${rec.suggested_quantity}股)</span>
                    <span class="capital-label">上限:</span>
                    <span class="capital-value">${rec.max_capital}元</span>
                </div>
                ${renderRecommendationDecisionBrief(rec)}
                <div class="rec-valuation-repair">
                    ${renderValuationRepairSummary(rec.valuation_repair)}
                </div>
            </div>
            <div class="rec-footer">
                <div class="rec-footer-meta">
                    <div class="rec-status status-${rec.status.toLowerCase()}">${getStatusText(rec.status)}</div>
                    ${rec.user_action_note ? `<div class="rec-user-note">${escapeHtml(rec.user_action_note)}</div>` : ''}
                </div>
                <div class="rec-actions">
                    <button class="btn btn-sm btn-outline" onclick="applyRecommendationAction('${rec.recommendation_id}', 'watch')">
                        加入观察
                    </button>
                    <button class="btn btn-sm btn-secondary" onclick="applyRecommendationAction('${rec.recommendation_id}', 'adopt')">
                        采纳
                    </button>
                    <button class="btn btn-sm btn-outline" onclick="applyRecommendationAction('${rec.recommendation_id}', 'ignore')">
                        忽略
                    </button>
                    <button class="btn btn-sm btn-primary"
                            onclick="openApprovalModal('${rec.recommendation_id}')"
                            data-recommendation-id="${rec.recommendation_id}"
                            data-security-code="${rec.security_code}"
                            data-security-name="${escapeHtml(rec.security_name || rec.security_code)}"
                            data-side="${rec.side}"
                            data-confidence="${rec.confidence}"
                            data-composite-score="${rec.composite_score}"
                            data-fair-value="${rec.fair_value}"
                            data-entry-low="${rec.entry_price_low}"
                            data-entry-high="${rec.entry_price_high}"
                            data-target-low="${rec.target_price_low}"
                            data-target-high="${rec.target_price_high}"
                            data-stop-loss="${rec.stop_loss_price}"
                            data-position-pct="${rec.position_pct}"
                            data-suggested-qty="${rec.suggested_quantity}"
                            data-max-capital="${rec.max_capital}"
                            data-regime="${rec.regime}"
                            data-regime-confidence="${rec.regime_confidence}"
                            data-policy-level="${rec.policy_level}"
                            data-beta-gate="${rec.beta_gate_passed}"
                            data-alpha-score="${rec.alpha_model_score}"
                            data-sentiment-score="${rec.sentiment_score}"
                            data-flow-score="${rec.flow_score}"
                            data-technical-score="${rec.technical_score}"
                            data-fundamental-score="${rec.fundamental_score}"
                            data-reason-codes='${JSON.stringify(rec.reason_codes)}'
                            data-rationale="${rec.human_rationale}">
                        查看详情
                    </button>
                </div>
            </div>
        </div>
    `).join('');
    syncDecisionFunnelGuardrails();
}

function renderValuationRepairSummary(repair) {
    if (!repair) {
        return `<div class="repair-summary empty">估值修复: 未命中快照</div>`;
    }

    const badges = [
        `<span class="repair-chip phase">${repair.phase || '-'}</span>`,
        repair.signal ? `<span class="repair-chip signal">${repair.signal}</span>` : '',
        repair.is_stalled ? `<span class="repair-chip stalled">stalled</span>` : '',
    ].join('');

    return `
        <div class="repair-summary">
            <div class="repair-summary-header">
                <span class="repair-summary-title">估值修复</span>
                <div class="repair-summary-badges">${badges}</div>
            </div>
            <div class="repair-summary-metrics">
                <span>分位 ${formatRepairPercent(repair.composite_percentile)}</span>
                <span>进度 ${formatRepairPercent(repair.repair_progress)}</span>
                <span>ETA ${formatRepairEta(repair.estimated_days_to_target)}</span>
            </div>
        </div>
    `;
}

function toggleRecommendationSelection(recommendationId, isSelected) {
    if (isSelected) {
        selectedRecommendationIds.add(recommendationId);
    } else {
        selectedRecommendationIds.delete(recommendationId);
    }
    const selectedCount = document.getElementById('selected-rec-count');
    if (selectedCount) {
        selectedCount.textContent = String(selectedRecommendationIds.size);
    }
}

async function applyRecommendationAction(recommendationId, action) {
    const accountId = getSelectedWorkspaceAccountId();

    try {
        const data = await window.fetchJsonOrThrow('/api/decision/workspace/recommendations/action/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                recommendation_id: recommendationId,
                account_id: accountId,
                action: action,
            }),
        });

        if (!data.success) {
            throw new Error(data.error || '写入用户动作失败');
        }

        const updated = data.data?.recommendation;
        if (updated?.security_code) {
            workspaceBridge.securityCode = updated.security_code;
            workspaceBridge.highlightedRecommendationId = updated.recommendation_id;
        }
        showBridgeBanner(data.data?.message || `已更新为${getUserActionText(updated?.user_action, updated?.user_action_label)}`, 'success');
        await loadRecommendations();
        return updated || null;
    } catch (error) {
        showBridgeBanner(`更新用户动作失败: ${error.message}`, 'danger');
        return null;
    }
}

async function loadTransitionPlanStep() {
    const summaryContainer = document.getElementById('transition-plan-summary');
    const ordersContainer = document.getElementById('transition-plan-orders');
    if (!summaryContainer || !ordersContainer) {
        return;
    }
    syncWorkspaceAccountSummary();

    if (!currentTransitionPlanId) {
        applyTransitionPlanState(null);
        summaryContainer.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">🧭</div>
                <p>当前还没有交易计划。先在 Step 4 采纳推荐，再点击“生成交易计划”。</p>
            </div>
        `;
        ordersContainer.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📝</div>
                <p>生成计划后，这里会显示当前持仓、目标持仓和 delta 调仓指令。</p>
            </div>
        `;
        return;
    }

    summaryContainer.innerHTML = '<div class="app-loading-state app-loading-state--compact"><div class="app-spinner" aria-hidden="true"></div><p class="app-loading-text">加载中...</p></div>';
    ordersContainer.innerHTML = summaryContainer.innerHTML;

    try {
        const payload = await window.fetchJsonOrThrow(`/api/decision/workspace/plans/${encodeURIComponent(currentTransitionPlanId)}/`, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });
        if (!payload.success || !payload.data) {
            throw new Error(payload.error || '加载交易计划失败');
        }
        renderTransitionPlan(payload.data);
    } catch (error) {
        summaryContainer.innerHTML = `<div class="error-state"><p>${escapeHtml(error.message)}</p></div>`;
        ordersContainer.innerHTML = `<div class="error-state"><p>${escapeHtml(error.message)}</p></div>`;
    }
}

function formatOrderPriceSource(source) {
    const labels = {
        entry_price_band_midpoint: '入场价带中位数',
        target_price_band_midpoint: '目标价带中位数',
        current_position_price: '当前持仓价',
        auto_115pct_execution_price: '成交价 115% 自动止盈',
        recommendation_stop_loss: '推荐止损价',
        auto_90pct_execution_price: '成交价 90% 自动止损',
        manual_override: '手工覆盖',
    };
    return labels[source] || '系统默认';
}

function renderTransitionPlan(plan) {
    const summaryContainer = document.getElementById('transition-plan-summary');
    const ordersContainer = document.getElementById('transition-plan-orders');
    if (!summaryContainer || !ordersContainer) {
        return;
    }

    applyTransitionPlanState(plan);

    const blockingIssues = (plan.blocking_issues || []).map(issue => `<li>${escapeHtml(issue)}</li>`).join('');
    summaryContainer.innerHTML = `
        <div style="display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px;">
            <div class="attention-card"><strong>计划 ID</strong><div>${escapeHtml(plan.plan_id)}</div></div>
            <div class="attention-card"><strong>订单数</strong><div>${plan.summary?.orders_count ?? 0}</div></div>
            <div class="attention-card"><strong>状态</strong><div>${escapeHtml(plan.status || 'DRAFT')}</div></div>
            <div class="attention-card"><strong>审批状态</strong><div>${plan.approval_request_id ? '已创建审批请求' : '未提交审批'}</div></div>
        </div>
        <div style="margin-top: 16px;">
            <strong>计划摘要</strong>
            <p style="margin-top: 8px; color: var(--color-text-muted);">
                BUY ${plan.summary?.buy_count ?? 0} / REDUCE ${plan.summary?.reduce_count ?? 0} / EXIT ${plan.summary?.exit_count ?? 0} / HOLD ${plan.summary?.hold_count ?? 0}
            </p>
            ${plan.can_enter_approval ? '<p style="color: var(--color-success); margin-top: 8px;">证伪条件与止损信息已齐备，可进入审批执行。</p>' : `<div style="margin-top: 8px; color: var(--color-danger);"><strong>阻塞项</strong><ul style="margin: 8px 0 0 18px;">${blockingIssues}</ul></div>`}
        </div>
    `;

    const orders = plan.orders || [];
    if (orders.length === 0) {
        ordersContainer.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📭</div>
                <p>当前计划没有可执行订单。</p>
            </div>
        `;
        return;
    }

    ordersContainer.innerHTML = orders.map(order => `
        <div class="approval-card approval-card-${String(order.action || 'hold').toLowerCase()}" data-plan-order-row="${escapeHtml(order.source_recommendation_id || '')}" data-security-code="${escapeHtml(order.security_code)}">
            <div class="approval-header">
                ${renderSecurityLabel(order.security_name, order.security_code, 'approval-asset-title')}
                <span class="approval-side approval-side-${String(order.action || 'hold').toLowerCase()}">${escapeHtml(order.action)}</span>
            </div>
            <div class="approval-body">
                <div class="approval-info" style="margin-bottom: 12px;">
                    <span>当前 ${order.current_qty}</span>
                    <span>目标 ${order.target_qty}</span>
                    <span>Delta ${order.delta_qty}</span>
                    <span>目标权重 ${order.target_weight}%</span>
                </div>
                ${renderOrderDecisionBrief(order)}
                <div class="form-row">
                    <div class="form-group">
                        <label class="form-label">${order.action === 'BUY' ? '推荐买入价' : '计划成交价'}</label>
                        <input class="form-input" data-plan-execution-price type="number" min="0" step="0.01" value="${order.execution_price || ''}" />
                        <div class="workspace-sidebar-subtitle">
                            来源：${escapeHtml(formatOrderPriceSource(order.price_source))}
                            ${order.price_band_low || order.price_band_high ? ` · 价格带 ${escapeHtml(order.price_band_low || '0')} - ${escapeHtml(order.price_band_high || '0')}` : ''}
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="form-label">止盈价</label>
                        <input class="form-input" data-plan-take-profit type="number" min="0" step="0.01" value="${order.take_profit_price || ''}" />
                        <div class="workspace-sidebar-subtitle">来源：${escapeHtml(formatOrderPriceSource(order.take_profit_source))}</div>
                    </div>
                    <div class="form-group">
                        <label class="form-label">止损价</label>
                        <input class="form-input" data-plan-stop-loss type="number" min="0" step="0.01" value="${order.stop_loss_price || ''}" />
                        <div class="workspace-sidebar-subtitle">来源：${escapeHtml(formatOrderPriceSource(order.stop_loss_source))}</div>
                    </div>
                    <div class="form-group">
                        <label class="form-label">复核日期</label>
                        <input class="form-input" data-plan-review-by type="date" value="${order.review_by || ''}" />
                    </div>
                </div>
                <div class="form-group">
                    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                        <label class="form-label" style="margin-bottom: 0;">证伪条件 JSON</label>
                        <div style="display: flex; gap: 8px;">
                            <button class="btn btn-outline btn-sm" onclick="applySystemInvalidationTemplate('${escapeHtml(order.source_recommendation_id || '')}', '${escapeHtml(order.security_code)}', '${escapeHtml(order.action)}')">系统建议</button>
                            <button class="btn btn-secondary btn-sm" onclick="generateAIInvalidationDraft('${escapeHtml(order.source_recommendation_id || '')}', '${escapeHtml(order.security_code)}', '${escapeHtml(order.action)}')">AI 生成</button>
                        </div>
                    </div>
                    <input class="form-input" data-plan-ai-prompt placeholder="可选：补充你的交易假设、关注指标、触发条件偏好" style="margin-bottom: 8px;" />
                    <div class="workspace-sidebar-subtitle" data-plan-context-note>可先用系统建议接入 Pulse/Regime，再用 AI 细化 JSON。</div>
                </div>
                <div class="form-group">
                    <label class="form-label">证伪条件 JSON</label>
                    <textarea class="form-input" data-plan-invalidation rows="4">${escapeHtml(JSON.stringify(order.invalidation_rule || {}, null, 2))}</textarea>
                </div>
                <div class="workspace-sidebar-subtitle">${escapeHtml(order.invalidation_description || '待补充证伪逻辑')}</div>
            </div>
        </div>
    `).join('');
}

async function generateTransitionPlan() {
    try {
        const eligibleRecommendationIds = getEligiblePlanRecommendationIds();
        if (!currentTransitionPlanId && eligibleRecommendationIds.length === 0) {
            throw new Error('请先在 Step 4 采纳至少 1 条推荐，再生成交易计划');
        }
        const body = {
            account_id: getSelectedWorkspaceAccountId(),
        };
        if (selectedRecommendationIds.size > 0) {
            if (eligibleRecommendationIds.length === 0) {
                throw new Error('已勾选推荐中没有已采纳项，请先采纳后再生成交易计划');
            }
            body.recommendation_ids = eligibleRecommendationIds;
        }
        const payload = await window.fetchJsonOrThrow('/api/decision/workspace/plans/generate/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify(body),
        });
        if (!payload.success || !payload.data) {
            throw new Error(payload.error || '生成交易计划失败');
        }
        renderTransitionPlan(payload.data);
        window.showToast('交易计划已生成', 'success');
    } catch (error) {
        window.showToast(`生成交易计划失败: ${error.message}`, 'error');
    }
}

function collectTransitionPlanPayload() {
    const rows = Array.from(document.querySelectorAll('[data-plan-order-row]'));
    return {
        risk_contract: {
            plan_owner: getSelectedWorkspaceAccountId(),
        },
        orders: rows.map(row => {
            let invalidationRule = {};
            const invalidationText = row.querySelector('[data-plan-invalidation]')?.value || '{}';
            try {
                invalidationRule = JSON.parse(invalidationText);
            } catch (error) {
                invalidationRule = {
                    requires_user_confirmation: true,
                    parse_error: error.message,
                    raw: invalidationText,
                };
            }
            return {
                source_recommendation_id: row.dataset.planOrderRow,
                security_code: row.dataset.securityCode,
                execution_price: row.querySelector('[data-plan-execution-price]')?.value || null,
                take_profit_price: row.querySelector('[data-plan-take-profit]')?.value || null,
                stop_loss_price: row.querySelector('[data-plan-stop-loss]')?.value || null,
                review_by: row.querySelector('[data-plan-review-by]')?.value || null,
                invalidation_rule: invalidationRule,
            };
        }),
    };
}

function getPlanOrderRow(recommendationId, securityCode) {
    return document.querySelector(
        `[data-plan-order-row="${CSS.escape(recommendationId)}"][data-security-code="${CSS.escape(securityCode)}"]`
    );
}

async function fetchRecommendationById(recommendationId) {
    const accountId = getSelectedWorkspaceAccountId();
    const payload = await window.fetchJsonOrThrow(`/api/decision/workspace/recommendations/?account_id=${encodeURIComponent(accountId)}&recommendation_id=${encodeURIComponent(recommendationId)}&include_ignored=true`, {
        headers: { 'X-CSRFToken': window.csrfToken }
    });
    if (!payload.success || !payload.data?.recommendations?.length) {
        return null;
    }
    return payload.data.recommendations[0];
}

async function applySystemInvalidationTemplate(recommendationId, securityCode, action) {
    const row = getPlanOrderRow(recommendationId, securityCode);
    if (!row) {
        return;
    }

    try {
        const recommendation = await fetchRecommendationById(recommendationId);
        const side = action === 'BUY' ? 'BUY' : 'SELL';
        const payload = await window.fetchJsonOrThrow('/api/decision/workspace/invalidation/template/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                security_code: securityCode,
                side: side,
                rationale: recommendation?.human_rationale || '',
            }),
        });
        if (!payload.success || !payload.data?.template) {
            throw new Error(payload.error || '生成系统模板失败');
        }
        row.querySelector('[data-plan-invalidation]').value = JSON.stringify(payload.data.template, null, 2);
        const note = row.querySelector('[data-plan-context-note]');
        if (note) {
            const pulse = payload.data.pulse_context || {};
            note.textContent = `已接入系统上下文：Pulse=${pulse.composite_score ?? '-'}，强弱=${pulse.regime_strength || '-'}。`;
        }
        window.showToast('已生成系统级证伪模板', 'success');
    } catch (error) {
        window.showToast(`系统模板生成失败: ${error.message}`, 'error');
    }
}

async function generateAIInvalidationDraft(recommendationId, securityCode, action) {
    const row = getPlanOrderRow(recommendationId, securityCode);
    if (!row) {
        return;
    }

    try {
        const recommendation = await fetchRecommendationById(recommendationId);
        const side = action === 'BUY' ? 'BUY' : 'SELL';
        let existingRule = {};
        try {
            existingRule = JSON.parse(row.querySelector('[data-plan-invalidation]').value || '{}');
        } catch (parseError) {
            existingRule = {
                requires_user_confirmation: true,
                raw: row.querySelector('[data-plan-invalidation]').value || '{}',
            };
        }
        const userPrompt = row.querySelector('[data-plan-ai-prompt]')?.value || '';
        const payload = await window.fetchJsonOrThrow('/api/decision/workspace/invalidation/ai-draft/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                security_code: securityCode,
                side: side,
                rationale: recommendation?.human_rationale || '',
                user_prompt: userPrompt,
                existing_rule: existingRule,
            }),
        });
        if (!payload.success || !payload.data?.draft) {
            throw new Error(payload.error || 'AI 生成失败');
        }
        row.querySelector('[data-plan-invalidation]').value = JSON.stringify(payload.data.draft, null, 2);
        const note = row.querySelector('[data-plan-context-note]');
        if (note) {
            note.textContent = `AI 已生成草稿：${payload.data.provider_used || 'AI provider'} / ${payload.data.model || 'default model'}`;
        }
        window.showToast('AI 证伪草稿已生成', 'success');
    } catch (error) {
        window.showToast(`AI 生成失败: ${error.message}`, 'error');
    }
}

async function saveTransitionPlan() {
    if (!currentTransitionPlanId) {
        window.showToast('请先生成交易计划', 'warning');
        return;
    }

    try {
        const payload = await window.fetchJsonOrThrow(`/api/decision/workspace/plans/${encodeURIComponent(currentTransitionPlanId)}/update/`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify(collectTransitionPlanPayload()),
        });
        if (!payload.success || !payload.data) {
            throw new Error(payload.error || '保存交易计划失败');
        }
        renderTransitionPlan(payload.data);
        window.showToast('交易计划已保存', 'success');
    } catch (error) {
        window.showToast(`保存交易计划失败: ${error.message}`, 'error');
    }
}

async function submitTransitionPlanForApproval() {
    if (!currentTransitionPlanId) {
        window.showToast('请先生成交易计划', 'warning');
        return;
    }
    await saveTransitionPlan();

    try {
        const payload = await window.fetchJsonOrThrow('/api/decision/execute/preview/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                plan_id: currentTransitionPlanId,
                create_request: true,
                account_id: getSelectedWorkspaceAccountId(),
            }),
        });
        if (!payload.success) {
            throw new Error(payload.error || '创建审批请求失败');
        }
        currentPlanApprovalRequestId = payload.data?.request_id || '';
        syncDecisionFunnelGuardrails();
        window.showToast('审批请求已创建，进入 Step 6 审批执行', 'success');
        if (window.decisionFunnelState) {
            window.decisionFunnelState.maxReached = Math.max(window.decisionFunnelState.maxReached, 6);
            window.decisionFunnelState.goToStep(6);
        }
    } catch (error) {
        window.showToast(`进入审批执行失败: ${error.message}`, 'error');
    }
}

async function loadExecutionPlanPanel() {
    const container = document.getElementById('execution-plan-panel');
    if (!container) {
        return;
    }

    if (!currentTransitionPlanId) {
        container.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📋</div>
                <p>当前还没有交易计划。请先在 Step 5 生成并提交审批请求。</p>
            </div>
        `;
        return;
    }

    container.innerHTML = '<div class="app-loading-state app-loading-state--compact"><div class="app-spinner" aria-hidden="true"></div><p class="app-loading-text">加载中...</p></div>';
    try {
        const payload = await window.fetchJsonOrThrow(`/api/decision/workspace/plans/${encodeURIComponent(currentTransitionPlanId)}/`, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });
        if (!payload.success || !payload.data) {
            throw new Error(payload.error || '加载审批面板失败');
        }
        const plan = payload.data;
        applyTransitionPlanState(plan);
        container.innerHTML = `
            <div class="approval-card">
                <div class="approval-header">
                    <strong>${escapeHtml(plan.plan_id)}</strong>
                    <span class="approval-side approval-side-${String(plan.status || 'draft').toLowerCase()}">${escapeHtml(plan.status)}</span>
                </div>
                <div class="approval-body">
                    <div class="approval-info" style="margin-bottom: 12px;">
                        <span>账户 ${escapeHtml(plan.account_id)}</span>
                        <span>订单 ${plan.summary?.orders_count ?? 0}</span>
                        <span>审批请求 ${escapeHtml(plan.approval_request_id || '未创建')}</span>
                    </div>
                    <textarea id="execution-plan-comments" class="form-input" rows="4" placeholder="填写审批意见、执行约束、落地说明（必填）"></textarea>
                </div>
                <div class="approval-footer" style="display: flex; gap: 10px;">
                    <button class="btn btn-outline" onclick="submitTransitionPlanForApproval()">刷新审批请求</button>
                    <button class="btn btn-secondary" onclick="rejectCurrentTransitionPlan()" ${!plan.approval_request_id ? 'disabled' : ''}>拒绝</button>
                    <button class="btn btn-primary" onclick="approveCurrentTransitionPlan()" ${!plan.approval_request_id ? 'disabled' : ''}>批准并执行</button>
                </div>
            </div>
        `;
    } catch (error) {
        container.innerHTML = `<div class="error-state"><p>${escapeHtml(error.message)}</p></div>`;
    }
}

async function approveCurrentTransitionPlan() {
    if (!currentPlanApprovalRequestId) {
        window.showToast('当前没有待审批请求', 'warning');
        return;
    }
    const reviewerComments = (document.getElementById('execution-plan-comments')?.value || '').trim();
    if (!reviewerComments) {
        window.showToast('请填写审批意见', 'warning');
        return;
    }

    try {
        const payload = await window.fetchJsonOrThrow('/api/decision/execute/approve/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                approval_request_id: currentPlanApprovalRequestId,
                reviewer_comments: reviewerComments,
            }),
        });
        if (!payload.success) {
            throw new Error(payload.error || '审批失败');
        }
        window.showToast('交易计划已批准', 'success');
        loadExecutionPlanPanel();
    } catch (error) {
        window.showToast(`审批失败: ${error.message}`, 'error');
    }
}

async function rejectCurrentTransitionPlan() {
    if (!currentPlanApprovalRequestId) {
        window.showToast('当前没有待审批请求', 'warning');
        return;
    }
    const reviewerComments = (document.getElementById('execution-plan-comments')?.value || '').trim();
    if (!reviewerComments) {
        window.showToast('请填写拒绝理由', 'warning');
        return;
    }

    try {
        const payload = await window.fetchJsonOrThrow('/api/decision/execute/reject/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken,
            },
            body: JSON.stringify({
                approval_request_id: currentPlanApprovalRequestId,
                reviewer_comments: reviewerComments,
            }),
        });
        if (!payload.success) {
            throw new Error(payload.error || '拒绝失败');
        }
        window.showToast('交易计划已拒绝', 'success');
        loadExecutionPlanPanel();
    } catch (error) {
        window.showToast(`拒绝失败: ${error.message}`, 'error');
    }
}

// ===== 加载审批列表 =====
async function loadApprovals() {
    const container = document.getElementById('approvals-list');
    if (!container) {
        return;
    }
    syncWorkspaceAccountSummary();
    const accountId = getSelectedWorkspaceAccountId();

    container.innerHTML = `
        <div class="app-loading-state app-loading-state--compact">
            <div class="app-spinner" aria-hidden="true"></div>
            <p class="app-loading-text">加载中...</p>
        </div>
    `;

    try {
        let url = '/api/decision/workspace/recommendations/';
        const params = new URLSearchParams();
        params.append('account_id', accountId || 'default');
        params.append('status', 'APPROVED');
        if (params.toString()) url += '?' + params.toString();

        const data = await window.fetchJsonOrThrow(url, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });

        if (data.success && data.data) {
            renderApprovals(data.data.recommendations || [], data.data.total_count || 0);
        } else {
            container.innerHTML = `
                <div class="error-state">
                    <p>加载失败: ${data.error || '未知错误'}</p>
                </div>
            `;
        }
    } catch (error) {
        container.innerHTML = `
            <div class="error-state">
                <p>网络错误: ${error.message}</p>
            </div>
        `;
    }
}

// ===== 渲染审批列表 =====
function renderApprovals(approvals, totalCount) {
    const container = document.getElementById('approvals-list');
    if (!container) {
        return;
    }
    const approvalsCount = document.getElementById('approvals-count');
    if (approvalsCount) {
        approvalsCount.textContent = totalCount;
    }
    const approvalCountBadge = document.getElementById('approval-count-badge');
    if (approvalCountBadge) {
        approvalCountBadge.textContent = totalCount;
    }

    if (!approvals || approvals.length === 0) {
        container.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📋</div>
                <p>暂无待执行审批</p>
            </div>
        `;
        return;
    }

    container.innerHTML = approvals.map(rec => `
        <div class="approval-card approval-card-${String(rec.side || 'hold').toLowerCase()}">
            <div class="approval-header">
                ${renderSecurityLabel(rec.security_name, rec.security_code, 'approval-asset-title')}
                <span class="approval-side approval-side-${rec.side.toLowerCase()}">${rec.side}</span>
            </div>
            <div class="approval-body">
                <div class="approval-info">
                    <span>置信度: ${(rec.confidence * 100).toFixed(1)}%</span>
                    <span>仓位: ${rec.position_pct}% (${rec.suggested_quantity}股)</span>
                    <span>入场: ${rec.entry_price_low} - ${rec.entry_price_high}</span>
                </div>
                ${renderRecommendationDecisionBrief(rec)}
            </div>
            <div class="approval-footer">
                <button class="btn btn-sm btn-primary" onclick="openApprovalModal('${rec.recommendation_id}')">
                    查看详情
                </button>
            </div>
        </div>
    `).join('');
}

// ===== 加载冲突列表 =====
async function loadConflicts() {
    const container = document.getElementById('conflicts-list');
    if (!container) {
        return;
    }
    syncWorkspaceAccountSummary();
    const accountId = getSelectedWorkspaceAccountId();

    container.innerHTML = `
        <div class="app-loading-state app-loading-state--compact">
            <div class="app-spinner" aria-hidden="true"></div>
            <p class="app-loading-text">加载中...</p>
        </div>
    `;

    try {
        let url = '/api/decision/workspace/conflicts/';
        const params = new URLSearchParams();
        params.append('account_id', accountId || 'default');
        if (params.toString()) url += '?' + params.toString();

        const data = await window.fetchJsonOrThrow(url, {
            headers: { 'X-CSRFToken': window.csrfToken }
        });

        if (data.success && data.data) {
            renderConflicts(data.data.conflicts || [], data.data.total_count || 0);
        } else {
            container.innerHTML = `
                <div class="error-state">
                    <p>加载失败: ${data.error || '未知错误'}</p>
                </div>
            `;
        }
    } catch (error) {
        container.innerHTML = `
            <div class="error-state">
                <p>网络错误: ${error.message}</p>
            </div>
        `;
    }
}

// ===== 渲染冲突列表 =====
function renderConflicts(conflicts, totalCount) {
    const container = document.getElementById('conflicts-list');
    if (!container) {
        return;
    }
    const conflictsCount = document.getElementById('conflicts-count');
    if (conflictsCount) {
        conflictsCount.textContent = totalCount;
    }
    const conflictCountBadge = document.getElementById('conflict-count-badge');
    if (conflictCountBadge) {
        conflictCountBadge.textContent = totalCount;
    }

    if (!conflicts || conflicts.length === 0) {
        container.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">✅</div>
                <p>暂无冲突</p>
            </div>
        `;
        return;
    }

    container.innerHTML = conflicts.map(conflict => `
        <div class="conflict-card">
            <div class="conflict-header">
                ${renderSecurityLabel(conflict.security_name, conflict.security_code, 'conflict-asset-title')}
                <span class="conflict-badge">BUY/SELL 冲突</span>
            </div>
            <div class="conflict-body">
                ${conflict.buy_recommendation ? `
                    <div class="conflict-side conflict-buy">
                        <span class="side-label">BUY:</span>
                        <span class="side-score">综合分 ${conflict.buy_recommendation.composite_score.toFixed(2)}</span>
                        <span class="side-confidence">置信度 ${(conflict.buy_recommendation.confidence * 100).toFixed(1)}%</span>
                    </div>
                ` : ''}
                ${conflict.sell_recommendation ? `
                    <div class="conflict-side conflict-sell">
                        <span class="side-label">SELL:</span>
                        <span class="side-score">综合分 ${conflict.sell_recommendation.composite_score.toFixed(2)}</span>
                        <span class="side-confidence">置信度 ${(conflict.sell_recommendation.confidence * 100).toFixed(1)}%</span>
                    </div>
                ` : ''}
            </div>
            <div class="conflict-footer">
                <p class="conflict-hint">${conflict.resolution_hint || '需要人工判断方向'}</p>
            </div>
        </div>
    `).join('');
}

// ===== 刷新推荐 =====
async function refreshRecommendations() {
    const btn = event.target.closest('button');
    const originalText = btn.innerHTML;
    btn.disabled = true;
    btn.innerHTML = '<i class="bi bi-arrow-clockwise spin"></i> 刷新中...';

    try {
        const data = await window.fetchJsonOrThrow('/api/decision/workspace/recommendations/refresh/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken
            },
            body: JSON.stringify({
                account_id: getSelectedWorkspaceAccountId(),
                force: true
            })
        });

        if (data.success) {
            window.showToast('推荐已刷新', 'success');
            refreshWorkspaceDecisionLists();
        } else {
            window.showToast('刷新失败: ' + (data.error || '未知错误'), 'error');
        }
    } catch (error) {
        window.showToast('网络错误: ' + error.message, 'error');
    } finally {
        btn.disabled = false;
        btn.innerHTML = originalText;
    }
}

// ===== 打开审批模态框 =====
async function openApprovalModal(recommendationId) {
    currentRecommendation = null;

    // 如果传入的是 ID，需要先获取推荐详情
    if (typeof recommendationId === 'string') {
        try {
            const accountId = getSelectedWorkspaceAccountId();
            const data = await window.fetchJsonOrThrow(`/api/decision/workspace/recommendations/?account_id=${encodeURIComponent(accountId)}&recommendation_id=${encodeURIComponent(recommendationId)}`, {
                headers: { 'X-CSRFToken': window.csrfToken }
            });

            if (data.success && data.data && data.data.recommendations && data.data.recommendations.length > 0) {
                currentRecommendation = data.data.recommendations[0];
            } else {
                window.showToast('获取推荐详情失败', 'error');
                return;
            }
        } catch (error) {
            window.showToast('网络错误', 'error');
            return;
        }
    } else {
        // 从按钮的 data 属性获取（用于快速打开）
        const button = event.target.closest('button');
        currentRecommendation = {
            recommendation_id: button.dataset.recommendationId,
            security_code: button.dataset.securityCode,
            security_name: button.dataset.securityName || button.dataset.securityCode,
            side: button.dataset.side,
            confidence: parseFloat(button.dataset.confidence) || 0,
            composite_score: parseFloat(button.dataset.compositeScore) || 0,
            fair_value: button.dataset.fairValue,
            entry_price_low: button.dataset.entryLow,
            entry_price_high: button.dataset.entryHigh,
            target_price_low: button.dataset.targetLow,
            target_price_high: button.dataset.targetHigh,
            stop_loss_price: button.dataset.stopLoss,
            position_pct: parseFloat(button.dataset.positionPct) || 0,
            suggested_quantity: parseInt(button.dataset.suggestedQty) || 0,
            max_capital: button.dataset.maxCapital,
            regime: button.dataset.regime,
            regime_confidence: parseFloat(button.dataset.regimeConfidence) || 0,
            policy_level: button.dataset.policyLevel,
            beta_gate_passed: button.dataset.betaGate === 'true',
            alpha_model_score: parseFloat(button.dataset.alphaScore) || 0,
            sentiment_score: parseFloat(button.dataset.sentimentScore) || 0,
            flow_score: parseFloat(button.dataset.flowScore) || 0,
            technical_score: parseFloat(button.dataset.technicalScore) || 0,
            fundamental_score: parseFloat(button.dataset.fundamentalScore) || 0,
            reason_codes: JSON.parse(button.dataset.reasonCodes || '[]'),
            human_rationale: button.dataset.rationale
        };
    }

    if (!currentRecommendation) {
        window.showToast('无法获取推荐信息', 'error');
        return;
    }
    const queueBtn = document.getElementById('queue-plan-btn');
    if (queueBtn) {
        queueBtn.textContent = currentRecommendation.user_action === 'ADOPTED'
            ? '纳入计划并前往 Step 5'
            : '采纳并纳入计划';
    }

    // 填充模态框基本信息
    document.getElementById('modal-recommendation-id').textContent = currentRecommendation.recommendation_id;
    document.getElementById('modal-security-code').innerHTML = renderSecurityLabel(
        currentRecommendation.security_name,
        currentRecommendation.security_code,
        'modal-security-display'
    );
    const sideEl = document.getElementById('modal-side');
    sideEl.textContent = currentRecommendation.side;
    sideEl.className = `info-value direction direction-${currentRecommendation.side.toLowerCase()}`;
    document.getElementById('modal-confidence').textContent = (currentRecommendation.confidence * 100).toFixed(1) + '%';

    // 填充价格信息
    document.getElementById('modal-fair-value').textContent = currentRecommendation.fair_value || '-';
    document.getElementById('modal-entry-range').textContent =
        (currentRecommendation.entry_price_low || '-') + ' - ' + (currentRecommendation.entry_price_high || '-');
    document.getElementById('modal-target-range').textContent =
        (currentRecommendation.target_price_low || '-') + ' - ' + (currentRecommendation.target_price_high || '-');
    document.getElementById('modal-stop-loss').textContent = currentRecommendation.stop_loss_price || '-';

    // 填充仓位信息
    document.getElementById('modal-position-pct').textContent = (currentRecommendation.position_pct || 0) + '%';
    document.getElementById('modal-suggested-qty').textContent = currentRecommendation.suggested_quantity || '-';
    document.getElementById('modal-max-capital').textContent = (currentRecommendation.max_capital || '-') + '元';

    // 填充 Top-down 信息
    document.getElementById('modal-regime').textContent = currentRecommendation.regime || '-';
    document.getElementById('modal-regime-confidence').textContent =
        (currentRecommendation.regime_confidence * 100).toFixed(1) + '%';
    document.getElementById('modal-policy-level').textContent = currentRecommendation.policy_level || '-';
    const betaGateEl = document.getElementById('modal-beta-gate');
    betaGateEl.textContent = currentRecommendation.beta_gate_passed ? '已通过' : '未通过';
    betaGateEl.className = 'topdown-value ' + (currentRecommendation.beta_gate_passed ? 'pass' : 'fail');

    // 填充 Bottom-up 分数
    const scores = ['alpha', 'sentiment', 'flow', 'technical', 'fundamental', 'composite'];
    const scoreKeys = ['alpha_model_score', 'sentiment_score', 'flow_score', 'technical_score', 'fundamental_score', 'composite_score'];
    scores.forEach((score, idx) => {
        const value = currentRecommendation[scoreKeys[idx]] || 0;
        const pct = Math.min(Math.max(value * 100, 0), 100);
        document.getElementById(`modal-${score}-score`).style.width = pct + '%';
        document.getElementById(`modal-${score}-score-value`).textContent = value.toFixed(2);
    });

    // 填充决策理由
    const reasonCodesEl = document.getElementById('modal-reason-codes');
    if (currentRecommendation.reason_codes && currentRecommendation.reason_codes.length > 0) {
        reasonCodesEl.innerHTML = currentRecommendation.reason_codes.map(code =>
            `<span class="reason-tag">${code}</span>`
        ).join('');
    } else {
        reasonCodesEl.innerHTML = '<span class="no-reasons">无原因代码</span>';
    }
    document.getElementById('modal-human-rationale').textContent = currentRecommendation.human_rationale || '-';
    fillValuationRepairPanel(currentRecommendation.valuation_repair);

    // 获取风险检查和预览
    await loadExecutionPreview();

    // 显示模态框
    document.getElementById('approvalModal').classList.add('active');
}

function fillValuationRepairPanel(repair) {
    document.getElementById('modal-repair-phase').textContent = repair?.phase || '-';
    document.getElementById('modal-repair-signal').textContent = repair?.signal || '-';
    document.getElementById('modal-repair-percentile').textContent = formatRepairPercent(repair?.composite_percentile);
    document.getElementById('modal-repair-progress').textContent = formatRepairPercent(repair?.repair_progress);
    document.getElementById('modal-repair-speed').textContent = formatRepairFloat(repair?.repair_speed_per_30d);
    document.getElementById('modal-repair-eta').textContent = formatRepairEta(repair?.estimated_days_to_target);
    document.getElementById('modal-repair-confidence').textContent = formatRepairPercent(repair?.confidence);
    document.getElementById('modal-repair-asof').textContent = repair?.as_of_date || '-';

    const noteEl = document.getElementById('modal-repair-note');
    if (!repair) {
        noteEl.textContent = '未命中估值修复快照，仅作为可选辅助信息。';
        return;
    }
    if (repair.is_stalled) {
        noteEl.textContent = '当前处于修复停滞区间，建议人工复核基本面和价格驱动。';
        return;
    }
    if (repair.phase === 'overshooting' || repair.phase === 'completed') {
        noteEl.textContent = '当前已接近或达到修复兑现区，适合作为风险提示，不建议单独作为追价理由。';
        return;
    }
    noteEl.textContent = '估值修复信息仅作为辅助决策信号，不构成硬门禁。';
}

// ===== 加载执行预览 =====
async function loadExecutionPreview() {
    const riskChecksContainer = document.getElementById('modal-risk-checks');
    riskChecksContainer.innerHTML = '<div class="risk-check-loading">检查中...</div>';

    try {
        const data = await window.fetchJsonOrThrow('/api/decision/execute/preview/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRFToken': window.csrfToken
            },
            body: JSON.stringify({
                recommendation_id: currentRecommendation.recommendation_id,
                create_request: false,
                account_id: getSelectedWorkspaceAccountId()
            })
        });

        if (data.success && data.data) {
            renderRiskChecks(data.data.risk_checks || {});
        } else {
            riskChecksContainer.innerHTML = `<div class="risk-check-error">加载失败: ${data.error || '未知错误'}</div>`;
        }
    } catch (error) {
        riskChecksContainer.innerHTML = `<div class="risk-check-error">网络错误: ${error.message}</div>`;
    }
}

async function queueRecommendationForPlan() {
    if (!currentRecommendation?.recommendation_id) {
        return;
    }

    if (currentRecommendation.user_action !== 'ADOPTED') {
        const updated = await applyRecommendationAction(currentRecommendation.recommendation_id, 'adopt');
        if (!updated || updated.user_action !== 'ADOPTED') {
            return;
        }
        currentRecommendation = {
            ...currentRecommendation,
            user_action: updated.user_action,
        };
    }

    selectedRecommendationIds.add(currentRecommendation.recommendation_id);
    const selectedCount = document.getElementById('selected-rec-count');
    if (selectedCount) {
        selectedCount.textContent = String(selectedRecommendationIds.size);
    }

    closeApprovalModal();
    window.showToast('已纳入交易计划，请在 Step 5 生成并完善交易计划', 'success');
    if (window.decisionFunnelState) {
        window.decisionFunnelState.maxReached = Math.max(window.decisionFunnelState.maxReached, 5);
        window.decisionFunnelState.goToStep(5);
    }
}

// ===== 渲染风险检查 =====
function renderRiskChecks(riskChecks) {
    const container = document.getElementById('modal-risk-checks');

    const items = [];

    // 价格验证
    if (riskChecks.price_validation) {
        const pv = riskChecks.price_validation;
        items.push({
            name: '价格验证',
            passed: pv.passed,
            reason: pv.reason || (pv.passed ? '通过' : '未通过')
        });
    }

    // 配额检查
    if (riskChecks.quota) {
        const q = riskChecks.quota;
        items.push({
            name: '配额检查',
            passed: q.passed,
            reason: q.reason || (q.passed ? `剩余 ${q.remaining}` : '配额不足')
        });
    }

    // 冷却期检查
    if (riskChecks.cooldown) {
        const c = riskChecks.cooldown;
        items.push({
            name: '冷却期检查',
            passed: c.passed,
            reason: c.reason || (c.passed ? '可执行' : `剩余 ${c.hours_remaining?.toFixed(1)} 小时`)
        });
    }

    if (items.length === 0) {
        items.push({ name: '风险检查', passed: true, reason: '未进行' });
    }

    container.innerHTML = items.map(item => `
        <div class="risk-check-item ${item.passed ? 'passed' : 'failed'}">
            <span class="check-icon">${item.passed ? '✓' : '✗'}</span>
            <span class="check-name">${item.name}</span>
            <span class="check-reason">${item.reason}</span>
        </div>
    `).join('');
}

// ===== 关闭审批模态框 =====
function closeApprovalModal() {
    document.getElementById('approvalModal').classList.remove('active');
    currentRecommendation = null;

    const queueBtn = document.getElementById('queue-plan-btn');
    if (queueBtn) {
        queueBtn.disabled = false;
        queueBtn.textContent = '纳入计划并前往 Step 5';
    }
}

// ===== 工具函数 =====
function getStatusText(status) {
    const statusMap = {
        'NEW': '新建',
        'REVIEWING': '审核中',
        'APPROVED': '已批准',
        'REJECTED': '已拒绝',
        'EXECUTED': '已执行',
        'FAILED': '执行失败',
        'CONFLICT': '冲突'
    };
    return statusMap[status] || status;
}

Object.assign(window, {
    loadRecommendations,
    toggleIgnoredRecommendationsFilter,
    loadTransitionPlanStep,
    generateTransitionPlan,
    saveTransitionPlan,
    submitTransitionPlanForApproval,
    loadExecutionPlanPanel,
    loadConflicts,
});
</script>

<style>
/* ===== 工作台样式 ===== */
.workspace-container {
    max-width: 1400px;
    margin: 0 auto;
    padding: 20px;
}

.workspace-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    padding-bottom: 20px;
    border-bottom: 1px solid #e2e8f0;
}

.workspace-title {
    display: flex;
    align-items: center;
    gap: 12px;
    font-size: 24px;
    font-weight: 700;
    margin: 0;
}

.title-icon {
    font-size: 28px;
}

.workspace-subtitle {
    color: #64748b;
    margin: 4px 0 0 40px;
    font-size: 14px;
}

.header-right {
    display: flex;
    align-items: center;
    gap: 16px;
}

.environment-badge {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: #f8fafc;
    border-radius: 8px;
    border: 1px solid #e2e8f0;
}

.badge-label {
    font-size: 12px;
    color: #64748b;
}

.badge-value {
    font-weight: 600;
    font-size: 14px;
}

.badge-value.regime-growth { color: #10b981; }
.badge-value.regime-stagflation { color: #f59e0b; }
.badge-value.regime-reflation { color: #3b82f6; }
.badge-value.regime-unknown { color: #64748b; }

.badge-value.policy-p0 { color: #ef4444; }
.badge-value.policy-p1 { color: #f59e0b; }
.badge-value.policy-p2 { color: #10b981; }

.tab-count {
    background: #e2e8f0;
    color: #475569;
    padding: 2px 8px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
}

/* Tab 内容 */
.workspace-content {
    min-height: 400px;
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

/* 区域头部 */
.section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
}

.section-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 18px;
    font-weight: 600;
    margin: 0;
}

.section-actions {
    display: flex;
    gap: 8px;
}

.form-select-sm {
    padding: 6px 12px;
    font-size: 13px;
}

/* 推荐卡片 */
.recommendation-card {
    background: white;
    border: 1px solid #cbd5e1;
    border-left: 4px solid #94a3b8;
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 12px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
    transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;
}

.recommendation-card:hover {
    border-color: #94a3b8;
    box-shadow: 0 8px 20px rgba(15, 23, 42, 0.10);
    transform: translateY(-1px);
}

.recommendation-card-highlight {
    border-color: #4f46e5;
    border-left-color: #4f46e5;
    box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.12);
}

.recommendation-card-buy,
.approval-card-buy {
    border-left-color: var(--color-rise-strong);
}

.recommendation-card-sell,
.approval-card-sell,
.approval-card-exit {
    border-left-color: var(--color-fall-strong);
}

.recommendation-card-hold,
.approval-card-hold,
.approval-card-reduce {
    border-left-color: #64748b;
}

.rec-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid #f1f5f9;
}

.rec-asset {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    flex-wrap: wrap;
}

.rec-asset strong {
    font-size: 18px;
}

.security-display {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    line-height: 1.1;
    min-width: 0;
}

a.security-display {
    color: inherit;
    text-decoration: none;
    border-radius: 6px;
    outline-offset: 3px;
}

a.security-display:hover .security-display-name,
a.security-display:focus-visible .security-display-name {
    color: #2563eb;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.security-display-name {
    font-weight: 700;
    color: var(--color-text-primary);
}

.security-display-code {
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text-secondary);
    letter-spacing: 0.02em;
}

.rec-asset-title .security-display-name,
.approval-asset-title .security-display-name,
.conflict-asset-title .security-display-name {
    font-size: 18px;
}

.modal-security-display .security-display-name {
    font-size: 14px;
}

.modal-security-display .security-display-code {
    font-size: 11px;
}

.rec-side {
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
}

.rec-side-buy {
    background: var(--color-rise-soft);
    color: var(--color-rise-strong);
}

.rec-side-sell {
    background: var(--color-fall-soft);
    color: var(--color-fall-strong);
}

.rec-confidence {
    font-size: 14px;
    color: #64748b;
}

.rec-user-action {
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}

.rec-user-action-pending {
    background: #e2e8f0;
    color: #475569;
}

.rec-user-action-watching {
    background: #ecfeff;
    color: #0f766e;
}

.rec-user-action-adopted {
    background: #ecfdf3;
    color: #15803d;
}

.rec-user-action-ignored {
    background: #f1f5f9;
    color: #64748b;
}

.rec-body {
    display: grid;
    gap: 12px;
}

.rec-scores {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px 12px;
    background: #f8fafc;
    border-radius: 8px;
}

.score-summary {
    font-weight: 600;
}

.score-value-composite {
    color: #667eea;
    font-size: 18px;
}

.score-breakdown {
    display: flex;
    gap: 12px;
    font-size: 12px;
    color: #64748b;
}

.rec-prices {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
}

.price-info {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 8px;
    background: #f8fafc;
    border-radius: 6px;
}

.price-label {
    font-size: 11px;
    color: #64748b;
}

.price-value {
    font-weight: 600;
    font-size: 13px;
}

.rec-position {
    display: flex;
    gap: 16px;
    padding: 8px 12px;
    background: #f0f9ff;
    border-radius: 6px;
    font-size: 13px;
}

.decision-brief {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr) minmax(190px, 0.75fr);
    gap: 10px;
}

.decision-brief-plan {
    margin-bottom: 14px;
}

.decision-brief-item {
    min-width: 0;
    padding: 10px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
    background: #f8fafc;
}

.decision-brief-item strong {
    display: block;
    margin-top: 4px;
    font-size: 13px;
    line-height: 1.45;
    color: #0f172a;
    overflow-wrap: anywhere;
}

.decision-brief-asof {
    display: block;
    margin-top: 6px;
    font-size: 11px;
    color: #64748b;
}

.decision-brief-item.compact {
    background: #ffffff;
}

.decision-brief-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    color: #64748b;
}

.decision-brief-pill {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px 10px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 700;
}

.decision-brief-pill small {
    font-size: 11px;
    font-weight: 600;
}

.decision-brief-pill.strong {
    background: #ecfdf3;
    color: #166534;
}

.decision-brief-pill.neutral {
    background: #eff6ff;
    color: #1d4ed8;
}

.decision-brief-pill.weak {
    background: #fef2f2;
    color: #b91c1c;
}

.decision-brief-pill.muted {
    background: #f1f5f9;
    color: #64748b;
}

.rec-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 12px;
    padding: 12px;
    border-top: 1px solid #f1f5f9;
    border-radius: 8px;
    background: #f8fafc;
}

.rec-status {
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
}

.rec-footer-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.rec-user-note {
    font-size: 12px;
    color: #64748b;
}

.rec-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.status-new { background: #e0f2fe; color: #0284c7; }
.status-reviewing { background: #fef3c7; color: #d97706; }
.status-approved { background: #dcfce7; color: #16a34a; }
.status-rejected { background: #fee2e2; color: #dc2626; }

.bridge-banner {
    margin-bottom: 12px;
    padding: 12px 16px;
    border-radius: 10px;
    font-size: 14px;
    font-weight: 500;
}

.bridge-banner-info {
    background: #eff6ff;
    color: #1d4ed8;
}

.bridge-banner-success {
    background: #ecfdf3;
    color: #15803d;
}

.bridge-banner-warning {
    background: #fffbeb;
    color: #b45309;
}

.bridge-banner-danger {
    background: #fef2f2;
    color: #b91c1c;
}

/* 审批卡片 */
.approval-card {
    background: white;
    border: 1px solid #cbd5e1;
    border-left: 4px solid #64748b;
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 12px;
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}

.approval-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

.approval-side {
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
}

.approval-side-buy {
    background: var(--color-rise-soft);
    color: var(--color-rise-strong);
}

.approval-side-sell {
    background: var(--color-fall-soft);
    color: var(--color-fall-strong);
}

.approval-body {
    padding: 8px 0;
}

.approval-info {
    display: flex;
    gap: 16px;
    font-size: 13px;
    color: #64748b;
    flex-wrap: wrap;
}

.approval-footer {
    margin-top: 12px;
    padding: 12px;
    border-top: 1px solid #f1f5f9;
    border-radius: 8px;
    background: #f8fafc;
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    flex-wrap: wrap;
}

/* 冲突卡片 */
.conflict-card {
    background: #fffbeb;
    border: 1px solid #fbbf24;
    border-left: 4px solid #f59e0b;
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 12px;
    box-shadow: 0 1px 2px rgba(146, 64, 14, 0.08);
}

.conflict-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

.conflict-badge {
    background: #fbbf24;
    color: #92400e;
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
}

.conflict-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.conflict-side {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-radius: 6px;
}

.conflict-buy {
    background: var(--color-rise-soft);
}

.conflict-sell {
    background: var(--color-fall-soft);
}

.side-label {
    font-weight: 600;
    width: 50px;
}

.conflict-footer {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid #fde68a;
}

.conflict-hint {
    font-size: 13px;
    color: #92400e;
}

/* 空状态和加载状态 */
.empty-state, .error-state {
    text-align: center;
    padding: 40px 20px;
    color: #64748b;
}

.empty-icon, .error-icon {
    font-size: 48px;
    margin-bottom: 16px;
}

.spin {
    animation: app-spin 1s linear infinite;
}

/* 徽章 */
.badge {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 12px;
    font-size: 12px;
    font-weight: 600;
}

.badge-primary { background: #e0f2fe; color: #0284c7; }
.badge-success { background: #dcfce7; color: #16a34a; }
.badge-warning { background: #fef3c7; color: #d97706; }

/* 模态框 */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}

.modal-overlay.active {
    display: flex;
}

.modal-container {
    background: white;
    border-radius: 16px;
    width: 90%;
    max-width: 700px;
    max-height: 90vh;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 16px 24px;
    border-bottom: 1px solid #e2e8f0;
}

.modal-header h3 {
    margin: 0;
    font-size: 18px;
}

.modal-close {
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: #64748b;
    padding: 0;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
}

.modal-close:hover {
    background: #f1f5f9;
}

.modal-body {
    padding: 20px 24px;
    overflow-y: auto;
    flex: 1;
}

.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding: 16px 24px;
    border-top: 1px solid #e2e8f0;
}

/* 审批模态框内容 */
.approval-section {
    margin-bottom: 20px;
    padding: 16px;
    background: #f8fafc;
    border-radius: 8px;
}

.section-label {
    font-size: 14px;
    font-weight: 600;
    color: #475569;
    margin: 0 0 12px 0;
}

.info-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.info-item {
    display: flex;
    flex-direction: column;
}

.info-label {
    font-size: 11px;
    color: #64748b;
}

.info-value {
    font-weight: 600;
    font-size: 14px;
}

.info-value.direction {
    font-weight: 700;
}

.info-value.direction-buy { color: var(--color-rise); }
.info-value.direction-sell { color: var(--color-fall); }

.price-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.price-item {
    text-align: center;
    padding: 8px;
    background: white;
    border-radius: 6px;
}

.price-label {
    display: block;
    font-size: 11px;
    color: #64748b;
    margin-bottom: 4px;
}

.price-value {
    font-weight: 600;
    font-size: 14px;
}

.price-value.stop-loss {
    color: #dc2626;
}

.position-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

.position-item {
    text-align: center;
    padding: 8px;
    background: white;
    border-radius: 6px;
}

.position-label {
    display: block;
    font-size: 11px;
    color: #64748b;
    margin-bottom: 4px;
}

.position-value {
    font-weight: 600;
    font-size: 14px;
}

.capital-label {
    font-size: 11px;
    color: #64748b;
}

.capital-value {
    font-weight: 600;
}

/* 风险检查 */
.risk-checks-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.risk-check-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    background: white;
    border-radius: 6px;
    font-size: 13px;
}

.risk-check-item.passed {
    color: #16a34a;
}

.risk-check-item.failed {
    color: #dc2626;
}

.check-icon {
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: currentColor;
    color: white;
    font-weight: 700;
}

.check-name {
    font-weight: 600;
    flex: 1;
}

.check-reason {
    color: #64748b;
}

.risk-check-loading, .risk-check-error {
    text-align: center;
    padding: 12px;
    color: #64748b;
    font-size: 13px;
}

.risk-check-error {
    color: #dc2626;
}

/* Top-down 信息 */
.topdown-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 12px;
}

.topdown-item {
    display: flex;
    flex-direction: column;
    padding: 8px;
    background: white;
    border-radius: 6px;
}

.topdown-label {
    font-size: 11px;
    color: #64748b;
}

.topdown-value {
    font-weight: 600;
    font-size: 14px;
}

.topdown-value.pass { color: #16a34a; }
.topdown-value.fail { color: #dc2626; }

/* Bottom-up 分数 */
.scores-grid {
    display: grid;
    gap: 8px;
}

.score-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    background: white;
    border-radius: 6px;
}

.score-label {
    font-size: 12px;
    color: #64748b;
    width: 80px;
}

.score-bar {
    flex: 1;
    height: 8px;
    background: #e2e8f0;
    border-radius: 4px;
    overflow: hidden;
}

.score-fill {
    height: 100%;
    background: linear-gradient(90deg, #667eea, #764ba2);
    transition: width 0.3s;
}

.score-bar.composite .score-fill {
    background: linear-gradient(90deg, #f59e0b, #ef4444);
}

.score-value {
    font-weight: 600;
    font-size: 13px;
    width: 40px;
    text-align: right;
}

/* 决策理由 */
.reason-codes {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 8px;
}

.reason-tag {
    padding: 4px 12px;
    background: #e0f2fe;
    color: #0284c7;
    border-radius: 12px;
    font-size: 12px;
}

.no-reasons {
    color: #64748b;
    font-size: 13px;
}

.human-rationale {
    padding: 12px;
    background: white;
    border-radius: 6px;
    font-size: 13px;
    color: #475569;
    margin: 0;
}

/* 表单 */
.form-group {
    margin-bottom: 16px;
}

.form-label {
    display: block;
    font-size: 13px;
    font-weight: 500;
    color: #475569;
    margin-bottom: 6px;
}

.required {
    color: #dc2626;
}

.form-select, .form-input, textarea.form-input {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    font-size: 14px;
    transition: border-color 0.2s;
}

.form-select:focus, .form-input:focus, textarea.form-input:focus {
    outline: none;
    border-color: #667eea;
}

.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}

textarea.form-input {
    resize: vertical;
    min-height: 80px;
}

/* 按钮 */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    border: none;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
}

.btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

.btn-primary {
    background: #667eea;
    color: white;
}

.btn-primary:hover:not(:disabled) {
    background: #5a67d8;
}

.btn-secondary {
    background: #64748b;
    color: white;
}

.btn-secondary:hover:not(:disabled) {
    background: #475569;
}

.btn-outline {
    background: transparent;
    border: 1px solid #e2e8f0;
    color: #475569;
}

.btn-outline:hover:not(:disabled) {
    background: #f8fafc;
    border-color: #cbd5e1;
}

.btn-sm {
    padding: 6px 12px;
    font-size: 13px;
}

/* 告警横幅 */
.alerts-section {
    margin-bottom: 20px;
}

.alert {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 8px;
}

.alert-success {
    background: #dcfce7;
    color: #16a34a;
}

.alert-warning {
    background: #fef3c7;
    color: #d97706;
}

.alert-error, .alert-danger {
    background: #fee2e2;
    color: #dc2626;
}

.alert-icon {
    font-size: 20px;
}

.alert-content {
    flex: 1;
}

.alert-close {
    background: none;
    border: none;
    font-size: 20px;
    cursor: pointer;
    color: inherit;
    opacity: 0.7;
}

.alert-close:hover {
    opacity: 1;
}

@media (max-width: 900px) {
    .decision-brief {
        grid-template-columns: 1fr;
    }

    .rec-prices {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .rec-footer,
    .approval-footer,
    .funnel-next-panel {
        align-items: stretch;
        flex-direction: column;
    }

    .rec-actions,
    .approval-footer {
        justify-content: stretch;
    }

    .rec-actions .btn,
    .approval-footer .btn,
    .funnel-next-panel .btn {
        width: 100%;
    }

    .funnel-next-spacer {
        display: none;
    }
}
</style>
{% endblock %}
