﻿<template>
  <!-- <ContentWrap class="page-hero">
    <div class="hero-panel">
      <div>
        <div class="hero-eyebrow">AI Companion Admin</div>
        <div class="hero-title">陪聊角色管理</div>
        <div class="hero-subtitle">
          聚焦角色筛选、上线状态和人设浏览，降低长表格的阅读负担。
        </div>
      </div>
      <div class="hero-metrics">
        <div class="metric-card">
          <div class="metric-label">当前页角色</div>
          <div class="metric-value">{{ list.length }}</div>
        </div>
        <div class="metric-card">
          <div class="metric-label">在线角色</div>
          <div class="metric-value">{{ onlineCount }}</div>
        </div>
        <div class="metric-card">
          <div class="metric-label">公开角色</div>
          <div class="metric-value">{{ publicCount }}</div>
        </div>
        <div class="metric-card accent">
          <div class="metric-label">已选中</div>
          <div class="metric-value">{{ checkedIds.length }}</div>
        </div>
      </div>
    </div>
  </ContentWrap> -->

  <ContentWrap>
    <div class="toolbar-header">
      <div>
        <div class="section-title">筛选条件</div>
        <div class="section-desc">保留高频条件直出，低频条件收进高级筛选。</div>
      </div>
      <el-button text type="primary" @click="showAdvancedFilters = !showAdvancedFilters">
        <Icon :icon="showAdvancedFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-4px" />
        {{ showAdvancedFilters ? '收起高级筛选' : '展开高级筛选' }}
      </el-button>
    </div>

    <el-form ref="queryFormRef" :model="queryParams" label-width="90px" class="filter-form">
      <div class="filter-grid">
        <el-form-item label="性别" prop="gender">
          <el-select v-model="queryParams.gender" placeholder="全部性别" clearable filterable class="!w-full">
            <el-option label="Male" value="male" />
            <el-option label="Female" value="female" />
            <el-option label="Other" value="other" />
          </el-select>
        </el-form-item>
        <el-form-item label="状态" prop="status">
          <el-select v-model="queryParams.status" placeholder="全部状态" clearable class="!w-full">
            <el-option label="在线" :value="1" />
            <el-option label="离线" :value="0" />
          </el-select>
        </el-form-item>
        <el-form-item label="可见性" prop="visibility">
          <el-select v-model="queryParams.visibility" placeholder="全部可见性" clearable class="!w-full">
            <el-option label="公开" :value="1" />
            <el-option label="内测" :value="2" />
            <el-option label="隐藏" :value="3" />
          </el-select>
        </el-form-item>
        <el-form-item label="性格标签" prop="personalityTags">
          <el-input v-model="queryParams.personalityTags" placeholder="如：温柔、治愈" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="说话风格" prop="speakingStyle">
          <el-input v-model="queryParams.speakingStyle" placeholder="如：理性、活泼" clearable @keyup.enter="handleQuery" />
        </el-form-item>
        <el-form-item label="语音 ID" prop="voiceId">
          <el-input v-model="queryParams.voiceId" placeholder="请输入 voiceId" clearable @keyup.enter="handleQuery" />
        </el-form-item>
      </div>

      <el-collapse-transition>
        <div v-show="showAdvancedFilters" class="advanced-panel">
          <div class="filter-grid">
            <el-form-item label="年龄段" prop="ageRange">
              <el-input v-model="queryParams.ageRange" placeholder="如：20s、25-30" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="系统 Prompt" prop="systemPrompt">
              <el-input v-model="queryParams.systemPrompt" placeholder="按核心人设搜索" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="开场白" prop="prologue">
              <el-input v-model="queryParams.prologue" placeholder="搜索开场白内容" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="热度分" prop="popularityScore">
              <el-input v-model="queryParams.popularityScore" placeholder="按热度分搜索" clearable
                @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="排序权重" prop="sortOrder">
              <el-input v-model="queryParams.sortOrder" placeholder="按排序权重搜索" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="创建时间" prop="createdAt">
              <el-date-picker v-model="queryParams.createdAt" type="date" value-format="YYYY-MM-DD" placeholder="选择创建日期"
                clearable class="!w-full" />
            </el-form-item>
            <el-form-item label="更新时间" prop="updatedAt">
              <el-date-picker v-model="queryParams.updatedAt" type="date" value-format="YYYY-MM-DD" placeholder="选择更新日期"
                clearable class="!w-full" />
            </el-form-item>
            <el-form-item label="头像 URL" prop="avatarUrl">
              <el-input v-model="queryParams.avatarUrl" placeholder="匹配头像 URL" clearable @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="封面 URL" prop="coverImageUrl">
              <el-input v-model="queryParams.coverImageUrl" placeholder="匹配封面 URL" clearable
                @keyup.enter="handleQuery" />
            </el-form-item>
            <el-form-item label="开场白音频" prop="prologueAudio">
              <el-input v-model="queryParams.prologueAudio" placeholder="匹配音频地址" clearable @keyup.enter="handleQuery" />
            </el-form-item>
          </div>
        </div>
      </el-collapse-transition>

      <div class="toolbar-actions">
        <div class="action-group">
          <el-button @click="handleQuery">
            <Icon icon="ep:search" class="mr-5px" />
            搜索
          </el-button>
          <el-button @click="resetQuery">
            <Icon icon="ep:refresh" class="mr-5px" />
            重置
          </el-button>
        </div>
        <div class="action-group">
          <el-button type="primary" @click="openForm('create')" v-hasPermi="['keyboard:ai-companion:create']">
            <Icon icon="ep:plus" class="mr-5px" />
            新增角色
          </el-button>
          <el-button type="success" plain @click="handleExport" :loading="exportLoading"
            v-hasPermi="['keyboard:ai-companion:export']">
            <Icon icon="ep:download" class="mr-5px" />
            导出
          </el-button>
          <el-button type="danger" plain :disabled="isEmpty(checkedIds)" @click="handleDeleteBatch"
            v-hasPermi="['keyboard:ai-companion:delete']">
            <Icon icon="ep:delete" class="mr-5px" />
            批量删除
          </el-button>
        </div>
      </div>
    </el-form>
  </ContentWrap>

  <ContentWrap>
    <div class="toolbar-header">
      <div>
        <div class="section-title">角色列表</div>
        <div class="section-desc">
          共 {{ total }} 条记录，当前展示 {{ list.length }} 条。
        </div>
      </div>
      <div class="selection-indicator" :class="{ active: checkedIds.length > 0 }">
        <Icon icon="ep:select" class="mr-6px" />
        已勾选 {{ checkedIds.length }} 项
      </div>
    </div>

    <el-table row-key="id" v-loading="loading" :data="list" stripe highlight-current-row :show-overflow-tooltip="false"
      @current-change="handleCurrentChange" @selection-change="handleRowCheckboxChange">
      <el-table-column type="selection" width="52" />
      <el-table-column label="角色信息" min-width="300">
        <template #default="{ row }">
          <div class="companion-cell">
            <el-image v-if="row.coverImageUrl" :src="row.coverImageUrl" :preview-src-list="buildPreviewList(row)"
              fit="cover" class="cover-image" preview-teleported />
            <div v-else class="cover-image cover-image--empty">无封面</div>

            <div class="companion-main">
              <div class="companion-head">
                <el-avatar v-if="row.avatarUrl" :src="row.avatarUrl" :size="42" />
                <div v-else class="avatar-fallback">AI</div>
                <div>
                  <div class="companion-id">ID {{ row.id }}</div>
                  <div class="companion-meta">
                    <span>{{ formatGender(row.gender) }}</span>
                    <span>{{ row.ageRange || '年龄未填' }}</span>
                  </div>
                </div>
              </div>
              <div class="tag-row">
                <el-tag v-for="tag in getTagList(row.personalityTags)" :key="tag" size="small" effect="plain" round>
                  {{ tag }}
                </el-tag>
                <span v-if="getTagList(row.personalityTags).length === 0" class="muted-text">
                  暂无标签
                </span>
              </div>
            </div>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="人设概览" min-width="330">
        <template #default="{ row }">
          <div class="stack-text">
            <div class="stack-title">{{ row.speakingStyle || '未填写说话风格' }}</div>
            <div class="stack-desc line-clamp-2">
              {{ row.systemPrompt || '暂无系统 Prompt' }}
            </div>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="状态" width="170" align="center">
        <template #default="{ row }">
          <div class="status-stack">
            <el-tag :type="getStatusMeta(row.status).type" round>
              {{ getStatusMeta(row.status).label }}
            </el-tag>
            <el-tag :type="getVisibilityMeta(row.visibility).type" effect="plain" round>
              {{ getVisibilityMeta(row.visibility).label }}
            </el-tag>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="排序 / 热度" width="150" align="center">
        <template #default="{ row }">
          <div class="score-stack">
            <div>排序 {{ row.sortOrder ?? '-' }}</div>
            <div class="score-highlight">热度 {{ row.popularityScore ?? '-' }}</div>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="开场白" min-width="260">
        <template #default="{ row }">
          <div class="line-clamp-3">{{ row.prologue || '暂无开场白' }}</div>
        </template>
      </el-table-column>
      <el-table-column label="语音" min-width="180">
        <template #default="{ row }">
          <div class="stack-text">
            <div class="stack-title mono-text">{{ row.voiceId || '-' }}</div>
            <div class="stack-desc line-clamp-1">{{ row.prologueAudio || '未配置开场音频' }}</div>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="更新时间" width="180" align="center">
        <template #default="{ row }">
          {{ dateFormatter(row.updatedAt) || '-' }}
        </template>
      </el-table-column>
      <el-table-column label="操作" align="center" width="130" fixed="right">
        <template #default="{ row }">
          <el-button link type="primary" @click="openForm('update', row.id)"
            v-hasPermi="['keyboard:ai-companion:update']">
            编辑
          </el-button>
          <el-button link type="danger" @click="handleDelete(row.id)" v-hasPermi="['keyboard:ai-companion:delete']">
            删除
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
      @pagination="getList" />
  </ContentWrap>

  <ContentWrap>
    <div class="toolbar-header">
      <div>
        <div class="section-title">角色详情</div>
        <div class="section-desc">点击表格行查看当前角色的人设摘要和国际化内容。</div>
      </div>
      <div v-if="currentRow.id" class="selection-indicator active">
        当前查看 ID {{ currentRow.id }}
      </div>
    </div>

    <el-empty v-if="!currentRow.id" description="请选择上方列表中的一条角色记录" :image-size="120" />
    <template v-else>
      <div class="detail-banner">
        <el-avatar v-if="currentRow.avatarUrl" :src="currentRow.avatarUrl" :size="56" />
        <div v-else class="avatar-fallback avatar-fallback--large">AI</div>
        <div class="detail-banner__content">
          <div class="detail-banner__title">
            角色 #{{ currentRow.id }}
            <el-tag size="small" :type="getStatusMeta(currentRow.status).type" round>
              {{ getStatusMeta(currentRow.status).label }}
            </el-tag>
            <el-tag size="small" :type="getVisibilityMeta(currentRow.visibility).type" effect="plain" round>
              {{ getVisibilityMeta(currentRow.visibility).label }}
            </el-tag>
          </div>
          <div class="detail-banner__subtitle">
            {{ formatGender(currentRow.gender) }} / {{ currentRow.ageRange || '年龄未填' }} / {{
              currentRow.speakingStyle || '说话风格未填'
            }}
          </div>
        </div>
      </div>

      <el-row :gutter="16">
        <el-col :xs="24" :lg="14">
          <el-card shadow="never" class="detail-card">
            <template #header>
              <div class="detail-card__title">角色摘要</div>
            </template>
            <el-descriptions :column="1" border>
              <el-descriptions-item label="性格标签">
                <div class="tag-row">
                  <el-tag v-for="tag in getTagList(currentRow.personalityTags)" :key="tag" size="small" effect="plain"
                    round>
                    {{ tag }}
                  </el-tag>
                  <span v-if="getTagList(currentRow.personalityTags).length === 0">暂无标签</span>
                </div>
              </el-descriptions-item>
              <el-descriptions-item label="系统 Prompt">
                {{ currentRow.systemPrompt || '暂无系统 Prompt' }}
              </el-descriptions-item>
              <el-descriptions-item label="开场白">
                {{ currentRow.prologue || '暂无开场白' }}
              </el-descriptions-item>
              <el-descriptions-item label="语音配置">
                <div class="detail-audio">
                  <span>voiceId：{{ currentRow.voiceId || '-' }}</span>
                  <span>音频：{{ currentRow.prologueAudio || '未配置' }}</span>
                </div>
              </el-descriptions-item>
            </el-descriptions>
          </el-card>
        </el-col>
        <el-col :xs="24" :lg="10">
          <el-card shadow="never" class="detail-card">
            <template #header>
              <div class="detail-card__title">运营信息</div>
            </template>
            <el-descriptions :column="1" border>
              <el-descriptions-item label="排序权重">
                {{ currentRow.sortOrder ?? '-' }}
              </el-descriptions-item>
              <el-descriptions-item label="热度评分">
                {{ currentRow.popularityScore ?? '-' }}
              </el-descriptions-item>
              <el-descriptions-item label="创建时间">
                {{ dateFormatter(currentRow.createdAt) || '-' }}
              </el-descriptions-item>
              <el-descriptions-item label="更新时间">
                {{ dateFormatter(currentRow.updatedAt) || '-' }}
              </el-descriptions-item>
            </el-descriptions>
          </el-card>
        </el-col>
      </el-row>

      <div class="i18n-panel">
        <el-tabs model-value="aiCompanionI18n">
          <el-tab-pane label="国际化内容" name="aiCompanionI18n">
            <AiCompanionI18nList :id="currentRow.id" />
          </el-tab-pane>
        </el-tabs>
      </div>
    </template>
  </ContentWrap>

  <AiCompanionForm ref="formRef" @success="getList" />
</template>

<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { isEmpty } from '@/utils/is'
import { AiCompanionApi, type AiCompanion } from '@/api/keyboard/aicompanion'
import AiCompanionForm from './AiCompanionForm.vue'
import AiCompanionI18nList from './components/AiCompanionI18nList.vue'

defineOptions({ name: 'KeyboardAiCompanion' })

type QueryParams = {
  pageNo: number
  pageSize: number
  avatarUrl: string | undefined
  coverImageUrl: string | undefined
  gender: string | undefined
  ageRange: string | undefined
  personalityTags: string | undefined
  speakingStyle: string | undefined
  systemPrompt: string | undefined
  status: number | undefined
  visibility: number | undefined
  sortOrder: number | string | undefined
  popularityScore: number | string | undefined
  createdAt: string | undefined
  updatedAt: string | undefined
  prologue: string | undefined
  prologueAudio: string | undefined
  voiceId: string | undefined
}

const message = useMessage()
const { t } = useI18n()

const loading = ref(true)
const exportLoading = ref(false)
const showAdvancedFilters = ref(false)
const list = ref<AiCompanion[]>([])
const total = ref(0)
const checkedIds = ref<number[]>([])
const currentRow = ref<Partial<AiCompanion>>({})
const queryFormRef = ref()
const formRef = ref()

const queryParams = reactive<QueryParams>({
  pageNo: 1,
  pageSize: 10,
  avatarUrl: undefined,
  coverImageUrl: undefined,
  gender: undefined,
  ageRange: undefined,
  personalityTags: undefined,
  speakingStyle: undefined,
  systemPrompt: undefined,
  status: undefined,
  visibility: undefined,
  sortOrder: undefined,
  popularityScore: undefined,
  createdAt: undefined,
  updatedAt: undefined,
  prologue: undefined,
  prologueAudio: undefined,
  voiceId: undefined
})

const onlineCount = computed(() => list.value.filter((item) => Number(item.status) === 1).length)
const publicCount = computed(() => list.value.filter((item) => Number(item.visibility) === 1).length)

const getList = async () => {
  loading.value = true
  try {
    const data = await AiCompanionApi.getAiCompanionPage(queryParams)
    list.value = data.list || []
    total.value = data.total || 0
    syncCurrentRow()
  } finally {
    loading.value = false
  }
}

const syncCurrentRow = () => {
  if (!list.value.length) {
    currentRow.value = {}
    return
  }
  const matchedRow = list.value.find((item) => item.id === currentRow.value.id)
  currentRow.value = matchedRow || list.value[0]
}

const handleQuery = () => {
  queryParams.pageNo = 1
  getList()
}

const resetQuery = () => {
  queryFormRef.value?.resetFields()
  checkedIds.value = []
  handleQuery()
}

const openForm = (type: string, id?: number) => {
  formRef.value?.open(type, id)
}

const handleDelete = async (id: number) => {
  try {
    await message.delConfirm()
    await AiCompanionApi.deleteAiCompanion(id)
    message.success(t('common.delSuccess'))
    checkedIds.value = checkedIds.value.filter((item) => item !== id)
    if (currentRow.value.id === id) {
      currentRow.value = {}
    }
    await getList()
  } catch { }
}

const handleDeleteBatch = async () => {
  try {
    await message.delConfirm()
    await AiCompanionApi.deleteAiCompanionList(checkedIds.value)
    checkedIds.value = []
    message.success(t('common.delSuccess'))
    await getList()
  } catch { }
}

const handleRowCheckboxChange = (records: AiCompanion[]) => {
  checkedIds.value = records.map((item) => item.id)
}

const handleExport = async () => {
  try {
    await message.exportConfirm()
    exportLoading.value = true
    const data = await AiCompanionApi.exportAiCompanion(queryParams)
    download.excel(data, 'AI陪聊角色.xls')
  } catch {
  } finally {
    exportLoading.value = false
  }
}

const handleCurrentChange = (row?: AiCompanion) => {
  currentRow.value = row || {}
}

const getStatusMeta = (status?: number) => {
  if (Number(status) === 1) {
    return { label: '在线', type: 'success' as const }
  }
  return { label: '离线', type: 'info' as const }
}

const getVisibilityMeta = (visibility?: number) => {
  if (Number(visibility) === 1) {
    return { label: '公开', type: 'success' as const }
  }
  if (Number(visibility) === 2) {
    return { label: '内测', type: 'warning' as const }
  }
  return { label: '隐藏', type: 'info' as const }
}

const formatGender = (gender?: string) => {
  if (!gender) return '未设置性别'
  const normalized = gender.toLowerCase()
  if (normalized === 'male') return 'Male'
  if (normalized === 'female') return 'Female'
  if (normalized === 'other') return 'Other'
  return gender
}

const getTagList = (tags?: AiCompanion['personalityTags']) => {
  if (!tags) return []
  if (Array.isArray(tags)) {
    return tags.map((item) => String(item)).filter(Boolean)
  }
  if (typeof tags === 'string') {
    return tags
      .split(/[，,、]/)
      .map((item) => item.trim())
      .filter(Boolean)
  }
  return []
}

const buildPreviewList = (row: AiCompanion) => {
  return [row.coverImageUrl, row.avatarUrl].filter(Boolean) as string[]
}

onMounted(() => {
  getList()
})
</script>

<style scoped>
.page-hero {
  overflow: hidden;
}

.hero-panel {
  display: flex;
  gap: 24px;
  justify-content: space-between;
  padding: 4px;
  color: #163247;
}

.hero-eyebrow {
  margin-bottom: 10px;
  color: #5b7a90;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.hero-title {
  margin-bottom: 10px;
  font-size: 28px;
  font-weight: 700;
  line-height: 1.2;
}

.hero-subtitle {
  max-width: 640px;
  color: #5f7386;
  line-height: 1.7;
}

.hero-metrics {
  display: grid;
  flex-shrink: 0;
  grid-template-columns: repeat(2, minmax(120px, 1fr));
  gap: 12px;
}

.metric-card {
  min-width: 120px;
  padding: 16px;
  background: linear-gradient(180deg, rgb(255 255 255 / 90%), rgb(243 248 252 / 92%));
  border: 1px solid rgb(118 153 177 / 18%);
  border-radius: 18px;
  box-shadow: 0 12px 30px rgb(109 141 160 / 10%);
}

.metric-card.accent {
  background: linear-gradient(135deg, #1c7ed6, #34a0a4);
  color: #fff;
}

.metric-label {
  margin-bottom: 10px;
  font-size: 12px;
  opacity: 0.75;
}

.metric-value {
  font-size: 24px;
  font-weight: 700;
}

.toolbar-header {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}

.section-title {
  color: var(--el-text-color-primary);
  font-size: 16px;
  font-weight: 700;
}

.section-desc {
  margin-top: 4px;
  color: var(--el-text-color-secondary);
  font-size: 13px;
}

.filter-form :deep(.el-form-item) {
  margin-bottom: 18px;
}

.filter-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0 16px;
}

.advanced-panel {
  padding-top: 8px;
  margin-top: 4px;
  border-top: 1px dashed var(--el-border-color-lighter);
}

.toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: space-between;
  padding-top: 4px;
}

.action-group {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.selection-indicator {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 8px 14px;
  color: var(--el-text-color-secondary);
  background: var(--el-fill-color-light);
  border-radius: 999px;
  transition: all var(--el-transition-duration);
}

.selection-indicator.active {
  color: #155e75;
  background: #e0f2fe;
}

.companion-cell {
  display: flex;
  gap: 14px;
  align-items: center;
}

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

.companion-head {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 8px;
}

.companion-id {
  color: var(--el-text-color-primary);
  font-weight: 700;
}

.companion-meta {
  display: flex;
  gap: 8px;
  margin-top: 3px;
  color: var(--el-text-color-secondary);
  font-size: 12px;
}

.avatar-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  color: #155e75;
  font-size: 13px;
  font-weight: 700;
  background: linear-gradient(135deg, #d7f3ff, #eefaf5);
  border-radius: 50%;
}

.avatar-fallback--large {
  width: 56px;
  height: 56px;
}

.cover-image {
  flex-shrink: 0;
  width: 88px;
  height: 56px;
  overflow: hidden;
  border-radius: 14px;
}

.cover-image--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--el-text-color-secondary);
  font-size: 12px;
  background: var(--el-fill-color-light);
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.muted-text {
  color: var(--el-text-color-secondary);
  font-size: 12px;
}

.stack-text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.stack-title {
  color: var(--el-text-color-primary);
  font-weight: 600;
}

.stack-desc {
  color: var(--el-text-color-secondary);
  line-height: 1.6;
}

.status-stack,
.score-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
}

.score-highlight {
  color: #0f766e;
  font-weight: 600;
}

.mono-text {
  font-family: Consolas, Monaco, 'Courier New', monospace;
}

.detail-banner {
  display: flex;
  gap: 14px;
  align-items: center;
  padding: 18px 20px;
  margin-bottom: 16px;
  background: linear-gradient(135deg, #f7fbff, #f7fcfa);
  border: 1px solid var(--el-border-color-lighter);
  border-radius: 18px;
}

.detail-banner__content {
  min-width: 0;
  flex: 1;
}

.detail-banner__title {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
  color: var(--el-text-color-primary);
  font-size: 18px;
  font-weight: 700;
}

.detail-banner__subtitle {
  color: var(--el-text-color-secondary);
  line-height: 1.6;
}

.detail-card {
  height: 100%;
  margin-bottom: 16px;
}

.detail-card__title {
  color: var(--el-text-color-primary);
  font-weight: 700;
}

.detail-audio {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.i18n-panel {
  margin-top: 8px;
}

:deep(.el-table .cell) {
  line-height: 1.5;
}

:deep(.el-table__row.current-row > td.el-table__cell) {
  background: #f0f9ff !important;
}

:deep(.el-image__error),
:deep(.el-image__placeholder) {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--el-text-color-secondary);
  background: var(--el-fill-color-light);
}

@media (max-width: 992px) {

  .hero-panel,
  .toolbar-header,
  .toolbar-actions {
    flex-direction: column;
    align-items: stretch;
  }

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

@media (max-width: 640px) {
  .hero-title {
    font-size: 24px;
  }

  .hero-metrics {
    grid-template-columns: 1fr;
  }

  .companion-cell,
  .detail-banner {
    align-items: flex-start;
  }
}
</style>
