<template>
  <view class="screen-page">
    <view class="screen-bg"></view>

    <view class="hero-panel">
      <view class="hero-main">
        <text class="eyebrow">HEALTH OVERVIEW</text>
        <text class="title">健康总览态势</text>
        <text class="subtitle">{{ scopeText }} · 档案、体温、就医、用药、活动联动监测</text>
      </view>
      <view class="score-ring">
        <text>{{ healthIndex }}</text>
        <text>{{ healthIndexText }}</text>
      </view>
    </view>

    <view class="filter-card" @click="showPerson = true">
      <view>
        <text class="filter-label">当前成员</text>
        <text class="filter-value">{{ selectedPersonName || '请选择成员' }}</text>
      </view>
      <view class="filter-action">
        <text>切换</text>
        <uni-icons type="right" size="16" color="#8ee8ff"></uni-icons>
      </view>
    </view>

    <view class="metric-grid">
      <view v-for="item in metrics" :key="item.key" class="metric-card">
        <view class="metric-dot" :class="item.type"></view>
        <text class="metric-label">{{ item.label }}</text>
        <view class="metric-value">
          <text>{{ item.value }}</text>
          <text>{{ item.unit }}</text>
        </view>
        <text class="metric-desc">{{ item.desc }}</text>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>总览趋势</text>
          <text>近一年 · 体温 / 就医 / 用药 / 档案</text>
        </view>
      </view>
      <view class="chart-box tall">
        <qiun-data-charts
          v-if="chartVisible && hasChartData(trendChartData)"
          type="line"
          :canvasId="`${canvasIdPrefix}_trend`"
          :chartData="trendChartData"
          :opts="lineChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
        <view v-else class="chart-empty">暂无趋势数据</view>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>档案结构</text>
          <text>人员档案数排行 · {{ formatNumber(summary.healthRecordCount) }} 份档案</text>
        </view>
      </view>
      <view class="chart-box">
        <qiun-data-charts
          v-if="chartVisible && hasChartData(recordChartData)"
          type="column"
          :canvasId="`${canvasIdPrefix}_record`"
          :chartData="recordChartData"
          :opts="recordChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
        <view v-else class="chart-empty">暂无档案结构数据</view>
      </view>
      <view class="structure-list" v-if="personRecordList.length">
        <view v-for="(item, index) in personRecordList" :key="`${item.name}-${index}`">
          <text>{{ item.name }}</text>
          <text>{{ formatNumber(item.value) }}份</text>
        </view>
      </view>
      <view class="mini-stat-row">
        <view>
          <text>进行中</text>
          <text>{{ formatNumber(record.activeCount) }}</text>
        </view>
        <view>
          <text>已康复</text>
          <text>{{ formatNumber(record.recoveredCount) }}</text>
        </view>
        <view>
          <text>成员数</text>
          <text>{{ formatNumber(summary.personCount) }}</text>
        </view>
      </view>
    </view>

    <view class="panel-card split-panel">
      <view class="panel-head">
        <view>
          <text>体温风险监测</text>
          <text>最近 {{ formatNumber(temperature.totalCount) }} 条</text>
        </view>
      </view>
      <view class="chart-box">
        <qiun-data-charts
          v-if="chartVisible"
          type="ring"
          :canvasId="`${canvasIdPrefix}_temp_ring`"
          :chartData="temperatureRingData"
          :opts="ringChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
      </view>
      <view class="risk-grid">
        <view v-for="item in tempBands" :key="item.label">
          <text>{{ item.label }}</text>
          <text>{{ formatNumber(item.value) }}</text>
        </view>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>用药频次</text>
          <text>近一年 · 共 {{ medicineRankList.length }} 种药品 / 图表Top5</text>
        </view>
      </view>
      <view class="chart-box">
        <qiun-data-charts
          v-if="chartVisible && hasChartData(medicineChartData)"
          type="bar"
          :canvasId="`${canvasIdPrefix}_medicine`"
          :chartData="medicineChartData"
          :opts="barChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
        <view v-else class="chart-empty">暂无用药排行数据</view>
      </view>
      <view class="rank-list">
        <view v-for="(item, index) in medicineRankList" :key="`${item.name}-${index}`" class="rank-row">
          <text>{{ String(index + 1).padStart(2, '0') }}</text>
          <view>
            <text>{{ item.name }}</text>
            <text>{{ formatNumber(item.count) }}次 / {{ formatNumber(item.useDays) }}天</text>
          </view>
        </view>
        <u-empty v-if="!medicineRankList.length && !loading" mode="data" text="暂无用药数据"></u-empty>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>就医费用分析</text>
          <text>近一年 · {{ formatMoney(doctor.doctorCost) }}</text>
        </view>
      </view>
      <view class="chart-box">
        <qiun-data-charts
          v-if="chartVisible && hasChartData(doctorCostChartData)"
          type="column"
          :canvasId="`${canvasIdPrefix}_doctor`"
          :chartData="doctorCostChartData"
          :opts="moneyChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
        <view v-else class="chart-empty">暂无就医费用数据</view>
      </view>
      <view class="mini-stat-row">
        <view>
          <text>就医次数</text>
          <text>{{ formatNumber(doctor.doctorCount) }}</text>
        </view>
        <view>
          <text>平均费用</text>
          <text>{{ formatMoney(doctor.avgDoctorCost) }}</text>
        </view>
        <view>
          <text>医院数</text>
          <text>{{ formatNumber(doctor.hospitalCount) }}</text>
        </view>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>活动与费用趋势</text>
          <text>最新 50 条</text>
        </view>
      </view>
      <view class="activity-summary">
        <text>{{ formatNumber(summary.activityCount) }} 次活动</text>
        <text>费用 {{ formatMoney(summary.activityCost) }}</text>
      </view>
      <view class="chart-box">
        <qiun-data-charts
          v-if="chartVisible && hasChartData(activityChartData)"
          type="mix"
          :canvasId="`${canvasIdPrefix}_activity`"
          :chartData="activityChartData"
          :opts="mixChartOpts"
          :loadingType="1"
          :ontouch="true"
          :inScrollView="true"
        />
        <view v-else class="chart-empty">暂无活动趋势数据</view>
      </view>
      <view class="event-list">
        <view v-for="(item, index) in activityList" :key="`${item.id || item.name}-${index}`" class="event-row">
          <text>{{ activityTitle(item) }}</text>
          <text>{{ formatDateTime(item.startTime) }} · {{ activityMeta(item) }}</text>
          <text>费用 {{ formatMoney(item.totalCost) }}</text>
        </view>
        <u-empty v-if="!activityList.length && !loading" mode="data" text="暂无活动记录"></u-empty>
      </view>
    </view>

    <view class="panel-card">
      <view class="panel-head">
        <view>
          <text>健康事件动态</text>
          <text>最新 {{ eventList.length }} 条</text>
        </view>
      </view>
      <view class="timeline-list">
        <view v-for="(item, index) in eventList" :key="`${item.type}-${item.time}-${index}`" class="timeline-row">
          <view class="timeline-tag">{{ eventTypeLabel(item.type) }}</view>
          <view>
            <text>{{ item.title || '--' }}</text>
            <text>{{ item.personName || '--' }} · {{ item.time || '--' }}</text>
            <text>{{ item.value || '--' }}</text>
          </view>
        </view>
        <u-empty v-if="!eventList.length && !loading" mode="data" text="暂无健康事件"></u-empty>
      </view>
    </view>

    <view class="panel-card last-panel">
      <view class="panel-head">
        <view>
          <text>健康运营建议</text>
          <text>自动生成</text>
        </view>
      </view>
      <view class="suggestion-list">
        <view v-for="(item, index) in suggestionList" :key="`${item.title}-${index}`" class="suggestion-row">
          <text>{{ index + 1 }}</text>
          <view>
            <text>{{ item.title }}</text>
            <text>{{ item.content }}</text>
          </view>
        </view>
        <u-empty v-if="!suggestionList.length && !loading" mode="data" text="暂无建议"></u-empty>
      </view>
    </view>

    <u-loading-page :loading="loading" loading-text="加载中"></u-loading-page>
    <u-picker :show="showPerson" :columns="[personOptions]" keyName="name" @cancel="showPerson = false" @confirm="handlePersonConfirm"></u-picker>
    <suspend></suspend>
  </view>
</template>

<script setup>
import { computed, ref } from 'vue'
import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
import { getHealthScreen } from '@/api/health/statisticAnalysis'
import { listPerson } from '@/api/health/person'
import { getDicts } from '@/api/system/dict/data.js'

const loading = ref(false)
const showPerson = ref(false)
const personOptions = ref([])
const selectedPersonId = ref(null)
const screenData = ref({})
const dictMap = ref({})
const canvasIdPrefix = `h5_health_${Date.now()}`
const chartVisible = computed(() => !showPerson.value)

const summary = computed(() => screenData.value.summary || {})
const record = computed(() => screenData.value.record || {})
const temperature = computed(() => screenData.value.temperature || {})
const medicine = computed(() => screenData.value.medicine || {})
const doctor = computed(() => screenData.value.doctor || {})
const activity = computed(() => screenData.value.activity || {})
const eventList = computed(() => (screenData.value.eventList || []).slice(0, 50))
const suggestionList = computed(() => screenData.value.suggestionList || [])
const healthIndex = computed(() => Number(summary.value.healthIndex || 0))
const selectedPersonName = computed(() => {
  const person = personOptions.value.find((item) => item.id === selectedPersonId.value)
  return person?.name || summary.value.selectedPersonName || ''
})
const scopeText = computed(() => selectedPersonName.value ? `${selectedPersonName.value}健康视角` : '健康总览视角')
const healthIndexText = computed(() => {
  if (healthIndex.value >= 85) return '整体平稳'
  if (healthIndex.value >= 70) return '持续观察'
  return '重点关注'
})

const metrics = computed(() => [
  { key: 'person', type: 'blue', label: '成员总数', value: formatNumber(summary.value.personCount), unit: '人', desc: '纳入健康管理' },
  { key: 'record', type: 'cyan', label: '健康档案', value: formatNumber(summary.value.healthRecordCount), unit: '份', desc: `人均 ${formatNumber(summary.value.avgRecordPerPerson)} 份` },
  { key: 'doctor', type: 'gold', label: '就医次数', value: formatNumber(summary.value.doctorCount), unit: '次', desc: `费用 ${formatMoney(summary.value.doctorCost)}` },
  { key: 'temperature', type: 'red', label: '体温记录', value: formatNumber(summary.value.temperatureTotalCount), unit: '条', desc: `发热 ${formatNumber(summary.value.feverDayCount)} 天` },
  { key: 'medicine', type: 'green', label: '用药记录', value: formatNumber(summary.value.marCount), unit: '次', desc: `${formatNumber(summary.value.medicalTypeCount)} 种药品` },
  { key: 'activity', type: 'purple', label: '活动记录', value: formatNumber(summary.value.activityCount), unit: '次', desc: `费用 ${formatMoney(summary.value.activityCost)}` }
])

const personRecordList = computed(() => {
  const list = (record.value.personRecordList || []).filter((item) => String(item.name || '').trim())
  const max = Math.max(...list.map((item) => Number(item.value || 0)), 1)
  return list.map((item) => ({ ...item, percent: Math.max(8, Math.round(Number(item.value || 0) / max * 100)) }))
})

const tempBands = computed(() => [
  { label: '正常', value: temperature.value.normalTempCount },
  { label: '低热', value: temperature.value.lowerTempCount },
  { label: '中热', value: temperature.value.middleTempCount },
  { label: '高热', value: temperature.value.higherTempCount }
])

const medicineRankList = computed(() => {
  const list = (medicine.value.marMapList || []).map((item) => ({
    name: item.medicalName || item.name || '未命名药品',
    count: Number(item.count || item.value || 0),
    useDays: Number(item.useDays || 0)
  }))
  const max = Math.max(...list.map((item) => item.count), 1)
  return list
    .sort((a, b) => b.count - a.count)
    .map((item) => ({ ...item, percent: Math.max(8, Math.round(item.count / max * 100)) }))
})

const activityList = computed(() => (activity.value.recentList || []).slice(0, 8))

const trendChartData = computed(() => {
  const recordMonth = record.value.monthList || []
  const temperatureDays = temperature.value.tableList || []
  const medicineDays = medicine.value.marList || []
  const doctorDays = doctor.value.doctorCountList || []
  const rawCategories = mergeTimes(recordMonth, temperatureDays, medicineDays, doctorDays).slice(-12)
  return {
    categories: rawCategories.map(formatChartDate),
    series: [
      { name: '档案', data: mapSeries(recordMonth, rawCategories), color: '#3ddcff' },
      { name: '体温', data: mapSeries(temperatureDays, rawCategories, 'count'), color: '#ff6b8b' },
      { name: '用药', data: mapSeries(medicineDays, rawCategories), color: '#58e6a7' },
      { name: '就医', data: mapSeries(doctorDays, rawCategories), color: '#ffd166' }
    ]
  }
})

const recordChartData = computed(() => ({
  categories: personRecordList.value.slice(0, 8).map((item, index) => `成员${index + 1}`),
  series: [{ name: '档案', data: personRecordList.value.slice(0, 8).map((item) => Number(item.value || 0)) }]
}))

const temperatureRingData = computed(() => ({
  series: [
    {
      data: ensurePieData(tempBands.value
        .filter((item) => Number(item.value || 0) > 0)
        .map((item) => ({ name: item.label, value: Number(item.value || 0) })))
    }
  ]
}))

const medicineChartData = computed(() => {
  const topList = medicineRankList.value.slice(0, 5).reverse()
  return {
    categories: topList.map((item, index) => `TOP${topList.length - index}`),
    series: [{ name: '用药次数', data: topList.map((item) => Number(item.count || 0)) }]
  }
})

const doctorCostChartData = computed(() => {
  const list = (doctor.value.doctorCostList || []).slice(-12)
  return {
    categories: list.map((item) => formatChartDate(item.time)),
    series: [{ name: '费用', data: list.map((item) => Number(item.value || 0)) }]
  }
})

const activityChartData = computed(() => {
  const countData = activity.value.countTrend || []
  const costData = activity.value.costTrend || []
  const rawCategories = mergeTimes(countData, costData).slice(-14)
  return {
    categories: rawCategories.map(formatChartDate),
    series: [
      { name: '活动次数', type: 'column', data: mapSeries(countData, rawCategories), color: '#3ddcff' },
      { name: '活动费用', type: 'line', data: mapSeries(costData, rawCategories), color: '#ffd166' }
    ]
  }
})

const baseAxis = {
  disableGrid: false,
  gridColor: 'rgba(110, 199, 255, 0.12)',
  fontColor: '#9fc7df',
  fontSize: 10,
  lineHeight: 16,
  labelCount: 4,
  marginTop: 8,
  title: ''
}

const lineChartOpts = computed(() => ({
  color: ['#3ddcff', '#ff6b8b', '#58e6a7', '#ffd166'],
  padding: [18, 12, 18, 8],
  dataLabel: false,
  dataPointShape: true,
  legend: { show: true, position: 'top', fontColor: '#c9f6ff', fontSize: 10, lineHeight: 18 },
  xAxis: { ...baseAxis, boundaryGap: 'justify', axisLine: false },
  yAxis: { showTitle: false, gridType: 'dash', dashLength: 4, gridColor: 'rgba(110, 199, 255, 0.12)', data: [{ min: 0, title: '', fontColor: '#9fc7df', fontSize: 10 }] },
  extra: { line: { type: 'curve', width: 2, activeType: 'hollow' }, tooltip: chartTooltip() }
}))

const recordChartOpts = computed(() => ({
  color: ['#3ddcff'],
  padding: [12, 12, 22, 8],
  dataLabel: false,
  legend: { show: false },
  xAxis: { ...baseAxis, axisLine: false },
  yAxis: { showTitle: false, gridType: 'dash', dashLength: 4, gridColor: 'rgba(110, 199, 255, 0.12)', data: [{ min: 0, title: '', fontColor: '#9fc7df', fontSize: 10 }] },
  extra: { column: { type: 'group', width: 18, barBorderCircle: true, linearType: 'custom' }, tooltip: chartTooltip() }
}))

const ringChartOpts = computed(() => ({
  color: ['#58e6a7', '#ffd166', '#ff9f43', '#ff5f6d'],
  padding: [10, 10, 10, 10],
  dataLabel: true,
  title: { name: '' },
  subtitle: { name: '' },
  legend: { show: true, position: 'bottom', fontColor: '#c9f6ff', fontSize: 10, lineHeight: 18 },
  extra: {
    ring: {
      ringWidth: 26,
      activeOpacity: 0.7,
      activeRadius: 4,
      offsetAngle: 0,
      labelWidth: 12,
      border: false
    },
    tooltip: chartTooltip()
  }
}))

const barChartOpts = computed(() => ({
  color: ['#58e6a7'],
  padding: [12, 18, 18, 8],
  dataLabel: false,
  legend: { show: false },
  xAxis: { ...baseAxis, axisLine: false },
  yAxis: { showTitle: false, gridType: 'dash', dashLength: 4, gridColor: 'rgba(110, 199, 255, 0.12)', data: [{ min: 0, title: '', fontColor: '#9fc7df', fontSize: 10 }] },
  extra: { bar: { type: 'group', width: 12, barBorderCircle: true, linearType: 'custom' }, tooltip: chartTooltip() }
}))

const moneyChartOpts = computed(() => ({
  color: ['#ffd166'],
  padding: [12, 12, 22, 8],
  dataLabel: false,
  legend: { show: false },
  xAxis: { ...baseAxis, axisLine: false },
  yAxis: { showTitle: false, gridType: 'dash', dashLength: 4, gridColor: 'rgba(110, 199, 255, 0.12)', data: [{ min: 0, title: '', fontColor: '#9fc7df', fontSize: 10 }] },
  extra: { column: { type: 'group', width: 18, barBorderCircle: true, linearType: 'custom' }, tooltip: chartTooltip() }
}))

const mixChartOpts = computed(() => ({
  color: ['#3ddcff', '#ffd166'],
  padding: [18, 12, 22, 8],
  dataLabel: false,
  dataPointShape: true,
  legend: { show: true, position: 'top', fontColor: '#c9f6ff', fontSize: 10, lineHeight: 18 },
  xAxis: { ...baseAxis, axisLine: false },
  yAxis: { showTitle: false, gridType: 'dash', dashLength: 4, gridColor: 'rgba(110, 199, 255, 0.12)', data: [{ min: 0, title: '', fontColor: '#9fc7df', fontSize: 10 }] },
  extra: {
    mix: { column: { width: 16 }, line: { width: 2 } },
    column: { width: 16, barBorderCircle: true },
    line: { type: 'curve', width: 2, activeType: 'hollow' },
    tooltip: chartTooltip()
  }
}))

function loadDicts() {
  return Promise.all([
    loadDict('activity_type'),
    loadDict('activity_exercise')
  ])
}

function loadDict(type) {
  return getDicts(type)
    .then((res) => {
      dictMap.value[type] = normalizeDictList(res.data || [])
    })
    .catch(() => {
      dictMap.value[type] = []
    })
}

function loadPersonOptions() {
  return listPerson({ pageNum: 1, pageSize: 999 }).then((res) => {
    personOptions.value = res.rows || res.data || []
    if (!selectedPersonId.value && personOptions.value.length) {
      selectedPersonId.value = personOptions.value[0].id
    }
  })
}

function loadScreen() {
  loading.value = true
  const query = selectedPersonId.value ? { id: selectedPersonId.value } : {}
  return getHealthScreen(query)
    .then((res) => {
      screenData.value = res.data || {}
    })
    .finally(() => {
      loading.value = false
      uni.stopPullDownRefresh()
    })
}

function initPage() {
  loading.value = true
  Promise.all([loadDicts(), loadPersonOptions()]).finally(loadScreen)
}

function handlePersonConfirm(e) {
  const item = e.value && e.value[0]
  selectedPersonId.value = item?.id || null
  showPerson.value = false
  loadScreen()
}

function chartTooltip() {
  return {
    showBox: true,
    showArrow: true,
    bgColor: '#06162e',
    bgOpacity: 0.92,
    fontColor: '#e9fbff',
    fontSize: 11,
    lineHeight: 16,
    borderRadius: 4,
    borderWidth: 1,
    borderColor: '#3ddcff',
    padding: [8, 10, 8, 10]
  }
}

function normalizeDictList(list) {
  return (list || []).map((item) => ({
    label: item.dictLabel ?? item.label ?? item.name ?? '',
    value: item.dictValue ?? item.value ?? item.code ?? ''
  }))
}

function dictLabel(type, value, fallback = '') {
  if (fallback) return fallback
  if (value === undefined || value === null || value === '') return ''
  const option = (dictMap.value[type] || []).find((item) => String(item.value) === String(value))
  return option?.label || ''
}

function eventTypeLabel(value) {
  const eventMap = {
    record: '档案',
    doctor: '就医',
    medicine: '用药',
    mar: '用药',
    temperature: '体温',
    temp: '体温',
    activity: '活动'
  }
  return eventMap[String(value || '').toLowerCase()] || value || '事件'
}

function activityTitle(item = {}) {
  return item.name || item.activityName || dictLabel('activity_type', item.type ?? item.activityType, item.typeName || item.activityTypeName) || '活动记录'
}

function activityMeta(item = {}) {
  return item.place || item.placeName || item.partner || item.partnerName || dictLabel('activity_exercise', item.activityVolume, item.activityVolumeName) || '--'
}

function ensurePieData(list) {
  return list && list.length ? list : [{ name: '暂无数据', value: 1 }]
}

function hasChartData(chartData = {}) {
  return (chartData.series || []).some((series) => (series.data || []).some((value) => Number(value || 0) !== 0))
}

function mergeTimes(...lists) {
  const set = new Set()
  lists.forEach((list) => {
    ;(list || []).forEach((item) => {
      if (item && item.time !== undefined && item.time !== null && item.time !== '') set.add(String(item.time))
    })
  })
  return Array.from(set).sort()
}

function mapSeries(list, categories, key = 'value') {
  const map = new Map((list || []).map((item) => [String(item.time), Number(item[key] ?? item.value ?? 0)]))
  return categories.map((time) => map.get(String(time)) || 0)
}

function shortText(value, length = 8) {
  const text = String(value || '--')
  return text.length > length ? text.slice(0, length) : text
}

function formatChartDate(value) {
  if (!value) return ''
  const text = String(value).replace('T', ' ').trim()
  const datePart = text.split(' ')[0]
  if (/^\d{4}-\d{2}-\d{2}$/.test(datePart)) return datePart.slice(5).replace('-', '/')
  if (/^\d{4}-\d{2}$/.test(datePart)) return `${datePart.slice(5)}月`
  if (/^\d{2}-\d{2}$/.test(datePart)) return datePart.replace('-', '/')
  if (/^\d{2}\/\d{2}$/.test(datePart)) return datePart
  return shortText(datePart, 6)
}

function formatNumber(value) {
  const num = Number(value || 0)
  return Number.isFinite(num) ? String(num) : '0'
}

function formatMoney(value) {
  const num = Number(value || 0)
  if (!Number.isFinite(num)) return '￥0.00'
  if (num >= 10000) return `￥${(num / 10000).toFixed(1)}万`
  return `￥${num.toFixed(2)}`
}

function formatDateTime(value) {
  if (!value) return '--'
  return String(value).replace('T', ' ').slice(0, 16)
}

onLoad(initPage)
onPullDownRefresh(loadScreen)
</script>

<style lang="scss" scoped>
.screen-page {
  position: relative;
  min-height: 100vh;
  padding: 24rpx;
  overflow-x: hidden;
  background: #071529;
  box-sizing: border-box;
}

.screen-bg {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(circle at 10% 0%, rgba(61, 220, 255, 0.22), transparent 42%),
    radial-gradient(circle at 90% 16%, rgba(88, 230, 167, 0.16), transparent 36%),
    linear-gradient(180deg, #0a2141 0%, #071529 48%, #06101f 100%);
}

.hero-panel,
.filter-card,
.metric-card,
.panel-card {
  position: relative;
  z-index: 1;
  border: 1rpx solid rgba(132, 219, 255, 0.18);
  background: rgba(9, 30, 58, 0.78);
  box-shadow: 0 18rpx 48rpx rgba(0, 8, 20, 0.32);
  backdrop-filter: blur(10px);
}

.hero-panel {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20rpx;
  padding: 30rpx;
  border-radius: 24rpx;
}

.hero-main {
  min-width: 0;
}

.eyebrow {
  color: #72e9ff;
  font-size: 21rpx;
  letter-spacing: 0;
}

.title {
  display: block;
  margin-top: 10rpx;
  color: #f2fdff;
  font-size: 42rpx;
  font-weight: 800;
  line-height: 1.15;
}

.subtitle {
  display: block;
  margin-top: 12rpx;
  color: #a6cbe0;
  font-size: 24rpx;
  line-height: 1.45;
}

.score-ring {
  flex: 0 0 134rpx;
  width: 134rpx;
  height: 134rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 8rpx solid rgba(61, 220, 255, 0.2);
  background: linear-gradient(180deg, rgba(61, 220, 255, 0.18), rgba(88, 230, 167, 0.1));

  text:first-child {
    color: #ffffff;
    font-size: 42rpx;
    font-weight: 800;
  }

  text:last-child {
    margin-top: 4rpx;
    color: #bdf6ff;
    font-size: 21rpx;
  }
}

.filter-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16rpx;
  margin-top: 20rpx;
  padding: 22rpx 24rpx;
  border-radius: 18rpx;
}

.filter-card > view:first-child {
  min-width: 0;
}

.filter-label {
  display: block;
  color: #82adc6;
  font-size: 23rpx;
}

.filter-value {
  display: block;
  margin-top: 8rpx;
  color: #f2fdff;
  font-size: 30rpx;
  font-weight: 700;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.filter-action {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4rpx;
  color: #8ee8ff;
  font-size: 24rpx;
}

.metric-grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16rpx;
  margin-top: 20rpx;
}

.metric-card {
  min-height: 164rpx;
  padding: 22rpx;
  border-radius: 18rpx;
  box-sizing: border-box;
}

.metric-dot {
  width: 28rpx;
  height: 6rpx;
  margin-bottom: 16rpx;
  border-radius: 999rpx;
  background: #3ddcff;
}

.metric-dot.cyan { background: #3ddcff; }
.metric-dot.blue { background: #6ba7ff; }
.metric-dot.gold { background: #ffd166; }
.metric-dot.red { background: #ff6b8b; }
.metric-dot.green { background: #58e6a7; }
.metric-dot.purple { background: #b98cff; }

.metric-label {
  display: block;
  color: #95bed5;
  font-size: 23rpx;
}

.metric-value {
  display: flex;
  align-items: baseline;
  gap: 6rpx;
  margin-top: 8rpx;

  text:first-child {
    min-width: 0;
    color: #ffffff;
    font-size: 38rpx;
    font-weight: 800;
    line-height: 1.15;
    overflow-wrap: anywhere;
  }

  text:last-child {
    color: #9fc7df;
    font-size: 22rpx;
  }
}

.metric-desc {
  display: block;
  margin-top: 8rpx;
  color: #779db7;
  font-size: 22rpx;
  line-height: 1.35;
}

.panel-card {
  margin-top: 20rpx;
  padding: 24rpx;
  border-radius: 20rpx;
  overflow: hidden;
}

.last-panel {
  margin-bottom: 36rpx;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16rpx;
  margin-bottom: 18rpx;

  view {
    min-width: 0;
  }

  text:first-child {
    display: block;
    color: #f2fdff;
    font-size: 30rpx;
    font-weight: 800;
    line-height: 1.25;
  }

  text:last-child {
    display: block;
    margin-top: 6rpx;
    color: #83aec8;
    font-size: 22rpx;
    line-height: 1.35;
  }
}

.chart-box {
  width: 100%;
  height: 430rpx;
  overflow: hidden;
}

.chart-box.tall {
  height: 470rpx;
}

.chart-empty {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #82adc6;
  font-size: 24rpx;
  border: 1rpx dashed rgba(132, 219, 255, 0.18);
  border-radius: 16rpx;
  background: rgba(7, 21, 41, 0.38);
}

.mini-stat-row,
.risk-grid,
.structure-list {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12rpx;
  margin-top: 18rpx;

  view {
    padding: 16rpx;
    border: 1rpx solid rgba(132, 219, 255, 0.14);
    background: rgba(7, 21, 41, 0.58);
    border-radius: 14rpx;
  }

  text {
    display: block;
  }

  text:first-child {
    color: #82adc6;
    font-size: 21rpx;
  }

  text:last-child {
    margin-top: 8rpx;
    color: #ffffff;
    font-size: 28rpx;
    font-weight: 800;
    line-height: 1.2;
  }
}

.risk-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));

  view {
    padding: 14rpx 8rpx;
  }

  text {
    text-align: center;
  }

  text:last-child {
    font-size: 26rpx;
    line-height: 1.2;
    overflow-wrap: anywhere;
  }
}

.structure-list {
  grid-template-columns: 1fr;
  margin-top: 16rpx;

  view {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16rpx;
  }

  text:first-child {
    min-width: 0;
    color: #d8f6ff;
    line-height: 1.45;
    overflow-wrap: anywhere;
  }

  text:last-child {
    flex: 0 0 auto;
    color: #3ddcff;
  }
}

.activity-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 12rpx;
  margin-bottom: 12rpx;

  text {
    padding: 8rpx 14rpx;
    color: #bdf6ff;
    background: rgba(61, 220, 255, 0.1);
    border: 1rpx solid rgba(61, 220, 255, 0.24);
    border-radius: 999rpx;
    font-size: 22rpx;
  }
}

.rank-list,
.event-list,
.timeline-list,
.suggestion-list {
  margin-top: 16rpx;
}

.rank-row {
  display: flex;
  gap: 16rpx;
  padding: 16rpx 0;
  border-bottom: 1rpx solid rgba(132, 219, 255, 0.1);

  > text {
    flex: 0 0 46rpx;
    color: #3ddcff;
    font-size: 24rpx;
    font-weight: 800;
  }

  view {
    min-width: 0;
    flex: 1;
  }

  view text:first-child {
    display: block;
    color: #f2fdff;
    font-size: 25rpx;
    font-weight: 700;
    line-height: 1.4;
    overflow-wrap: anywhere;
  }

  view text:last-child {
    display: block;
    margin-top: 4rpx;
    color: #8eb8d1;
    font-size: 22rpx;
  }
}

.event-row,
.timeline-row,
.suggestion-row {
  border: 1rpx solid rgba(132, 219, 255, 0.12);
  background: rgba(7, 21, 41, 0.56);
  border-radius: 16rpx;
}

.event-row {
  display: flex;
  flex-direction: column;
  gap: 6rpx;
  margin-bottom: 12rpx;
  padding: 18rpx;

  text:first-child {
    color: #ffffff;
    font-size: 26rpx;
    font-weight: 700;
    line-height: 1.4;
  }

  text:nth-child(2),
  text:nth-child(3) {
    color: #8eb8d1;
    font-size: 23rpx;
    line-height: 1.45;
  }
}

.timeline-row {
  display: flex;
  gap: 14rpx;
  margin-bottom: 12rpx;
  padding: 18rpx;
}

.timeline-tag {
  flex: 0 0 auto;
  height: 42rpx;
  padding: 0 12rpx;
  display: flex;
  align-items: center;
  color: #051529;
  background: #3ddcff;
  border-radius: 999rpx;
  font-size: 21rpx;
  font-weight: 800;
}

.timeline-row view:last-child {
  min-width: 0;
  flex: 1;

  text {
    display: block;
    line-height: 1.45;
  }

  text:first-child {
    color: #ffffff;
    font-size: 26rpx;
    font-weight: 700;
    overflow-wrap: anywhere;
  }

  text:nth-child(2),
  text:nth-child(3) {
    margin-top: 4rpx;
    color: #8eb8d1;
    font-size: 23rpx;
    overflow-wrap: anywhere;
  }
}

.suggestion-row {
  display: flex;
  gap: 16rpx;
  margin-bottom: 12rpx;
  padding: 18rpx;

  > text {
    flex: 0 0 42rpx;
    width: 42rpx;
    height: 42rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #06162e;
    background: #58e6a7;
    border-radius: 50%;
    font-size: 23rpx;
    font-weight: 800;
  }

  view {
    min-width: 0;
    flex: 1;
  }

  view text:first-child {
    display: block;
    color: #ffffff;
    font-size: 26rpx;
    font-weight: 700;
  }

  view text:last-child {
    display: block;
    margin-top: 6rpx;
    color: #92bdd6;
    font-size: 23rpx;
    line-height: 1.5;
    overflow-wrap: anywhere;
  }
}
</style>
