<template>
  <section class="idea-detail-panel">
    <div class="detail-header">
      <h2 class="detail-title">{{ idea.title }}</h2>
      <div class="detail-header-actions">
        <!-- P0-② 转化为项目按钮前置到标题行右侧(原底部操作区按钮移入),保持 promoting 态 -->
        <button
          v-if="idea.status === 'approved' && !idea.promoted_to"
          class="btn btn-primary btn-sm"
          :disabled="promoting"
          @click="$emit('promote')"
        >
          {{ promoting ? $t('ideas.promoting') : $t('ideas.promoteToProject') }}
        </button>
        <router-link
          v-else-if="idea.promoted_to"
          class="btn btn-primary btn-sm"
          :to="`/projects/${idea.promoted_to}`"
        >
          🚀 {{ $t('ideas.promotedProject') }} →
        </router-link>
        <span class="status-tag" :class="'status-' + idea.status">{{ $t(statusLabelKey(idea.status)) }}</span>
      </div>
    </div>
    <!-- B-260615-25:灵感描述 Markdown 渲染,复用 useMarkdown composable(同 B-24 TaskDetail),空值回退 — -->
    <template v-if="editing">
      <textarea v-model="editDesc" class="detail-desc-edit" rows="4"></textarea>
      <div class="desc-edit-actions">
        <button class="btn btn-primary btn-sm" :disabled="savingDesc" @click="saveEdit">
          {{ savingDesc ? $t('common.loading') : $t('ideas.saveDesc') }}
        </button>
        <button class="btn btn-ghost btn-sm" :disabled="savingDesc" @click="cancelEdit">{{ $t('ideas.cancelEdit') }}</button>
      </div>
    </template>
    <template v-else>
      <!-- P1-③ 描述超阈值折叠:max-height:300px 截断,溢出显「展开/收起」(沿用 ProjectCard 测量模式) -->
      <div
        v-if="idea.description"
        class="detail-desc-wrap"
        :class="{ 'is-expanded': descExpanded }"
      >
        <p
          ref="descRef"
          class="detail-desc ai-md"
          v-html="renderedDesc"
        ></p>
        <button v-if="descOverflow" class="desc-toggle" @click="descExpanded = !descExpanded">
          {{ descExpanded ? $t('common.collapse') : $t('common.expand') }}
        </button>
      </div>
      <p v-else class="detail-desc">—</p>
      <button class="btn btn-ghost btn-sm desc-edit-btn" :disabled="savingDesc" @click="startEdit">{{ $t('ideas.editDesc') }}</button>
    </template>

    <!-- 对抗式评估 -->
    <div class="detail-section">
      <h3>{{ $t('ideas.adversarialTitle') }} <span class="eval-mode-tag">{{ $t(evalModeLabelKey()) }}</span></h3>
      <div v-if="adversarialEval" class="adversarial-eval">
        <!-- P0-① 评估结论前置:分析师结论(徽章/评分/倾向/摘要)提到正反方论据之前,
             一眼看到评估结果;详细论据(正反方/行动建议)折叠,点击展开 -->
        <div class="analyst-conclusion">
          <h4>{{ $t('ideas.analystTitle') }}</h4>
          <div class="assessment-badge" :class="assessmentClass(adversarialEval.recommendation)">
            {{ localAssessmentLabel(adversarialEval.recommendation) }}
          </div>
          <p class="final-score">{{ $t('ideas.finalScore', { score: adversarialEval.final_score.toFixed(1) }) }}</p>
          <div class="net-sentiment" :class="sentimentClass(adversarialEval.net_sentiment)">
            {{ $t('ideas.netSentiment', { tone: adversarialEval.net_sentiment > 0 ? $t('ideas.sentimentPositive') : (adversarialEval.net_sentiment < 0 ? $t('ideas.sentimentNegative') : $t('ideas.sentimentNeutral')), n: (adversarialEval.net_sentiment * 100).toFixed(0) }) }}
          </div>
          <p class="summary">{{ adversarialEval.analyst.summary }}</p>
        </div>

        <!-- 详细论据(正反方观点 + 行动建议):折叠态默认收起,降低首屏信息密度 -->
        <div class="debate-toggle-row">
          <button class="debate-toggle-btn" @click="debateExpanded = !debateExpanded">
            {{ debateExpanded ? $t('common.collapse') : $t('common.expand') }} · {{ $t('ideas.positive') }} / {{ $t('ideas.negative') }}
            <span class="debate-toggle-arrow" :class="{ 'is-open': debateExpanded }">▾</span>
          </button>
        </div>
        <div v-show="debateExpanded" class="debate-detail">
          <div class="debate-container">
            <div class="debate-column positive">
              <h4>{{ $t('ideas.positive') }}</h4>
              <div class="confidence-bar">
                <div class="confidence-fill" :style="{ width: (adversarialEval.positive_strength * 100) + '%' }"></div>
              </div>
              <div class="confidence-text">{{ $t('ideas.confidence', { n: (adversarialEval.positive_strength * 100).toFixed(0) }) }}</div>
              <p class="thesis">{{ adversarialEval.positive.thesis }}</p>
              <ul>
                <li v-for="evidence in adversarialEval.positive.evidence" :key="evidence">• {{ evidence }}</li>
              </ul>
            </div>

            <div class="debate-column negative">
              <h4>{{ $t('ideas.negative') }}</h4>
              <div class="confidence-bar">
                <div class="confidence-fill" :style="{ width: (adversarialEval.negative_strength * 100) + '%' }"></div>
              </div>
              <div class="confidence-text">{{ $t('ideas.confidence', { n: (adversarialEval.negative_strength * 100).toFixed(0) }) }}</div>
              <p class="thesis">{{ adversarialEval.negative.thesis }}</p>
              <ul>
                <li v-for="evidence in adversarialEval.negative.evidence" :key="evidence">• {{ evidence }}</li>
              </ul>
            </div>
          </div>

          <!-- 行动建议 -->
          <div class="action-recommendations">
            <h4>{{ $t('ideas.actionTitle') }}</h4>
            <ul>
              <li v-for="action in adversarialEval.action_items" :key="action">• {{ action }}</li>
            </ul>
          </div>
        </div>
      </div>
      <div v-else class="eval-report eval-report--muted">
        <button class="btn-evaluate" :disabled="evaluating" @click="$emit('evaluate')">
          {{ evaluating ? $t('ideas.evaluating') : $t('ideas.startEval') }}
        </button>
        <!-- P1-⑥ 重试样式:错误提示分两行,重试用 ghost btn-sm(替代突兀的内联 accent 按钮) -->
        <div v-if="evalError" class="eval-error">
          <p class="eval-error-msg">⚠️ {{ evalError }}</p>
          <button class="btn btn-ghost btn-sm btn-retry" :disabled="evaluating" @click="$emit('evaluate')">
            {{ $t('ideas.retryEval') }}
          </button>
        </div>
      </div>
    </div>

    <!-- 评估历史(版本时间线) -->
    <div class="detail-section">
      <h3>{{ $t('ideas.historyTitle') }}</h3>
      <div v-if="historyLoading" class="eval-report eval-report--muted">{{ $t('ideas.historyLoading') }}</div>
      <div v-else-if="evalHistory.length === 0" class="eval-report eval-report--muted">{{ $t('ideas.historyEmpty') }}</div>
      <div v-else class="eval-history-list">
        <div
          v-for="rec in evalHistory"
          :key="rec.id"
          class="eval-history-item"
          :class="{ expanded: expandedVersion === rec.version }"
          @click="toggleVersion(rec.version)"
        >
          <div class="history-row-main">
            <span class="version-badge">{{ $t('ideas.historyVersion') }} v{{ rec.version }}</span>
            <span v-if="rec.version === latestVersion" class="latest-tag">{{ $t('ideas.historyLatest') }}</span>
            <span class="history-eval-mode">{{ $t(evalModeLabelKeyFromStr(rec.evaluated_by)) }}</span>
            <span class="history-score">{{ rec.score == null ? '—' : rec.score.toFixed(1) }}</span>
            <span class="history-date">{{ formatDate(rec.evaluated_at) }}</span>
          </div>
          <div v-if="expandedVersion === rec.version" class="history-detail">
            <template v-if="historySummary(rec.ai_analysis)">
              <p class="history-summary">{{ historySummary(rec.ai_analysis)?.summary ?? '—' }}</p>
              <p v-if="historySummary(rec.ai_analysis)?.recommendation" class="history-rec">
                {{ historySummary(rec.ai_analysis)?.recommendation }}
              </p>
            </template>
            <p v-else class="history-summary">—</p>
          </div>
        </div>
      </div>
    </div>

    <!-- 关联灵感 -->
    <div class="detail-section">
      <h3>{{ $t('ideas.relatedTitle') }}</h3>
      <!-- 展示态 -->
      <template v-if="!relatedEditing">
        <div v-if="relatedIds.length > 0" class="related-list">
          <template v-for="row in relatedRows" :key="row.id">
            <router-link
              v-if="row.title"
              class="related-chip"
              :to="`/ideas/${row.id}`"
            >{{ row.title }}</router-link>
            <span v-else class="related-chip related-chip-missing">#{{ row.id }}</span>
          </template>
        </div>
        <div v-else class="eval-report eval-report--muted">{{ $t('ideas.relatedEmpty') }}</div>
        <button class="btn btn-ghost btn-sm" @click="startRelateEdit">{{ $t('ideas.relatedManage') }}</button>
      </template>
      <!-- 编辑态 -->
      <template v-else>
        <div v-if="candidateIdeas.length > 0" class="related-edit-list">
          <label
            v-for="idea in candidateIdeas"
            :key="idea.id"
            class="related-edit-item"
          >
            <input
              type="checkbox"
              :checked="relatedSelected.includes(idea.id)"
              @change="toggleSelect(idea.id)"
            />
            <span>{{ idea.title }}</span>
          </label>
        </div>
        <div v-else class="eval-report eval-report--muted">{{ $t('ideas.relatedEmpty') }}</div>
        <div class="related-edit-actions">
          <button class="btn btn-primary btn-sm" @click="confirmRelate">{{ $t('ideas.relatedConfirm') }}</button>
          <button class="btn btn-ghost btn-sm" @click="cancelRelate">{{ $t('ideas.relatedCancel') }}</button>
        </div>
      </template>
    </div>

    <!-- 传统评分条(score-bar) -->
    <div class="detail-section">
      <h3>{{ $t('ideas.multiScoreTitle') }}</h3>
      <div class="score-bar-chart" v-if="parseScores(idea.scores).length > 0">
        <div class="score-bar-row" v-for="dim in parseScores(idea.scores)" :key="dim.name">
          <span class="score-bar-label">{{ dim.name }}</span>
          <div class="score-bar-track">
            <div class="score-bar-fill" :style="{ width: dim.score + '%' }" :class="'fill-' + scoreTier(dim.score)"></div>
          </div>
          <span class="score-bar-value">{{ dim.score }}</span>
        </div>
      </div>
      <div v-else class="eval-report eval-report--muted">{{ $t('ideas.noEval') }}</div>
    </div>

    <!-- 标签 -->
    <div class="detail-section">
      <h3>{{ $t('ideas.tagsTitle') }}</h3>
      <div class="tag-list" v-if="parseTags(idea.tags).length > 0">
        <span class="tag" v-for="tag in parseTags(idea.tags)" :key="tag">{{ tag }}</span>
      </div>
      <div v-else class="eval-report eval-report--muted">{{ $t('ideas.noTags') }}</div>
    </div>

    <!-- 状态管理:P1-④ select → badge 点击(当前态显色 badge,点击展开下拉选项) -->
    <div class="detail-section">
      <h3>{{ $t('ideas.statusTitle') }}</h3>
      <div class="status-controls">
        <div class="status-badge-select" v-click-outside="closeStatusMenu">
          <button
            class="status-tag status-current"
            :class="'status-' + idea.status"
            @click="statusMenuOpen = !statusMenuOpen"
          >
            {{ $t(statusLabelKey(idea.status)) }}
            <span class="status-caret" :class="{ 'is-open': statusMenuOpen }">▾</span>
          </button>
          <ul v-show="statusMenuOpen" class="status-menu">
            <li
              v-for="s in statusOptions"
              :key="s.value"
              class="status-menu-item"
              :class="{ active: s.value === idea.status }"
              @click="pickStatus(s.value)"
            >
              <span class="status-tag" :class="'status-' + s.value">{{ $t(s.labelKey) }}</span>
            </li>
          </ul>
        </div>
      </div>
    </div>

    <!-- 操作(P0-② 立项按钮已上移至标题行,此处仅留删除) -->
    <div class="detail-section" style="margin-top:8px">
      <div class="action-buttons">
        <button class="btn btn-ghost" :disabled="deleting" @click="$emit('delete')">
          {{ deleting ? $t('ideas.deleting') : $t('ideas.deleteIdea') }}
        </button>
      </div>
    </div>
  </section>
</template>

<script setup lang="ts">
import { computed, ref, watch, onMounted, nextTick, type Directive } from 'vue'
import { useI18n } from 'vue-i18n'
import { parseTags } from '../../stores/knowledge'
import { useProjectStore } from '../../stores/project'
import { useRendered } from '../../composables/useMarkdown'
import { ideaApi } from '../../api'
import { formatDate } from '../../utils/time'
import { parseScores, assessmentClass, assessmentLabel, scoreTier } from '../../utils/ideaEval'
import type { IdeaRecord, IdeaStatus, IdeaEvaluationRecord } from '../../api/types'

const props = defineProps<{
  idea: IdeaRecord
  evaluating: boolean
  evalError: string
  promoting: boolean
  deleting: boolean
  statusOptions: { value: IdeaStatus; labelKey: string }[]
}>()

const emit = defineEmits<{
  (e: 'evaluate'): void
  (e: 'promote'): void
  (e: 'delete'): void
  (e: 'status-change', value: IdeaStatus): void
  (e: 'update-desc', value: string): void
  (e: 'update-related', ids: string[]): void
}>()

const { t } = useI18n()
const store = useProjectStore()

// 描述可编辑模式
const editing = ref(false)
const editDesc = ref('')
// P1-⑥ 描述编辑 loading:saveEdit 为异步(emit → 父 store.updateIdea → IPC),期间禁用按钮防双击
const savingDesc = ref(false)

function startEdit() {
  editDesc.value = props.idea.description ?? ''
  editing.value = true
}

// P1-⑥ saveEdit 改异步:emit 后父组件 store.updateIdea 是 Promise,但 emit 不回传结果;
// 这里用本地 savingDesc 包裹一个最小延迟窗口(等待父组件 patch 同步 props.idea.description
// 完成),保证 UI 反馈一致。父组件 updateIdea 失败会 throw 但不冒泡回子组件(沿用既有契约)。
async function saveEdit() {
  if (savingDesc.value) return
  savingDesc.value = true
  try {
    emit('update-desc', editDesc.value)
    editing.value = false
    // 等下一帧让父组件 patch 生效再释放(微观反馈,失败也释放不卡死)
    await nextTick()
  } finally {
    savingDesc.value = false
  }
}

function cancelEdit() {
  editing.value = false
}

// P1-③ 描述溢出测量(沿用 ProjectCard 测量模式):scrollHeight > clientHeight 说明被
// CSS max-height 截断。Markdown 异步渲染 + 切 idea 都需重测。
const descRef = ref<HTMLParagraphElement | null>(null)
const descOverflow = ref(false)
const descExpanded = ref(false)

// P0-① 详细论据(正反方/行动建议)折叠:默认收起,降低首屏信息密度,结论前置后用户按需展开
const debateExpanded = ref(false)

function measureDesc() {
  const el = descRef.value
  if (!el) return
  descOverflow.value = el.scrollHeight - el.clientHeight > 1
}

// 切换 idea 重置展开态 + 重测;描述 Markdown 异步渲染完成会触发 props.idea.description
// 不变但 DOM 文本变,因此额外 watch renderedDesc(渲染输出)重测 —— 见 useRendered 之后
watch(() => props.idea.id, () => {
  descExpanded.value = false
  debateExpanded.value = false
  void nextTick(measureDesc)
})
watch(() => props.idea.description, () => void nextTick(measureDesc))

// P1-④ 状态切换 select → badge 点击:点击当前 badge 展开/收起下拉菜单,
// 选中项后 emit('status-change') 交父组件确认+落库(沿用既有契约,不破坏 statusOptions 来源)。
const statusMenuOpen = ref(false)
function closeStatusMenu() {
  statusMenuOpen.value = false
}
function pickStatus(s: IdeaStatus) {
  statusMenuOpen.value = false
  if (s === props.idea.status) return
  emit('status-change', s)
}

// v-click-outside:轻量内联指令(状态菜单点击外部关闭),不引入新依赖。
// mounted 时绑定 mousedown 监听,点击落点不在 el 内 → 调 binding.value()。
interface ClickOutsideEl extends HTMLElement { _dfClickOutside?: ((e: MouseEvent) => void) | null }
const vClickOutside: Directive<HTMLElement, () => void> = {
  mounted(el, binding) {
    const host = el as ClickOutsideEl
    host._dfClickOutside = (e: MouseEvent) => {
      if (el.contains(e.target as Node)) return
      binding.value?.()
    }
    document.addEventListener('mousedown', host._dfClickOutside)
  },
  unmounted(el) {
    const host = el as ClickOutsideEl
    if (host._dfClickOutside) {
      document.removeEventListener('mousedown', host._dfClickOutside)
      host._dfClickOutside = null
    }
  },
}

// ===== 关联灵感(related_ids JSON 数组字符串)=====
// 解析 props.idea.related_ids(JSON 字符串数组,null/空/非法 → [])
const relatedIds = computed<string[]>(() => {
  const raw = props.idea.related_ids
  if (!raw) return []
  try {
    const parsed = JSON.parse(raw)
    return Array.isArray(parsed) ? parsed.filter((x): x is string => typeof x === 'string') : []
  } catch {
    return []
  }
})

// 反查标题:relatedIds 在 store.ideas 中找对应灵感(找不到留待展示态显 #id)。
// 项3 DRY/性能:原模板 v-for 内对每个 id 调 relatedIdeas.find 两次(O(n)×2);
// 改为一次性构建 {id, title|null} 数组(保留原始顺序含缺失项),模板直接 v-for 对象,O(1)。
const relatedRows = computed<{ id: string; title: string | null }[]>(() => {
  // store.ideas → Map 一次构建,O(1) 查找,避免对每个 relatedId 线性扫 store.ideas
  const byId = new Map(store.ideas.map(i => [i.id, i.title] as const))
  return relatedIds.value.map(id => ({ id, title: byId.get(id) ?? null }))
})

// 编辑态
const relatedEditing = ref(false)
const relatedSelected = ref<string[]>([])

// 可选关联的其他灵感(排除当前灵感自身)
const candidateIdeas = computed(() => store.ideas.filter(i => i.id !== props.idea.id))

function startRelateEdit() {
  relatedSelected.value = [...relatedIds.value]
  relatedEditing.value = true
}

function confirmRelate() {
  emit('update-related', relatedSelected.value)
  relatedEditing.value = false
}

function cancelRelate() {
  relatedEditing.value = false
}

function toggleSelect(id: string) {
  const idx = relatedSelected.value.indexOf(id)
  if (idx >= 0) {
    relatedSelected.value.splice(idx, 1)
  } else {
    relatedSelected.value.push(id)
  }
}

// 任意 status 字符串 → 对应 i18n key;未知状态回退到原值显示
function statusLabelKey(status: IdeaStatus): string {
  return props.statusOptions.find(s => s.value === status)?.labelKey ?? status
}

// B-260615-25:灵感描述 Markdown 渲染(复用 AiChat/TaskDetail 同款渲染器,模块级单例),
// useRendered 封装 computed(读 mdReady 触发响应式 + renderMd)+ ensureLoaded(幂等预热)
// BUG-2026-07-08:原漏解构 ensureLoaded + onMounted 未调用,冷启动(marked 未被其他组件预热)
// 时 mdReady 永远 false,renderMd 走 escapeFallback 纯文本降级,Markdown 语法不渲染。
const { rendered: renderedDesc, ensureLoaded: ensureMdLoaded } = useRendered(
  () => props.idea.description ?? '',
)
// Markdown 异步渲染完成(renderedDesc 变化)后重测描述溢出(max-height 截断阈值依赖渲染后的高度)
watch(renderedDesc, () => void nextTick(measureDesc))

// parseScores / assessmentClass / assessmentLabel 抽到 ../../utils/ideaEval 复用(消除与 ProjectDetail 的 DRY 重复)。

interface AdversarialEval {
  positive_strength: number
  negative_strength: number
  net_sentiment: number
  recommendation: string
  final_score: number
  summary: string
  action_items: string[]
  positive: { thesis: string; evidence: string[] }
  negative: { thesis: string; evidence: string[] }
  analyst: { summary: string }
  evaluated_by?: string
}

// 对抗式评估数据持久化在 ai_analysis JSON 字段中，前端解析渲染
const adversarialEval = computed<AdversarialEval | null>(() => {
  if (!props.idea.ai_analysis) return null
  try {
    return JSON.parse(props.idea.ai_analysis) as AdversarialEval
  } catch {
    return null
  }
})

// 评估深度标签动态化(P0):根据 evaluated_by 字段映射 i18n key
// 'Llm' → LLM 深度评估;'HeuristicFallback' → 启发式降级;
// 其他(undefined / 'Heuristic' / 老数据无此字段)→ 启发式
// 映射逻辑与 evalModeLabelKeyFromStr 同,这里直接透传避免重复(项2 DRY)
function evalModeLabelKey(): string {
  return evalModeLabelKeyFromStr(adversarialEval.value?.evaluated_by)
}

// assessmentClass 直接复用 ../../utils/ideaEval(无 i18n 依赖,模板可直调)。
// assessmentLabel 需要 t 注入,这里留一个绑定 t 的薄包装,消除映射逻辑重复(项1 DRY)。
const localAssessmentLabel = (recommendation: string): string =>
  assessmentLabel(t, recommendation)

function sentimentClass(sentiment: number) {
  // 统一三档(FR-C2: 原 >=0 与模板 >0 矛盾，net_sentiment=0 时文案负面样式 positive)
  if (sentiment > 0) return 'positive'
  if (sentiment < 0) return 'negative'
  return 'neutral'
}

// (原 onStatusChange select 处理器已移除:状态切换改 badge 点击 pickStatus 触发 emit)

// ===== 评估历史(版本时间线)=====
const evalHistory = ref<IdeaEvaluationRecord[]>([])
const historyLoading = ref(false)
const expandedVersion = ref<number | null>(null)

async function loadHistory() {
  historyLoading.value = true
  try {
    evalHistory.value = await ideaApi.listEvaluations(props.idea.id)
  } catch {
    evalHistory.value = []
  } finally {
    historyLoading.value = false
  }
}

// 最新版本 = version 最大者(后端按 DESC 返回,首项即最新;这里用 max 兜底)
const latestVersion = computed(() =>
  evalHistory.value.reduce((max, r) => Math.max(max, r.version), -1),
)

function toggleVersion(v: number) {
  expandedVersion.value = expandedVersion.value === v ? null : v
}

// 针对字符串 evaluated_by 映射 i18n key(与 evalModeLabelKey 同映射规则,接收裸字符串)
function evalModeLabelKeyFromStr(source: string | null | undefined): string {
  if (source === 'Llm') return 'ideas.evalModeLlm'
  if (source === 'HeuristicFallback') return 'ideas.evalModeFallback'
  return 'ideas.evalModeHeuristic'
}

// 解析历史 ai_analysis JSON,取 summary / recommendation(对抗式评估格式)。
// 老数据或非 LLM 评估可能无该结构 → 返回 null。
interface HistorySummary { summary: string | null; recommendation: string | null }
function historySummary(aiAnalysis: string | null | undefined): HistorySummary | null {
  if (!aiAnalysis) return null
  try {
    const parsed = JSON.parse(aiAnalysis)
    if (typeof parsed !== 'object' || parsed === null) return null
    const obj = parsed as Record<string, unknown>
    const summary = typeof obj.summary === 'string' ? obj.summary
      : (typeof obj.analyst === 'object' && obj.analyst !== null
          && typeof (obj.analyst as Record<string, unknown>).summary === 'string'
        ? ((obj.analyst as Record<string, unknown>).summary as string)
        : null)
    const recommendation = typeof obj.recommendation === 'string' ? obj.recommendation : null
    if (!summary && !recommendation) return null
    return { summary, recommendation }
  } catch {
    return null
  }
}

onMounted(() => {
  ensureMdLoaded() // 后台预热 Markdown 渲染器(模块单例,与 AiChat/TaskDetail 共享),不阻塞
  loadHistory()
})
watch(() => props.idea.id, loadHistory)
</script>

<style scoped>
/* ===== 右侧详情 ===== */
.idea-detail-panel {
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-lg);
  padding: var(--df-pad-panel);
  max-height: calc(100vh - 200px);
  overflow-y: auto;
}

.detail-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: var(--df-gap-head);
}
.detail-title { font-size: 20px; font-weight: 500; color: var(--df-text); flex: 1; min-width: 0; }
/* P0-② 标题行右侧操作组:立项按钮 + 状态 badge 一行排布 */
.detail-header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* P1-③ 描述折叠容器:默认 max-height:300px 截断,展开态取消 */
.detail-desc-wrap {
  position: relative;
  margin-bottom: var(--df-gap-page);
}
.detail-desc-wrap .detail-desc { margin-bottom: 0; }
.detail-desc-wrap:not(.is-expanded) .detail-desc {
  max-height: 300px;
  overflow: hidden;
  /* 底部渐变提示「下方还有」,与 max-height 截断视觉呼应 */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
}
.desc-toggle {
  display: inline-block;
  margin-top: 6px;
  padding: 0;
  background: transparent;
  border: none;
  color: var(--df-accent);
  font-size: 12px;
  cursor: pointer;
  line-height: 1.4;
}
.desc-toggle:hover { text-decoration: underline; }

.detail-desc {
  font-size: 14px;
  color: var(--df-text-secondary);
  line-height: 1.6;
  margin-bottom: var(--df-gap-page);
}

/* ===== 灵感描述 Markdown 渲染(B-260615-25,基础样式收敛至全局 ai-md.css) ===== */
.detail-desc.ai-md { white-space: normal; color: var(--df-text-secondary); }

.detail-section {
  margin-bottom: var(--df-gap-page);
}
.detail-section h3 {
  font-size: 14px;
  font-weight: 500;
  color: var(--df-text);
  margin-bottom: 12px;
}

.eval-report {
  font-size: 13px;
  color: var(--df-text-secondary);
  line-height: 1.6;
  padding: 14px 16px;
  background: rgba(108, 99, 255, 0.06);
  border-left: 3px solid var(--df-accent);
  border-radius: 0 8px 8px 0;
}
/* 弱化态(空数据/加载中占位,原 inline opacity:0.5 统一为 class) */
.eval-report--muted { opacity: 0.5; }

/* ===== 状态标签已提取到 styles/components.css 全局(.status-tag 系列) ===== */

/* ===== 对抗式评估 ===== */
.adversarial-eval {
  background: var(--df-bg-raised);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius);
  padding: 1rem;
  margin-bottom: 1rem;
}

.debate-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.debate-column {
  padding: 1rem;
  border-radius: var(--df-radius);
  position: relative;
}

.debate-column.positive {
  background: rgba(61, 219, 160, 0.08);
  border: 0.5px solid rgba(61, 219, 160, 0.2);
}

.debate-column.negative {
  background: rgba(240, 101, 101, 0.08);
  border: 0.5px solid rgba(240, 101, 101, 0.2);
}

.debate-column h4 {
  font-size: 14px;
  font-weight: 500;
  margin: 0 0 0.5rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.confidence-bar {
  height: 4px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: var(--df-radius-xs);
  margin-bottom: 0.25rem;
  overflow: hidden;
}

.confidence-fill {
  height: 100%;
  border-radius: var(--df-radius-xs);
  transition: width 0.4s;
}

.debate-column.positive .confidence-fill { background: var(--df-success); }
.debate-column.negative .confidence-fill { background: var(--df-danger); }

.confidence-text {
  font-size: 11px;
  color: var(--df-text-dim);
  margin-bottom: 0.5rem;
}

.debate-column .thesis {
  font-size: 12px;
  color: var(--df-text);
  margin-bottom: 0.5rem;
  font-weight: 500;
}

.debate-column ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.debate-column li {
  font-size: 11px;
  color: var(--df-text-secondary);
  margin-bottom: 0.25rem;
  padding-left: 0.5rem;
}

.analyst-conclusion {
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius);
  padding: 1rem;
  margin-bottom: 1rem;
}

/* assessment-badge 系列已提取到 styles/components.css 全局 */

.final-score {
  font-size: 14px;
  font-weight: 500;
  color: var(--df-text);
  margin: 0.5rem 0;
}

.net-sentiment {
  font-size: 12px;
  padding: 4px 8px;
  border-radius: var(--df-radius-xs);
  display: inline-block;
  margin: 0.5rem 0;
}

.net-sentiment.positive { background: rgba(61, 219, 160, 0.15); color: var(--df-success); }
.net-sentiment.negative { background: rgba(240, 101, 101, 0.15); color: var(--df-danger); }
.net-sentiment.neutral { background: var(--df-bg-raised); color: var(--df-text-secondary); }

.summary {
  font-size: 12px;
  color: var(--df-text-secondary);
  line-height: 1.5;
  margin: 0.5rem 0;
}

.action-recommendations {
  background: var(--df-bg-raised);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius);
  padding: 1rem;
}

.action-recommendations h4 {
  font-size: 14px;
  font-weight: 500;
  margin: 0 0 0.5rem;
}

.action-recommendations ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.action-recommendations li {
  font-size: 12px;
  color: var(--df-text-secondary);
  margin-bottom: 0.25rem;
  padding-left: 0.5rem;
}

/* P0-① 详细论据折叠切换条 */
.debate-toggle-row { margin-bottom: 0.75rem; }
.debate-toggle-btn {
  background: transparent;
  border: none;
  color: var(--df-accent);
  font-size: 12px;
  cursor: pointer;
  padding: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.debate-toggle-btn:hover { text-decoration: underline; }
.debate-toggle-arrow {
  font-size: 10px;
  transition: transform 0.15s;
}
.debate-toggle-arrow.is-open { transform: rotate(180deg); }
.debate-detail { margin-top: 0.5rem; }
.debate-detail .debate-container { margin-bottom: 0.75rem; }

.btn-evaluate {
  background: var(--df-accent);
  color: #fff;
  border: none;
  padding: 8px 16px;
  border-radius: var(--df-radius);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s;
}

.btn-evaluate:hover {
  background: var(--df-accent-hover);
}

/* P1-⑥ 重试样式:错误提示与重试按钮分行,重试用 ghost btn-sm(替代突兀的内联 accent 按钮) */
.eval-error {
  margin-top: 8px;
  font-size: 12px;
  color: var(--df-danger);
}
.eval-error-msg { margin: 0 0 8px; }
.btn-retry { margin-top: 4px; }

.eval-mode-tag {
  font-size: 11px;
  font-weight: 400;
  padding: 1px 8px;
  border-radius: var(--df-radius-xs);
  background: rgba(255, 217, 61, 0.15);
  color: var(--df-warning);
  margin-left: 6px;
  vertical-align: middle;
}

/* ===== 评估历史(版本时间线)===== */
.eval-history-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.eval-history-item {
  background: var(--df-bg-raised);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius);
  padding: 8px 12px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}
.eval-history-item:hover {
  background: var(--df-bg-card);
  border-color: var(--df-accent);
}
.eval-history-item.expanded {
  border-color: var(--df-accent);
}
.history-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 12px;
}
.version-badge {
  font-size: 11px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: var(--df-radius-xs);
  background: rgba(108, 99, 255, 0.12);
  color: var(--df-accent);
}
.latest-tag {
  font-size: 10px;
  font-weight: 500;
  padding: 1px 6px;
  border-radius: var(--df-radius-xs);
  background: rgba(100, 255, 218, 0.15);
  color: var(--df-success);
}
.history-eval-mode {
  font-size: 11px;
  padding: 1px 6px;
  border-radius: var(--df-radius-xs);
  background: rgba(255, 217, 61, 0.12);
  color: var(--df-warning);
}
.history-score {
  font-size: 12px;
  font-weight: 500;
  color: var(--df-text);
  min-width: 32px;
}
.history-date {
  font-size: 11px;
  color: var(--df-text-dim);
  margin-left: auto;
}
.history-detail {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 0.5px solid var(--df-border);
}
.history-summary {
  font-size: 12px;
  color: var(--df-text-secondary);
  line-height: 1.5;
  margin: 0;
}
.history-rec {
  font-size: 11px;
  color: var(--df-accent);
  margin: 6px 0 0;
}

/* ===== 多维评分条已提取到 styles/components.css 全局(.score-bar-* 系列) ===== */

/* ===== 标签 ===== */
.tag-list { display: flex; gap: 8px; flex-wrap: wrap; }
.tag {
  font-size: 12px; padding: 4px 10px;
  border-radius: var(--df-radius-xs);
  background: rgba(108, 99, 255, 0.1);
  color: var(--df-accent);
}

/* ===== 关联灵感 ===== */
.related-list { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.related-chip {
  font-size: 12px; padding: 4px 10px;
  border-radius: var(--df-radius-xs);
  background: rgba(108, 99, 255, 0.1);
  color: var(--df-accent);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s;
}
.related-chip:hover { background: rgba(108, 99, 255, 0.2); }
.related-chip-missing { cursor: default; opacity: 0.6; }

.related-edit-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 8px;
}
.related-edit-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--df-text-secondary);
  cursor: pointer;
}
.related-edit-item input { cursor: pointer; }
.related-edit-actions { display: flex; gap: 8px; }

/* ===== 按钮已提取到 global.css 全局(.btn/.btn-primary/.btn-ghost/.btn-sm) ===== */
/* IdeaDetail 特有按钮定位 */
.desc-edit-btn { margin-bottom: var(--df-gap-page); margin-top: 4px; }
.desc-edit-actions { display: flex; gap: 8px; margin-bottom: var(--df-gap-page); margin-top: 8px; }

/* 描述编辑 textarea */
.detail-desc-edit {
  width: 100%;
  padding: 8px 10px;
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-sm);
  background: var(--df-bg);
  color: var(--df-text);
  font-size: 14px;
  line-height: 1.6;
  font-family: inherit;
  resize: vertical;
  margin-bottom: var(--df-gap-page);
  box-sizing: border-box;
}
.detail-desc-edit:focus {
  outline: none;
  border-color: var(--df-accent);
  background: var(--df-bg-raised);
}

/* (旧 .btn-retry 内联 accent 按钮样式已废弃:重试改用 ghost btn-sm,统一样式收敛) */

/* ===== 状态管理:P1-④ select → badge 点击下拉 ===== */
.status-controls {
  margin-top: 8px;
}

.status-badge-select {
  position: relative;
  display: inline-block;
}

/* 当前态 badge:点击展开下拉(复用全局 .status-tag 显色,加 cursor + caret) */
.status-current {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  user-select: none;
  border: 0.5px solid transparent;
  transition: border-color 0.15s;
}
.status-current:hover { border-color: var(--df-accent); }

.status-caret {
  font-size: 10px;
  opacity: 0.7;
  transition: transform 0.15s;
}
.status-caret.is-open { transform: rotate(180deg); }

/* 下拉菜单(绝对定位浮层) */
.status-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 10;
  list-style: none;
  margin: 0;
  padding: 6px;
  min-width: 160px;
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-sm);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.status-menu-item {
  cursor: pointer;
  padding: 4px 6px;
  border-radius: var(--df-radius-xs);
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  transition: background 0.15s;
}
.status-menu-item:hover { background: rgba(108, 99, 255, 0.08); }
.status-menu-item.active { background: rgba(108, 99, 255, 0.12); font-weight: 500; }
/* menu 内 badge 取消 emoji 之外的全局 hover 等副作用,仅作色标 */
.status-menu-item .status-tag { cursor: pointer; }

/* ═══ 响应式:窄屏对抗式评估双栏堆叠 ═══ */
@media (max-width: 760px) {
  .debate-container {
    grid-template-columns: 1fr;
  }
}
</style>
