<template>
  <div class="tasks">
    <!-- 顶部工具栏:标题 + 搜索 + 新建 -->
    <header class="page-header">
      <h1>{{ $t('tasks.title') }}</h1>
      <div class="header-actions">
        <input
          v-model="searchKeyword"
          class="search-input"
          :placeholder="$t('tasks.searchPlaceholder')"
          @keyup.esc="searchKeyword = ''"
        />
        <button class="btn btn-primary" @click="openCreateModal">{{ $t('tasks.create') }}</button>
      </div>
    </header>

    <!-- 筛选栏(紧凑下拉) -->
    <div class="filter-bar">
      <div class="filter-group">
        <span class="filter-label">{{ $t('tasks.filter.project') }}</span>
        <select v-model="activeProject" class="filter-select">
          <option value="all">{{ $t('tasks.filter.all') }}</option>
          <option v-for="p in store.projects" :key="p.id" :value="p.id">{{ p.name }}</option>
        </select>
      </div>
      <div class="filter-group">
        <span class="filter-label">{{ $t('tasks.filter.status') }}</span>
        <select v-model="activeStatus" class="filter-select">
          <option v-for="s in statusFilters" :key="s.key" :value="s.key">
            {{ s.icon }} {{ s.label }}
          </option>
        </select>
      </div>
      <div class="filter-group">
        <span class="filter-label">{{ $t('tasks.sort.label') }}</span>
        <select v-model="sortBy" class="filter-select">
          <option value="updated_at">{{ $t('tasks.sort.updated') }}</option>
          <option value="created_at">{{ $t('tasks.sort.created') }}</option>
          <option value="priority">{{ $t('tasks.sort.priority') }}</option>
          <option value="status">{{ $t('tasks.sort.status') }}</option>
        </select>
      </div>
      <span class="filter-count">{{ $t('common.pagination.total', { n: store.tasks.length }) }}</span>
    </div>

    <!-- 任务分组列表 -->
    <div class="task-groups">
      <div v-if="loading" class="empty-state">{{ $t('common.loading') }}</div>
      <div v-else-if="store.error" class="empty-state">{{ store.error }}</div>
      <div v-else-if="filteredGroups.length === 0" class="empty-state">
        <div class="empty-icon">📋</div>
        <div>{{ $t('tasks.group.empty') }}</div>
        <button class="btn btn-primary btn-sm" @click="openCreateModal">{{ $t('tasks.create') }}</button>
      </div>
      <template v-else>
        <section
          v-for="group in filteredGroups"
          :key="group.projectName"
          class="task-group"
          :class="{ collapsed: collapsedGroups.has(group.projectName) }"
        >
          <div class="group-header" @click="toggleGroup(group.projectName)">
            <span class="group-chevron">{{ collapsedGroups.has(group.projectName) ? '▸' : '▾' }}</span>
            <span class="group-icon">{{ group.icon }}</span>
            <h2 class="group-name">{{ group.projectName }}</h2>
            <span class="group-count">{{ group.tasks.length }}</span>
          </div>
          <div v-show="!collapsedGroups.has(group.projectName)" class="task-list">
            <div
              class="task-item"
              v-for="task in group.tasks"
              :key="task.id"
              @click="router.push(`/tasks/${task.id}`)"
            >
              <div class="task-main">
                <div class="task-title-row">
                  <span class="task-title">{{ task.title }}</span>
                  <span class="priority-badge" :class="priorityClass(task.priority)">{{ priorityLabel(task.priority) }}</span>
                </div>
                <div class="task-meta">
                  <span class="branch-tag" v-if="task.branch_name">
                    <span class="branch-icon">⑂</span>{{ task.branch_name }}
                  </span>
                  <span class="task-date">{{ formatRelative(task.updated_at) }}</span>
                </div>
              </div>
              <div class="task-actions">
                <span class="status-tag" :class="taskStatusClass(task.status)">{{ $t(statusLabel(task.status)) }}</span>
                <button class="task-quick-btn" :title="$t('tasks.quickActions')" @click.stop="toggleQuickMenu(task.id)">⚙️</button>
                <div v-if="quickMenuId === task.id" class="quick-menu" @click.stop>
                  <div class="quick-menu-section">
                    <div class="quick-menu-label">{{ $t('tasks.quickStatus') }}</div>
                    <button v-for="s in quickStatuses" :key="s.key" class="quick-menu-item" @click="quickAdvance(task.id, s.key)">
                      <span>{{ s.icon }}</span>{{ s.label }}
                    </button>
                  </div>
                  <div class="quick-menu-divider"></div>
                  <div class="quick-menu-section">
                    <div class="quick-menu-label">{{ $t('tasks.quickPriority') }}</div>
                    <button v-for="p in quickPriorities" :key="p.value" class="quick-menu-item" @click="quickPriority(task.id, p.value)">
                      <span :class="p.cls">●</span>{{ p.label }}
                    </button>
                  </div>
                  <div class="quick-menu-divider"></div>
                  <button class="quick-menu-item quick-menu-danger" @click="quickDelete(task)">{{ $t('tasks.quickDelete') }}</button>
                </div>
              </div>
            </div>
          </div>
        </section>
      </template>
    </div>

    <!-- 分页器 -->
    <Paginator
      v-model:page="page"
      v-model:pageSize="pageSize"
      :total="totalTasks"
    />

    <!-- 新建任务模态框(统一样式,去内联 style) -->
    <div class="modal-overlay" v-if="showCreateModal" @click.self="showCreateModal = false">
      <div class="modal-box">
        <h3>{{ $t('tasks.modal.title') }}</h3>
        <div class="modal-field">
          <label>{{ $t('tasks.modal.project') }}</label>
          <select v-model="newTaskProjectId">
            <option v-for="p in store.projects" :key="p.id" :value="p.id">{{ p.name }}</option>
          </select>
        </div>
        <div class="modal-field">
          <label>{{ $t('tasks.modal.titleField') }}</label>
          <input v-model="newTaskTitle" :placeholder="$t('tasks.modal.titlePlaceholder')" @keyup.enter="confirmCreate" />
        </div>
        <div class="modal-field">
          <label>{{ $t('tasks.modal.desc') }}</label>
          <input v-model="newTaskDesc" :placeholder="$t('tasks.modal.descPlaceholder')" />
        </div>
        <div class="modal-field">
          <label>{{ $t('tasks.modal.branch') }}</label>
          <input v-model="newTaskBranch" :placeholder="$t('tasks.modal.branchPlaceholder')" />
        </div>
        <div class="modal-field">
          <label>{{ $t('tasks.modal.priority') }}</label>
          <select v-model="newTaskPriority">
            <option :value="0">{{ $t('tasks.modal.priorityCritical') }}</option>
            <option :value="1">{{ $t('tasks.modal.priorityHigh') }}</option>
            <option :value="2">{{ $t('tasks.modal.priorityMedium') }}</option>
            <option :value="3">{{ $t('tasks.modal.priorityLow') }}</option>
          </select>
        </div>
        <!-- F-260619-01:关联灵感(1对1 单向,可选)。空串=不关联,与后端/AI 工具层一致。 -->
        <div class="modal-field">
          <label>{{ $t('tasks.modal.idea') }}</label>
          <select v-model="newTaskIdeaId">
            <option value="">{{ $t('tasks.modal.ideaPlaceholder') }}</option>
            <option v-for="idea in store.ideas" :key="idea.id" :value="idea.id">{{ idea.title }}</option>
          </select>
        </div>
        <div class="modal-actions">
          <button class="btn btn-ghost" @click="showCreateModal = false">{{ $t('common.cancel') }}</button>
          <button class="btn btn-primary" @click="confirmCreate" :disabled="submitting || !newTaskTitle.trim()">{{ $t('common.confirm') }}</button>
        </div>
      </div>
    </div>

    <!-- 确认弹层(删除任务,替代原生 window.confirm) -->
    <ConfirmDialog :visible="confirmState.visible" :msg="confirmState.msg" @result="answerConfirm" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch, reactive } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useProjectStore } from '@/stores/project'
import { formatRelative } from '@/utils/time'
import { taskStatusLabel as statusLabel, taskStatusClass, priorityLabel, priorityClass } from '../constants/project'
import { taskApi } from '@/api'
import type { TaskRecord, TaskQuery, ProjectId } from '@/api/types'
import Paginator from '../components/Paginator.vue'
import ConfirmDialog from '@/components/ConfirmDialog.vue'
import { useConfirm } from '@/composables/useConfirm'
import { usePersistedRef } from '@/composables/usePersistedRef'

const router = useRouter()
const store = useProjectStore()
const { t } = useI18n()
const { confirmState, confirmDialog, answerConfirm } = useConfirm()

// 列表筛选/分页状态持久化到 localStorage(key 前缀 'tasks.'),
// 刷新页面后保留用户上次选择。collapsedGroups 单独走 df-tasks-collapsed(沿用既有实现)。
const activeProject = usePersistedRef('tasks.activeProject', 'all')
const activeStatus = usePersistedRef('tasks.activeStatus', 'all')
const sortBy = usePersistedRef('tasks.sortBy', 'updated_at')
const searchKeyword = usePersistedRef('tasks.searchKeyword', '')
const loading = ref(false)

// 分页(默认开启 20 条/页)
const page = usePersistedRef('tasks.page', 1)
const pageSize = usePersistedRef('tasks.pageSize', 20)
const totalTasks = ref(0)

// 分组折叠状态(localStorage 记忆)
const collapsedGroups = reactive(new Set<string>())

// 快捷菜单
const quickMenuId = ref<string | null>(null)
function toggleQuickMenu(id: string) {
  quickMenuId.value = quickMenuId.value === id ? null : id
}
const quickStatuses = computed(() => [
  { key: 'todo', icon: '📝', label: t('tasks.statusFilter.todo') },
  { key: 'in_progress', icon: '🔨', label: t('tasks.statusFilter.in_progress') },
  { key: 'in_review', icon: '👀', label: t('tasks.statusFilter.in_review') },
  { key: 'testing', icon: '🧪', label: t('tasks.statusFilter.testing') },
  { key: 'done', icon: '✅', label: t('tasks.statusFilter.done') },
  { key: 'blocked', icon: '🚫', label: t('tasks.statusFilter.blocked') },
])
const quickPriorities = computed(() => [
  { value: 0, label: t('tasks.modal.priorityCritical'), cls: 'priority-critical' },
  { value: 1, label: t('tasks.modal.priorityHigh'), cls: 'priority-high' },
  { value: 2, label: t('tasks.modal.priorityMedium'), cls: 'priority-medium' },
  { value: 3, label: t('tasks.modal.priorityLow'), cls: 'priority-low' },
])
async function quickAdvance(id: string, target: string) {
  quickMenuId.value = null
  try {
    await taskApi.advance(id, target)
    await store.loadTasks(buildTaskQuery())
  } catch (e) { console.error('快捷改状态失败:', e) }
}
async function quickPriority(id: string, priority: number) {
  quickMenuId.value = null
  try {
    await store.updateTask(id, 'priority', String(priority))
    await store.loadTasks(buildTaskQuery())
  } catch (e) { console.error('快捷改优先级失败:', e) }
}
async function quickDelete(task: TaskRecord) {
  quickMenuId.value = null
  if (!await confirmDialog(t('tasks.confirmDelete', { title: task.title }))) return
  try {
    await store.deleteTask(task.id)
  } catch (e) { console.error('删除失败:', e) }
}
// 点击外部关闭快捷菜单
function closeQuickMenu() { quickMenuId.value = null }
function toggleGroup(name: string) {
  if (collapsedGroups.has(name)) {
    collapsedGroups.delete(name)
  } else {
    collapsedGroups.add(name)
  }
  localStorage.setItem('df-tasks-collapsed', JSON.stringify([...collapsedGroups]))
}
// 恢复折叠记忆
try {
  const saved = localStorage.getItem('df-tasks-collapsed')
  if (saved) {
    for (const name of JSON.parse(saved)) collapsedGroups.add(name)
  }
} catch { /* 忽略脏数据 */ }

// 搜索防抖
let _searchTimer: ReturnType<typeof setTimeout> | null = null
watch(searchKeyword, () => {
  if (_searchTimer) clearTimeout(_searchTimer)
  _searchTimer = setTimeout(() => {
    page.value = 1
    loading.value = true
    Promise.all([
      store.loadTasks(buildTaskQuery()),
      taskApi.count(buildTaskQuery()).then(n => totalTasks.value = n),
    ]).finally(() => { loading.value = false })
  }, 300)
})

// ── 新建任务模态框 ──
const showCreateModal = ref(false)
const newTaskProjectId = ref('')
const newTaskTitle = ref('')
const newTaskDesc = ref('')
const newTaskBranch = ref('')
const newTaskPriority = ref(2)
// F-260619-01:关联灵感(空串=不关联,与后端 idea_id 空串处理一致)
const newTaskIdeaId = ref('')
const submitting = ref(false)

interface TaskGroup {
  projectName: string
  icon: string
  tasks: TaskRecord[]
}

const statusFilters = computed<{ key: string; label: string; icon: string }[]>(() => [
  { key: 'all', label: t('tasks.statusFilter.all'), icon: '📋' },
  { key: 'todo', label: t('tasks.statusFilter.todo'), icon: '📝' },
  { key: 'in_progress', label: t('tasks.statusFilter.in_progress'), icon: '🔨' },
  { key: 'in_review', label: t('tasks.statusFilter.in_review'), icon: '👀' },
  { key: 'testing', label: t('tasks.statusFilter.testing'), icon: '🧪' },
  { key: 'done', label: t('tasks.statusFilter.done'), icon: '✅' },
  { key: 'blocked', label: t('tasks.statusFilter.blocked'), icon: '🚫' },
  { key: 'cancelled', label: t('tasks.statusFilter.cancelled'), icon: '🗑️' },
])

function getProjectName(projectId: string): string {
  return store.projects.find(p => p.id === projectId)?.name ?? t('tasks.group.unknownProject')
}

const projectIcons: Record<string, string> = {
  'u-ask': '🤖',
  'u-img': '🖼️',
  'flux': '⚡',
}

const filteredGroups = computed(() => {
  // 后端已分页(limit/offset),store.tasks 是当前页数据,直接分组无需再 slice
  const sorted = [...store.tasks]
  sorted.sort((a: any, b: any) => {
    if (sortBy.value === 'priority') return (a.priority ?? 2) - (b.priority ?? 2)
    if (sortBy.value === 'status') return String(a.status).localeCompare(String(b.status))
    const av = a[sortBy.value] ?? ''
    const bv = b[sortBy.value] ?? ''
    return String(bv).localeCompare(String(av))
  })

  // 按项目分组
  const groupMap = new Map<string, TaskRecord[]>()
  for (const task of sorted) {
    if (!groupMap.has(task.project_id)) {
      groupMap.set(task.project_id, [])
    }
    groupMap.get(task.project_id)!.push(task)
  }

  const result: TaskGroup[] = []
  for (const [projectId, groupTasks] of groupMap) {
    const name = getProjectName(projectId)
    result.push({
      projectName: name,
      icon: projectIcons[name] || '📂',
      tasks: groupTasks,
    })
  }
  return result
})

function buildTaskQuery(): TaskQuery | undefined {
  const projAll = activeProject.value === 'all'
  const statusAll = activeStatus.value === 'all'
  const kw = searchKeyword.value.trim()
  const query: TaskQuery = { order_by: sortBy.value }
  if (!projAll) query.project_id = activeProject.value
  if (!statusAll) query.status = activeStatus.value
  if (kw) query.keyword = kw
  // 后端真分页:传 limit/offset,配合 count_by_query 获取 total
  if (pageSize.value > 0) {
    query.limit = pageSize.value
    query.offset = (page.value - 1) * pageSize.value
  }
  return query
}

function openCreateModal() {
  newTaskProjectId.value = store.projects.length > 0 ? store.projects[0].id : ''
  newTaskTitle.value = ''
  newTaskDesc.value = ''
  newTaskBranch.value = ''
  newTaskPriority.value = 2
  newTaskIdeaId.value = ''
  showCreateModal.value = true
}

async function confirmCreate() {
  if (!newTaskTitle.value.trim() || !newTaskProjectId.value) return
  submitting.value = true
  try {
    const r = await store.createTask({
      project_id: newTaskProjectId.value as ProjectId,
      title: newTaskTitle.value.trim(),
      description: newTaskDesc.value.trim(),
      branch_name: newTaskBranch.value.trim() || undefined,
      priority: newTaskPriority.value,
      // F-260619-01:空串=不关联(对齐后端 idea_id 空串语义)
      idea_id: newTaskIdeaId.value.trim() || undefined,
    })
    if (!r) return
    showCreateModal.value = false
  } finally {
    submitting.value = false
  }
}

// 筛选切换重载
watch(activeProject, () => {
  store.setActiveTaskProject(activeProject.value)
  page.value = 1
  loading.value = true
  Promise.all([
    store.loadTasks(buildTaskQuery()),
    taskApi.count(buildTaskQuery()).then(n => totalTasks.value = n),
  ]).finally(() => { loading.value = false })
})

watch(activeStatus, () => {
  store.setActiveTaskStatus(activeStatus.value)
  page.value = 1
  loading.value = true
  Promise.all([
    store.loadTasks(buildTaskQuery()),
    taskApi.count(buildTaskQuery()).then(n => totalTasks.value = n),
  ]).finally(() => { loading.value = false })
})

watch(sortBy, () => {
  page.value = 1
  loading.value = true
  Promise.all([
    store.loadTasks(buildTaskQuery()),
    taskApi.count(buildTaskQuery()).then(n => totalTasks.value = n),
  ]).finally(() => { loading.value = false })
})

// 分页翻页/改每页条数:重新查询后端
watch([page, pageSize], () => {
  loading.value = true
  Promise.all([
    store.loadTasks(buildTaskQuery()),
    taskApi.count(buildTaskQuery()).then(n => totalTasks.value = n),
  ]).finally(() => { loading.value = false })
})

// Ctrl+N 新建 / Ctrl+F 搜索(桌面快捷键)
function onKeydown(e: KeyboardEvent) {
  if ((e.ctrlKey || e.metaKey) && e.key === 'n') {
    e.preventDefault()
    openCreateModal()
  } else if ((e.ctrlKey || e.metaKey) && e.key === 'f') {
    e.preventDefault()
    document.querySelector<HTMLInputElement>('.search-input')?.focus()
  }
}

onMounted(async () => {
  store.setActiveTaskProject(activeProject.value)
  store.setActiveTaskStatus(activeStatus.value)
  loading.value = true
  try {
    await Promise.all([
      store.loadProjects(),
      store.loadTasks(),
      // F-260619-01:加载灵感供新建任务模态关联下拉选择(幂等,已加载则 no-op)
      store.loadIdeas(),
      taskApi.count().then(n => totalTasks.value = n),
    ])
  } finally {
    loading.value = false
  }
  window.addEventListener('keydown', onKeydown)
  document.addEventListener('click', closeQuickMenu)
})

onUnmounted(() => {
  window.removeEventListener('keydown', onKeydown)
  document.removeEventListener('click', closeQuickMenu)
  if (_searchTimer) clearTimeout(_searchTimer)
})
</script>

<style scoped>
.tasks { padding: 16px 20px 20px; }

/* page-header / page-header h1 / header-actions 已提取到全局 global.css */

/* 搜索框 */
.search-input {
  width: 220px;
  max-width: 100%;
  flex: 1 1 220px;
  padding: 6px 12px;
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-sm);
  background: var(--df-bg-card);
  color: var(--df-text);
  font-size: 13px;
  outline: none;
  transition: border-color 0.15s;
}
.search-input:focus { border-color: var(--df-accent); }
.search-input::placeholder { color: var(--df-text-dim); }

/* btn / btn-primary / btn-ghost / btn-sm 已提取到全局 global.css */

/* 筛选栏(紧凑) */
/* filter-bar 已提取到全局 global.css，下方仅保留 Tasks 特有筛选类 */
.filter-group {
  display: flex;
  align-items: center;
  gap: 6px;
}
.filter-label {
  font-size: 12px;
  color: var(--df-text-dim);
  white-space: nowrap;
}
.filter-select {
  padding: 4px 10px;
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-sm);
  background: var(--df-bg);
  color: var(--df-text);
  font-size: 12px;
  cursor: pointer;
  outline: none;
  transition: border-color 0.15s;
}
.filter-select:hover { border-color: var(--df-accent); }
.filter-count {
  margin-left: auto;
  font-size: 12px;
  color: var(--df-text-dim);
}

/* 任务分组 */
.task-groups {
  display: flex;
  flex-direction: column;
  gap: var(--df-gap-grid);
}

.task-group {
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-lg);
  overflow: hidden;
}

.group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  cursor: pointer;
  user-select: none;
  border-bottom: 0.5px solid var(--df-border);
  transition: background 0.1s;
}
.group-header:hover { background: rgba(108, 99, 255, 0.04); }
.task-group.collapsed .group-header { border-bottom: none; }
.group-chevron { font-size: 10px; color: var(--df-text-dim); width: 12px; text-align: center; }
.group-icon { font-size: 16px; }
.group-name { font-size: 14px; font-weight: 500; color: var(--df-text); flex: 1; }
.group-count {
  font-size: 11px;
  color: var(--df-text-dim);
  background: rgba(255,255,255,0.06);
  padding: 1px 8px;
  border-radius: 8px;
}

/* 任务条目(紧凑) */
.task-list {
  display: flex;
  flex-direction: column;
}
.task-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 14px;
  border-bottom: 0.5px solid rgba(255,255,255,0.03);
  transition: background 0.1s;
  cursor: pointer;
}
.task-item:last-child { border-bottom: none; }
.task-item:hover { background: rgba(108, 99, 255, 0.04); }

.task-main { flex: 1; min-width: 0; }

.task-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.task-title {
  font-size: 13px;
  font-weight: 500;
  color: var(--df-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.priority-badge {
  font-size: 10px;
  font-weight: 500;
  padding: 1px 6px;
  border-radius: var(--df-radius-xs);
  flex-shrink: 0;
}
.priority-critical { background: rgba(255,107,107,0.2); color: var(--df-danger); }
.priority-high { background: rgba(255,152,0,0.2); color: #ff9800; }
.priority-medium { background: rgba(100,181,246,0.2); color: var(--df-info); }
.priority-low { background: rgba(90,99,128,0.2); color: var(--df-text-dim); }

.task-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 2px;
}
.branch-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  color: var(--df-text-dim);
}
.task-date {
  font-size: 11px;
  color: var(--df-text-dim);
}

.status-tag {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: var(--df-radius-xs);
  flex-shrink: 0;
  white-space: nowrap;
}

/* 快捷操作 */
.task-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  position: relative;
}
.task-quick-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 14px;
  padding: 2px 4px;
  opacity: 0;
  transition: opacity 0.15s;
}
.task-item:hover .task-quick-btn { opacity: 0.6; }
.task-quick-btn:hover { opacity: 1; }

.quick-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 160px;
  background: var(--df-bg-card);
  border: 0.5px solid var(--df-border);
  border-radius: var(--df-radius-sm);
  box-shadow: 0 6px 16px rgba(0,0,0,0.25);
  z-index: 20;
  padding: 6px 0;
}
.quick-menu-section { padding: 4px 0; }
.quick-menu-label {
  font-size: 10px;
  color: var(--df-text-dim);
  padding: 2px 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.quick-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 5px 12px;
  background: none;
  border: none;
  color: var(--df-text);
  font-size: 12px;
  cursor: pointer;
  text-align: left;
}
.quick-menu-item:hover { background: rgba(255,255,255,0.06); }
.quick-menu-divider {
  height: 0.5px;
  background: var(--df-border);
  margin: 4px 0;
}
.quick-menu-danger { color: var(--df-danger); }

/* 空态 */
/* empty-state 已提取到全局 global.css */
.empty-icon { font-size: 32px; opacity: 0.4; }

/* 模态框 overlay/box/modal-field/modal-actions 已提取到 global.css 全局 */
</style>
