<template>
  <div class="security-center">
    <section class="audit-metrics">
      <article v-for="card in metricCards" :key="card.label" class="metric-card" :class="card.tone">
        <div class="metric-icon">
          <component :is="card.icon" />
        </div>
        <div class="metric-body">
          <span class="metric-label">{{ card.label }}</span>
          <strong class="metric-value">{{ card.value }}</strong>
        </div>
      </article>
    </section>

    <section class="audit-grid">
      <article class="ranking-card">
        <div class="section-head">
          <div class="section-title-group">
            <h4>异常排行</h4>
          </div>
          <el-tag effect="plain" size="small" type="info">TOP {{ ipRiskStats.length }}</el-tag>
        </div>
        <div v-if="ipRiskStats.length" class="risk-rank-list">
          <div v-for="(item, index) in ipRiskStats" :key="item.ip" class="risk-rank-row">
            <span class="rank-no" :class="{ 'rank-top': index < 3 }">{{ String(index + 1).padStart(2, "0") }}</span>
            <div class="rank-user">
              <div class="rank-main-line">
                <strong>{{ item.ip }}</strong>
                <small>{{ item.location }}</small>
              </div>
              <div class="rank-meta-line">
                <span>{{ item.categoryText }}</span>
                <span>最后访问 {{ formatTime(item.lastSeenAt) }}</span>
              </div>
            </div>
            <div class="rank-count">
              <strong>{{ item.total }}</strong>
              <small :class="{ 'denied-highlight': item.highRiskCount > 0 }">{{ item.highRiskCount }} 高危</small>
            </div>
          </div>
        </div>
        <el-empty v-else description="暂无异常数据" :image-size="72" />
      </article>

      <article class="ranking-card event-distribution-card">
        <div class="section-head">
          <div class="section-title-group">
            <h4>事件分布</h4>
          </div>
        </div>
        <div class="distribution-section">
          <div class="distribution-section-head">
            <strong>访问的接口类型</strong>
          </div>
          <div v-if="endpointTypeStats.length" class="distribution-list">
            <div v-for="item in endpointTypeStats" :key="item.type" class="distribution-row">
              <div class="distribution-info">
                <strong>{{ item.type }}</strong>
                <small>{{ item.samplePath }}</small>
              </div>
              <div class="distribution-meter">
                <span :style="{ width: `${item.percent}%` }" />
              </div>
              <strong class="distribution-count">{{ item.total }}</strong>
            </div>
          </div>
          <el-empty v-else description="暂无接口类型数据" :image-size="72" />
        </div>

        <div class="distribution-section compact-risk-section">
          <div class="distribution-section-head">
            <strong>风险等级</strong>
          </div>
          <div class="risk-level-list">
            <div v-for="item in riskLevelStats" :key="item.value" class="risk-level-row">
              <span class="risk-dot" :class="item.tone" />
              <span>{{ item.label }}</span>
              <div class="risk-level-meter">
                <span :class="item.tone" :style="{ width: `${item.percent}%` }" />
              </div>
              <strong>{{ item.total }}</strong>
            </div>
          </div>
        </div>
      </article>
    </section>

    <section class="security-table-wrap">
      <div class="section-head table-head">
        <div class="section-title-group">
          <h4>安全事件明细</h4>
        </div>
        <section class="audit-filters detail-filters">
          <el-select v-model="severityFilter" placeholder="风险等级" clearable style="width: 130px" @change="onFilterChange">
            <el-option v-for="item in severityOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
          <el-select v-model="categoryFilter" placeholder="事件分类" clearable style="width: 150px" @change="onFilterChange">
            <el-option v-for="item in categoryOptions" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
          <el-select v-model="authFilter" placeholder="认证状态" clearable style="width: 140px" @change="onFilterChange">
            <el-option label="匿名" value="ANONYMOUS" />
            <el-option label="无效令牌" value="INVALID_TOKEN" />
            <el-option label="已认证" value="AUTHENTICATED" />
          </el-select>
          <el-input
            v-model="keyword"
            placeholder="搜索 IP、位置、账号、路径或 UA"
            clearable
            class="security-search"
            :prefix-icon="SearchIcon"
          />
          <el-button type="primary" :loading="loading" @click="loadSecurityEvents">刷新</el-button>
        </section>
        <el-tag effect="plain" size="small" type="info">{{ securityTotal }} 条</el-tag>
      </div>
      <el-table :data="paginatedEvents" v-loading="loading" class="security-table" table-layout="fixed">
        <el-table-column label="级别" width="96">
          <template #default="{ row }">
            <el-tag :type="severityTagType(row.severity)" effect="dark" size="small">{{ severityLabel(row.severity) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="分类" width="130">
          <template #default="{ row }">
            <span class="category-pill">{{ categoryLabel(row.category) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="时间" width="160">
          <template #default="{ row }">{{ formatTime(row.created_at) }}</template>
        </el-table-column>
        <el-table-column label="IP" width="132">
          <template #default="{ row }">{{ row.client_ip || "未知 IP" }}</template>
        </el-table-column>
        <el-table-column label="位置" width="180">
          <template #default="{ row }">{{ formatIpLocation(row) }}</template>
        </el-table-column>
        <el-table-column label="账号" width="140" prop="account_label" />
        <el-table-column label="请求" min-width="320">
          <template #default="{ row }">
            <div class="request-cell">
              <strong>{{ row.method }} {{ row.status_code }} / {{ resolveEndpointType(row.path) }}</strong>
              <span>{{ row.path }}</span>
            </div>
          </template>
        </el-table-column>
        <el-table-column label="耗时" width="86">
          <template #default="{ row }">{{ row.elapsed_ms.toFixed(1) }}ms</template>
        </el-table-column>
        <el-table-column label="操作" width="90" align="center">
          <template #default="{ row }">
            <el-button link type="primary" @click="openDetail(row)">详情</el-button>
          </template>
        </el-table-column>
      </el-table>
      <div v-if="securityTotal > 0" class="pagination-wrap">
        <el-pagination
          v-model:current-page="page"
          v-model:page-size="pageSize"
          :page-sizes="[10, 20, 50]"
          :total="securityTotal"
          layout="prev, pager, next, sizes, total"
          small
          @size-change="onPageSizeChange"
        />
      </div>
    </section>

    <el-drawer v-model="detailVisible" size="520px" direction="rtl" :show-close="false">
      <template #header>
        <div class="security-detail-head">
          <strong>安全事件详情</strong>
          <el-button size="small" @click="detailVisible = false">关闭</el-button>
        </div>
      </template>
      <div v-if="selectedEvent" class="security-detail">
        <div class="detail-grid">
          <div><span>级别</span><strong>{{ severityLabel(selectedEvent.severity) }}</strong></div>
          <div><span>分类</span><strong>{{ categoryLabel(selectedEvent.category) }}</strong></div>
          <div><span>状态码</span><strong>{{ selectedEvent.status_code }}</strong></div>
          <div><span>认证状态</span><strong>{{ authLabel(selectedEvent.auth_status) }}</strong></div>
          <div><span>IP</span><strong>{{ selectedEvent.client_ip || "未知" }}</strong></div>
          <div><span>位置</span><strong>{{ formatIpLocation(selectedEvent) }}</strong></div>
          <div><span>接口类型</span><strong>{{ resolveEndpointType(selectedEvent.path) }}</strong></div>
          <div><span>账号</span><strong>{{ selectedEvent.account_label }}</strong></div>
        </div>
        <div class="detail-section">
          <span>请求路径</span>
          <code>{{ selectedEvent.method }} {{ selectedEvent.path }}</code>
        </div>
        <div class="detail-section">
          <span>User Agent</span>
          <code>{{ selectedEvent.user_agent || "-" }}</code>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<script setup lang="ts">
import { computed, h, onMounted, ref, watch } from "vue";
import { Search as SearchIcon } from "@element-plus/icons-vue";
import { fetchSecurityAccessLogs } from "@/api/projectPermissions";
import type { SecurityAccessLogItem } from "@/types/api";

type MetricTone = "blue" | "cyan" | "danger" | "indigo";

const MetricIconShield = () => 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 MetricIconIp = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("circle", { cx: "12", cy: "10", r: "3" }),
  h("path", { d: "M12 21s7-5.2 7-11a7 7 0 1 0-14 0c0 5.8 7 11 7 11z" }),
]);
const MetricIconAlert = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("path", { d: "M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z" }),
  h("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
  h("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" }),
]);
const MetricIconServer = () => h("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2" }, [
  h("rect", { x: "3", y: "4", width: "18", height: "8", rx: "2" }),
  h("rect", { x: "3", y: "12", width: "18", height: "8", rx: "2" }),
  h("line", { x1: "7", y1: "8", x2: "7.01", y2: "8" }),
  h("line", { x1: "7", y1: "16", x2: "7.01", y2: "16" }),
]);

const loading = ref(false);
const statsEvents = ref<SecurityAccessLogItem[]>([]);
const page = ref(1);
const pageSize = ref(10);
const keyword = ref("");
const severityFilter = ref("");
const categoryFilter = ref("");
const authFilter = ref("");
const detailVisible = ref(false);
const selectedEvent = ref<SecurityAccessLogItem | null>(null);

const severityOptions = [
  { label: "严重", value: "CRITICAL", tone: "critical" },
  { label: "高", value: "HIGH", tone: "high" },
  { label: "中", value: "MEDIUM", tone: "medium" },
  { label: "低", value: "LOW", tone: "low" },
];

const categoryOptions = [
  { label: "敏感路径探测", value: "PROBE" },
  { label: "异常IP", value: "ABNORMAL_IP" },
  { label: "无效令牌", value: "INVALID_TOKEN" },
  { label: "服务异常", value: "SERVER_ERROR" },
  { label: "匿名 API", value: "ANONYMOUS_API" },
  { label: "普通 404", value: "NOT_FOUND_NOISE" },
  { label: "其他", value: "OTHER" },
];

const severityLabel = (value: string) => severityOptions.find((item) => item.value === value)?.label || value;
const categoryLabel = (value: string) => categoryOptions.find((item) => item.value === value)?.label || value;

const authLabel = (value: string) => {
  const labels: Record<string, string> = {
    ANONYMOUS: "匿名",
    INVALID_TOKEN: "无效令牌",
    AUTHENTICATED: "已认证",
  };
  return labels[value] || value;
};

const severityTagType = (value: string) => {
  if (value === "CRITICAL" || value === "HIGH") return "danger";
  if (value === "MEDIUM") return "warning";
  return "info";
};

const formatNumber = (value: number) => new Intl.NumberFormat("zh-CN").format(value || 0);
const formatTime = (value: string) => new Date(value).toLocaleString("zh-CN", { hour12: false });

const isHighRisk = (event: SecurityAccessLogItem) => event.severity === "CRITICAL" || event.severity === "HIGH";

const fallbackIpLocation = (ip: string | null) => {
  if (!ip) return "未知位置";
  if (ip === "127.0.0.1" || ip === "::1") return "本机访问";
  if (/^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[0-1])\.)/.test(ip)) return "内网地址";
  return "未知位置";
};

const formatIpLocation = (row: SecurityAccessLogItem) => {
  const parts = [
    row.ip_country && row.ip_country !== "中国" ? row.ip_country : "",
    row.ip_province,
    row.ip_city,
    row.ip_isp,
  ].filter(Boolean);
  if (parts.length) return parts.join(" / ");
  return row.ip_location || fallbackIpLocation(row.client_ip);
};

const resolveEndpointType = (path: string) => {
  const normalizedPath = path.toLowerCase();
  if (normalizedPath.includes("/auth") || normalizedPath.includes("/login")) return "认证接口";
  if (normalizedPath.startsWith("/api/")) return "业务 API";
  if (normalizedPath.match(/\.(js|css|png|jpg|jpeg|svg|ico|map)$/)) return "静态资源";
  if ([".env", "wp-", "php", "admin", "shell", "config"].some((marker) => normalizedPath.includes(marker))) return "探测路径";
  return "其他请求";
};

const detailFilteredEvents = computed(() => {
  const token = keyword.value.trim().toLowerCase();
  return statsEvents.value.filter((event) => {
    if (severityFilter.value && event.severity !== severityFilter.value) return false;
    if (categoryFilter.value && event.category !== categoryFilter.value) return false;
    if (authFilter.value && event.auth_status !== authFilter.value) return false;
    if (!token) return true;
    return [
      event.client_ip,
      formatIpLocation(event),
      event.account_label,
      event.path,
      resolveEndpointType(event.path),
      event.user_agent,
      event.auth_status,
      event.status_code,
    ].some((value) => String(value || "").toLowerCase().includes(token));
  });
});

const securityTotal = computed(() => detailFilteredEvents.value.length);

const paginatedEvents = computed(() => {
  const start = (page.value - 1) * pageSize.value;
  return detailFilteredEvents.value.slice(start, start + pageSize.value);
});

const countByCategory = (category: string) => statsEvents.value.filter((event) => event.category === category).length;

const metricCards = computed<Array<{ label: string; value: string; tone: MetricTone; icon: any }>>(() => {
  const uniqueIpCount = new Set(statsEvents.value.map((event) => event.client_ip || "未知 IP")).size;
  const highRiskCount = statsEvents.value.filter(isHighRisk).length;
  const serverErrorCount = countByCategory("SERVER_ERROR");
  return [
    { label: "安全事件", value: formatNumber(statsEvents.value.length), tone: "blue", icon: MetricIconShield },
    { label: "异常 IP", value: formatNumber(uniqueIpCount), tone: "cyan", icon: MetricIconIp },
    { label: "高危风险", value: formatNumber(highRiskCount), tone: highRiskCount > 0 ? "danger" : "indigo", icon: MetricIconAlert },
    { label: "服务异常", value: formatNumber(serverErrorCount), tone: serverErrorCount > 0 ? "danger" : "indigo", icon: MetricIconServer },
  ];
});

const ipRiskStats = computed(() => {
  const stats = new Map<string, { ip: string; location: string; categoryText: string; total: number; highRiskCount: number; lastSeenAt: string }>();
  statsEvents.value.forEach((event) => {
    const ip = event.client_ip || "未知 IP";
    const current = stats.get(ip) || {
      ip,
      location: formatIpLocation(event),
      categoryText: categoryLabel(event.category),
      total: 0,
      highRiskCount: 0,
      lastSeenAt: event.created_at,
    };
    current.total += 1;
    if (isHighRisk(event)) current.highRiskCount += 1;
    if (new Date(event.created_at).getTime() > new Date(current.lastSeenAt).getTime()) {
      current.lastSeenAt = event.created_at;
      current.categoryText = categoryLabel(event.category);
    }
    stats.set(ip, current);
  });
  return [...stats.values()].sort((a, b) => b.highRiskCount - a.highRiskCount || b.total - a.total).slice(0, 10);
});

const endpointTypeStats = computed(() => {
  const stats = new Map<string, { type: string; total: number; samplePath: string }>();
  statsEvents.value.forEach((event) => {
    const type = resolveEndpointType(event.path);
    const current = stats.get(type) || { type, total: 0, samplePath: event.path };
    current.total += 1;
    stats.set(type, current);
  });
  const maxTotal = Math.max(1, ...[...stats.values()].map((item) => item.total));
  return [...stats.values()]
    .sort((a, b) => b.total - a.total)
    .map((item) => ({ ...item, percent: Math.max(8, Math.round((item.total / maxTotal) * 100)) }));
});

const riskLevelStats = computed(() => {
  const filteredCounts = severityOptions.map((item) => ({
    ...item,
    total: statsEvents.value.filter((event) => event.severity === item.value).length,
  }));
  const maxTotal = Math.max(1, ...filteredCounts.map((item) => item.total));
  return filteredCounts.map((item) => {
    return {
      ...item,
      percent: item.total > 0 ? Math.max(8, Math.round((item.total / maxTotal) * 100)) : 0,
    };
  });
});

const SECURITY_STATS_PAGE_SIZE = 200;

const loadSecurityEvents = async () => {
  loading.value = true;
  try {
    await loadSecurityStats();
  } finally {
    loading.value = false;
  }
};

const loadSecurityStats = async () => {
  const first = await fetchSecurityAccessLogs({
    status_min: 400,
    auth_status: authFilter.value || undefined,
    page: 1,
    page_size: SECURITY_STATS_PAGE_SIZE,
  });
  const allItems = [...first.data.items];
  const total = first.data.total;
  const totalPages = Math.ceil(total / SECURITY_STATS_PAGE_SIZE);

  for (let nextPage = 2; nextPage <= totalPages; nextPage += 1) {
    const res = await fetchSecurityAccessLogs({
      status_min: 400,
      auth_status: authFilter.value || undefined,
      page: nextPage,
      page_size: SECURITY_STATS_PAGE_SIZE,
    });
    allItems.push(...res.data.items);
  }
  statsEvents.value = allItems;
};

const onFilterChange = () => {
  page.value = 1;
  loadSecurityEvents();
};

const onPageSizeChange = (size: number) => {
  pageSize.value = size;
  page.value = 1;
};

watch(keyword, () => {
  page.value = 1;
});

const openDetail = (event: SecurityAccessLogItem) => {
  selectedEvent.value = event;
  detailVisible.value = true;
};

onMounted(loadSecurityEvents);

defineExpose({ refresh: loadSecurityEvents });
</script>

<style scoped>
.security-center {
  --audit-ink: #1a2332;
  --audit-muted: #64748b;
  --audit-border: #e2e8f0;
  --audit-blue: #3b82f6;
  --audit-cyan: #06b6d4;
  --audit-danger: #ef4444;
  --audit-indigo: #6366f1;
  --card-radius: 16px;
  --card-shadow: 0 1px 3px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(0, 0, 0, 0.03);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.audit-filters {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  padding: 14px 18px;
  background: #fff;
  border-radius: var(--card-radius);
  border: 1px solid var(--audit-border);
  box-shadow: var(--card-shadow);
}

.security-search {
  width: 280px;
}

.audit-metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.metric-card {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 10px 16px;
  border-radius: var(--card-radius);
  background: #fff;
  border: 1px solid var(--audit-border);
  box-shadow: var(--card-shadow);
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

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

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

.metric-card.blue::before { background: linear-gradient(90deg, #3b82f6, #60a5fa); }
.metric-card.cyan::before { background: linear-gradient(90deg, #06b6d4, #22d3ee); }
.metric-card.danger::before { background: linear-gradient(90deg, #ef4444, #f87171); }
.metric-card.indigo::before { background: linear-gradient(90deg, #6366f1, #818cf8); }

.metric-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  flex-shrink: 0;
}

.metric-icon svg {
  width: 22px;
  height: 22px;
}

.metric-card.blue .metric-icon { background: #eff6ff; color: #3b82f6; }
.metric-card.cyan .metric-icon { background: #ecfeff; color: #06b6d4; }
.metric-card.danger .metric-icon { background: #fef2f2; color: #ef4444; }
.metric-card.indigo .metric-icon { background: #eef2ff; color: #6366f1; }

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

.metric-label {
  color: var(--audit-muted);
  font-size: 13px;
  font-weight: 500;
}

.metric-value {
  color: var(--audit-ink);
  font-size: 24px;
  font-weight: 700;
  line-height: 1.1;
}

.audit-grid {
  display: grid;
  grid-template-columns: minmax(320px, 1fr) minmax(0, 1.35fr);
  gap: 14px;
}

.ranking-card,
.security-table-wrap {
  min-width: 0;
  padding: 20px;
  border: 1px solid var(--audit-border);
  border-radius: var(--card-radius);
  background: #fff;
  box-shadow: var(--card-shadow);
}

.section-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}

.table-head {
  align-items: center;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.table-head .section-title-group {
  flex-shrink: 0;
}

.table-head .el-tag {
  margin-left: auto;
  flex-shrink: 0;
}

.detail-filters {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  box-shadow: none;
}

.section-title-group h4 {
  margin: 0;
  color: var(--audit-ink);
  font-size: 16px;
  font-weight: 600;
}

.section-title-group p {
  margin: 4px 0 0;
  color: var(--audit-muted);
  font-size: 12px;
}

.risk-rank-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

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

.risk-rank-row:hover {
  background: #f8fafc;
}

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

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

.rank-user,
.rank-count {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.rank-main-line,
.rank-meta-line {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

.rank-main-line strong {
  flex-shrink: 0;
  overflow: hidden;
  color: var(--audit-ink);
  font-size: 14px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rank-main-line small {
  overflow: hidden;
  color: var(--audit-muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rank-meta-line span {
  color: var(--audit-muted);
  font-size: 12px;
}

.rank-count {
  align-items: flex-end;
}

.rank-count strong {
  color: var(--audit-ink);
  font-size: 18px;
  font-weight: 700;
}

.rank-count small {
  color: var(--audit-muted);
  font-size: 11px;
}

.rank-count .denied-highlight {
  color: var(--audit-danger);
  font-weight: 600;
}

.distribution-list,
.risk-level-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.event-distribution-card {
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.distribution-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.distribution-section + .distribution-section {
  padding-top: 24px;
  border-top: 1px solid var(--audit-border);
}

.event-distribution-card > .section-head {
  margin-bottom: 0;
}

.event-distribution-card .section-title-group h4 {
  font-size: 16px;
}

.distribution-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.distribution-section-head strong {
  color: var(--audit-ink);
  font-size: 15px;
  font-weight: 700;
}

.distribution-row {
  display: grid;
  grid-template-columns: minmax(160px, 0.9fr) minmax(120px, 1fr) 44px;
  gap: 12px;
  align-items: center;
}

.distribution-info {
  min-width: 0;
}

.distribution-info strong {
  display: block;
  color: var(--audit-ink);
  font-size: 14px;
  font-weight: 600;
}

.distribution-info small {
  display: block;
  overflow: hidden;
  margin-top: 3px;
  color: var(--audit-muted);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.distribution-meter,
.risk-level-meter {
  overflow: hidden;
  height: 8px;
  border-radius: 999px;
  background: #f1f5f9;
}

.distribution-meter span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #06b6d4, #3b82f6);
}

.distribution-count {
  color: var(--audit-ink);
  font-size: 16px;
  text-align: right;
}

.risk-level-row {
  display: grid;
  grid-template-columns: 10px 52px minmax(0, 1fr) 44px;
  gap: 10px;
  align-items: center;
}

.risk-dot {
  width: 8px;
  height: 8px;
  border-radius: 999px;
}

.risk-dot.critical,
.risk-level-meter span.critical { background: #991b1b; }
.risk-dot.high,
.risk-level-meter span.high { background: #ef4444; }
.risk-dot.medium,
.risk-level-meter span.medium { background: #f59e0b; }
.risk-dot.low,
.risk-level-meter span.low { background: #64748b; }

.risk-level-row > span:nth-child(2) {
  color: var(--audit-ink);
  font-size: 13px;
  font-weight: 600;
}

.risk-level-meter span {
  display: block;
  height: 100%;
  border-radius: inherit;
}

.risk-level-row strong {
  color: var(--audit-ink);
  font-size: 14px;
  text-align: right;
}

.security-table-wrap {
  overflow: hidden;
}

.pagination-wrap {
  display: flex;
  justify-content: flex-end;
  margin-top: 10px;
  padding: 8px 16px 0;
}

.category-pill {
  display: inline-flex;
  align-items: center;
  max-width: 112px;
  padding: 3px 8px;
  border-radius: 999px;
  background: #eef2f7;
  color: #334155;
  font-size: 12px;
  font-weight: 600;
}

.request-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.request-cell strong {
  font-size: 12px;
  color: #475569;
}

.request-cell span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--audit-ink);
}

.security-detail-head {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
}

.security-detail {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.detail-grid div,
.detail-section {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px;
  border: 1px solid var(--audit-border);
  border-radius: 8px;
  background: #f8fafc;
}

.detail-grid span,
.detail-section span {
  color: var(--audit-muted);
  font-size: 12px;
}

.detail-grid strong {
  color: var(--audit-ink);
  font-size: 14px;
}

.detail-section code {
  white-space: pre-wrap;
  word-break: break-all;
  color: var(--audit-ink);
}

@media (max-width: 1100px) {
  .audit-metrics,
  .audit-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .audit-metrics,
  .audit-grid {
    grid-template-columns: 1fr;
  }

  .security-search {
    width: 100%;
  }

  .distribution-row {
    grid-template-columns: 1fr 44px;
  }

  .distribution-meter {
    grid-column: 1 / -1;
    grid-row: 2;
  }
}
</style>
