<template>
  <div class="permission-monitoring" :class="{ 'is-source-tab': activeTab === 'ip-locations' }">
    <el-tabs v-model="activeTab" class="soybean-monitoring-tabs" @tab-change="onTabChange">
      <el-tab-pane label="运行概览" name="overview">
        <template #label>
          <span class="soybean-tab-label">
            <component :is="IconCheck" />
            <span>运行概览</span>
          </span>
        </template>
        <div v-if="statsSummary" class="stats-summary">
          <div v-for="card in summaryCards" :key="card.label" class="summary-card" :class="card.tone">
            <div class="summary-icon">
              <component :is="card.icon" />
            </div>
            <div class="summary-body">
              <span class="summary-label">{{ card.label }}</span>
              <strong class="summary-value">{{ card.value }}</strong>
            </div>
          </div>
        </div>

        <div class="overview-grid">
          <div v-if="health" class="health-card">
            <div class="health-header">
              <h3>系统健康状态</h3>
              <el-tag :type="getHealthType(health.status)" effect="dark" round>
                {{ getHealthLabel(health.status) }}
              </el-tag>
            </div>
            <div class="health-score-ring">
              <el-progress
                type="dashboard"
                :percentage="health.health_score"
                :color="getScoreColor(health.health_score)"
                :width="140"
                :stroke-width="10"
              >
                <template #default>
                  <div class="score-inner">
                    <strong>{{ health.health_score }}</strong>
                    <span>健康分</span>
                  </div>
                </template>
              </el-progress>
            </div>
            <div class="score-breakdown">
              <span v-for="item in healthScoreItems" :key="item.label">
                {{ item.label }} {{ item.deduction ? `-${item.deduction}` : "正常" }}
              </span>
            </div>
            <div v-if="!health.sample_sufficient" class="sample-warning">
              近 1 小时仅 {{ health.last_hour.total_checks }} 次检查，样本不足，当前评分仅供参考
            </div>
            <div v-if="health.issues.length > 0" class="health-issues">
              <div v-for="(issue, index) in health.issues" :key="index" class="issue-item">
                <span class="issue-dot" />
                <span>{{ issue }}</span>
              </div>
            </div>
            <div v-else-if="health.sample_sufficient" class="health-ok">
              <span class="ok-icon">&#10003;</span>
              <span>系统运行正常，未发现问题</span>
            </div>
          </div>

          <div v-if="metrics" class="cache-card">
            <div class="cache-title">
              <h3>缓存效率</h3>
              <span>近 1 小时</span>
            </div>
            <div class="cache-stats">
              <div class="cache-stat primary">
                <div class="cache-stat-header">
                  <span class="stat-label">
                    综合命中率（{{ metrics.cache_metrics.cache_hits }}/{{ metrics.cache_metrics.total_accesses }}）
                  </span>
                  <strong class="stat-value" :style="{ color: getProgressColor(metrics.cache_metrics.hit_rate) }">
                    {{ metrics.cache_metrics.hit_rate.toFixed(1) }}%
                  </strong>
                </div>
                <el-progress
                  :percentage="metrics.cache_metrics.hit_rate"
                  :color="getProgressColor(metrics.cache_metrics.hit_rate)"
                  :stroke-width="8"
                  :show-text="false"
                />
              </div>
              <div class="cache-scope-details">
                <span>
                  项目权限
                  {{ metrics.cache_metrics.by_cache.project_permissions.hit_rate.toFixed(1) }}%
                  （{{ metrics.cache_metrics.by_cache.project_permissions.cache_hits }}/{{
                    metrics.cache_metrics.by_cache.project_permissions.total_accesses
                  }}）
                </span>
                <span>
                  成员角色
                  {{ metrics.cache_metrics.by_cache.member_roles.hit_rate.toFixed(1) }}%
                  （{{ metrics.cache_metrics.by_cache.member_roles.cache_hits }}/{{
                    metrics.cache_metrics.by_cache.member_roles.total_accesses
                  }}）
                </span>
              </div>
              <div class="cache-stat-row">
                <div class="cache-stat-mini">
                  <span class="stat-label">缓存项目</span>
                  <strong>{{ health?.cache_stats?.cache_items.total_count || 0 }}</strong>
                </div>
                <div class="cache-stat-mini">
                  <span class="stat-label">失效次数</span>
                  <strong>{{ metrics.cache_metrics.cache_invalidations }}</strong>
                </div>
              </div>
            </div>
          </div>
        </div>

        <div v-if="topDenied && topDenied.length > 0" class="denied-card">
          <div class="card-header">
            <h3>异常拒绝排行</h3>
            <el-tag effect="plain" size="small" type="info">近 7 天</el-tag>
          </div>
          <div class="denied-list">
            <div v-for="(item, index) in topDenied" :key="index" class="denied-row">
              <span class="denied-rank" :class="{ top: index < 3 }">{{ index + 1 }}</span>
              <div class="denied-info">
                <strong>{{ item.endpoint_key }}</strong>
                <small>{{ item.role }}</small>
              </div>
              <span class="denied-count">{{ item.denied_count }}</span>
            </div>
          </div>
        </div>

        <div class="alerts-card">
          <div class="card-header">
            <h3>最近告警</h3>
            <el-tag v-if="alerts && alerts.alerts.length > 0" effect="dark" size="small" type="warning" round>
              {{ alerts.alerts.length }} 条
            </el-tag>
          </div>
          <div v-if="alerts && alerts.alerts.length > 0" class="alerts-list">
            <div v-for="(alert, index) in alerts.alerts" :key="index" class="alert-row" :class="alert.level">
              <div class="alert-level">
                <el-tag :type="getAlertType(alert.level)" size="small" effect="dark" round>{{ alert.level }}</el-tag>
              </div>
              <div class="alert-body">
                <strong>{{ alert.type }}</strong>
                <span>{{ alert.message }}</span>
              </div>
              <span class="alert-time">{{ formatTime(alert.timestamp) }}</span>
            </div>
          </div>
          <el-empty v-else description="暂无告警，系统运行正常" :image-size="60" />
        </div>
      </el-tab-pane>

      <el-tab-pane label="性能趋势" name="trends">
        <template #label>
          <span class="soybean-tab-label">
            <component :is="IconActivity" />
            <span>性能趋势</span>
          </span>
        </template>
        <PermissionTrendCharts ref="trendChartsRef" />
      </el-tab-pane>

      <el-tab-pane v-if="props.isAdmin" label="安全中心" name="security">
        <template #label>
          <span class="soybean-tab-label">
            <component :is="IconShield" />
            <span>安全中心</span>
          </span>
        </template>
        <SecurityCenter v-if="props.isAdmin" ref="securityCenterRef" />
      </el-tab-pane>

      <el-tab-pane label="访问审计" name="logs">
        <template #label>
          <span class="soybean-tab-label">
            <component :is="IconDatabase" />
            <span>访问审计</span>
          </span>
        </template>
        <PermissionAccessLogs ref="accessLogsRef" :show-security-log="props.isAdmin" />
      </el-tab-pane>

      <el-tab-pane label="来源分析" name="ip-locations">
        <template #label>
          <span class="soybean-tab-label">
            <component :is="IconPercent" />
            <span>来源分析</span>
          </span>
        </template>
        <div class="ip-locations-pane">
          <PermissionIpLocations ref="ipLocationsRef" />
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, h, nextTick, onMounted, onUnmounted } from "vue";
import type {
  PermissionMetricsResponse,
  AlertsResponse,
  HealthResponse,
  TopDeniedItem,
  StatsSummaryResponse,
} from "@/types/api";
import {
  fetchPermissionMetrics,
  fetchPermissionAlerts,
  fetchPermissionHealth,
  fetchTopDenied,
  fetchStatsSummary,
} from "@/api/projectPermissions";
import PermissionTrendCharts from "./PermissionTrendCharts.vue";
import PermissionAccessLogs from "./PermissionAccessLogs.vue";
import PermissionIpLocations from "./PermissionIpLocations.vue";
import SecurityCenter from "./SecurityCenter.vue";

const IconCheck = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("polyline", { points: "20 6 9 17 4 12" }),
]);
const IconActivity = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" }),
]);
const IconPercent = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("line", { x1: "19", y1: "5", x2: "5", y2: "19" }),
  h("circle", { cx: "6.5", cy: "6.5", r: "2.5" }),
  h("circle", { cx: "17.5", cy: "17.5", r: "2.5" }),
]);
const IconClock = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("circle", { cx: "12", cy: "12", r: "10" }),
  h("polyline", { points: "12 6 12 12 16 14" }),
]);
const IconDatabase = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("ellipse", { cx: "12", cy: "5", rx: "9", ry: "3" }),
  h("path", { d: "M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" }),
  h("path", { d: "M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" }),
]);
const IconShield = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }),
]);

const activeTab = ref("overview");
const props = withDefaults(defineProps<{ isAdmin?: boolean }>(), {
  isAdmin: false,
});
const metrics = ref<PermissionMetricsResponse | null>(null);
const health = ref<HealthResponse | null>(null);
const alerts = ref<AlertsResponse | null>(null);
const topDenied = ref<TopDeniedItem[]>([]);
const statsSummary = ref<StatsSummaryResponse | null>(null);

const trendChartsRef = ref<InstanceType<typeof PermissionTrendCharts>>();
const accessLogsRef = ref<InstanceType<typeof PermissionAccessLogs>>();
type IpLocationsExpose = {
  refresh: () => void | Promise<void>;
  resize: () => void | Promise<void>;
};

const ipLocationsRef = ref<IpLocationsExpose>();
const securityCenterRef = ref<InstanceType<typeof SecurityCenter>>();

const formatTime = (timestamp: number): string => {
  return new Date(timestamp * 1000).toLocaleString("zh-CN");
};

const getHealthType = (status: string) => {
  const map: Record<string, string> = { healthy: "success", degraded: "warning", unhealthy: "danger" };
  return map[status] || "info";
};

const getHealthLabel = (status: string) => {
  const map: Record<string, string> = { healthy: "健康", degraded: "降级", unhealthy: "不健康" };
  return map[status] || status;
};

const getAlertType = (level: string) => {
  const map: Record<string, string> = { info: "info", warning: "warning", error: "danger" };
  return map[level] || "info";
};

const getProgressColor = (percentage: number): string => {
  if (percentage >= 80) return "#10b981";
  if (percentage >= 50) return "#f59e0b";
  return "#ef4444";
};

const getScoreColor = (score: number): string => {
  if (score >= 80) return "#10b981";
  if (score >= 60) return "#f59e0b";
  return "#ef4444";
};

const summaryCards = computed(() => {
  if (!statsSummary.value) return [];
  return [
    {
      label: "今日监测事件",
      value: statsSummary.value.today.total_checks.toLocaleString(),
      tone: "blue",
      icon: IconCheck,
    },
    {
      label: "每分钟事件",
      value: statsSummary.value.last_hour.requests_per_minute,
      tone: "cyan",
      icon: IconActivity,
    },
    {
      label: "今日通过率",
      value: `${statsSummary.value.today.allow_rate}%`,
      tone: statsSummary.value.today.allow_rate >= 80 ? "green" : "warning",
      icon: IconPercent,
    },
    {
      label: "平均响应时间",
      value: `${statsSummary.value.today.avg_elapsed_ms}ms`,
      tone: statsSummary.value.today.avg_elapsed_ms > 10 ? "danger" : "indigo",
      icon: IconClock,
    },
    {
      label: "历史事件总数",
      value: statsSummary.value.total_logs.toLocaleString(),
      tone: "violet",
      icon: IconDatabase,
    },
  ];
});

const healthScoreItems = computed(() => {
  if (!health.value) return [];
  return [
    { label: "性能", deduction: health.value.score_breakdown.performance.deduction },
    { label: "拒绝率", deduction: health.value.score_breakdown.deny_rate.deduction },
    { label: "缓存", deduction: health.value.score_breakdown.cache.deduction },
    { label: "告警", deduction: health.value.score_breakdown.alerts.deduction },
  ];
});

const loadOverviewData = async () => {
  const [metricsRes, healthRes, alertsRes, deniedRes, summaryRes] = await Promise.allSettled([
    fetchPermissionMetrics(),
    fetchPermissionHealth(),
    fetchPermissionAlerts(undefined, 20),
    fetchTopDenied({ days: 7, limit: 10 }),
    fetchStatsSummary(),
  ]);
  if (metricsRes.status === "fulfilled") metrics.value = metricsRes.value.data;
  if (healthRes.status === "fulfilled") health.value = healthRes.value.data;
  if (alertsRes.status === "fulfilled") alerts.value = alertsRes.value.data;
  if (deniedRes.status === "fulfilled") topDenied.value = deniedRes.value.data.items;
  if (summaryRes.status === "fulfilled") statsSummary.value = summaryRes.value.data;
};

const onTabChange = async (tab: string) => {
  if (tab === "overview") loadOverviewData();
  if (tab === "ip-locations") {
    await nextTick();
    await ipLocationsRef.value?.resize();
  }
};

const refresh = () => {
  if (activeTab.value === "overview") loadOverviewData();
  else if (activeTab.value === "trends") trendChartsRef.value?.refresh();
  else if (activeTab.value === "security") securityCenterRef.value?.refresh();
  else if (activeTab.value === "logs") accessLogsRef.value?.refresh();
  else if (activeTab.value === "ip-locations") ipLocationsRef.value?.refresh();
};

let overviewRefreshTimer: number | undefined;

onMounted(() => {
  loadOverviewData();
  overviewRefreshTimer = window.setInterval(() => {
    if (activeTab.value === "overview") loadOverviewData();
  }, 60_000);
});

onUnmounted(() => {
  if (overviewRefreshTimer !== undefined) window.clearInterval(overviewRefreshTimer);
});

defineExpose({ refresh });
</script>

<style scoped>
.permission-monitoring {
  --mon-ink: #1a2332;
  --mon-muted: #64748b;
  --mon-border: #e2e8f0;
  --mon-tab-active: #6c63ff;
  --mon-tab-active-bg: #f0edff;
  --mon-radius: 16px;
  --mon-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(0, 0, 0, 0.03);
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  padding: 0;
}

.soybean-monitoring-tabs {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

.soybean-monitoring-tabs :deep(.el-tabs__header) {
  height: 56px;
  margin: 0 0 16px;
  padding: 0 24px;
  background: #ffffff;
  border-top: 1px solid var(--mon-border);
  border-bottom: 1px solid var(--mon-border);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
}

.soybean-monitoring-tabs :deep(.el-tabs__nav-wrap) {
  height: 56px;
}

.soybean-monitoring-tabs :deep(.el-tabs__nav-wrap::after),
.soybean-monitoring-tabs :deep(.el-tabs__active-bar) {
  display: none;
}

.soybean-monitoring-tabs :deep(.el-tabs__nav-scroll),
.soybean-monitoring-tabs :deep(.el-tabs__nav) {
  height: 100%;
}

.soybean-monitoring-tabs :deep(.el-tabs__nav) {
  display: flex;
  align-items: center;
}

.soybean-monitoring-tabs :deep(.el-tabs__item) {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  height: 36px;
  margin: 0 4px;
  padding: 0 18px;
  border-radius: 10px;
  color: #303133;
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  transition: color 0.2s ease, background 0.2s ease;
}

:deep(.soybean-monitoring-tabs.el-tabs--top > .el-tabs__header .el-tabs__item:nth-child(2)) {
  padding-left: 18px;
}

:deep(.soybean-monitoring-tabs.el-tabs--top > .el-tabs__header .el-tabs__item:last-child) {
  padding-right: 18px;
}

.soybean-monitoring-tabs :deep(.el-tabs__item:not(.is-active)::after) {
  content: "";
  position: absolute;
  top: 10px;
  right: -5px;
  width: 1px;
  height: 16px;
  background: #dcdfe6;
}

.soybean-monitoring-tabs :deep(.el-tabs__item:last-child::after),
.soybean-monitoring-tabs :deep(.el-tabs__item.is-active + .el-tabs__item::after) {
  display: none;
}

.soybean-monitoring-tabs :deep(.el-tabs__item:hover) {
  color: var(--mon-tab-active);
}

.soybean-monitoring-tabs :deep(.el-tabs__item.is-active) {
  background: var(--mon-tab-active-bg);
  color: var(--mon-tab-active);
}

.soybean-monitoring-tabs :deep(.el-tabs__content) {
  flex: 1 1 auto;
  min-height: 0;
  padding: 0;
  overflow: auto;
}

.permission-monitoring.is-source-tab .soybean-monitoring-tabs :deep(.el-tabs__content) {
  overflow: hidden;
}

.soybean-monitoring-tabs :deep(.el-tab-pane) {
  min-height: 100%;
}

.soybean-monitoring-tabs :deep(.el-tab-pane[aria-hidden="false"]) {
  height: 100%;
  min-height: 0;
}

.ip-locations-pane {
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

.soybean-tab-label {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  min-width: 0;
  line-height: 1;
}

.soybean-tab-label svg {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

.stats-summary {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 16px;
}

.summary-card {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 18px;
  border-radius: var(--mon-radius);
  background: #fff;
  border: 1px solid var(--mon-border);
  box-shadow: var(--mon-shadow);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.summary-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}

.summary-card::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  border-radius: var(--mon-radius) var(--mon-radius) 0 0;
}

.summary-card.blue::before { background: linear-gradient(90deg, #3b82f6, #60a5fa); }
.summary-card.cyan::before { background: linear-gradient(90deg, #06b6d4, #22d3ee); }
.summary-card.green::before { background: linear-gradient(90deg, #10b981, #34d399); }
.summary-card.warning::before { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
.summary-card.indigo::before { background: linear-gradient(90deg, #6366f1, #818cf8); }
.summary-card.danger::before { background: linear-gradient(90deg, #ef4444, #f87171); }
.summary-card.violet::before { background: linear-gradient(90deg, #8b5cf6, #a78bfa); }

.summary-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  flex-shrink: 0;
}

.summary-icon svg {
  width: 20px;
  height: 20px;
}

.summary-card.blue .summary-icon { background: #eff6ff; color: #3b82f6; }
.summary-card.cyan .summary-icon { background: #ecfeff; color: #06b6d4; }
.summary-card.green .summary-icon { background: #ecfdf5; color: #10b981; }
.summary-card.warning .summary-icon { background: #fffbeb; color: #f59e0b; }
.summary-card.indigo .summary-icon { background: #eef2ff; color: #6366f1; }
.summary-card.danger .summary-icon { background: #fef2f2; color: #ef4444; }
.summary-card.violet .summary-icon { background: #f5f3ff; color: #8b5cf6; }

.summary-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.summary-label {
  color: var(--mon-muted);
  font-size: 12px;
  font-weight: 500;
}

.summary-value {
  color: var(--mon-ink);
  font-size: 22px;
  font-weight: 700;
  line-height: 1.1;
}

.overview-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 16px;
}

.health-card,
.cache-card,
.denied-card,
.alerts-card {
  background: #fff;
  border: 1px solid var(--mon-border);
  border-radius: var(--mon-radius);
  padding: 20px;
  box-shadow: var(--mon-shadow);
}

.denied-card,
.alerts-card {
  margin-bottom: 16px;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.card-header h3 {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--mon-ink);
}

.health-card h3,
.cache-card h3 {
  margin: 0 0 16px;
  font-size: 15px;
  font-weight: 600;
  color: var(--mon-ink);
}

.health-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.health-header h3 {
  margin: 0;
}

.health-score-ring {
  display: flex;
  justify-content: center;
  padding: 8px 0 16px;
}

.score-breakdown {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: -6px 0 12px;
}

.score-breakdown span {
  padding: 3px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: var(--mon-muted);
  font-size: 11px;
}

.sample-warning {
  margin-bottom: 10px;
  padding: 9px 12px;
  border-radius: 10px;
  background: #fffbeb;
  color: #b45309;
  font-size: 12px;
  text-align: center;
}

.score-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.score-inner strong {
  font-size: 32px;
  font-weight: 700;
  color: var(--mon-ink);
  line-height: 1;
}

.score-inner span {
  font-size: 12px;
  color: var(--mon-muted);
  margin-top: 4px;
}

.health-issues {
  padding-top: 12px;
  border-top: 1px solid var(--mon-border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.issue-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #dc2626;
}

.issue-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #ef4444;
  flex-shrink: 0;
}

.health-ok {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px;
  border-radius: 10px;
  background: #ecfdf5;
  color: #059669;
  font-size: 13px;
  font-weight: 500;
}

.ok-icon {
  font-size: 16px;
  font-weight: 700;
}

.cache-stats {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.cache-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cache-title h3 {
  margin: 0;
}

.cache-title span {
  color: var(--mon-muted);
  font-size: 12px;
}

.cache-scope-details {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cache-scope-details span {
  flex: 1 1 180px;
  padding: 8px 10px;
  border-radius: 8px;
  background: #f8fafc;
  color: var(--mon-muted);
  font-size: 12px;
}

.cache-stat.primary {
  padding: 14px;
  background: #f8fafc;
  border-radius: 12px;
}

.cache-stat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.cache-stat-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.cache-stat-mini {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px;
  background: #f8fafc;
  border-radius: 10px;
}

.cache-stat-mini strong {
  font-size: 20px;
  font-weight: 700;
  color: var(--mon-ink);
}

.stat-label {
  font-size: 12px;
  color: var(--mon-muted);
  font-weight: 500;
}

.stat-value {
  font-size: 18px;
  font-weight: 700;
}

.denied-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.denied-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  border-radius: 10px;
  transition: background 0.15s ease;
}

.denied-row:hover {
  background: #f8fafc;
}

.denied-rank {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: #f1f5f9;
  color: #94a3b8;
  font-size: 12px;
  font-weight: 700;
}

.denied-rank.top {
  background: linear-gradient(135deg, #ef4444, #f87171);
  color: #fff;
}

.denied-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.denied-info strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--mon-ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.denied-info small {
  font-size: 11px;
  color: var(--mon-muted);
}

.denied-count {
  font-size: 16px;
  font-weight: 700;
  color: #ef4444;
}

.alerts-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.alert-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--mon-border);
  transition: background 0.15s ease;
}

.alert-row:hover {
  background: #f8fafc;
}

.alert-row.error {
  border-color: #fecaca;
  background: #fef2f2;
}

.alert-row.warning {
  border-color: #fed7aa;
  background: #fffbeb;
}

.alert-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.alert-body strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--mon-ink);
}

.alert-body span {
  font-size: 12px;
  color: var(--mon-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alert-time {
  font-size: 11px;
  color: #94a3b8;
  white-space: nowrap;
}

@media (max-width: 1200px) {
  .stats-summary {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .stats-summary {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .overview-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 600px) {
  .stats-summary {
    grid-template-columns: 1fr;
  }
}
</style>
