<script setup lang="ts">
import type { Component } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import {
  Calendar,
  Checked,
  DataAnalysis,
  DocumentChecked,
  EditPen,
  List,
  Management,
  OfficeBuilding,
  Operation,
  Reading,
  School,
  Tickets,
  UserFilled,
  Warning,
} from '@element-plus/icons-vue'
import http from '../api/http'
import { useAuthStore } from '../stores/auth'
import StudentDashboardView from './StudentDashboardView.vue'
import TeacherDashboardView from './TeacherDashboardView.vue'

interface DashboardData {
  audience: {
    level: 'System' | 'School' | 'College' | 'Leadership' | 'Counselor' | 'Teaching'
    title: string
    scopeName: string
    description: string
  }
  currentTerm?: {
    id: string
    name: string
    startDate: string
    endDate: string
  }
  counts: {
    students: number
    teachers: number
    courses: number
    teachingTasks: number
    publishedTeachingTasks: number
    scheduledTeachingTasks: number
    courseEnrollments: number
    gradeSheets: number
    publishedGradeSheets: number
    submittedGradeSheets: number
    openCourseSelectionRounds: number
  }
  pending: {
    teacherApplications: number
    gradeSheets: number
    courseAdjustments: number
    studentStatusChanges: number
    gradeModifications: number
    classroomReservations: number
    generalApprovals: number
  }
  greeting: DashboardGreeting
  generatedAt: string
}

interface DashboardGreeting {
  role: string
  title: string
  subtitle: string
  label: string
  narrative: string
  insights: Array<{
    label: string
    value: string
    hint: string
    tone: 'calm' | 'positive' | 'attention'
  }>
}

interface DashboardLink {
  key: string
  label: string
  description: string
  route: string
  icon: Component
}

interface WarningRecord {
  id: string
  studentName: string
  studentNumber: string
  className: string
  status: number
  detail: string
}

const router = useRouter()
const auth = useAuthStore()
const roles = computed(() => auth.user?.roles ?? [])
const isStudentOverview = computed(() =>
  roles.value.includes('Student') &&
  !roles.value.some((role) =>
    ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin', 'Counselor'].includes(role),
  ),
)
const isTeacherOverview = computed(() =>
  roles.value.includes('Teacher') &&
  !roles.value.some((role) => ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin', 'Counselor', 'Student'].includes(role)),
)
const loading = ref(true)
const loadError = ref('')
const data = ref<DashboardData | null>(null)
const counselorWarnings = ref<WarningRecord[]>([])
const now = ref(new Date())

function hasRole(...allowedRoles: string[]) {
  return roles.value.some((role) => allowedRoles.includes(role))
}

const isCounselorDashboard = computed(() =>
  hasRole('Counselor') && !hasRole('SuperAdmin', 'AcademicAdmin', 'CollegeAdmin'),
)

const activeCounselorWarnings = computed(() =>
  counselorWarnings.value.filter((warning) => warning.status === 1),
)

function parseDateOnly(value?: string) {
  if (!value) return null
  const [year, month, day] = value.slice(0, 10).split('-').map(Number)
  if (!year || !month || !day) return null
  return new Date(year, month - 1, day)
}

function startOfDay(value: Date) {
  return new Date(value.getFullYear(), value.getMonth(), value.getDate())
}

function formatDate(value?: string) {
  const date = parseDateOnly(value)
  if (!date) return '待设置'
  return new Intl.DateTimeFormat('zh-CN', {
    month: 'long',
    day: 'numeric',
  }).format(date)
}

function formatNumber(value: number) {
  return new Intl.NumberFormat('zh-CN').format(value)
}

function ratio(value: number, total: number) {
  if (total <= 0) return 0
  return Math.min(100, Math.round(value / total * 100))
}

const termProgress = computed(() => {
  const start = parseDateOnly(data.value?.currentTerm?.startDate)
  const end = parseDateOnly(data.value?.currentTerm?.endDate)
  if (!start || !end) return 0
  const total = Math.max(1, end.getTime() - start.getTime())
  const elapsed = startOfDay(now.value).getTime() - start.getTime()
  return Math.min(100, Math.max(0, Math.round(elapsed / total * 100)))
})

const termContext = computed(() => {
  const start = parseDateOnly(data.value?.currentTerm?.startDate)
  const end = parseDateOnly(data.value?.currentTerm?.endDate)
  if (!start || !end) return '尚未设置学期日历'
  const today = startOfDay(now.value)
  const day = 86400000
  if (today < start) {
    return `距离开学 ${Math.ceil((start.getTime() - today.getTime()) / day)} 天`
  }
  if (today > end) return '本学期已结束'
  const currentWeek = Math.floor((today.getTime() - start.getTime()) / day / 7) + 1
  const totalWeeks = Math.ceil((end.getTime() - start.getTime() + day) / day / 7)
  return `第 ${currentWeek} 教学周 / 共 ${totalWeeks} 周`
})

const pendingTotal = computed(() =>
  Object.values(data.value?.pending ?? {}).reduce((sum, value) => sum + value, 0),
)

const todoItems = computed(() => {
  const pending = data.value?.pending
  if (!pending) return []
  const items = [
    {
      key: 'teacher-applications',
      label: '授课资格审核',
      description: '教师申报的授课科目等待确认',
      route: '/teaching-preferences',
      count: pending.teacherApplications,
    },
    {
      key: 'grade-sheets',
      label: '成绩登记审核',
      description: '教师已提交，等待审核或发布',
      route: '/grades',
      count: pending.gradeSheets,
    },
    {
      key: 'course-adjustments',
      label: '调停课审核',
      description: '调课、停课、补课或代课申请',
      route: '/course-adjustments',
      count: pending.courseAdjustments,
    },
    {
      key: 'student-status',
      label: '学籍异动审核',
      description: data.value?.audience.level === 'College'
        ? '辅导员已审核，等待学院处理'
        : '学院已审核，等待校级处理',
      route: '/student-status-changes',
      count: pending.studentStatusChanges,
    },
    {
      key: 'grade-modifications',
      label: '成绩修改审核',
      description: data.value?.audience.level === 'College'
        ? '教师申请的成绩修改等待学院审核'
        : '学院已审核，等待校级终审',
      route: '/approvals',
      count: pending.gradeModifications,
    },
    {
      key: 'classroom-reservations',
      label: '教室借用审核',
      description: '本学院提交的教室借用申请',
      route: '/classroom-reservations',
      count: pending.classroomReservations,
    },
    {
      key: 'general-approvals',
      label: '其他教学审批',
      description: '免修、缓考、课程替代或考勤申诉',
      route: '/approvals',
      count: pending.generalApprovals,
    },
  ]
  return items.filter((item) => item.count > 0)
})

const adminMetrics = computed(() => {
  const counts = data.value?.counts
  if (!counts) return []
  return [
    {
      key: 'students',
      label: '在籍学生',
      value: formatNumber(counts.students),
      hint: `${data.value?.audience.scopeName}当前有效学籍`,
      route: '/students',
    },
    {
      key: 'tasks',
      label: '本学期教学班',
      value: formatNumber(counts.teachingTasks),
      hint: `${counts.publishedTeachingTasks} 个已发布`,
      route: '/teaching-tasks',
    },
    {
      key: 'schedules',
      label: '已进入课表',
      value: formatNumber(counts.scheduledTeachingTasks),
      hint: `覆盖 ${ratio(counts.scheduledTeachingTasks, counts.publishedTeachingTasks)}% 已发布教学班`,
      route: hasRole('SuperAdmin', 'AcademicAdmin') ? '/schedules' : '/class-timetable',
    },
    {
      key: 'enrollments',
      label: '有效选课',
      value: formatNumber(counts.courseEnrollments),
      hint: counts.openCourseSelectionRounds > 0
        ? `${counts.openCourseSelectionRounds} 个选课批次开放中`
        : '当前无开放选课批次',
      route: '/course-selections',
    },
  ]
})

const quickActions = computed<DashboardLink[]>(() => {
  if (hasRole('SuperAdmin')) {
    return [
      { key: 'organization', label: '组织与学期', description: '维护基础数据', route: '/base-data/organization', icon: School },
      { key: 'personnel', label: '人员档案', description: '教师与学生', route: '/teachers', icon: UserFilled },
      { key: 'tasks', label: '教学任务', description: '生成并发布教学班', route: '/teaching-tasks', icon: List },
      { key: 'schedules', label: '排课与课表', description: '排课、校验与发布', route: '/schedules', icon: Calendar },
      { key: 'approvals', label: '审批中心', description: '集中处理业务申请', route: '/approvals', icon: DocumentChecked },
      { key: 'statistics', label: '统计报表', description: '观察教学质量', route: '/statistics', icon: DataAnalysis },
      { key: 'operations', label: '运维与审计', description: '任务、日志与系统状态', route: '/operations', icon: Operation },
    ]
  }
  if (hasRole('AcademicAdmin')) {
    return [
      { key: 'terms', label: '学年学期', description: '维护教学日历', route: '/base-data/terms', icon: Calendar },
      { key: 'tasks', label: '教学任务', description: '统筹全校开课', route: '/teaching-tasks', icon: List },
      { key: 'schedules', label: '排课与课表', description: '排课、校验与发布', route: '/schedules', icon: Management },
      { key: 'selections', label: '选课管理', description: '批次与选课名单', route: '/course-selections', icon: Tickets },
      { key: 'grades', label: '成绩管理', description: '审核并发布成绩', route: '/grades', icon: Checked },
      { key: 'exams', label: '考试管理', description: '考试与考场安排', route: '/exams', icon: EditPen },
      { key: 'approvals', label: '审批中心', description: '处理校级审核', route: '/approvals', icon: DocumentChecked },
      { key: 'statistics', label: '统计报表', description: '跨学院教学分析', route: '/statistics', icon: DataAnalysis },
    ]
  }
  if (hasRole('CollegeAdmin')) {
    return [
      { key: 'personnel', label: '学院人员', description: '教师与学生档案', route: '/teachers', icon: UserFilled },
      { key: 'qualifications', label: '授课资格', description: '审核教师申报', route: '/teaching-preferences', icon: Checked },
      { key: 'curriculum', label: '培养方案', description: '维护专业课程结构', route: '/curriculum', icon: Reading },
      { key: 'tasks', label: '教学任务', description: '落实本学院开课', route: '/teaching-tasks', icon: List },
      { key: 'selections', label: '选课管理', description: '查看选课与名单', route: '/course-selections', icon: Tickets },
      { key: 'grades', label: '成绩管理', description: '审核课程成绩', route: '/grades', icon: EditPen },
      { key: 'rooms', label: '教室借用', description: '审核学院申请', route: '/classroom-reservations', icon: OfficeBuilding },
      { key: 'approvals', label: '审批中心', description: '处理学院级审核', route: '/approvals', icon: DocumentChecked },
    ]
  }
  if (hasRole('Leader')) {
    return [
      { key: 'statistics', label: '统计报表', description: '查看教学运行数据', route: '/statistics', icon: DataAnalysis },
      { key: 'timetable', label: '课表查询', description: '查看全校课表', route: '/class-timetable', icon: Calendar },
      { key: 'evaluations', label: '教学评价', description: '查看评价结果', route: '/evaluations', icon: Checked },
    ]
  }
  if (hasRole('Counselor')) {
    return [
      { key: 'students', label: '学生档案', description: '查看所带学生', route: '/students', icon: UserFilled },
      { key: 'attendance', label: '教学点名', description: '查看班级考勤', route: '/teacher-attendance', icon: Checked },
      { key: 'approvals', label: '审批中心', description: '处理学生申请', route: '/approvals', icon: DocumentChecked },
      { key: 'warnings', label: '学业预警', description: '跟进风险学生', route: '/warnings', icon: Warning },
    ]
  }
  return [
    { key: 'timetable', label: '我的课表', description: '查看近期授课', route: '/my-timetable', icon: Calendar },
    { key: 'roster', label: '选课名单', description: '查看课程学生', route: '/teacher-roster', icon: UserFilled },
    { key: 'grades', label: '成绩录入', description: '维护课程成绩', route: '/grades', icon: EditPen },
    { key: 'adjustments', label: '调停课', description: '提交教学调整', route: '/course-adjustments', icon: Operation },
  ]
})

const readiness = computed(() => {
  const counts = data.value?.counts
  if (!counts) return []
  return [
    {
      key: 'tasks',
      label: '教学任务发布',
      value: counts.publishedTeachingTasks,
      total: counts.teachingTasks,
      percent: ratio(counts.publishedTeachingTasks, counts.teachingTasks),
      route: '/teaching-tasks',
      note: counts.teachingTasks === 0
        ? '本学期尚未建立教学任务'
        : `${counts.teachingTasks - counts.publishedTeachingTasks} 个任务尚未发布`,
    },
    {
      key: 'schedules',
      label: '课表覆盖',
      value: counts.scheduledTeachingTasks,
      total: counts.publishedTeachingTasks,
      percent: ratio(counts.scheduledTeachingTasks, counts.publishedTeachingTasks),
      route: hasRole('SuperAdmin', 'AcademicAdmin') ? '/schedules' : '/class-timetable',
      note: counts.publishedTeachingTasks === 0
        ? '发布教学任务后可安排课表'
        : `${Math.max(0, counts.publishedTeachingTasks - counts.scheduledTeachingTasks)} 个已发布教学班尚未进入课表`,
    },
    {
      key: 'grades',
      label: '成绩发布',
      value: counts.publishedGradeSheets,
      total: counts.gradeSheets,
      percent: ratio(counts.publishedGradeSheets, counts.gradeSheets),
      route: '/grades',
      note: counts.submittedGradeSheets > 0
        ? `${counts.submittedGradeSheets} 张成绩登记册等待审核`
        : counts.gradeSheets === 0
          ? '本学期尚未生成成绩登记册'
          : '当前没有待审核成绩',
    },
  ]
})

const primaryActionRoute = computed(() =>
  todoItems.value[0]?.route ?? quickActions.value[0]?.route ?? '/notifications',
)

async function loadDashboard() {
  loading.value = true
  loadError.value = ''
  try {
    data.value = (await http.get<DashboardData>('/dashboard')).data
    if (isCounselorDashboard.value) {
      counselorWarnings.value = (await http.get<WarningRecord[]>('/warnings/records', {
        params: { academicTermId: data.value.currentTerm?.id },
      })).data
    }
  } catch {
    loadError.value = '教务总览暂时无法加载，请检查服务连接后重试。'
  } finally {
    loading.value = false
  }
}

onMounted(async () => {
  if (isStudentOverview.value || isTeacherOverview.value) {
    loading.value = false
    return
  }
  await loadDashboard()
})
</script>

<template>
  <StudentDashboardView v-if="isStudentOverview" />
  <TeacherDashboardView v-else-if="isTeacherOverview" />

  <div v-else v-loading="loading" class="admin-dashboard">
    <el-result
      v-if="loadError"
      icon="warning"
      title="教务总览加载失败"
      :sub-title="loadError"
    >
      <template #extra>
        <el-button type="primary" @click="loadDashboard">重新加载</el-button>
      </template>
    </el-result>

    <template v-else-if="data">
      <section class="overview-hero">
        <div class="overview-heading">
          <div class="scope-line">
            <span>{{ data.audience.scopeName }}</span>
            <i>数据范围</i>
          </div>
          <p class="overview-eyebrow">ACADEMIC OPERATIONS</p>
          <h1>{{ data.greeting.title }}</h1>
          <p class="overview-description">{{ data.greeting.subtitle }}</p>
        </div>

        <button class="pending-brief" type="button" @click="router.push(primaryActionRoute)">
          <span>当前待处理</span>
          <strong>{{ pendingTotal }}</strong>
          <small>{{ pendingTotal > 0 ? '项工作需要跟进' : '暂无积压事项' }}</small>
          <b>{{ pendingTotal > 0 ? '立即处理' : '进入工作区' }} →</b>
        </button>

        <div v-if="data.currentTerm" class="term-ruler">
          <div class="term-ruler-head">
            <div>
              <span>当前学期</span>
              <strong>{{ data.currentTerm.name }}</strong>
            </div>
            <b>{{ termContext }}</b>
          </div>
          <div class="term-track" :style="{ '--term-progress': `${termProgress}%` }">
            <span class="term-track-fill" />
            <i class="term-track-marker" />
          </div>
          <div class="term-dates">
            <span>{{ formatDate(data.currentTerm.startDate) }} 开学</span>
            <span>学期进度 {{ termProgress }}%</span>
            <span>{{ formatDate(data.currentTerm.endDate) }} 结束</span>
          </div>
        </div>

        <div v-else class="term-ruler term-ruler-empty">
          <div>
            <span>当前学期</span>
            <strong>尚未设置</strong>
          </div>
          <button
            v-if="hasRole('SuperAdmin', 'AcademicAdmin')"
            type="button"
            @click="router.push('/base-data/terms')"
          >
            去维护学期 →
          </button>
          <p v-else>请联系校级教务管理员维护当前学期。</p>
        </div>
      </section>

      <section class="greeting-insights" :aria-label="data.greeting.label">
        <span class="greeting-insights-label">{{ data.greeting.label }}</span>
        <div>
          <article
            v-for="insight in data.greeting.insights"
            :key="insight.label"
            :class="`greeting-insight ${insight.tone}`"
          >
            <span>{{ insight.label }}</span>
            <strong>{{ insight.value }}</strong>
            <small>{{ insight.hint }}</small>
          </article>
        </div>
      </section>

      <p class="greeting-narrative">{{ data.greeting.narrative }}</p>

      <section class="overview-metrics" aria-label="关键教学数据">
        <button
          v-for="metric in adminMetrics"
          :key="metric.key"
          type="button"
          @click="router.push(metric.route)"
        >
          <span>{{ metric.label }}</span>
          <strong>{{ metric.value }}</strong>
          <small>{{ metric.hint }}</small>
          <i>查看详情 →</i>
        </button>
      </section>

      <section class="dashboard-work-grid">
        <article v-if="isCounselorDashboard" class="dashboard-panel counselor-radar">
          <header class="panel-heading">
            <div>
              <span class="panel-index">RADAR / COUNSELOR</span>
              <h2>需重点关注的学生</h2>
              <p>{{ activeCounselorWarnings.length ? `当前有 ${activeCounselorWarnings.length} 条生效预警，按最新记录展示。` : '当前没有生效中的学业预警。' }}</p>
            </div>
            <button type="button" class="radar-link" @click="router.push('/warnings')">完整预警 →</button>
          </header>
          <div v-if="activeCounselorWarnings.length" class="counselor-risk-list">
            <button v-for="warning in activeCounselorWarnings.slice(0, 4)" :key="warning.id" type="button" @click="router.push('/warnings')">
              <span>{{ warning.className }}</span>
              <b>{{ warning.studentName }}</b>
              <small>{{ warning.detail }}</small>
              <i>查看 →</i>
            </button>
          </div>
          <div v-else class="todo-empty">
            <el-icon><Checked /></el-icon>
            <div><b>当前没有重点关注学生</b><span>新的学业预警会自动出现在这里。</span></div>
          </div>
        </article>

        <article class="dashboard-panel todo-panel">
          <header class="panel-heading">
            <div>
              <span class="panel-index">01 / ACTION</span>
              <h2>需要处理</h2>
              <p>只显示当前角色和数据范围内可处理的事项。</p>
            </div>
            <span v-if="pendingTotal > 0" class="pending-badge">{{ pendingTotal }} 项</span>
          </header>

          <div v-if="todoItems.length" class="todo-list">
            <button
              v-for="(item, index) in todoItems"
              :key="item.key"
              type="button"
              @click="router.push(item.route)"
            >
              <span class="todo-order">{{ String(index + 1).padStart(2, '0') }}</span>
              <span class="todo-copy">
                <b>{{ item.label }}</b>
                <small>{{ item.description }}</small>
              </span>
              <strong>{{ item.count }}</strong>
              <i>→</i>
            </button>
          </div>

          <div v-else class="todo-empty">
            <el-icon><Checked /></el-icon>
            <div>
              <b>当前没有待处理事项</b>
              <span>新的审核任务到达后会在这里集中显示。</span>
            </div>
          </div>
        </article>

        <article class="dashboard-panel quick-panel">
          <header class="panel-heading">
            <div>
              <span class="panel-index">02 / SHORTCUTS</span>
              <h2>常用工作</h2>
              <p>按当前角色整理的高频业务入口。</p>
            </div>
          </header>

          <div class="quick-grid">
            <button
              v-for="action in quickActions"
              :key="action.key"
              type="button"
              @click="router.push(action.route)"
            >
              <el-icon><component :is="action.icon" /></el-icon>
              <span>
                <b>{{ action.label }}</b>
                <small>{{ action.description }}</small>
              </span>
              <i>↗</i>
            </button>
          </div>
        </article>
      </section>

      <section class="dashboard-panel readiness-panel">
        <header class="panel-heading">
          <div>
            <span class="panel-index">03 / TERM READINESS</span>
            <h2>本学期运行状态</h2>
            <p>从任务发布到课表落地、成绩归档，快速发现业务断点。</p>
          </div>
          <span class="refresh-time">数据更新于 {{ new Date(data.generatedAt).toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }) }}</span>
        </header>

        <div class="readiness-list">
          <button
            v-for="item in readiness"
            :key="item.key"
            type="button"
            @click="router.push(item.route)"
          >
            <span class="readiness-label">{{ item.label }}</span>
            <span class="readiness-bar">
              <i :style="{ width: `${item.percent}%` }" />
            </span>
            <strong>{{ item.percent }}%</strong>
            <small>{{ item.value }} / {{ item.total }}</small>
            <em>{{ item.note }}</em>
            <b>查看 →</b>
          </button>
        </div>

        <footer class="scope-summary">
          <span><b>{{ formatNumber(data.counts.teachers) }}</b> 名在岗教师</span>
          <span><b>{{ formatNumber(data.counts.courses) }}</b> 门启用课程</span>
          <span><b>{{ formatNumber(data.counts.courseEnrollments) }}</b> 条有效选课</span>
          <span>
            <b>{{ data.counts.openCourseSelectionRounds }}</b>
            个选课批次开放中
          </span>
        </footer>
      </section>
    </template>
  </div>
</template>

<style scoped>
.admin-dashboard {
  --dashboard-navy: #17284f;
  --dashboard-blue: #274683;
  --dashboard-teal: #0b8175;
  --dashboard-cyan: #58c5b7;
  --dashboard-amber: #d09439;
  --dashboard-paper: #fff;
  display: grid;
  gap: 18px;
  min-height: 420px;
}

.overview-hero {
  position: relative;
  min-height: 300px;
  padding: 34px 36px 28px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 210px;
  grid-template-rows: 1fr auto;
  gap: 24px 34px;
  overflow: hidden;
  color: #fff;
  background:
    linear-gradient(90deg, rgba(255, 255, 255, .035) 1px, transparent 1px),
    linear-gradient(180deg, rgba(255, 255, 255, .035) 1px, transparent 1px),
    linear-gradient(120deg, #17284f 0%, #213a73 64%, #0b706c 125%);
  background-size: 32px 32px, 32px 32px, auto;
}

.greeting-insights {
  display: grid;
  grid-template-columns: 120px minmax(0, 1fr);
  gap: 18px;
  align-items: stretch;
  padding: 17px 21px;
  border: 1px solid #dce6eb;
  background: #f7faf9;
}

.greeting-insights-label {
  align-self: center;
  color: var(--dashboard-teal);
  font: 700 10px/1.5 Consolas, monospace;
  letter-spacing: .12em;
}

.greeting-insights > div {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.greeting-insight {
  min-width: 0;
  padding-left: 13px;
  display: grid;
  gap: 3px;
  border-left: 2px solid #a9bcc6;
}

.greeting-insight.positive { border-color: var(--dashboard-teal); }
.greeting-insight.attention { border-color: var(--dashboard-amber); }
.greeting-insight span { color: #687788; font-size: 11px; }
.greeting-insight strong { color: var(--dashboard-navy); font-size: 20px; }
.greeting-insight small { overflow: hidden; color: #84909d; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }

.greeting-narrative {
  margin: -7px 0 0;
  padding: 0 3px;
  color: #526078;
  font-size: 12px;
  line-height: 1.7;
}

.overview-hero::after {
  content: "";
  position: absolute;
  right: 180px;
  top: -215px;
  width: 410px;
  height: 410px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 50%;
  box-shadow:
    0 0 0 58px rgba(255, 255, 255, .025),
    0 0 0 118px rgba(255, 255, 255, .018);
  pointer-events: none;
}

.overview-heading,
.pending-brief,
.term-ruler {
  position: relative;
  z-index: 1;
}

.scope-line {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 6px 9px 6px 10px;
  border-left: 2px solid var(--dashboard-cyan);
  background: rgba(255, 255, 255, .07);
}

.scope-line span {
  font-size: 12px;
  font-weight: 700;
}

.scope-line i {
  color: #aab8d8;
  font-size: 9px;
  font-style: normal;
  letter-spacing: .08em;
}

.overview-eyebrow,
.panel-index {
  margin: 22px 0 0;
  color: #73d0c4;
  font: 700 9px/1.2 Consolas, monospace;
  letter-spacing: .18em;
}

.overview-heading h1 {
  margin: 8px 0 7px;
  font-family: "STZhongsong", "Songti SC", serif;
  font-size: clamp(28px, 3.2vw, 42px);
  font-weight: 700;
  letter-spacing: .06em;
}

.overview-description {
  margin: 0;
  color: #c2cce5;
  font-size: 13px;
}

.pending-brief {
  align-self: stretch;
  padding: 21px 20px 18px;
  display: grid;
  align-content: center;
  text-align: left;
  border: 1px solid rgba(255, 255, 255, .25);
  color: #fff;
  background: rgba(255, 255, 255, .08);
  transition: background .18s ease, transform .18s ease;
}

.pending-brief:hover {
  background: rgba(255, 255, 255, .14);
  transform: translateY(-2px);
}

.pending-brief span {
  color: #c6d0e8;
  font-size: 11px;
}

.pending-brief strong {
  margin-top: 4px;
  font: 700 48px/1 Consolas, monospace;
}

.pending-brief small {
  margin-top: 7px;
  color: #c6d0e8;
  font-size: 11px;
}

.pending-brief b {
  margin-top: 22px;
  color: #75d8ca;
  font-size: 11px;
}

.term-ruler {
  grid-column: 1 / -1;
  padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .16);
}

.term-ruler-head {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 20px;
}

.term-ruler-head div {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.term-ruler-head span,
.term-ruler-head b {
  color: #aebbd9;
  font-size: 10px;
  font-weight: 500;
}

.term-ruler-head strong {
  font-size: 14px;
}

.term-track {
  position: relative;
  height: 4px;
  margin-top: 13px;
  background: rgba(255, 255, 255, .17);
}

.term-track::before,
.term-track::after {
  content: "";
  position: absolute;
  top: -3px;
  width: 1px;
  height: 10px;
  background: rgba(255, 255, 255, .55);
}

.term-track::before { left: 0; }
.term-track::after { right: 0; }

.term-track-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--term-progress);
  background: linear-gradient(90deg, #47bbaa, #77dbcc);
}

.term-track-marker {
  position: absolute;
  left: var(--term-progress);
  top: 50%;
  width: 10px;
  height: 10px;
  border: 2px solid #fff;
  border-radius: 50%;
  background: var(--dashboard-amber);
  box-shadow: 0 0 0 4px rgba(208, 148, 57, .2);
  transform: translate(-50%, -50%);
}

.term-dates {
  margin-top: 8px;
  display: flex;
  justify-content: space-between;
  color: #98a8cb;
  font-size: 9px;
}

.term-ruler-empty {
  display: flex;
  align-items: center;
  gap: 16px;
}

.term-ruler-empty span,
.term-ruler-empty strong {
  display: block;
}

.term-ruler-empty strong { margin-top: 4px; }

.term-ruler-empty button {
  margin-left: auto;
  padding: 9px 12px;
  border: 1px solid rgba(255, 255, 255, .25);
  color: #fff;
  background: rgba(255, 255, 255, .08);
}

.term-ruler-empty p {
  margin: 0 0 0 auto;
  color: #b8c4df;
  font-size: 12px;
}

.overview-metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border: 1px solid #dce2ea;
  background: var(--dashboard-paper);
}

.overview-metrics button {
  position: relative;
  min-width: 0;
  min-height: 122px;
  padding: 22px 23px 19px;
  display: grid;
  text-align: left;
  border: none;
  border-right: 1px solid #e4e8ee;
  color: #182033;
  background: transparent;
  transition: background .16s ease;
}

.overview-metrics button:last-child { border-right: none; }
.overview-metrics button:hover { background: #f7fafb; }

.overview-metrics span {
  color: #6d7689;
  font-size: 11px;
}

.overview-metrics strong {
  margin-top: 6px;
  font: 700 30px/1 Consolas, monospace;
}

.overview-metrics small {
  margin-top: 8px;
  overflow: hidden;
  color: #727c8e;
  font-size: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.overview-metrics i {
  position: absolute;
  top: 22px;
  right: 20px;
  color: var(--dashboard-teal);
  font-size: 9px;
  font-style: normal;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity .16s ease, transform .16s ease;
}

.overview-metrics button:hover i {
  opacity: 1;
  transform: none;
}

.dashboard-work-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.16fr) minmax(400px, .84fr);
  gap: 18px;
}

.dashboard-panel {
  border: 1px solid #dce2ea;
  background: var(--dashboard-paper);
}

.counselor-radar { border-top: 3px solid var(--dashboard-amber); }
.radar-link { padding: 5px 0; border: 0; color: #806136; background: transparent; font-size: 12px; white-space: nowrap; }
.radar-link:hover { color: var(--dashboard-blue); }
.counselor-risk-list { display: grid; }
.counselor-risk-list button {
  padding: 13px 0;
  display: grid;
  grid-template-columns: 76px 68px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  text-align: left;
  border: 0;
  border-bottom: 1px solid #eee8dc;
  background: transparent;
}
.counselor-risk-list button:last-child { border-bottom: 0; }
.counselor-risk-list button:hover b { color: var(--dashboard-blue); }
.counselor-risk-list span { color: #987337; font: 700 9px/1.3 Consolas, monospace; letter-spacing: .04em; }
.counselor-risk-list b { color: #3a4758; font-size: 13px; }
.counselor-risk-list small { overflow: hidden; color: #6c7788; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.counselor-risk-list i { color: #8d7042; font-size: 11px; font-style: normal; white-space: nowrap; }

.todo-panel,
.quick-panel,
.readiness-panel {
  padding: 26px 28px;
}

.panel-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
}

.panel-index {
  display: block;
  margin: 0;
  color: var(--dashboard-teal);
}

.panel-heading h2 {
  margin: 7px 0 5px;
  font-family: "STZhongsong", "Songti SC", serif;
  font-size: 20px;
  letter-spacing: .04em;
}

.panel-heading p {
  margin: 0;
  color: #7a8394;
  font-size: 11px;
}

.pending-badge {
  padding: 5px 9px;
  border-radius: 20px;
  color: #9b5c06;
  background: #fff2dc;
  font-size: 10px;
  font-weight: 700;
}

.todo-list {
  margin-top: 20px;
  border-top: 1px solid #e7eaf0;
}

.todo-list button {
  width: 100%;
  min-height: 68px;
  padding: 12px 4px;
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) auto 18px;
  gap: 12px;
  align-items: center;
  text-align: left;
  border: none;
  border-bottom: 1px solid #e7eaf0;
  color: #1d2638;
  background: transparent;
}

.todo-list button:hover .todo-copy b { color: var(--dashboard-blue); }
.todo-list button:hover > i { transform: translateX(3px); }

.todo-order {
  color: #a2a9b5;
  font: 500 10px/1 Consolas, monospace;
}

.todo-copy {
  min-width: 0;
  display: grid;
  gap: 4px;
}

.todo-copy b { font-size: 13px; }

.todo-copy small {
  overflow: hidden;
  color: #7a8394;
  font-size: 10px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.todo-list button > strong {
  min-width: 28px;
  text-align: right;
  color: #a46408;
  font: 700 20px/1 Consolas, monospace;
}

.todo-list button > i {
  color: var(--dashboard-teal);
  font-style: normal;
  transition: transform .16s ease;
}

.todo-empty {
  min-height: 228px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  color: #617083;
}

.todo-empty .el-icon {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  color: var(--dashboard-teal);
  background: #eaf6f3;
  font-size: 20px;
}

.todo-empty b,
.todo-empty span {
  display: block;
}

.todo-empty b { font-size: 13px; }

.todo-empty span {
  margin-top: 5px;
  color: #8991a0;
  font-size: 10px;
}

.quick-grid {
  margin-top: 20px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  border-top: 1px solid #e7eaf0;
  border-left: 1px solid #e7eaf0;
}

.quick-grid button {
  min-height: 78px;
  padding: 13px;
  display: grid;
  grid-template-columns: 31px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  text-align: left;
  border: none;
  border-right: 1px solid #e7eaf0;
  border-bottom: 1px solid #e7eaf0;
  color: #1d2638;
  background: #fbfcfd;
}

.quick-grid button:hover { background: #f2f8f7; }

.quick-grid .el-icon {
  width: 31px;
  height: 31px;
  color: var(--dashboard-blue);
  background: #edf1f8;
  font-size: 15px;
}

.quick-grid span {
  min-width: 0;
  display: grid;
  gap: 4px;
}

.quick-grid b { font-size: 12px; }

.quick-grid small {
  overflow: hidden;
  color: #7c8594;
  font-size: 9px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.quick-grid i {
  align-self: start;
  color: #a8aeba;
  font-size: 10px;
  font-style: normal;
}

.readiness-panel {
  padding-bottom: 0;
}

.refresh-time {
  color: #939aa7;
  font-size: 9px;
}

.readiness-list {
  margin-top: 23px;
  border-top: 1px solid #e7eaf0;
}

.readiness-list button {
  width: 100%;
  min-height: 68px;
  padding: 14px 0;
  display: grid;
  grid-template-columns: 112px minmax(140px, 1fr) 46px 58px minmax(180px, .8fr) 54px;
  gap: 14px;
  align-items: center;
  text-align: left;
  border: none;
  border-bottom: 1px solid #e7eaf0;
  color: #20293a;
  background: transparent;
}

.readiness-list button:hover {
  background: linear-gradient(90deg, transparent, #f7fafb 9%, #f7fafb 91%, transparent);
}

.readiness-label { font-size: 12px; font-weight: 700; }

.readiness-bar {
  height: 6px;
  overflow: hidden;
  background: #e8edf1;
}

.readiness-bar i {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--dashboard-blue), var(--dashboard-teal));
}

.readiness-list strong {
  text-align: right;
  font: 700 14px/1 Consolas, monospace;
}

.readiness-list small {
  color: #7d8593;
  font: 500 10px/1 Consolas, monospace;
}

.readiness-list em {
  overflow: hidden;
  color: #6f7888;
  font-size: 10px;
  font-style: normal;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.readiness-list button > b {
  text-align: right;
  color: var(--dashboard-teal);
  font-size: 10px;
}

.scope-summary {
  margin: 0 -28px;
  min-height: 59px;
  padding: 14px 28px;
  display: flex;
  align-items: center;
  gap: 0;
  color: #778090;
  background: #f7f9fb;
  font-size: 10px;
}

.scope-summary span {
  padding: 0 20px;
  border-right: 1px solid #dfe4ea;
}

.scope-summary span:first-child { padding-left: 0; }
.scope-summary span:last-child { border-right: none; }

.scope-summary b {
  margin-right: 4px;
  color: #28344b;
  font: 700 13px/1 Consolas, monospace;
}

button:focus-visible {
  outline: 2px solid #2d8f85;
  outline-offset: 2px;
}

@media (max-width: 1100px) {
  .greeting-insights { grid-template-columns: 1fr; gap: 12px; }
  .dashboard-work-grid {
    grid-template-columns: 1fr;
  }

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

  .readiness-list button {
    grid-template-columns: 105px minmax(120px, 1fr) 44px 54px minmax(130px, .7fr) 48px;
    gap: 10px;
  }
}

@media (max-width: 760px) {
  .greeting-insights { padding: 15px; }
  .greeting-insights > div { grid-template-columns: 1fr; }
  .counselor-risk-list button { grid-template-columns: 1fr auto; }
  .counselor-risk-list span { grid-column: 1 / -1; }
  .counselor-risk-list small { white-space: normal; }
  .admin-dashboard { gap: 10px; }

  .overview-hero {
    min-height: 0;
    padding: 24px 20px 21px;
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    gap: 20px;
  }

  .overview-hero::after {
    right: -210px;
  }

  .overview-heading h1 {
    font-size: 28px;
  }

  .pending-brief {
    min-height: 108px;
    grid-template-columns: 1fr auto;
    align-items: center;
  }

  .pending-brief strong {
    grid-row: 1 / 4;
    grid-column: 2;
    font-size: 42px;
  }

  .pending-brief b { margin-top: 10px; }

  .term-ruler { grid-column: 1; }

  .term-ruler-head {
    align-items: flex-start;
  }

  .term-ruler-head div {
    display: grid;
    gap: 4px;
  }

  .term-dates span:nth-child(2) { display: none; }

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

  .overview-metrics button {
    min-height: 105px;
    padding: 18px;
  }

  .overview-metrics button:nth-child(2) { border-right: none; }
  .overview-metrics button:nth-child(-n + 2) { border-bottom: 1px solid #e4e8ee; }

  .todo-panel,
  .quick-panel,
  .readiness-panel {
    padding: 21px 18px;
  }

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

  .readiness-list button {
    grid-template-columns: 1fr auto auto;
    gap: 8px 12px;
  }

  .readiness-label { grid-column: 1; }
  .readiness-list strong { grid-column: 2; }
  .readiness-list small { grid-column: 3; }
  .readiness-bar { grid-column: 1 / -1; grid-row: 2; }
  .readiness-list em { grid-column: 1 / 3; grid-row: 3; }
  .readiness-list button > b { grid-column: 3; grid-row: 3; }

  .scope-summary {
    margin: 0 -18px;
    padding: 13px 18px;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 9px;
  }

  .scope-summary span {
    padding: 0;
    border-right: none;
  }

  .refresh-time { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .pending-brief,
  .todo-list button > i,
  .overview-metrics i {
    transition: none;
  }
}
</style>
