<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import VChart from 'vue-echarts'
import PageCard from '@/components/PageCard.vue'
import '@/plugins/echarts-hardware'
import { getSystemInfo } from '@/api/modules/system'
import type { GpuInfo, SystemInfo } from '@/types'

interface Snapshot {
  time: string
  cpu: number
  memory: number
  disk: number
  gpuAverage: number
  gpu: Array<{ usage: number; memory: number; temperature: number }>
}

const info = ref<SystemInfo>({})
const loading = ref(true)
const refreshing = ref(false)
const loadError = ref('')
const lastUpdated = ref<Date | null>(null)
const autoRefresh = ref(true)
const refreshInterval = ref(5000)
const snapshots = ref<Snapshot[]>([])
const drawerVisible = ref(false)
const selectedGpuIndex = ref(0)

let timer: ReturnType<typeof setTimeout> | null = null
let disposed = false
let requesting = false

const gpus = computed(() => info.value.gpu ?? [])
const selectedGpu = computed(() => gpus.value[selectedGpuIndex.value])

const gpuAverage = computed(() => {
  if (!gpus.value.length) return 0
  return Math.round(gpus.value.reduce((sum, gpu) => sum + safePercent(gpu.gpu_percent), 0) / gpus.value.length)
})

const gpuMemoryTotal = computed(() =>
  gpus.value.reduce((sum, gpu) => sum + Number(gpu.memory_total_gb || 0), 0),
)

const gpuMemoryUsed = computed(() =>
  gpus.value.reduce((sum, gpu) => sum + Number(gpu.memory_used_gb || 0), 0),
)

const busyGpuCount = computed(() =>
  gpus.value.filter((gpu) => gpuStatus(gpu).key === 'busy').length,
)

const systemHealth = computed(() => {
  const hasOffline = gpus.value.some((gpu) => gpuStatus(gpu).key === 'offline')
  const hasWarning =
    safePercent(info.value.cpu?.percent) >= 90 ||
    safePercent(info.value.memory?.percent) >= 90 ||
    safePercent(info.value.disk?.percent) >= 90 ||
    gpus.value.some((gpu) => gpuStatus(gpu).key === 'warning')

  if (hasOffline) return { label: '存在离线设备', className: 'is-danger' }
  if (hasWarning) return { label: '资源需要关注', className: 'is-warning' }
  return { label: '平台运行正常', className: 'is-healthy' }
})

const resourceChartOption = computed(() => ({
  animationDuration: 300,
  color: ['#4f46e5', '#0ea5e9', '#10b981', '#f59e0b'],
  tooltip: { trigger: 'axis', valueFormatter: (value: number) => `${value}%` },
  legend: { top: 0, right: 0, itemWidth: 10, itemHeight: 10, textStyle: { color: '#606266' } },
  grid: { left: 14, right: 14, top: 42, bottom: 8, containLabel: true },
  xAxis: {
    type: 'category',
    boundaryGap: false,
    data: snapshots.value.map((item) => item.time),
    axisLine: { lineStyle: { color: '#dcdfe6' } },
    axisLabel: { color: '#909399', hideOverlap: true },
  },
  yAxis: {
    type: 'value',
    min: 0,
    max: 100,
    axisLabel: { formatter: '{value}%', color: '#909399' },
    splitLine: { lineStyle: { color: '#ebeef5', type: 'dashed' } },
  },
  series: [
    chartSeries('CPU', snapshots.value.map((item) => item.cpu)),
    chartSeries('内存', snapshots.value.map((item) => item.memory)),
    chartSeries('磁盘', snapshots.value.map((item) => item.disk)),
    chartSeries('GPU 平均', snapshots.value.map((item) => item.gpuAverage)),
  ],
}))

const gpuChartOption = computed(() => {
  const records = snapshots.value
    .map((item) => ({ time: item.time, gpu: item.gpu[selectedGpuIndex.value] }))
    .filter((item) => item.gpu)

  return {
    animationDuration: 300,
    color: ['#4f46e5', '#0ea5e9', '#f59e0b'],
    tooltip: { trigger: 'axis', valueFormatter: (value: number) => `${value}%` },
    legend: { top: 0, right: 0, itemWidth: 10, itemHeight: 10 },
    grid: { left: 12, right: 12, top: 40, bottom: 6, containLabel: true },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: records.map((item) => item.time),
      axisLine: { lineStyle: { color: '#dcdfe6' } },
      axisLabel: { color: '#909399', hideOverlap: true },
    },
    yAxis: {
      type: 'value',
      min: 0,
      max: 100,
      axisLabel: { formatter: '{value}%', color: '#909399' },
      splitLine: { lineStyle: { color: '#ebeef5', type: 'dashed' } },
    },
    series: [
      chartSeries('利用率', records.map((item) => item.gpu.usage)),
      chartSeries('显存', records.map((item) => item.gpu.memory)),
    ],
  }
})

function chartSeries(name: string, data: number[]) {
  return {
    name,
    type: 'line',
    data,
    showSymbol: false,
    smooth: true,
    lineStyle: { width: 2 },
    areaStyle: { opacity: 0.05 },
  }
}

function safePercent(value?: number) {
  return Math.min(100, Math.max(0, Number(value || 0)))
}

function memoryPercent(gpu?: GpuInfo) {
  if (!gpu) return 0
  if (gpu.memory_percent != null) return safePercent(gpu.memory_percent)
  if (!gpu.memory_total_gb) return 0
  return Math.round((gpu.memory_used_gb / gpu.memory_total_gb) * 100)
}

function gpuStatus(gpu: GpuInfo) {
  if (gpu.status === 'offline') return { key: 'offline', label: '离线', className: 'is-danger' }
  if (gpu.status === 'warning' || gpu.temperature >= 80 || memoryPercent(gpu) >= 90) {
    return { key: 'warning', label: '需关注', className: 'is-warning' }
  }
  if (gpu.status === 'busy' || gpu.gpu_percent >= 10) {
    return { key: 'busy', label: '运行中', className: 'is-busy' }
  }
  return { key: 'idle', label: '空闲', className: 'is-idle' }
}

function progressColor(value: number) {
  if (value >= 90) return '#f56c6c'
  if (value >= 75) return '#e6a23c'
  return '#4f46e5'
}

function recordSnapshot(data: SystemInfo) {
  const gpuList = data.gpu ?? []
  const average = gpuList.length
    ? Math.round(gpuList.reduce((sum, gpu) => sum + safePercent(gpu.gpu_percent), 0) / gpuList.length)
    : 0
  const now = new Date()

  snapshots.value = [
    ...snapshots.value,
    {
      time: now.toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }),
      cpu: safePercent(data.cpu?.percent),
      memory: safePercent(data.memory?.percent),
      disk: safePercent(data.disk?.percent),
      gpuAverage: average,
      gpu: gpuList.map((gpu) => ({
        usage: safePercent(gpu.gpu_percent),
        memory: memoryPercent(gpu),
        temperature: safePercent(gpu.temperature),
      })),
    },
  ].slice(-60)
}

async function fetchInfo() {
  if (requesting || disposed) return
  requesting = true
  refreshing.value = true
  clearTimer()

  try {
    const data = await getSystemInfo()
    info.value = data
    lastUpdated.value = new Date()
    loadError.value = ''
    recordSnapshot(data)
  } catch (error) {
    loadError.value = error instanceof Error ? error.message : '监控数据更新失败，请稍后重试'
  } finally {
    loading.value = false
    refreshing.value = false
    requesting = false
    scheduleNext()
  }
}

function scheduleNext() {
  clearTimer()
  if (!disposed && autoRefresh.value && document.visibilityState === 'visible') {
    timer = setTimeout(fetchInfo, refreshInterval.value)
  }
}

function clearTimer() {
  if (timer) {
    clearTimeout(timer)
    timer = null
  }
}

function changeInterval() {
  scheduleNext()
}

function changeAutoRefresh() {
  if (autoRefresh.value) scheduleNext()
  else clearTimer()
}

function handleVisibilityChange() {
  if (document.visibilityState === 'hidden') clearTimer()
  else if (autoRefresh.value) fetchInfo()
}

function openGpuDetail(index: number) {
  selectedGpuIndex.value = index
  drawerVisible.value = true
  nextTick(() => document.querySelector<HTMLElement>('.gpu-detail-drawer .el-drawer__body')?.focus())
}

function handleGpuKeydown(event: KeyboardEvent, index: number) {
  if (event.key === 'Enter' || event.key === ' ') {
    event.preventDefault()
    openGpuDetail(index)
  }
}

function formatNumber(value?: number, digits = 1) {
  return Number(value || 0).toFixed(digits).replace(/\.0$/, '')
}

function formatRate(value?: number) {
  return value == null ? '--' : formatNumber(value)
}

function formatUptime(seconds?: number) {
  if (!seconds) return '-'
  const days = Math.floor(seconds / 86400)
  const hours = Math.floor((seconds % 86400) / 3600)
  const minutes = Math.floor((seconds % 3600) / 60)
  return `${days ? `${days}天 ` : ''}${hours}小时 ${minutes}分钟`
}

function formatLastUpdated(date: Date | null) {
  return date ? date.toLocaleTimeString('zh-CN', { hour12: false }) : '等待首次更新'
}

onMounted(fetchInfo)
onMounted(() => document.addEventListener('visibilitychange', handleVisibilityChange))
onUnmounted(() => {
  disposed = true
  clearTimer()
  document.removeEventListener('visibilitychange', handleVisibilityChange)
})
</script>

<template>
  <PageCard title="平台性能" subtitle="实时监控计算、存储、网络与 GPU 资源池状态">
    <template #extra>
      <div class="monitor-actions">
        <div class="health-state" :class="systemHealth.className">
          <span class="health-dot" aria-hidden="true" />
          {{ systemHealth.label }}
        </div>
        <span class="update-time">更新于 {{ formatLastUpdated(lastUpdated) }}</span>
        <el-switch
          v-model="autoRefresh"
          inline-prompt
          active-text="自动"
          inactive-text="暂停"
          aria-label="自动刷新"
          @change="changeAutoRefresh"
        />
        <el-select
          v-model="refreshInterval"
          class="interval-select"
          size="small"
          aria-label="刷新频率"
          :disabled="!autoRefresh"
          @change="changeInterval"
        >
          <el-option :value="1000" label="1 秒" />
          <el-option :value="3000" label="3 秒" />
          <el-option :value="5000" label="5 秒" />
          <el-option :value="10000" label="10 秒" />
        </el-select>
        <el-button :loading="refreshing" aria-label="立即刷新平台性能数据" @click="fetchInfo">
          <i class="fa fa-refresh" aria-hidden="true" />
          刷新
        </el-button>
      </div>
    </template>

    <el-alert
      v-if="loadError"
      class="load-alert"
      type="warning"
      :closable="false"
      show-icon
      title="最新数据获取失败，当前仍展示上一次成功采集的数据"
      :description="loadError"
    />

    <div v-loading="loading" class="performance-content">
      <section class="overview-grid" aria-label="硬件资源概览">
        <article class="overview-card">
          <div class="metric-heading">
            <span class="metric-icon is-cpu"><i class="fa fa-microchip" /></span>
            <div><h3>CPU</h3><p>{{ info.cpu?.model || `${info.cpu?.cores || 0} 个逻辑核心` }}</p></div>
          </div>
          <strong class="metric-number">{{ safePercent(info.cpu?.percent) }}<small>%</small></strong>
          <el-progress :percentage="safePercent(info.cpu?.percent)" :stroke-width="6" :show-text="false" :color="progressColor(safePercent(info.cpu?.percent))" />
        </article>

        <article class="overview-card">
          <div class="metric-heading">
            <span class="metric-icon is-memory"><i class="fa fa-database" /></span>
            <div><h3>内存</h3><p>{{ formatNumber(info.memory?.used_gb) }} / {{ formatNumber(info.memory?.total_gb) }} GB</p></div>
          </div>
          <strong class="metric-number">{{ safePercent(info.memory?.percent) }}<small>%</small></strong>
          <el-progress :percentage="safePercent(info.memory?.percent)" :stroke-width="6" :show-text="false" :color="progressColor(safePercent(info.memory?.percent))" />
        </article>

        <article class="overview-card">
          <div class="metric-heading">
            <span class="metric-icon is-disk"><i class="fa fa-hdd-o" /></span>
            <div><h3>磁盘</h3><p>{{ formatNumber(info.disk?.used_gb) }} / {{ formatNumber(info.disk?.total_gb) }} GB</p></div>
          </div>
          <strong class="metric-number">{{ safePercent(info.disk?.percent) }}<small>%</small></strong>
          <el-progress :percentage="safePercent(info.disk?.percent)" :stroke-width="6" :show-text="false" :color="progressColor(safePercent(info.disk?.percent))" />
        </article>

        <article class="overview-card">
          <div class="metric-heading">
            <span class="metric-icon is-network"><i class="fa fa-exchange" /></span>
            <div><h3>网络吞吐</h3><p>实时接收 / 发送</p></div>
          </div>
          <div class="network-values">
            <strong><i class="fa fa-arrow-down" /> {{ formatRate(info.network?.download_mb_s) }} <small>MB/s</small></strong>
            <strong><i class="fa fa-arrow-up" /> {{ formatRate(info.network?.upload_mb_s) }} <small>MB/s</small></strong>
          </div>
        </article>
      </section>

      <section class="panel resource-panel" aria-labelledby="resource-trend-title">
        <div class="panel-heading">
          <div><h2 id="resource-trend-title">系统资源趋势</h2><p>展示最近 60 次前端采集快照</p></div>
          <span class="sample-count">{{ snapshots.length }} / 60 个采样点</span>
        </div>
        <VChart class="resource-chart" :option="resourceChartOption" autoresize aria-label="CPU、内存、磁盘和GPU平均利用率趋势图" />
      </section>

      <section class="gpu-section" aria-labelledby="gpu-pool-title">
        <div class="section-heading">
          <div>
            <h2 id="gpu-pool-title">GPU 资源池</h2>
            <p>共 {{ gpus.length }} 张卡，{{ busyGpuCount }} 张运行中 · 显存 {{ formatNumber(gpuMemoryUsed) }} / {{ formatNumber(gpuMemoryTotal) }} GB</p>
          </div>
          <div class="gpu-summary"><span>平均利用率</span><strong>{{ gpuAverage }}%</strong></div>
        </div>

        <el-empty v-if="!gpus.length && !loading" description="当前未检测到 GPU 设备" />
        <div v-else class="gpu-grid">
          <article
            v-for="(gpu, index) in gpus"
            :key="gpu.uuid || gpu.id || index"
            class="gpu-card"
            role="button"
            tabindex="0"
            :aria-label="`查看 GPU ${index} 详情`"
            @click="openGpuDetail(index)"
            @keydown="handleGpuKeydown($event, index)"
          >
            <div class="gpu-card-heading">
              <div class="gpu-identity"><span class="gpu-index">GPU {{ index }}</span><h3>{{ gpu.name }}</h3></div>
              <span class="status-pill" :class="gpuStatus(gpu).className"><i />{{ gpuStatus(gpu).label }}</span>
            </div>
            <div class="gpu-primary">
              <strong>{{ safePercent(gpu.gpu_percent) }}<small>%</small></strong>
              <span>计算利用率</span>
            </div>
            <el-progress :percentage="safePercent(gpu.gpu_percent)" :stroke-width="7" :show-text="false" :color="progressColor(safePercent(gpu.gpu_percent))" />
            <dl class="gpu-metrics">
              <div><dt>显存</dt><dd>{{ formatNumber(gpu.memory_used_gb) }} / {{ formatNumber(gpu.memory_total_gb) }} GB</dd></div>
              <div><dt>温度</dt><dd :class="{ 'is-hot': gpu.temperature >= 80, 'is-warm': gpu.temperature >= 70 && gpu.temperature < 80 }">{{ gpu.temperature }}°C</dd></div>
              <div><dt>功耗</dt><dd>{{ formatNumber(gpu.power_w, 0) }} W</dd></div>
              <div><dt>风扇</dt><dd>{{ gpu.fan_speed ?? '-' }}{{ gpu.fan_speed != null ? '%' : '' }}</dd></div>
            </dl>
            <div class="gpu-card-footer">查看设备详情 <i class="fa fa-angle-right" /></div>
          </article>
        </div>
      </section>

      <section class="panel host-panel" aria-labelledby="host-info-title">
        <div class="panel-heading compact"><div><h2 id="host-info-title">主机信息</h2><p>节点运行环境与基础状态</p></div></div>
        <dl class="host-info-grid">
          <div><dt>操作系统</dt><dd>{{ info.system?.os || '-' }}</dd></div>
          <div><dt>运行时长</dt><dd>{{ formatUptime(info.system?.uptime_seconds) }}</dd></div>
          <div><dt>运行进程</dt><dd>{{ info.system?.process_count ?? '-' }}</dd></div>
          <div><dt>GPU 驱动</dt><dd>{{ gpus[0]?.driver_version || '-' }}</dd></div>
        </dl>
      </section>
    </div>
  </PageCard>

  <el-drawer v-model="drawerVisible" class="gpu-detail-drawer" size="min(720px, 92vw)" destroy-on-close>
    <template #header>
      <div v-if="selectedGpu" class="drawer-heading">
        <span class="gpu-index">GPU {{ selectedGpuIndex }}</span>
        <div><h2>{{ selectedGpu.name }}</h2><p>{{ selectedGpu.uuid || '设备详细运行信息' }}</p></div>
        <span class="status-pill" :class="gpuStatus(selectedGpu).className"><i />{{ gpuStatus(selectedGpu).label }}</span>
      </div>
    </template>

    <template v-if="selectedGpu">
      <section class="drawer-metrics" aria-label="GPU 关键指标">
        <div><span>计算利用率</span><strong>{{ safePercent(selectedGpu.gpu_percent) }}%</strong></div>
        <div><span>显存占用</span><strong>{{ memoryPercent(selectedGpu) }}%</strong><small>{{ formatNumber(selectedGpu.memory_used_gb) }} / {{ formatNumber(selectedGpu.memory_total_gb) }} GB</small></div>
        <div><span>温度</span><strong>{{ selectedGpu.temperature }}°C</strong></div>
        <div><span>实时功耗</span><strong>{{ formatNumber(selectedGpu.power_w, 0) }} W</strong><small v-if="selectedGpu.power_limit_w">上限 {{ selectedGpu.power_limit_w }} W</small></div>
      </section>

      <section class="drawer-section" aria-labelledby="gpu-trend-title">
        <div class="drawer-section-heading"><h3 id="gpu-trend-title">设备趋势</h3><span>最近 60 次采样</span></div>
        <VChart class="gpu-detail-chart" :option="gpuChartOption" autoresize aria-label="单卡利用率和显存占用趋势图" />
      </section>

      <section class="drawer-section" aria-labelledby="gpu-process-title">
        <div class="drawer-section-heading"><h3 id="gpu-process-title">GPU 进程</h3><span>{{ selectedGpu.processes?.length || 0 }} 个</span></div>
        <el-table :data="selectedGpu.processes || []" stripe empty-text="当前没有占用此 GPU 的进程">
          <el-table-column prop="pid" label="PID" width="90" />
          <el-table-column prop="task_name" label="任务" min-width="130" show-overflow-tooltip />
          <el-table-column prop="name" label="进程" min-width="130" show-overflow-tooltip />
          <el-table-column prop="user" label="用户" width="100" />
          <el-table-column label="显存" width="110" align="right">
            <template #default="{ row }">{{ row.memory_used_gb != null ? `${formatNumber(row.memory_used_gb)} GB` : '-' }}</template>
          </el-table-column>
        </el-table>
      </section>

      <section class="drawer-section device-properties" aria-labelledby="gpu-property-title">
        <div class="drawer-section-heading"><h3 id="gpu-property-title">设备属性</h3></div>
        <dl>
          <div><dt>风扇转速</dt><dd>{{ selectedGpu.fan_speed != null ? `${selectedGpu.fan_speed}%` : '-' }}</dd></div>
          <div><dt>核心频率</dt><dd>{{ selectedGpu.clock_mhz ? `${selectedGpu.clock_mhz} MHz` : '-' }}</dd></div>
          <div><dt>驱动版本</dt><dd>{{ selectedGpu.driver_version || '-' }}</dd></div>
          <div><dt>设备标识</dt><dd>{{ selectedGpu.uuid || selectedGpu.id || `GPU-${selectedGpuIndex}` }}</dd></div>
        </dl>
      </section>
    </template>
  </el-drawer>
</template>

<style scoped lang="scss">
.monitor-actions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 10px; }
.health-state { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 500; color: #606266; }
.health-dot { width: 8px; height: 8px; border-radius: 50%; background: #10b981; box-shadow: 0 0 0 3px rgba(16, 185, 129, .12); }
.health-state.is-warning .health-dot { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245, 158, 11, .12); }
.health-state.is-danger .health-dot { background: #ef4444; box-shadow: 0 0 0 3px rgba(239, 68, 68, .12); }
.update-time { color: #909399; font-size: 12px; }
.interval-select { width: 78px; }
.load-alert { margin-bottom: 16px; }
.performance-content { min-height: 320px; }
.overview-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 16px; }
.overview-card, .panel, .gpu-card { border: 1px solid #e4e7ed; border-radius: 8px; background: #fff; }
.overview-card { position: relative; padding: 18px; overflow: hidden; }
.metric-heading { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.metric-heading h3, .metric-heading p { margin: 0; }
.metric-heading h3 { color: #303133; font-size: 14px; font-weight: 600; }
.metric-heading p { margin-top: 2px; color: #909399; font-size: 12px; }
.metric-icon { display: grid; width: 34px; height: 34px; place-items: center; border-radius: 7px; font-size: 15px; }
.metric-icon.is-cpu { color: #4f46e5; background: #eef2ff; }
.metric-icon.is-memory { color: #0ea5e9; background: #ecfeff; }
.metric-icon.is-disk { color: #10b981; background: #ecfdf5; }
.metric-icon.is-network { color: #f59e0b; background: #fffbeb; }
.metric-number { display: block; margin-bottom: 10px; color: #1f2937; font-size: 29px; line-height: 1; }
.metric-number small, .network-values small, .gpu-primary small { margin-left: 2px; color: #909399; font-size: 13px; font-weight: 500; }
.network-values { display: flex; flex-wrap: wrap; gap: 12px 18px; min-height: 38px; align-items: center; }
.network-values strong { color: #374151; font-size: 17px; }
.network-values i { margin-right: 3px; color: #10b981; font-size: 12px; }
.network-values strong:last-child i { color: #f59e0b; }
.panel { padding: 18px 20px; }
.resource-panel { margin-bottom: 24px; }
.panel-heading, .section-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.panel-heading h2, .panel-heading p, .section-heading h2, .section-heading p { margin: 0; }
.panel-heading h2, .section-heading h2 { color: #303133; font-size: 15px; font-weight: 600; }
.panel-heading p, .section-heading p { margin-top: 4px; color: #909399; font-size: 12px; }
.sample-count { color: #909399; font-size: 12px; }
.resource-chart { height: 260px; margin-top: 8px; }
.gpu-section { margin-bottom: 24px; }
.gpu-summary { min-width: 100px; text-align: right; }
.gpu-summary span { display: block; color: #909399; font-size: 12px; }
.gpu-summary strong { color: #303133; font-size: 22px; }
.gpu-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-top: 14px; }
.gpu-card { padding: 16px; cursor: pointer; transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease; }
.gpu-card:hover, .gpu-card:focus-visible { border-color: #a5b4fc; box-shadow: 0 5px 16px rgba(79, 70, 229, .08); outline: none; transform: translateY(-1px); }
.gpu-card-heading { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.gpu-identity { min-width: 0; }
.gpu-index { display: inline-block; margin-bottom: 4px; padding: 2px 7px; border-radius: 4px; color: #4338ca; background: #eef2ff; font-size: 11px; font-weight: 600; }
.gpu-identity h3 { overflow: hidden; margin: 0; color: #303133; font-size: 13px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.status-pill { display: inline-flex; flex: none; align-items: center; gap: 5px; padding: 3px 7px; border-radius: 999px; color: #047857; background: #ecfdf5; font-size: 11px; }
.status-pill i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.status-pill.is-busy { color: #4338ca; background: #eef2ff; }
.status-pill.is-warning { color: #b45309; background: #fffbeb; }
.status-pill.is-danger { color: #b91c1c; background: #fef2f2; }
.gpu-primary { display: flex; align-items: baseline; justify-content: space-between; margin: 17px 0 8px; }
.gpu-primary strong { color: #1f2937; font-size: 25px; }
.gpu-primary span { color: #909399; font-size: 11px; }
.gpu-metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px; margin: 15px 0 0; }
.gpu-metrics div { min-width: 0; }
.gpu-metrics dt { margin-bottom: 2px; color: #909399; font-size: 11px; }
.gpu-metrics dd { overflow: hidden; margin: 0; color: #606266; font-size: 12px; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; }
.gpu-metrics dd.is-warm { color: #b45309; }
.gpu-metrics dd.is-hot { color: #dc2626; }
.gpu-card-footer { margin: 14px -16px -16px; padding: 9px 16px; border-top: 1px solid #f0f2f5; color: #909399; font-size: 11px; text-align: right; }
.host-panel { padding-bottom: 4px; }
.host-info-grid { display: grid; grid-template-columns: 2fr 1.2fr 1fr 1fr; margin: 15px 0 0; }
.host-info-grid > div { min-width: 0; padding: 0 18px 14px; border-left: 1px solid #ebeef5; }
.host-info-grid > div:first-child { padding-left: 0; border-left: 0; }
.host-info-grid dt { margin-bottom: 5px; color: #909399; font-size: 12px; }
.host-info-grid dd { overflow: hidden; margin: 0; color: #303133; font-size: 13px; font-weight: 500; text-overflow: ellipsis; white-space: nowrap; }
.drawer-heading { display: flex; width: 100%; align-items: center; gap: 12px; }
.drawer-heading .gpu-index { margin: 0; }
.drawer-heading div { min-width: 0; flex: 1; }
.drawer-heading h2, .drawer-heading p { margin: 0; }
.drawer-heading h2 { color: #303133; font-size: 16px; }
.drawer-heading p { overflow: hidden; margin-top: 3px; color: #909399; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.drawer-metrics { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.drawer-metrics > div { min-width: 0; padding: 13px; border: 1px solid #e4e7ed; border-radius: 7px; background: #fafafa; }
.drawer-metrics span, .drawer-metrics small { display: block; overflow: hidden; color: #909399; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.drawer-metrics strong { display: block; margin: 6px 0 2px; color: #303133; font-size: 20px; }
.drawer-section { margin-top: 22px; }
.drawer-section-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.drawer-section-heading h3 { margin: 0; color: #303133; font-size: 14px; }
.drawer-section-heading span { color: #909399; font-size: 11px; }
.gpu-detail-chart { height: 230px; border: 1px solid #ebeef5; border-radius: 7px; }
.device-properties dl { display: grid; grid-template-columns: 1fr 1fr; margin: 0; border: 1px solid #ebeef5; border-radius: 7px; }
.device-properties dl > div { display: flex; min-width: 0; justify-content: space-between; gap: 14px; padding: 11px 13px; border-bottom: 1px solid #ebeef5; }
.device-properties dl > div:nth-last-child(-n + 2) { border-bottom: 0; }
.device-properties dt { color: #909399; font-size: 12px; }
.device-properties dd { overflow: hidden; margin: 0; color: #303133; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }

:deep(.gpu-detail-drawer .el-drawer__header) { margin-bottom: 0; padding-bottom: 17px; border-bottom: 1px solid #ebeef5; }
:deep(.gpu-detail-drawer .el-drawer__body) { outline: none; }

@media (max-width: 1280px) {
  .overview-grid, .gpu-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 860px) {
  .monitor-actions { justify-content: flex-start; }
  .update-time { width: 100%; }
  .host-info-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .host-info-grid > div:nth-child(3) { padding-left: 0; border-left: 0; }
  .drawer-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
  .overview-grid, .gpu-grid { grid-template-columns: 1fr; }
  .resource-chart { height: 230px; }
  .section-heading { flex-direction: column; }
  .gpu-summary { text-align: left; }
  .host-info-grid, .device-properties dl { grid-template-columns: 1fr; }
  .host-info-grid > div { padding-left: 0; border-left: 0; }
  .device-properties dl > div { border-bottom: 1px solid #ebeef5 !important; }
  .device-properties dl > div:last-child { border-bottom: 0 !important; }
}
</style>
