<template>
  <div class="knowledge">
    <!-- 页面头部 -->
    <header class="page-header">
      <h1>{{ $t('knowledge.title') }}</h1>
      <div class="header-actions">
        <button class="btn btn-primary" @click="openCreateModal">{{ $t('knowledge.add') }}</button>
      </div>
    </header>

    <!-- 顶层 Tab: 知识库 / 审核收件箱 -->
    <div class="top-tabs">
      <button class="top-tab" :class="{ active: topTab === 'library' }" @click="switchTopTab('library')">
        {{ $t('knowledge.tab.library') }}
      </button>
      <button class="top-tab" :class="{ active: topTab === 'inbox' }" @click="switchTopTab('inbox')">
        {{ $t('knowledge.tab.inbox') }}
        <span v-if="store.candidates.length" class="inbox-badge">{{ store.candidates.length }}</span>
      </button>
    </div>

    <!-- 左右分栏: 列表 + 详情 -->
    <div class="kn-layout">
      <!-- ===== 左侧:列表 ===== -->
      <div class="kn-list-panel">
        <!-- 搜索栏(仅知识库) -->
        <div v-if="topTab === 'library'" class="search-bar">
          <input
            v-model="searchQuery"
            type="text"
            class="search-input"
            :placeholder="$t('knowledge.searchPlaceholder')"
            @input="onSearchInput"
          />
        </div>

        <!-- 分类(仅知识库) -->
        <div v-if="topTab === 'library'" class="category-tabs">
          <button
            v-for="cat in categories"
            :key="cat.key"
            class="cat-chip"
            :class="{ 'cat-active': activeKind === cat.key }"
            @click="activeKind = cat.key"
          >
            <span>{{ cat.icon }}</span>
            <span>{{ catLabel(cat.key) }}</span>
            <span class="cat-count">{{ getCategoryCount(cat.key) }}</span>
          </button>
        </div>

        <!-- 卡片列表 -->
        <div class="list-cards">
          <div
            v-for="item in listItems"
            :key="item.id"
            class="kn-card"
            :class="{ selected: selectedId === item.id }"
            @click="selectKnowledge(item.id)"
          >
            <div class="kn-card-head">
              <span class="kn-card-title">{{ item.title }}</span>
              <span class="kn-card-status" :class="'st-' + item.status">{{ statusLabel(item.status) }}</span>
            </div>
            <div class="kn-card-desc">{{ item.content }}</div>
            <div class="kn-card-meta">
              <span class="meta-kind">{{ kindLabel(item.kind) }}</span>
              <span v-if="item.confidence" :class="'conf-' + item.confidence">{{ confidenceLabel(item.confidence) }}</span>
              <span class="meta-reuse">🔄 {{ item.reuse_count }}</span>
            </div>
          </div>

          <div v-if="listItems.length === 0" class="list-empty">
            <div>{{ topTab === 'inbox' ? $t('knowledge.emptyInbox') : $t('knowledge.emptyLibrary') }}</div>
          </div>
        </div>
      </div>

      <!-- ===== 右侧:详情 ===== -->
      <div class="kn-detail-panel">
        <template v-if="detail">
          <!-- ① 基本信息 -->
          <section class="detail-section">
            <div class="detail-head">
              <div class="detail-title-row">
                <span class="detail-kind-icon">{{ kindIcon(detail.knowledge.kind) }}</span>
                <span v-if="!editing" class="detail-title">{{ detail.knowledge.title }}</span>
                <input v-else v-model="editForm.title" class="edit-input edit-input-title" />
              </div>
              <div class="detail-actions" v-if="!editing">
                <button class="btn btn-ghost btn-sm" @click="startEdit">{{ $t('knowledge.edit') }}</button>
                <template v-if="topTab === 'inbox'">
                  <button class="btn btn-primary btn-sm" @click="publishCurrent">{{ $t('knowledge.publish') }}</button>
                  <button class="btn btn-ghost btn-sm" @click="rejectCurrent">{{ $t('knowledge.reject') }}</button>
                </template>
                <button v-else class="btn btn-ghost btn-sm" @click="archiveCurrent">{{ $t('knowledge.archive') }}</button>
              </div>
              <div class="detail-actions" v-else>
                <button class="btn btn-ghost btn-sm" @click="cancelEdit">{{ $t('common.cancel') }}</button>
                <button class="btn btn-primary btn-sm" @click="saveEdit" :disabled="!editForm.title.trim()">{{ $t('common.save') }}</button>
              </div>
            </div>

            <div class="detail-badges">
              <span class="kn-card-status" :class="'st-' + detail.knowledge.status">{{ statusLabel(detail.knowledge.status) }}</span>
              <span v-if="detail.knowledge.confidence" :class="'conf-' + detail.knowledge.confidence">{{ $t('knowledge.confidenceBadge', { label: confidenceLabel(detail.knowledge.confidence) }) }}</span>
              <span class="badge-plain">{{ $t('knowledge.reuseCount', { n: detail.knowledge.reuse_count }) }}</span>
              <span class="badge-plain">{{ kindLabel(detail.knowledge.kind) }}</span>
            </div>

            <div class="detail-field">
              <label>{{ $t('knowledge.contentLabel') }}</label>
              <!-- B-260615-25:知识内容 Markdown 渲染(展示态),复用 useMarkdown composable(同 B-24 TaskDetail);编辑态保持 textarea -->
              <div
                v-if="!editing && detail.knowledge.content"
                class="detail-content ai-md"
                v-html="renderedContent"
              ></div>
              <div v-else-if="!editing" class="detail-content">—</div>
              <textarea v-else v-model="editForm.content" class="edit-input edit-textarea"></textarea>
            </div>

            <div class="detail-field">
              <label>{{ $t('knowledge.tagsLabel') }}</label>
              <div v-if="!editing" class="detail-tags">
                <span class="tag" v-for="tag in parseTags(detail.knowledge.tags)" :key="tag">{{ tag }}</span>
                <span v-if="parseTags(detail.knowledge.tags).length === 0" class="muted">{{ $t('knowledge.tagsNone') }}</span>
              </div>
              <input v-else v-model="editForm.tagsInput" class="edit-input" :placeholder="$t('knowledge.tagsPlaceholder')" />
            </div>
          </section>

          <!-- ② 溯源 -->
          <section class="detail-section">
            <div class="section-title">{{ $t('knowledge.traceTitle') }}</div>
            <div class="trace-row">
              <span class="trace-label">{{ $t('knowledge.traceMethod') }}</span>
              <span>{{ originMethod }}</span>
            </div>
            <div class="trace-row" v-if="originConvTitle">
              <span class="trace-label">{{ $t('knowledge.traceSource') }}</span>
              <span>{{ originConvTitle }}</span>
            </div>
            <div class="trace-row" v-if="originTime">
              <span class="trace-label">{{ $t('knowledge.traceTime') }}</span>
              <span>{{ originTime }}</span>
            </div>
            <div class="detail-field" v-if="reasoningText">
              <label>{{ $t('knowledge.reasoningLabel') }}</label>
              <div class="reasoning-box">{{ reasoningText }}</div>
            </div>
          </section>

          <!-- ③ 引用 -->
          <section class="detail-section">
            <div class="section-title">{{ $t('knowledge.refTitle', { n: referenceEvents.length }) }}</div>
            <div v-if="referenceEvents.length === 0" class="muted">{{ $t('knowledge.refEmpty') }}</div>
            <div v-else class="ref-list">
              <div v-for="ref in referenceEvents.slice(0, refLimit)" :key="ref.id" class="ref-item">
                <span class="ref-time">{{ relativeTime(ref.timestamp) }}</span>
                <span class="ref-conv">{{ refConvTitle(ref) }}</span>
                <span class="ref-query" v-if="refQuery(ref)">“{{ refQuery(ref) }}”</span>
              </div>
              <button v-if="referenceEvents.length > refLimit" class="btn btn-ghost btn-sm load-more" @click="refLimit += 10">
                {{ $t('knowledge.loadMore', { n: referenceEvents.length - refLimit }) }}
              </button>
            </div>
          </section>

          <!-- ④ 生命周期时间线 -->
          <section class="detail-section">
            <div class="section-title">{{ $t('knowledge.lifecycleTitle') }}</div>
            <div class="timeline">
              <div v-for="(node, idx) in timelineNodes" :key="node.id" class="tl-node">
                <div class="tl-dot">{{ node.icon }}</div>
                <div v-if="idx < timelineNodes.length - 1" class="tl-line"></div>
                <div class="tl-body">
                  <div class="tl-label">{{ node.label }}</div>
                  <div class="tl-time">{{ relativeTime(node.timestamp) }}</div>
                  <div class="tl-summary" v-if="node.summary">{{ node.summary }}</div>
                </div>
              </div>
            </div>
          </section>
        </template>

        <div v-else class="detail-empty">
          <div class="detail-empty-icon">👈</div>
          <div>{{ $t('knowledge.detailEmptyHint') }}</div>
        </div>
      </div>
    </div>

    <!-- ===== 新增知识对话框 ===== -->
    <div v-if="showCreateModal" class="modal-overlay" @click.self="closeCreateModal">
      <div class="modal-box">
        <div class="modal-title">{{ $t('knowledge.createTitle') }}</div>
        <div class="form-row">
          <label>{{ $t('knowledge.kindLabel') }}</label>
          <select v-model="form.kind" class="form-select">
            <option v-for="k in KNOWLEDGE_KINDS" :key="k.key" :value="k.key">{{ k.icon }} {{ kindText(k.key) }}</option>
          </select>
        </div>
        <div class="form-row">
          <label>{{ $t('knowledge.titleLabel') }}</label>
          <input v-model="form.title" type="text" class="form-input" :placeholder="$t('knowledge.titlePlaceholder')" />
        </div>
        <div class="form-row">
          <label>{{ $t('knowledge.contentLabel') }}</label>
          <textarea v-model="form.content" class="form-input form-textarea" :placeholder="$t('knowledge.contentPlaceholder')"></textarea>
        </div>
        <div class="form-row">
          <label>{{ $t('knowledge.tagsFieldLabel') }}</label>
          <input v-model="form.tagsInput" type="text" class="form-input" :placeholder="$t('knowledge.tagsFieldPlaceholder')" />
        </div>
        <div class="form-row">
          <label>{{ $t('knowledge.confidenceLabel') }}</label>
          <select v-model="form.confidence" class="form-select">
            <option value="">{{ $t('knowledge.confidenceNone') }}</option>
            <option value="high">{{ $t('knowledge.confidence.high') }}</option>
            <option value="medium">{{ $t('knowledge.confidence.medium') }}</option>
            <option value="low">{{ $t('knowledge.confidence.low') }}</option>
          </select>
        </div>
        <div class="modal-actions">
          <button class="btn btn-ghost" @click="closeCreateModal">{{ $t('common.cancel') }}</button>
          <button class="btn btn-primary" @click="submitCreate" :disabled="!form.title.trim()">{{ $t('knowledge.create') }}</button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useKnowledgeStore, KNOWLEDGE_KINDS, parseTags } from '../stores/knowledge'
import { useRendered } from '../composables/useMarkdown'
import type { KnowledgeDetailPayload, KnowledgeEventRecord } from '../api/types'

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

// 顶层 Tab: library(知识库) | inbox(审核收件箱)
const topTab = ref<'library' | 'inbox'>('library')

const categories = [
  { key: 'all', icon: '📦' },
  ...KNOWLEDGE_KINDS.map(k => ({ key: k.key, icon: k.icon })),
]
// 分类 chip 的展示文案:"全部" 走 categoryAll,其余走 knowledge.kind.<key>
function catLabel(key: string): string {
  return key === 'all' ? t('knowledge.categoryAll') : kindText(key)
}
// 纯类型文案(无 icon),用于下拉/分类
function kindText(key: string): string {
  return t(`knowledge.kind.${key}`)
}
const activeKind = ref('all')
const searchQuery = ref('')
let searchTimer: ReturnType<typeof setTimeout> | null = null

function onSearchInput() {
  if (searchTimer) clearTimeout(searchTimer)
  searchTimer = setTimeout(() => {
    if (searchQuery.value.trim()) {
      store.search(searchQuery.value)
    } else {
      store.loadList()
    }
  }, 300)
}

function switchTopTab(tab: 'library' | 'inbox') {
  topTab.value = tab
  selectedId.value = null
  detail.value = null
  if (tab === 'inbox') {
    store.loadCandidates()
  } else {
    store.loadList()
  }
}

// 左侧列表(随 Tab 切换数据源 + 知识库的分类过滤)
const listItems = computed(() => {
  const src = topTab.value === 'inbox' ? store.candidates : store.items
  if (topTab.value === 'library' && activeKind.value !== 'all') {
    return src.filter(i => i.kind === activeKind.value)
  }
  return src
})

function getCategoryCount(key: string): number {
  if (key === 'all') return store.items.length
  return store.items.filter(i => i.kind === key).length
}

// ===== 详情选中 + 加载 =====
const selectedId = ref<string | null>(null)
const detail = ref<KnowledgeDetailPayload | null>(null)
// B-260615-25:知识内容 Markdown 渲染(复用 AiChat/TaskDetail 同款渲染器,模块级单例),
// useRendered 封装 computed(读 mdReady 触发响应式 + renderMd)+ ensureLoaded(幂等预热)
const { rendered: renderedContent, ensureLoaded } = useRendered(
  () => detail.value?.knowledge.content ?? '',
)
const refLimit = ref(10)

async function selectKnowledge(id: string) {
  selectedId.value = id
  refLimit.value = 10
  try {
    detail.value = await store.getDetail(id)
  } catch (e: any) {
    console.error('加载详情失败', e)
  }
}

// 列表数据变化时(如刷新),若选中项已被移除则清空详情
watch(listItems, items => {
  if (selectedId.value && !items.some(i => i.id === selectedId.value)) {
    selectedId.value = null
    detail.value = null
  }
})

// ===== 编辑 =====
const editing = ref(false)
const editForm = ref({ title: '', content: '', tagsInput: '', confidence: '' })

function startEdit() {
  if (!detail.value) return
  const k = detail.value.knowledge
  editForm.value = {
    title: k.title,
    content: k.content,
    tagsInput: parseTags(k.tags).join(', '),
    confidence: k.confidence ?? '',
  }
  editing.value = true
}

function cancelEdit() {
  editing.value = false
}

async function saveEdit() {
  if (!detail.value || !editForm.value.title.trim()) return
  const tags = editForm.value.tagsInput.split(',').map(t => t.trim()).filter(Boolean)
  await store.update(detail.value.knowledge.id, {
    title: editForm.value.title.trim(),
    content: editForm.value.content,
    tags: JSON.stringify(tags),
    confidence: editForm.value.confidence,  // 空串=清空(后端映射 None),非 undefined
  })
  editing.value = false
  // 重新拉详情
  await selectKnowledge(detail.value.knowledge.id)
}

// ===== 审核操作(收件箱) =====
async function publishCurrent() {
  if (!detail.value) return
  await store.updateStatus(detail.value.knowledge.id, 'published')
  selectedId.value = null
  detail.value = null
}

async function rejectCurrent() {
  if (!detail.value) return
  await store.archive(detail.value.knowledge.id)
  selectedId.value = null
  detail.value = null
}

async function archiveCurrent() {
  if (!detail.value) return
  await store.archive(detail.value.knowledge.id)
  selectedId.value = null
  detail.value = null
}

// ===== 新增对话框 =====
const showCreateModal = ref(false)
const form = ref({ kind: 'pitfall', title: '', content: '', tagsInput: '', confidence: '' })

function openCreateModal() {
  form.value = { kind: 'pitfall', title: '', content: '', tagsInput: '', confidence: '' }
  showCreateModal.value = true
}
function closeCreateModal() {
  showCreateModal.value = false
}
async function submitCreate() {
  const tags = form.value.tagsInput.split(',').map(t => t.trim()).filter(Boolean)
  await store.create({
    kind: form.value.kind,
    title: form.value.title.trim(),
    content: form.value.content.trim(),
    tags: JSON.stringify(tags),
    confidence: form.value.confidence || undefined,
  })
  showCreateModal.value = false
  switchTopTab('inbox')
}

// ===== 事件解析辅助 =====
function parseContext(e: KnowledgeEventRecord): Record<string, any> {
  if (!e.context_json) return {}
  try { return JSON.parse(e.context_json) } catch { return {} }
}

function refConvTitle(e: KnowledgeEventRecord): string {
  return parseContext(e).conv_title || parseContext(e).conv_id || ''
}
function refQuery(e: KnowledgeEventRecord): string {
  return parseContext(e).query || ''
}

// 溯源:提取事件(created/extracted)
const extractedEvent = computed(() => detail.value?.events.find(e => e.event_type === 'extracted'))
const createdEvent = computed(() => detail.value?.events.find(e => e.event_type === 'created'))

const originMethod = computed(() => {
  if (extractedEvent.value) return t('knowledge.originExtracted')
  if (createdEvent.value) return t('knowledge.originManual')
  return t('knowledge.originUnknown')
})
const originConvTitle = computed(() => {
  if (!extractedEvent.value) return ''
  const ctx = parseContext(extractedEvent.value)
  return ctx.conv_title || ''
})
const originTime = computed(() => {
  const e = extractedEvent.value || createdEvent.value
  return e ? relativeTime(e.timestamp) : ''
})
const reasoningText = computed(() => {
  // 优先取主表 reasoning 字段,降级取 extracted 事件 context
  if (detail.value?.knowledge.reasoning) return detail.value.knowledge.reasoning
  if (extractedEvent.value) return parseContext(extractedEvent.value).reasoning || ''
  return ''
})

// 引用事件(倒序)
const referenceEvents = computed(() =>
  (detail.value?.events ?? []).filter(e => e.event_type === 'referenced').reverse()
)

// 生命周期时间线节点(正序 + 未来占位)
const timelineNodes = computed(() => {
  const events = detail.value?.events ?? []
  const nodes = events.map(e => {
    const ctx = parseContext(e)
    let icon = '•', label = e.event_type, summary = ''
    if (e.event_type === 'extracted') {
      icon = '🤖'; label = t('knowledge.timeline.extracted')
      summary = ctx.conv_title ? t('knowledge.timeline.summarySource', { title: ctx.conv_title }) : ''
    } else if (e.event_type === 'created') {
      icon = '✍️'; label = t('knowledge.timeline.created')
    } else if (e.event_type === 'status_changed') {
      const to = ctx.to
      if (to === 'published') { icon = '✅'; label = t('knowledge.timeline.published') }
      else if (to === 'archived') { icon = '🗄️'; label = t('knowledge.timeline.archived') }
      else if (to === 'pending_review') { icon = '👀'; label = t('knowledge.timeline.enterReview') }
      else { icon = '🔄'; label = t('knowledge.timeline.statusChanged', { to }) }
    } else if (e.event_type === 'referenced') {
      icon = '🔄'; label = t('knowledge.timeline.referenced')
      summary = ctx.conv_title ? t('knowledge.timeline.summaryConv', { title: ctx.conv_title }) : ''
    }
    return { id: e.id, icon, label, summary, timestamp: e.timestamp }
  })
  return nodes
})

// ===== 标签/时间辅助 =====
function kindLabel(key: string): string {
  const k = KNOWLEDGE_KINDS.find(c => c.key === key)
  return k ? `${k.icon} ${kindText(key)}` : key
}
function kindIcon(key: string): string {
  return KNOWLEDGE_KINDS.find(c => c.key === key)?.icon ?? '📄'
}
function statusLabel(status: string): string {
  const key = `knowledge.status.${status}`
  const msg = t(key)
  return msg === key ? status : msg
}
function confidenceLabel(c: string): string {
  const key = `knowledge.confidence.${c}`
  const msg = t(key)
  return msg === key ? c : msg
}
// 相对时间:复用 common.* 既有 key(justNow/minutesAgo/hoursAgo/dayAgo),30 天以上回退绝对值
function relativeTime(millisStr: string): string {
  const ms = Number(millisStr)
  if (!ms) return ''
  const diff = Date.now() - ms
  const min = Math.floor(diff / 60000)
  if (min < 1) return t('common.justNow')
  if (min < 60) return t('common.minutesAgo', { n: min })
  const hr = Math.floor(min / 60)
  if (hr < 24) return t('common.hoursAgo', { n: hr })
  const day = Math.floor(hr / 24)
  if (day < 30) return t('common.dayAgo', { n: day })
  return t('common.ago', { time: new Date(ms).toLocaleDateString() })
}

onMounted(() => {
  ensureLoaded() // 后台预热 Markdown 渲染器(模块单例,与 AiChat/TaskDetail 共享),不阻塞
  store.loadList()
  store.loadCandidates()
})
</script>

<style scoped>
.knowledge { padding: 16px 20px 20px; height: 100%; display: flex; flex-direction: column; }

.page-header {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: var(--df-gap-page);
}
.page-header h1 { font-size: 24px; font-weight: 500; color: var(--df-text); }
.header-actions { display: flex; gap: 8px; }

/* ===== 顶层 Tab ===== */
.top-tabs { display: flex; gap: 4px; margin-bottom: var(--df-gap-page); border-bottom: 0.5px solid var(--df-border); }
.top-tab {
  padding: 8px 16px; border: none; background: transparent; color: var(--df-text-secondary);
  font-size: 13px; cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.15s;
  display: flex; align-items: center; gap: 6px;
}
.top-tab:hover { color: var(--df-text); }
.top-tab.active { color: var(--df-accent); border-bottom-color: var(--df-accent); }
.inbox-badge {
  font-size: 11px; background: var(--df-danger); color: #fff;
  padding: 1px 6px; border-radius: var(--df-radius); min-width: 16px; text-align: center;
}

/* ===== 左右分栏 ===== */
.kn-layout {
  display: grid; grid-template-columns: 360px 1fr; gap: var(--df-gap-page);
  flex: 1; min-height: 0;
}
.kn-list-panel, .kn-detail-panel {
  background: var(--df-bg-panel, var(--df-bg-card));
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-lg);
  overflow: hidden; display: flex; flex-direction: column;
}
.kn-detail-panel { overflow-y: auto; padding: 20px; }

/* 左侧搜索 + 分类 */
.search-bar { padding: 12px 12px 0; }
.search-input {
  width: 100%; padding: 8px 12px; background: var(--df-bg-card);
  border: 0.5px solid var(--df-border); border-radius: var(--df-radius);
  color: var(--df-text); font-size: 13px; outline: none; box-sizing: border-box;
}
.search-input:focus { border-color: var(--df-accent); }
.category-tabs { display: flex; flex-wrap: wrap; gap: 4px; padding: 10px 12px; }
.cat-chip {
  display: flex; align-items: center; gap: 4px; padding: 4px 8px;
  border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm);
  background: transparent; color: var(--df-text-secondary); font-size: 12px; cursor: pointer;
}
.cat-chip:hover { background: var(--df-bg-card); }
.cat-active { background: var(--df-accent); color: #fff; border-color: var(--df-accent); }
.cat-count { font-size: 10px; opacity: 0.8; }

/* 左侧卡片列表 */
.list-cards { flex: 1; overflow-y: auto; padding: 8px 12px 12px; display: flex; flex-direction: column; gap: 8px; }
.kn-card {
  background: var(--df-bg-card); border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius); padding: 10px 12px; cursor: pointer; transition: all 0.15s;
}
.kn-card:hover { border-color: var(--df-accent); }
.kn-card.selected { border-color: var(--df-accent); box-shadow: inset 3px 0 0 var(--df-accent); }
.kn-card-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 6px; }
.kn-card-title { font-size: 13px; font-weight: 500; color: var(--df-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kn-card-desc {
  font-size: 12px; color: var(--df-text-secondary); line-height: 1.4; margin-bottom: 6px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.kn-card-meta { display: flex; gap: 8px; align-items: center; font-size: 11px; color: var(--df-text-dim); flex-wrap: wrap; }
.meta-kind { background: rgba(90,99,128,0.2); padding: 1px 6px; border-radius: var(--df-radius-sm); }
.meta-reuse { color: var(--df-info); }
.list-empty { text-align: center; padding: 40px 0; color: var(--df-text-dim); font-size: 13px; }

/* ===== 详情面板 ===== */
.detail-empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--df-text-dim); gap: 12px; }
.detail-empty-icon { font-size: 40px; }

.detail-section { padding-bottom: 18px; margin-bottom: 18px; border-bottom: 0.5px solid var(--df-border); }
.detail-section:last-child { border-bottom: none; margin-bottom: 0; }

.detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
.detail-title-row { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
.detail-kind-icon { font-size: 20px; }
.detail-title { font-size: 18px; font-weight: 500; color: var(--df-text); word-break: break-word; }
.detail-actions { display: flex; gap: 6px; flex-shrink: 0; }

.detail-badges { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; font-size: 11px; }
.badge-plain { color: var(--df-text-dim); }
.detail-field { margin-bottom: 12px; }
.detail-field label { display: block; font-size: 12px; color: var(--df-text-secondary); margin-bottom: 4px; }
.detail-content { font-size: 13px; color: var(--df-text); line-height: 1.6; white-space: pre-wrap; }

/* ===== 知识内容 Markdown 渲染(B-260615-25,样式同 TaskDetail B-24 .ai-md 收敛) ===== */
.detail-content.ai-md { white-space: normal; }
.detail-content.ai-md :deep(p) { margin: 0 0 6px; }
.detail-content.ai-md :deep(p:last-child) { margin-bottom: 0; }
.detail-content.ai-md :deep(ul), .detail-content.ai-md :deep(ol) { margin: 4px 0; padding-left: 20px; }
.detail-content.ai-md :deep(li) { margin: 2px 0; line-height: 1.5; }
.detail-content.ai-md :deep(code) {
  font-family: var(--df-font-mono);
  font-size: 12px;
  padding: 1px 5px;
  background: rgba(255,255,255,0.06);
  border-radius: var(--df-radius-sm);
  color: var(--df-accent);
}
.detail-content.ai-md :deep(pre) {
  margin: 8px 0;
  padding: 10px 12px;
  background: var(--df-bg);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius);
  overflow-x: auto;
}
.detail-content.ai-md :deep(pre code) {
  padding: 0;
  background: transparent;
  border-radius: 0;
  color: var(--df-text-secondary);
  font-size: 12px;
  line-height: 1.5;
}
.detail-content.ai-md :deep(blockquote) {
  margin: 6px 0;
  padding: 4px 12px;
  border-left: 2px solid var(--df-accent);
  color: var(--df-text-secondary);
}
.detail-content.ai-md :deep(h1), .detail-content.ai-md :deep(h2), .detail-content.ai-md :deep(h3) {
  font-weight: 500;
  color: var(--df-text);
  margin: 8px 0 4px;
}
.detail-content.ai-md :deep(h1) { font-size: 16px; }
.detail-content.ai-md :deep(h2) { font-size: 14px; }
.detail-content.ai-md :deep(h3) { font-size: 13px; }
.detail-content.ai-md :deep(a) { color: var(--df-accent); text-decoration: none; }
.detail-content.ai-md :deep(a:hover) { text-decoration: underline; }
.detail-content.ai-md :deep(strong) { font-weight: 500; color: var(--df-text); }
.detail-content.ai-md :deep(hr) { border: none; border-top: 0.5px solid var(--df-border); margin: 8px 0; }
.detail-content.ai-md :deep(table) {
  width: 100%; border-collapse: collapse; margin: 6px 0;
  font-size: 12px; overflow-x: auto; display: block;
}
.detail-content.ai-md :deep(th), .detail-content.ai-md :deep(td) {
  padding: 4px 8px; border: 0.5px solid var(--df-border); text-align: left;
}
.detail-content.ai-md :deep(th) { font-weight: 500; background: var(--df-bg); }
.detail-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.tag { font-size: 11px; padding: 2px 8px; border-radius: var(--df-radius-xs); background: rgba(108,99,255,0.1); color: var(--df-accent); }
.muted { color: var(--df-text-dim); font-size: 12px; }

/* 状态徽章 / 置信度 */
.kn-card-status { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: var(--df-radius-xs); white-space: nowrap; }
.st-candidate { background: rgba(255,217,61,0.15); color: var(--df-warning); }
.st-pending_review { background: rgba(108,159,255,0.15); color: var(--df-info); }
.st-published { background: rgba(100,255,218,0.15); color: var(--df-success); }
.st-archived { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }
.conf-high { background: rgba(100,255,218,0.15); color: var(--df-success); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-medium { background: rgba(255,217,61,0.15); color: var(--df-warning); padding: 1px 6px; border-radius: var(--df-radius-xs); }
.conf-low { background: rgba(255,107,107,0.15); color: var(--df-danger); padding: 1px 6px; border-radius: var(--df-radius-xs); }

/* 溯源 */
.section-title { font-size: 13px; font-weight: 500; color: var(--df-text); margin-bottom: 10px; }
.trace-row { display: flex; gap: 12px; font-size: 12px; margin-bottom: 6px; }
.trace-label { color: var(--df-text-dim); min-width: 72px; }
.reasoning-box {
  font-size: 13px; color: var(--df-text-secondary); line-height: 1.6;
  background: var(--df-bg-card); border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius); padding: 10px 12px; white-space: pre-wrap;
}

/* 引用 */
.ref-list { display: flex; flex-direction: column; gap: 8px; }
.ref-item {
  display: flex; gap: 10px; align-items: center; font-size: 12px;
  padding: 6px 10px; background: var(--df-bg-card); border-radius: var(--df-radius-sm);
}
.ref-time { color: var(--df-text-dim); white-space: nowrap; }
.ref-conv { color: var(--df-text); }
.ref-query { color: var(--df-text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.load-more { align-self: flex-start; margin-top: 4px; }

/* 生命周期时间线 */
.timeline { display: flex; flex-direction: column; }
.tl-node { display: flex; gap: 12px; position: relative; padding-bottom: 4px; }
.tl-dot {
  width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; font-size: 13px;
  background: var(--df-bg-card); border: 0.5px solid var(--df-border); z-index: 1;
}
.tl-line { position: absolute; left: 14px; top: 28px; bottom: -4px; width: 0.5px; background: var(--df-border); }
.tl-body { padding-top: 4px; }
.tl-label { font-size: 13px; color: var(--df-text); }
.tl-time { font-size: 11px; color: var(--df-text-dim); }
.tl-summary { font-size: 11px; color: var(--df-text-secondary); margin-top: 2px; }

/* ===== 编辑输入 ===== */
.edit-input {
  width: 100%; padding: 8px 10px; background: var(--df-bg-card);
  border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm);
  color: var(--df-text); font-size: 13px; outline: none; box-sizing: border-box;
}
.edit-input:focus { border-color: var(--df-accent); }
.edit-input-title { font-size: 16px; font-weight: 500; }
.edit-textarea { min-height: 100px; resize: vertical; font-family: inherit; }

/* ===== 按钮 ===== */
.btn {
  padding: 8px 16px; border: none; border-radius: var(--df-radius-sm);
  font-size: 13px; cursor: pointer; transition: all 0.15s;
}
.btn-sm { padding: 4px 10px; font-size: 12px; }
.btn-primary { background: var(--df-accent); color: #fff; }
.btn-primary:hover { background: var(--df-accent-hover); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-ghost { background: transparent; color: var(--df-text-secondary); border: 0.5px solid var(--df-border); }
.btn-ghost:hover { background: var(--df-bg-card); color: var(--df-text); }

/* ===== 新增对话框 ===== */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(0,0,0,0.5);
  display: flex; align-items: center; justify-content: center; z-index: 1000;
}
.modal-box {
  background: var(--df-bg-panel, var(--df-bg-card)); border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-lg); padding: 24px; width: 90%; max-width: 520px;
}
.modal-title { font-size: 16px; font-weight: 500; color: var(--df-text); margin-bottom: 16px; }
.form-row { margin-bottom: 12px; }
.form-row label { display: block; font-size: 12px; color: var(--df-text-secondary); margin-bottom: 4px; }
.form-input, .form-select {
  width: 100%; padding: 8px 10px; background: var(--df-bg-card);
  border: 0.5px solid var(--df-border); border-radius: var(--df-radius-sm);
  color: var(--df-text); font-size: 13px; outline: none; box-sizing: border-box;
}
.form-input:focus, .form-select:focus { border-color: var(--df-accent); }
.form-textarea { min-height: 80px; resize: vertical; font-family: inherit; }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
</style>
