<template>
  <div>
        <!-- 仪表盘 -->
        <div v-show="activeMenu === 'dashboard'" class="section-content">

          <!-- Row 1: 6 个统计卡 — 文字在上，数字在下 -->
          <div class="dash-row dash-row-stats">
            <el-card
              v-for="item in statItems" :key="item.key"
              class="stat-card stt-card"
            >
              <div class="stt-label">{{ item.label }}</div>
              <div class="stt-value">{{ (stats as any)[item.key] ?? 0 }}</div>
            </el-card>
          </div>

          <!-- Row 2: 网盘使用空间 — flex-wrap 自适应 -->
          <div class="dash-row">
            <el-card class="storage-section-card">
              <template #header><span>💾 网盘使用空间</span></template>
              <div class="storage-grid">
                <div
                  v-for="item in stats.cloudUsage" :key="item.cloudType + '-' + (item.nickname || '')"
                  class="storage-drive-card"
                >
                  <div class="drive-header">
                    <img :src="driveIcon(item.cloudType)" class="drive-icon" />
                    <span class="drive-name">{{ item.nickname || item.cloudType }}</span>
                    <span :class="['drive-status', item.isActive ? 'active' : 'inactive']">
                      {{ item.isActive ? '正常' : '停用' }}
                    </span>
                  </div>
                  <div class="drive-space">
                    <span class="drive-used">{{ item.storageUsed || '--' }}</span>
                    <span class="drive-sep">/</span>
                    <span class="drive-total">{{ item.storageTotal || '--' }}</span>
                  </div>
                  <el-progress
                    :percentage="cloudStoragePercent(item)"
                    :stroke-width="12"
                    :color="cloudStoragePercent(item) > 80 ? '#f56c6c' : cloudStoragePercent(item) > 60 ? '#e6a23c' : '#67c23a'"
                  />
                </div>
                <el-empty v-if="stats.cloudUsage.length === 0" description="暂无网盘数据" :image-size="80" />
              </div>
            </el-card>
          </div>

          <!-- Row 3: 近 7 天趋势 + 热门搜索关键词 Top 20 + 操作来源 IP Top 10 -->
          <div class="dash-row dash-row-cols-3">
            <el-card class="insight-card trend-card">
              <template #header>
                <div class="insight-header">
                  <span>📈 网站使用趋势图</span>
                  <div class="trend-day-btns">
                    <button
                      v-for="d in trendDayOptions" :key="d"
                      :class="['trend-day-btn', { active: trendDays === d }]"
                      @click="switchTrendDays(d)"
                    >{{ d }}天</button>
                  </div>
                </div>
              </template>
              <div v-if="trendSummary" class="trend-summary-row">
                <div class="trend-summary-item">
                  <span class="trend-summary-num">{{ trendSummary.totalSearches }}</span>
                  <span class="trend-summary-desc">总搜索</span>
                </div>
                <div class="trend-summary-item">
                  <span class="trend-summary-num">{{ trendSummary.totalSaves }}</span>
                  <span class="trend-summary-desc">总保存</span>
                </div>
                <div class="trend-summary-item">
                  <span class="trend-summary-num">{{ trendSummary.avgSearches }}/{{ trendSummary.avgSaves }}</span>
                  <span class="trend-summary-desc">日均搜索/保存</span>
                </div>
                <div class="trend-summary-item">
                  <span class="trend-summary-num">{{ trendSummary.peakDay }}</span>
                  <span class="trend-summary-desc">峰值日 {{ trendSummary.peakSearches }}+{{ trendSummary.peakSaves }}</span>
                </div>
              </div>
              <div ref="chartRef" class="trend-chart-echarts"></div>
            </el-card>

            <el-card class="insight-card">
              <template #header><span>🔍 热门搜索关键词 Top 20</span></template>
              <div class="keyword-list">
                <el-tag
                  v-for="(kw, i) in stats.hotKeywords" :key="kw.keyword"
                  :type="keywordTagType(i)"
                  size="small"
                  class="keyword-tag"
                >{{ kw.keyword }}<sup class="kw-count">{{ kw.count }}</sup></el-tag>
                <el-empty v-if="stats.hotKeywords.length === 0" description="暂无搜索数据" :image-size="60" />
              </div>
            </el-card>

            <el-card class="insight-card">
              <template #header>
                <el-tabs v-model="rightTab" class="card-tabs" @tab-click="handleTabClick">
                  <el-tab-pane label="🌐 IP Top 10" name="ip" />
                  <el-tab-pane label="🗺️ 地域 Top 10" name="province" />
                </el-tabs>
              </template>
              <div class="ip-list" v-show="rightTab === 'ip'">
                <div v-for="(ip, i) in stats.topIps" :key="ip.ip" class="ip-row">
                  <span class="ip-rank">{{ i + 1 }}</span>
                  <span class="ip-addr">{{ ip.ip }}</span>
                  <span class="ip-loc" v-if="ip.ip_location">{{ formatLocation(ip.ip_location) }}</span>
                  <span class="ip-count">{{ ip.count }} 次</span>
                </div>
                <el-empty v-if="stats.topIps.length === 0" description="暂无数据" :image-size="60" />
              </div>
              <div class="province-list" v-show="rightTab === 'province'">
                <div
                  v-for="(item, i) in stats.provinceRankings.slice(0, 10)"
                  :key="item.province"
                  class="province-row"
                >
                  <span class="province-rank">{{ i + 1 }}</span>
                  <span class="province-bar-wrap">
                    <span
                      class="province-bar"
                      :style="{
                        width: (item.count / maxProvinceCount) * 100 + '%',
                        background: provinceBarColor(i),
                      }"
                    ></span>
                  </span>
                  <span class="province-name">{{ item.province }}</span>
                  <span class="province-count">{{ item.count }} 次</span>
                </div>
                <el-empty v-if="!stats.provinceRankings?.length" description="暂无数据" :image-size="60" />
              </div>
            </el-card>
          </div>
        </div>

        <!-- 网盘配置 - 设置及授权 -->
        <div v-if="showCloudToggle" class="section-content">
          <el-card class="config-card">
            <template #header><span>📂 网盘设置及授权</span></template>
            <div class="cloud-toggle-grid">
              <div
                v-for="ct in cloudTypes"
                :key="ct.type"
                class="cloud-toggle-chip"
              >
                <img :src="ct.icon" class="cloud-icon-img" />
                <span class="cloud-label">{{ ct.label }}</span>
                <el-tag v-if="ct.type === 'others'" size="small" type="info">关</el-tag>
                <el-switch
                  :model-value="ct.enabled"
                  size="small"
                  @change="(val: boolean) => handleCloudToggle(ct.type, val)"
                />
              </div>
            </div>
            <div class="form-tip" style="margin-top: 12px;">
              关闭的网盘类型在搜索结果中不会展示。修改后立即生效，无需点击保存。
            </div>
          </el-card>
          <CloudConfig />
        </div>


        <!-- 系统配置 -->
        <div v-if="showSystemConfig" class="section-content">
          <SystemConfig :section="activeSystemSection" />
        </div>

        <!-- 转存日志 -->
        <div v-if="activeMenu === 'save-records'" class="section-content">
          <SaveRecords />
        </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, reactive, watch, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { useTrendChart, type TrendSummary } from '../../composables/useTrendChart'
import {
  DataBoard,
  Connection,
  Setting,
  SwitchButton,
  DocumentCopy,
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { getStats, getCloudConfigs, getSiteConfig, getCloudTypes, toggleCloudType } from '../../api'
import type { StatsData } from '../../types'
import CloudConfig from './CloudConfig.vue'
import SystemConfig from './SystemConfig.vue'
import SaveRecords from './SaveRecords.vue'

interface CloudTypeInfo {
  type: string
  label: string
  icon: string
  enabled: boolean
}

const router = useRouter()

const appVersion = ref("")
const stats = ref<StatsData>({
  todaySearches: 0,
  todaySaves: 0,
  monthSearches: 0,
  monthSaves: 0,
  totalSearches: 0,
  totalSaves: 0,
  hotKeywords: [],
  trendTrend: [],
  cloudUsage: [],
  topIps: [],
  provinceRankings: [],
})
const siteName = ref('')
const cloudTypes = ref<CloudTypeInfo[]>([])

// ── ECharts trend chart (via composable) ──
const { chartRef: _chartRef, render: renderTrendChart, initResize: initTrendChart } = useTrendChart(computed(() => stats.value.trendTrend), (s: any) => { trendSummary.value = s })
const chartRef = _chartRef as any

// Force render after mount (data may already be loaded)
watch(() => stats.value.trendTrend, () => {
  renderTrendChart()
}, { deep: true })

// Reload chart when switching back to dashboard
watch(() => activeMenu.value, (val, oldVal) => {
  if (val === 'dashboard' && oldVal !== 'dashboard') {
    nextTick(() => {
      // v-show keeps DOM alive; chart instance may need to be re-initialized
      // after being hidden (ECharts can lose its canvas when container has display:none)
      const el = document.querySelector('.trend-chart-echarts') as HTMLElement | null
      if (el && el.childElementCount === 0) {
        renderTrendChart()
        initTrendChart()
      } else if (el) {
        // Chart still exists, just resize
        initTrendChart()
      }
    })
  }
})

// ── Dashboard stat items: label top, value bottom ──
const statItems = [
  { key: 'todaySearches', label: '今日搜索' },
  { key: 'todaySaves', label: '今日保存' },
  { key: 'monthSearches', label: '本月搜索' },
  { key: 'monthSaves', label: '本月保存' },
  { key: 'totalSearches', label: '总搜索量' },
  { key: 'totalSaves', label: '总保存量' },
]

function keywordTagType(i: number): string {
  if (i === 0) return 'danger'
  if (i < 3) return 'warning'
  if (i < 8) return ''
  return 'info'
}

/** Strip "中国/China" prefix from location string for consistent display */
function formatLocation(loc: string): string {
  if (!loc) return ''
  return loc.replace(/^(中国|China)\s*/i, '').trim()
}

// ── Province ranking helpers ──
const maxProvinceCount = computed(() => {
  const items = stats.value.provinceRankings
  return items.length > 0 ? Math.max(...items.map(i => i.count)) : 1
})
const PROVINCE_COLORS = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399', '#b37feb', '#36cfc9', '#ff85c0']
function provinceBarColor(i: number): string {
  return PROVINCE_COLORS[i % PROVINCE_COLORS.length]
}

// ── Right card tabs ──
const rightTab = ref('ip')
function handleTabClick() {
  // no-op for now, tabs handle switching via v-show
}

// ── Drive icon lookup from API data ──
const FALLBACK_ICON = 'data:image/svg+xml,' + encodeURIComponent('<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect rx="4" width="24" height="24" fill="#909399"/><text x="12" y="16" text-anchor="middle" fill="white" font-size="14" font-weight="bold" font-family="Arial">☁</text></svg>')
function driveIcon(type: string): string {
  return cloudTypes.value.find(c => c.type === type)?.icon || FALLBACK_ICON
}

// ── Trend day range ──
const trendDayOptions = [7, 15, 30, 60]
const trendDays = ref(7)
const trendSummary = ref<TrendSummary | null>(null)
async function switchTrendDays(d: number) {
  trendDays.value = d
  await loadStats()
}

// Menu selection
const activeMenu = ref('dashboard')
const activeSystemSection = ref('')

// ── Recent saves ──
const recentSaves = ref<any[]>([])
const systemInfo = reactive({
  uptime: '--',
  memory: '--',
  version: '--',
  dbOk: false,
  redisOk: false,
  pansouOk: false,
})

async function loadRecentSaves() {
  try {
    const res = await fetch('/api/admin/save-records?pageSize=5&page=1')
    const data = await res.json()
    recentSaves.value = data.records || data.data || []
  } catch { recentSaves.value = [] }
}

async function loadSystemInfo() {
  try {
    const res = await fetch('/health')
    const h = await res.json()
    systemInfo.uptime = formatUptime(h.uptime || 0)
    systemInfo.memory = formatBytes(h.memory || 0)
    systemInfo.version = h.version || '--'
    systemInfo.dbOk = h.components?.db === 'connected'
    systemInfo.redisOk = h.components?.redis === 'connected'
    systemInfo.pansouOk = h.components?.pansou === 'ok'
  } catch {}
}

function formatUptime(s: number): string {
  const d = Math.floor(s / 86400)
  const h = Math.floor((s % 86400) / 3600)
  const m = Math.floor((s % 3600) / 60)
  const parts = []
  if (d > 0) parts.push(d + '天')
  if (h > 0) parts.push(h + '时')
  parts.push(m + '分')
  return parts.join(' ')
}

function formatBytes(b: number): string {
  if (b >= 1073741824) return (b / 1073741824).toFixed(1) + ' GB'
  if (b >= 1048576) return (b / 1048576).toFixed(0) + ' MB'
  return (b / 1024).toFixed(0) + ' KB'
}

function formatSaveTime(t: string): string {
  if (!t) return ''
  const d = new Date(t)
  if (isNaN(d.getTime())) return t.slice(0, 10)
  const diff = Date.now() - d.getTime()
  const mins = Math.floor(diff / 60000)
  if (mins < 60) return mins <= 1 ? '刚刚' : mins + '分钟前'
  const hours = Math.floor(mins / 60)
  if (hours < 24) return hours + '小时前'
  return t.slice(0, 10)
}

const pageTitles: Record<string, string> = {
  dashboard: '仪表盘',
  'save-records': '转存日志',
}
const sysSectionTitles: Record<string, string> = {
  'sys-site': '网站设置',
  'sys-services': '外部服务 & 缓存',
  'sys-strategy': '搜索结果展示策略',
  'sys-validation': '链接验证配置',
  'sys-filter': '搜索标题过滤规则',
  'sys-password': '修改管理员密码',
}

const pageTitle = computed(() => {
  if (activeMenu.value.startsWith('sys-')) {
    return '系统配置 — ' + (sysSectionTitles[activeMenu.value] || '')
  }
  if (activeMenu.value === 'cloud-configs-toggle' || activeMenu.value === 'cloud-configs-cleanup') {
    return '网盘配置'
  }
  return pageTitles[activeMenu.value] || '管理后台'
})

const showCloudToggle = computed(() => {
  return activeMenu.value === 'cloud-configs-toggle'
})

const showSystemConfig = computed(() => {
  return activeMenu.value.startsWith('sys-')
})

onMounted(async () => {
  try {
    const cfg = await getSiteConfig()
    if (cfg.site_name) {
      siteName.value = cfg.site_name
      document.title = cfg.site_name + ' - 管理后台'
    }
  } catch {}
  try {
    const [configs, ctResult] = await Promise.all([
      getCloudConfigs(),
      getCloudTypes(),
    ])
    cloudTypes.value = ctResult.types
    await loadStats()
    await loadRecentSaves()
    await loadSystemInfo()
    initTrendChart()
  } catch (e) {
    console.error('加载数据失败', e)
  }
})

async function loadStats() {
  try {
    stats.value = await getStats(trendDays.value)
    try { const h = await fetch("/health"); const hv = await h.json(); appVersion.value = hv.version; } catch {}
  } catch (e) {
    console.error('加载统计数据失败', e)
  }
}

function cloudStoragePercent(item: { storageUsed: string; storageTotal: string }): number {
  if (!item.storageUsed || !item.storageTotal) return 0
  const used = parseFloat(item.storageUsed)
  const total = parseFloat(item.storageTotal)
  if (total <= 0) return 0
  return Math.round((used / total) * 100)
}

function handleMenuSelect(index: string) {
  if (index === 'logout') {
    handleLogout()
    return
  }
  activeMenu.value = index

  // For system config sub-items, set which section to scroll to
  if (index.startsWith('sys-')) {
    activeSystemSection.value = index
  }

  // Refresh cloud types when switching to cloud configs
  if (index === 'cloud-configs-toggle') {
    getCloudTypes().then(r => { cloudTypes.value = r.types }).catch(() => {})
  }
}

function handleLogout() {
  localStorage.removeItem('admin_token')
  router.push('/admin/login')
}

function goBackHome() {
  window.location.href = '/'
}

// ── 网盘类型开关 ──

async function handleCloudToggle(type: string, enabled: boolean) {
  const ct = cloudTypes.value.find(c => c.type === type)
  if (!ct) return
  try {
    await toggleCloudType(type, enabled)
    ct.enabled = enabled
  } catch (e: any) {
    ElMessage.error(e.message || '切换失败')
    // Revert optimistic update
    ct.enabled = !enabled
  }
}
</script>

<style scoped>
.admin-layout {
  display: flex;
  min-height: 100vh;
}

/* === 左侧菜单：深色渐变背景 === */
.admin-menu {
  width: 220px;
  min-height: 100vh;
  background: linear-gradient(180deg, #1a1a2e 0%, #16213e 100%);
  border-right: none;
  flex-shrink: 0;
  transition: box-shadow 0.3s ease;
}
.admin-menu :deep(.el-menu-item) {
  color: #a2a3b7;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}
.admin-menu :deep(.el-menu-item)::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: linear-gradient(180deg, #409eff, #7c3aed);
  transform: scaleY(0);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 0 2px 2px 0;
}
.admin-menu :deep(.el-menu-item.is-active) {
  color: #409eff;
  background: linear-gradient(90deg, rgba(64, 158, 255, 0.15) 0%, rgba(124, 58, 237, 0.08) 100%);
}
.admin-menu :deep(.el-menu-item.is-active)::after {
  transform: scaleY(1);
}
.admin-menu :deep(.el-menu-item:hover) {
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.02) 100%);
  color: #e0e0e0;
}
/* Sub-menu styles */
.admin-menu :deep(.el-sub-menu__title) {
  color: #a2a3b7;
  transition: all 0.3s ease;
}
.admin-menu :deep(.el-sub-menu__title:hover) {
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.02) 100%);
  color: #e0e0e0;
}
.admin-menu :deep(.el-sub-menu.is-active .el-sub-menu__title) {
  color: #409eff;
}
.admin-menu :deep(.el-sub-menu .el-menu) {
  background: rgba(0, 0, 0, 0.15);
}
.admin-menu :deep(.el-sub-menu .el-menu .el-menu-item) {
  padding-left: 56px !important;
  font-size: 13px;
}
.menu-header {
  padding: 24px 20px 16px;
  color: #fff;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  margin-bottom: 8px;
}
.menu-header h2 {
  font-size: 20px;
  font-weight: 700;
  margin-bottom: 4px;
  background: linear-gradient(90deg, #fff, #90caf9);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.menu-header p {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.5);
}

.version-footer {
  position: fixed;
  bottom: 12px;
  left: 0;
  width: 220px;
  text-align: center;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.35);
  letter-spacing: 0.5px;
  padding: 8px 0;
  pointer-events: none;
}

/* === 右侧内容区 === */
.admin-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: auto;
}
.content-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 24px;
  border-bottom: none;
  background: linear-gradient(135deg, #f5f7fa 0%, #eef1f5 100%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  position: relative;
  z-index: 1;
}
.content-header h2 {
  font-size: 20px;
  font-weight: 600;
  color: #303133;
}
.content-body {
  padding: 24px;
  flex: 1;
}

/* === 网盘类型开关 — 网格布局 === */
.config-card {
  margin-bottom: 24px;
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, 0.06) !important;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
  overflow: hidden;
}
.config-card :deep(.el-card__header) {
  border-bottom: 1px solid rgba(0, 0, 0, 0.04);
  padding: 16px 20px;
  font-weight: 600;
  background: linear-gradient(135deg, #fafafa, #f5f5f5);
}
.config-card :deep(.el-card__body) {
  padding: 20px;
}
.cloud-toggle-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}
.cloud-toggle-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-radius: 10px;
  background: #f8f9fa;
  border: 1px solid #eee;
  transition: background 0.2s, box-shadow 0.15s;
}
.cloud-toggle-chip:hover {
  background: #f0f2f5;
  box-shadow: 0 2px 6px rgba(0,0,0,0.04);
}
.cloud-icon-img {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  flex-shrink: 0;
  object-fit: contain;
}
.cloud-label {
  font-size: 13px;
  font-weight: 500;
  flex: 1;
}
.form-tip {
  font-size: 12px;
  color: #909399;
  line-height: 1.5;
}

/* === 仪表盘布局 === */
.dash-row {
  margin-bottom: 24px;
}
.dash-row-stats {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 16px;
}
@media (max-width: 1200px) { .dash-row-stats { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px) { .dash-row-stats { grid-template-columns: repeat(2, 1fr); } }

/* 统计卡片 — 文字在上，数字在下 */
.stt-card {
  text-align: center;
  border: none !important;
  background: linear-gradient(135deg, #f0f5ff, #e8f0fe);
  border-radius: 14px;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.stt-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(64, 158, 255, 0.15);
}
.stt-card :deep(.el-card__body) {
  padding: 20px 12px 16px;
}
.stt-label {
  font-size: 13px;
  color: #909399;
  font-weight: 500;
  margin-bottom: 6px;
}
.stt-value {
  font-size: 32px;
  font-weight: 800;
  background: linear-gradient(135deg, #409eff, #7c3aed);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  letter-spacing: -1px;
  line-height: 1.2;
}

/* === 第二排：3 列洞察卡片 === */
.dash-row-cols-3 {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
}
@media (max-width: 1100px) { .dash-row-cols-3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 700px) { .dash-row-cols-3 { grid-template-columns: 1fr; } }

.insight-card {
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, 0.06) !important;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.insight-card :deep(.el-card__header) {
  border-bottom: 1px solid rgba(0, 0, 0, 0.04);
  padding: 14px 18px;
  font-weight: 600;
  font-size: 14px;
  background: linear-gradient(135deg, #fafafa, #f5f5f5);
}
.insight-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.trend-day-btns {
  display: flex;
  gap: 4px;
}
.trend-day-btn {
  padding: 2px 10px;
  border-radius: 6px;
  border: 1px solid #dcdfe6;
  background: #fff;
  font-size: 11px;
  color: #909399;
  cursor: pointer;
  transition: all 0.2s;
  font-family: inherit;
}
.trend-day-btn:hover {
  border-color: #409eff;
  color: #409eff;
}
.trend-day-btn.active {
  background: #409eff;
  border-color: #409eff;
  color: #fff;
}
.insight-card :deep(.el-card__body) {
  padding: 0;
}
.insight-card.trend-card :deep(.el-card__body) {
  padding: 8px 6px 0;
  height: 380px;
  overflow: hidden;
}
.insight-card:not(.trend-card) :deep(.el-card__body) {
  padding: 14px 18px;
  max-height: 380px;
  overflow-y: auto;
}

/* ECharts 趋势图容器 — 铺满整个卡片 */
.trend-chart-echarts {
  width: 100%;
  height: 100%;
  min-height: 310px;
}

/* 趋势汇总行 */
.trend-summary-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  padding: 10px 12px 4px;
  border-bottom: 1px solid #f0f0f0;
}
.trend-summary-item {
  text-align: center;
}
.trend-summary-num {
  display: block;
  font-size: 18px;
  font-weight: 700;
  color: #303133;
  line-height: 1.3;
}
.trend-summary-desc {
  display: block;
  font-size: 11px;
  color: #909399;
  margin-top: 2px;
}

/* 关键词列表 */
.keyword-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-content: flex-start;
}
.keyword-tag {
  cursor: default;
}
.kw-count {
  font-size: 9px;
  margin-left: 2px;
  opacity: 0.7;
  font-weight: 400;
}

/* IP 列表 */
.ip-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ip-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 8px;
  background: #f8f9fa;
  transition: background 0.2s;
}
.ip-row:hover {
  background: #f0f2f5;
}
.ip-rank {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: linear-gradient(135deg, #409eff, #7c3aed);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.ip-addr {
  font-family: 'SF Mono', 'Fira Code', monospace;
  font-size: 13px;
  color: #303133;
  font-weight: 500;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ip-loc {
  font-size: 11px;
  padding: 1px 6px;
  border-radius: 4px;
  background: rgba(64, 158, 255, 0.1);
  color: #409eff;
  white-space: nowrap;
  flex-shrink: 0;
}
.ip-count {
  font-size: 12px;
  color: #909399;
  white-space: nowrap;
  flex-shrink: 0;
}

/* 地域使用榜（省份排行） */
.province-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.province-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 8px;
  border-radius: 6px;
  background: #f8f9fa;
}
.province-row:hover {
  background: #f0f2f5;
}
.province-rank {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: linear-gradient(135deg, #409eff, #7c3aed);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.province-bar-wrap {
  flex: 1;
  height: 16px;
  background: #e8e8e8;
  border-radius: 8px;
  overflow: hidden;
  min-width: 0;
}
.province-bar {
  display: block;
  height: 100%;
  border-radius: 8px;
  transition: width 0.4s ease;
  min-width: 4px;
}
.province-name {
  font-size: 13px;
  color: #303133;
  font-weight: 500;
  white-space: nowrap;
  width: 90px;
  text-align: right;
  flex-shrink: 0;
}
.province-count {
  font-size: 12px;
  color: #909399;
  white-space: nowrap;
  width: 50px;
  text-align: right;
  flex-shrink: 0;
}

/* === 第三排：网盘空间 — flex-wrap 自适应 === */
.storage-section-card {
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, 0.06) !important;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.storage-section-card :deep(.el-card__header) {
  border-bottom: 1px solid rgba(0, 0, 0, 0.04);
  padding: 14px 20px;
  font-weight: 600;
  font-size: 14px;
  background: linear-gradient(135deg, #fafafa, #f5f5f5);
}
.storage-section-card :deep(.el-card__body) {
  padding: 16px 20px;
}
.storage-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.storage-drive-card {
  flex: 1 1 280px;
  min-width: 260px;
  border: 1px solid #ebeef5;
  border-radius: 12px;
  padding: 16px;
  background: #fafbfc;
  transition: box-shadow 0.2s;
}
.storage-drive-card:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
}
.drive-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.drive-icon {
  width: 24px;
  height: 24px;
  border-radius: 5px;
  flex-shrink: 0;
  object-fit: contain;
}
.drive-name {
  font-size: 14px;
  font-weight: 600;
  color: #303133;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.drive-status {
  font-size: 11px;
  padding: 2px 8px;
  border-radius: 4px;
  flex-shrink: 0;
}
.drive-status.active { background: #f0f9eb; color: #67c23a; }
.drive-status.inactive { background: #fef0f0; color: #f56c6c; }
.drive-space {
  display: flex;
  align-items: baseline;
  gap: 4px;
  margin-bottom: 8px;
  font-size: 14px;
}
.drive-used {
  font-weight: 600;
  color: #303133;
}
.drive-sep {
  color: #c0c4cc;
}
.drive-total {
  color: #909399;
}

/* Section content scroll */
.section-content {
  min-height: 400px;
}

/* Tabs switcher inside card header */
.insight-card :deep(.card-tabs) {
  margin-top: -10px;
}
.insight-card :deep(.card-tabs .el-tabs__header) {
  margin: 0;
}
.insight-card :deep(.card-tabs .el-tabs__nav-wrap::after) {
  height: 0;
}
.insight-card :deep(.card-tabs .el-tabs__item) {
  height: 36px;
  line-height: 36px;
  font-size: 13px;
  padding: 0 12px;
}
.insight-card :deep(.card-tabs .el-tabs__active-bar) {
  height: 2px;
}

/* Province rows in narrow card */
.province-list .province-row {
  gap: 4px;
  padding: 3px 0;
}
.province-list .province-rank {
  width: 20px;
  height: 20px;
  font-size: 10px;
}
.province-list .province-bar-wrap {
  height: 12px;
}
.province-list .province-name {
  width: 60px;
  font-size: 12px;
}
.province-list .province-count {
  width: 42px;
  font-size: 11px;
}

/* Remove old tab styles */
.admin-tabs :deep(.el-tabs__header) {
  display: none;
}
</style>
